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; } }
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); }
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; } } } }
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); }
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); } }
/* 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; }
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; }
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); }
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); }