Beispiel #1
0
static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect)
{
    uint8_t *src;
    uint8_t *dst = ds_get_data(qxl->vga.ds);
    int len, i;

    if (is_buffer_shared(qxl->vga.ds->surface)) {
        return;
    }
    if (!qxl->guest_primary.data) {
        trace_qxl_render_blit_guest_primary_initialized();
        qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram);
    }
    trace_qxl_render_blit(qxl->guest_primary.qxl_stride,
            rect->left, rect->right, rect->top, rect->bottom);
    src = qxl->guest_primary.data;
    if (qxl->guest_primary.qxl_stride < 0) {
        /* qxl surface is upside down, walk src scanlines
         * in reverse order to flip it */
        src += (qxl->guest_primary.surface.height - rect->top - 1) *
            qxl->guest_primary.abs_stride;
    } else {
        src += rect->top * qxl->guest_primary.abs_stride;
    }
    dst += rect->top  * qxl->guest_primary.abs_stride;
    src += rect->left * qxl->guest_primary.bytes_pp;
    dst += rect->left * qxl->guest_primary.bytes_pp;
    len  = (rect->right - rect->left) * qxl->guest_primary.bytes_pp;

    for (i = rect->top; i < rect->bottom; i++) {
        memcpy(dst, src, len);
        dst += qxl->guest_primary.abs_stride;
        src += qxl->guest_primary.qxl_stride;
    }
}
Beispiel #2
0
static void sdl_setdata(DisplayState *ds)
{
    if (guest_screen != NULL) SDL_FreeSurface(guest_screen);

    guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds),
                                            ds_get_bits_per_pixel(ds), ds_get_linesize(ds),
                                            ds->surface->pf.rmask, ds->surface->pf.gmask,
                                            ds->surface->pf.bmask, ds->surface->pf.amask);
}
Beispiel #3
0
static void qemu_spice_create_update(SimpleSpiceDisplay *ssd)
{
    static const int blksize = 32;
    int blocks = (ds_get_width(ssd->ds) + blksize - 1) / blksize;
    int dirty_top[blocks];
    int y, yoff, x, xoff, blk, bw;
    int bpp = ds_get_bytes_per_pixel(ssd->ds);
    uint8_t *guest, *mirror;

    if (qemu_spice_rect_is_empty(&ssd->dirty)) {
        return;
    };

    if (ssd->conv == NULL) {
        PixelFormat dst = qemu_default_pixelformat(32);
        ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf);
        assert(ssd->conv);
    }
    if (ssd->ds_mirror == NULL) {
        int size = ds_get_height(ssd->ds) * ds_get_linesize(ssd->ds);
        ssd->ds_mirror = g_malloc0(size);
    }

    for (blk = 0; blk < blocks; blk++) {
        dirty_top[blk] = -1;
    }

    guest = ds_get_data(ssd->ds);
    mirror = ssd->ds_mirror;
    for (y = ssd->dirty.top; y < ssd->dirty.bottom; y++) {
        yoff = y * ds_get_linesize(ssd->ds);
        for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) {
            xoff = x * bpp;
            blk = x / blksize;
            bw = MIN(blksize, ssd->dirty.right - x);
            if (memcmp(guest + yoff + xoff,
                       mirror + yoff + xoff,
                       bw * bpp) == 0) {
                if (dirty_top[blk] != -1) {
                    QXLRect update = {
                        .top    = dirty_top[blk],
                        .bottom = y,
                        .left   = x,
                        .right  = x + bw,
                    };
                    qemu_spice_create_one_update(ssd, &update);
                    dirty_top[blk] = -1;
                }
            } else {
                if (dirty_top[blk] == -1) {
                    dirty_top[blk] = y;
                }
            }
        }
    }
Beispiel #4
0
Datei: sdl.c Projekt: CPFL/gxen
static void opengl_update(DisplayState *ds, int x, int y, int w, int h)
{  
    int bpp = ds_get_bytes_per_pixel(ds);
    GLvoid *pixels = ds_get_data(ds) + y * ds_get_linesize(ds) + x * bpp;
    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_ref);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, ds_get_linesize(ds) / bpp);
    glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, x, y, w, h, tex_format, tex_type, pixels);
    glBegin(GL_QUADS);
        glTexCoord2d(0, 0);
        glVertex2d(0, 0);
        glTexCoord2d(ds_get_width(ds), 0);
        glVertex2d(real_screen->w, 0);
        glTexCoord2d(ds_get_width(ds), ds_get_height(ds));
        glVertex2d(real_screen->w, real_screen->h);
        glTexCoord2d(0, ds_get_height(ds));
        glVertex2d(0, real_screen->h);
    glEnd();
    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
    SDL_GL_SwapBuffers();
}
/*
 * This copies data from the guest framebuffer region, into QEMU's
 * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
 * uses something else we must convert and copy, otherwise we can
 * supply the buffer directly and no thing here.
 */
static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
{
    int line, oops = 0;
    int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
    int linesize = ds_get_linesize(xenfb->c.ds);
    uint8_t *data = ds_get_data(xenfb->c.ds);

    if (!is_buffer_shared(xenfb->c.ds->surface)) {
        switch (xenfb->depth) {
        case 8:
            if (bpp == 16) {
                BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
            } else if (bpp == 32) {
                BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
            } else {
                oops = 1;
            }
            break;
        case 24:
            if (bpp == 16) {
                BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
            } else if (bpp == 32) {
                BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
            } else {
                oops = 1;
            }
            break;
        default:
            oops = 1;
	}
    }
    if (oops) /* should not happen */
        xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
                      __FUNCTION__, xenfb->depth, bpp);

    dpy_update(xenfb->c.ds, x, y, w, h);
}
Beispiel #6
0
Datei: tcx.c Projekt: asias/qemu
static void tcx24_update_display(void *opaque)
{
    TCXState *ts = opaque;
    ram_addr_t page, page_min, page_max, cpage, page24;
    int y, y_start, dd, ds;
    uint8_t *d, *s;
    uint32_t *cptr, *s24;

    if (ds_get_bits_per_pixel(ts->ds) != 32)
            return;
    page = 0;
    page24 = ts->vram24_offset;
    cpage = ts->cplane_offset;
    y_start = -1;
    page_min = -1;
    page_max = 0;
    d = ds_get_data(ts->ds);
    s = ts->vram;
    s24 = ts->vram24;
    cptr = ts->cplane;
    dd = ds_get_linesize(ts->ds);
    ds = 1024;

    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
            page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
        if (check_dirty(ts, page, page24, cpage)) {
            if (y_start < 0)
                y_start = y;
            if (page < page_min)
                page_min = page;
            if (page > page_max)
                page_max = page;
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
            d += dd;
            s += ds;
            cptr += ds;
            s24 += ds;
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
            d += dd;
            s += ds;
            cptr += ds;
            s24 += ds;
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
            d += dd;
            s += ds;
            cptr += ds;
            s24 += ds;
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
            d += dd;
            s += ds;
            cptr += ds;
            s24 += ds;
        } else {
            if (y_start >= 0) {
                /* flush to display */
                dpy_update(ts->ds, 0, y_start,
                           ts->width, y - y_start);
                y_start = -1;
            }
            d += dd * 4;
            s += ds * 4;
            cptr += ds * 4;
            s24 += ds * 4;
        }
    }
    if (y_start >= 0) {
        /* flush to display */
        dpy_update(ts->ds, 0, y_start,
                   ts->width, y - y_start);
    }
    /* reset modified pages */
    if (page_max >= page_min) {
        reset_dirty(ts, page_min, page_max, page24, cpage);
    }
}
Beispiel #7
0
Datei: tcx.c Projekt: asias/qemu
/* Fixed line length 1024 allows us to do nice tricks not possible on
   VGA... */
static void tcx_update_display(void *opaque)
{
    TCXState *ts = opaque;
    ram_addr_t page, page_min, page_max;
    int y, y_start, dd, ds;
    uint8_t *d, *s;
    void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);

    if (ds_get_bits_per_pixel(ts->ds) == 0)
        return;
    page = 0;
    y_start = -1;
    page_min = -1;
    page_max = 0;
    d = ds_get_data(ts->ds);
    s = ts->vram;
    dd = ds_get_linesize(ts->ds);
    ds = 1024;

    switch (ds_get_bits_per_pixel(ts->ds)) {
    case 32:
        f = tcx_draw_line32;
        break;
    case 15:
    case 16:
        f = tcx_draw_line16;
        break;
    default:
    case 8:
        f = tcx_draw_line8;
        break;
    case 0:
        return;
    }

    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
        if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE,
                                    DIRTY_MEMORY_VGA)) {
            if (y_start < 0)
                y_start = y;
            if (page < page_min)
                page_min = page;
            if (page > page_max)
                page_max = page;
            f(ts, d, s, ts->width);
            d += dd;
            s += ds;
            f(ts, d, s, ts->width);
            d += dd;
            s += ds;
            f(ts, d, s, ts->width);
            d += dd;
            s += ds;
            f(ts, d, s, ts->width);
            d += dd;
            s += ds;
        } else {
            if (y_start >= 0) {
                /* flush to display */
                dpy_update(ts->ds, 0, y_start,
                           ts->width, y - y_start);
                y_start = -1;
            }
            d += dd * 4;
            s += ds * 4;
        }
    }
    if (y_start >= 0) {
        /* flush to display */
        dpy_update(ts->ds, 0, y_start,
                   ts->width, y - y_start);
    }
    /* reset modified pages */
    if (page_max >= page_min) {
        memory_region_reset_dirty(&ts->vram_mem,
                                  page_min, page_max + TARGET_PAGE_SIZE,
                                  DIRTY_MEMORY_VGA);
    }
}
static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
{
    SimpleSpiceUpdate *update;
    QXLDrawable *drawable;
    QXLImage *image;
    QXLCommand *cmd;
    uint8_t *src, *dst;
    int by, bw, bh;
    struct timespec time_space;

    if (qemu_spice_rect_is_empty(&ssd->dirty)) {
        return NULL;
    };

    trace_qemu_spice_create_update(
           ssd->dirty.left, ssd->dirty.right,
           ssd->dirty.top, ssd->dirty.bottom);

    update   = g_malloc0(sizeof(*update));
    drawable = &update->drawable;
    image    = &update->image;
    cmd      = &update->ext.cmd;

    bw       = ssd->dirty.right - ssd->dirty.left;
    bh       = ssd->dirty.bottom - ssd->dirty.top;
    update->bitmap = g_malloc(bw * bh * 4);

    drawable->bbox            = ssd->dirty;
    drawable->clip.type       = SPICE_CLIP_TYPE_NONE;
    drawable->effect          = QXL_EFFECT_OPAQUE;
    drawable->release_info.id = (uintptr_t)update;
    drawable->type            = QXL_DRAW_COPY;
    drawable->surfaces_dest[0] = -1;
    drawable->surfaces_dest[1] = -1;
    drawable->surfaces_dest[2] = -1;
    clock_gettime(CLOCK_MONOTONIC, &time_space);
    /* time in milliseconds from epoch. */
    drawable->mm_time = time_space.tv_sec * 1000
                      + time_space.tv_nsec / 1000 / 1000;

    drawable->u.copy.rop_descriptor  = SPICE_ROPD_OP_PUT;
    drawable->u.copy.src_bitmap      = (uintptr_t)image;
    drawable->u.copy.src_area.right  = bw;
    drawable->u.copy.src_area.bottom = bh;

    QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ssd->unique++);
    image->descriptor.type   = SPICE_IMAGE_TYPE_BITMAP;
    image->bitmap.flags      = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN;
    image->bitmap.stride     = bw * 4;
    image->descriptor.width  = image->bitmap.x = bw;
    image->descriptor.height = image->bitmap.y = bh;
    image->bitmap.data = (uintptr_t)(update->bitmap);
    image->bitmap.palette = 0;
    image->bitmap.format = SPICE_BITMAP_FMT_32BIT;

    if (ssd->conv == NULL) {
        PixelFormat dst = qemu_default_pixelformat(32);
        ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf);
        assert(ssd->conv);
    }

    src = ds_get_data(ssd->ds) +
        ssd->dirty.top * ds_get_linesize(ssd->ds) +
        ssd->dirty.left * ds_get_bytes_per_pixel(ssd->ds);
    dst = update->bitmap;
    for (by = 0; by < bh; by++) {
        qemu_pf_conv_run(ssd->conv, dst, src, bw);
        src += ds_get_linesize(ssd->ds);
        dst += image->bitmap.stride;
    }

    cmd->type = QXL_CMD_DRAW;
    cmd->data = (uintptr_t)drawable;

    memset(&ssd->dirty, 0, sizeof(ssd->dirty));
    return update;
}
void framebuffer_update_display(
    DisplayState *ds,
    MemoryRegion *address_space,
    target_phys_addr_t base,
    int cols, /* Width in pixels.  */
    int rows, /* Height in pixels.  */
    int src_width, /* Length of source line, in bytes.  */
    int dest_row_pitch, /* Bytes between adjacent horizontal output pixels.  */
    int dest_col_pitch, /* Bytes between adjacent vertical output pixels.  */
    int invalidate, /* nonzero to redraw the whole image.  */
    drawfn fn,
    void *opaque,
    int *first_row, /* Input and output.  */
    int *last_row /* Output only */)
{
    target_phys_addr_t src_len;
    uint8_t *dest;
    uint8_t *src;
    uint8_t *src_base;
    int first, last = 0;
    int dirty;
    int i;
    ram_addr_t addr;
    MemoryRegionSection mem_section;
    MemoryRegion *mem;

    i = *first_row;
    *first_row = -1;
    src_len = src_width * rows;

    mem_section = memory_region_find(address_space, base, src_len);
    if (mem_section.size != src_len || !memory_region_is_ram(mem_section.mr)) {
        return;
    }
    mem = mem_section.mr;
    assert(mem);
    assert(mem_section.offset_within_address_space == base);

    memory_region_sync_dirty_bitmap(mem);
    src_base = cpu_physical_memory_map(base, &src_len, 0);
    /* If we can't map the framebuffer then bail.  We could try harder,
       but it's not really worth it as dirty flag tracking will probably
       already have failed above.  */
    if (!src_base)
        return;
    if (src_len != src_width * rows) {
        cpu_physical_memory_unmap(src_base, src_len, 0, 0);
        return;
    }
    src = src_base;
    dest = ds_get_data(ds);
    if (dest_col_pitch < 0)
        dest -= dest_col_pitch * (cols - 1);
    if (dest_row_pitch < 0) {
        dest -= dest_row_pitch * (rows - 1);
    }
    first = -1;
    addr = mem_section.offset_within_region;

    addr += i * src_width;
    src += i * src_width;
    dest += i * dest_row_pitch;

    for (; i < rows; i++) {
        dirty = memory_region_get_dirty(mem, addr, src_width,
                                             DIRTY_MEMORY_VGA);
        if (dirty || invalidate) {
            fn(opaque, dest, src, cols, dest_col_pitch);
            if (first == -1)
                first = i;
            last = i;
        }
        addr += src_width;
        src += src_width;
        dest += dest_row_pitch;
    }
    cpu_physical_memory_unmap(src_base, src_len, 0, 0);
    if (first < 0) {
        return;
    }
    memory_region_reset_dirty(mem, mem_section.offset_within_region, src_len,
                              DIRTY_MEMORY_VGA);
    *first_row = first;
    *last_row = last;
    return;
}
Beispiel #10
0
void framebuffer_update_display(
    DisplayState *ds,
    target_phys_addr_t base,
    int cols, /* Width in pixels.  */
    int rows, /* Leight in pixels.  */
    int src_width, /* Length of source line, in bytes.  */
    int dest_row_pitch, /* Bytes between adjacent horizontal output pixels.  */
    int dest_col_pitch, /* Bytes between adjacent vertical output pixels.  */
    int invalidate, /* nonzero to redraw the whole image.  */
    drawfn fn,
    void *opaque,
    int *first_row, /* Input and output.  */
    int *last_row /* Output only */)
{
    target_phys_addr_t src_len;
    uint8_t *dest;
    uint8_t *src;
    uint8_t *src_base;
    int first, last = 0;
    int dirty;
    int i;
    ram_addr_t addr;
    ram_addr_t pd;
    ram_addr_t pd2;

    i = *first_row;
    *first_row = -1;
    src_len = src_width * rows;

    cpu_physical_sync_dirty_bitmap(base, base + src_len);
    pd = cpu_get_physical_page_desc(base);
    pd2 = cpu_get_physical_page_desc(base + src_len - 1);
    /* We should reall check that this is a continuous ram region.
       Instead we just check that the first and last pages are
       both ram, and the right distance apart.  */
    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM
        || (pd2 & ~TARGET_PAGE_MASK) > IO_MEM_ROM) {
        return;
    }
    pd = (pd & TARGET_PAGE_MASK) + (base & ~TARGET_PAGE_MASK);
    if (((pd + src_len - 1) & TARGET_PAGE_MASK) != (pd2 & TARGET_PAGE_MASK)) {
        return;
    }

    src_base = cpu_physical_memory_map(base, &src_len, 0);
    /* If we can't map the framebuffer then bail.  We could try harder,
       but it's not really worth it as dirty flag tracking will probably
       already have failed above.  */
    if (!src_base)
        return;
    if (src_len != src_width * rows) {
        cpu_physical_memory_unmap(src_base, src_len, 0, 0);
        return;
    }
    src = src_base;
    dest = ds_get_data(ds);
    if (dest_col_pitch < 0)
        dest -= dest_col_pitch * (cols - 1);
    if (dest_row_pitch < 0) {
        dest -= dest_row_pitch * (rows - 1);
    }
    first = -1;
    addr = pd;

    addr += i * src_width;
    src += i * src_width;
    dest += i * dest_row_pitch;

    for (; i < rows; i++) {
        target_phys_addr_t dirty_offset;
        dirty = 0;
        dirty_offset = 0;
        while (addr + dirty_offset < TARGET_PAGE_ALIGN(addr + src_width)) {
            dirty |= cpu_physical_memory_get_dirty(addr + dirty_offset,
                                                   VGA_DIRTY_FLAG);
            dirty_offset += TARGET_PAGE_SIZE;
        }

        if (dirty || invalidate) {
            fn(opaque, dest, src, cols, dest_col_pitch);
            if (first == -1)
                first = i;
            last = i;
        }
        addr += src_width;
        src += src_width;
        dest += dest_row_pitch;
    }
    cpu_physical_memory_unmap(src_base, src_len, 0, 0);
    if (first < 0) {
        return;
    }
    cpu_physical_memory_reset_dirty(pd, pd + src_len, VGA_DIRTY_FLAG);
    *first_row = first;
    *last_row = last;
    return;
}
Beispiel #11
0
static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd,
        QXLRect *rect)
{
    SimpleSpiceUpdate *update;
    QXLDrawable *drawable;
    QXLImage *image;
    QXLCommand *cmd;
    uint8_t *src, *mirror, *dst;
    int by, bw, bh, offset, bytes;

    trace_qemu_spice_create_update(
        rect->left, rect->right,
        rect->top, rect->bottom);

    update   = qemu_mallocz(sizeof(*update));
    drawable = &update->drawable;
    image    = &update->image;
    cmd      = &update->ext.cmd;

    bw       = rect->right - rect->left;
    bh       = rect->bottom - rect->top;
    update->bitmap = qemu_malloc(bw * bh * 4);

    drawable->bbox            = *rect;
    drawable->clip.type       = SPICE_CLIP_TYPE_NONE;
    drawable->effect          = QXL_EFFECT_OPAQUE;
    drawable->release_info.id = (intptr_t)update;
    drawable->type            = QXL_DRAW_COPY;
    drawable->surfaces_dest[0] = -1;
    drawable->surfaces_dest[1] = -1;
    drawable->surfaces_dest[2] = -1;

    drawable->u.copy.rop_descriptor  = SPICE_ROPD_OP_PUT;
    drawable->u.copy.src_bitmap      = (intptr_t)image;
    drawable->u.copy.src_area.right  = bw;
    drawable->u.copy.src_area.bottom = bh;

    QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ssd->unique++);
    image->descriptor.type   = SPICE_IMAGE_TYPE_BITMAP;
    image->bitmap.flags      = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN;
    image->bitmap.stride     = bw * 4;
    image->descriptor.width  = image->bitmap.x = bw;
    image->descriptor.height = image->bitmap.y = bh;
    image->bitmap.data = (intptr_t)(update->bitmap);
    image->bitmap.palette = 0;
    image->bitmap.format = SPICE_BITMAP_FMT_32BIT;

    offset =
        rect->top * ds_get_linesize(ssd->ds) +
        rect->left * ds_get_bytes_per_pixel(ssd->ds);
    bytes = ds_get_bytes_per_pixel(ssd->ds) * bw;
    src = ds_get_data(ssd->ds) + offset;
    mirror = ssd->ds_mirror + offset;
    dst = update->bitmap;
    for (by = 0; by < bh; by++) {
        memcpy(mirror, src, bytes);
        qemu_pf_conv_run(ssd->conv, dst, mirror, bw);
        src += ds_get_linesize(ssd->ds);
        mirror += ds_get_linesize(ssd->ds);
        dst += image->bitmap.stride;
    }

    cmd->type = QXL_CMD_DRAW;
    cmd->data = (intptr_t)drawable;

    QTAILQ_INSERT_TAIL(&ssd->updates, update, next);
}
Beispiel #12
0
Datei: sdl.c Projekt: CPFL/gxen
static void opengl_setdata(DisplayState *ds)
{
    glEnable(GL_TEXTURE_RECTANGLE_ARB);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glClearColor(0, 0, 0, 0);
    glDisable(GL_BLEND);
    glDisable(GL_LIGHTING);
    glDisable(GL_DEPTH_TEST);
    glDepthMask(GL_FALSE);
    glDisable(GL_CULL_FACE);
    glViewport( 0, 0, real_screen->w, real_screen->h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, real_screen->w, real_screen->h, 0, -1,1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glClear(GL_COLOR_BUFFER_BIT);

    if (texture_ref) {
        glDeleteTextures(1, &texture_ref);
        texture_ref = 0;
    }

    glGenTextures(1, &texture_ref);
    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_ref);
    glPixelStorei(GL_UNPACK_LSB_FIRST, 1);
    switch (ds_get_bits_per_pixel(ds)) {
        case 16:
            tex_format = GL_RGB;
            tex_type = GL_UNSIGNED_SHORT_5_6_5;
            break;
        case 24:
            tex_format = GL_BGR;
            tex_type = GL_UNSIGNED_BYTE;
            break;
        case 32:
            if (bgr == (ds->surface->pf.rshift < ds->surface->pf.bshift)) {
                tex_format = GL_BGRA;
                tex_type = GL_UNSIGNED_BYTE;
            } else {
                tex_format = GL_RGBA;
                tex_type = GL_UNSIGNED_BYTE;                
            }
            break;
    }   
    glPixelStorei(GL_UNPACK_ROW_LENGTH, (ds_get_linesize(ds) / ds_get_bytes_per_pixel(ds)));
    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, gl_format, ds_get_width(ds), ds_get_height(ds), 0, tex_format, tex_type, ds_get_data(ds));
    glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_PRIORITY, 1.0);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
}