static void draw_vertical_line(DisplaySurface *ds, int posx, int posy1, int posy2, uint32_t color) { uint8_t *d; int y, bpp; bpp = (surface_bits_per_pixel(ds) + 7) >> 3; d = surface_data(ds) + surface_stride(ds) * posy1 + bpp * posx; switch(bpp) { case 1: for (y = posy1; y <= posy2; y++) { *((uint8_t *)d) = color; d += surface_stride(ds); } break; case 2: for (y = posy1; y <= posy2; y++) { *((uint16_t *)d) = color; d += surface_stride(ds); } break; case 4: for (y = posy1; y <= posy2; y++) { *((uint32_t *)d) = color; d += surface_stride(ds); } break; } }
void surface_gl_create_texture(ConsoleGLState *gls, DisplaySurface *surface) { assert(gls); assert(surface_stride(surface) % surface_bytes_per_pixel(surface) == 0); switch (surface->format) { case PIXMAN_BE_b8g8r8x8: case PIXMAN_BE_b8g8r8a8: surface->glformat = GL_BGRA_EXT; surface->gltype = GL_UNSIGNED_BYTE; break; case PIXMAN_r5g6b5: surface->glformat = GL_RGB; surface->gltype = GL_UNSIGNED_SHORT_5_6_5; break; default: g_assert_not_reached(); } glGenTextures(1, &surface->texture); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, surface->texture); glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, surface_stride(surface) / surface_bytes_per_pixel(surface)); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, surface_width(surface), surface_height(surface), 0, surface->glformat, surface->gltype, surface_data(surface)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); }
static void draw_horizontal_line(DisplaySurface *ds, int posy, int posx1, int posx2, uint32_t color) { uint8_t *d; int x, bpp; bpp = (surface_bits_per_pixel(ds) + 7) >> 3; d = surface_data(ds) + surface_stride(ds) * posy + bpp * posx1; switch(bpp) { case 1: for (x = posx1; x <= posx2; x++) { *((uint8_t *)d) = color; d++; } break; case 2: for (x = posx1; x <= posx2; x++) { *((uint16_t *)d) = color; d += 2; } break; case 4: for (x = posx1; x <= posx2; x++) { *((uint32_t *)d) = color; d += 4; } break; } }
static uint32_t vigs_dpy_get_stride(void *user_data) { VIGSState *s = user_data; DisplaySurface *ds = qemu_console_surface(s->con); return surface_stride(ds); }
static void sdl_switch(DisplayChangeListener *dcl, DisplaySurface *new_surface) { PixelFormat pf; /* temporary hack: allows to call sdl_switch to handle scaling changes */ if (new_surface) { surface = new_surface; } pf = qemu_pixelformat_from_pixman(surface->format); if (!scaling_active) { do_sdl_resize(surface_width(surface), surface_height(surface), 0); } else if (real_screen->format->BitsPerPixel != surface_bits_per_pixel(surface)) { do_sdl_resize(real_screen->w, real_screen->h, surface_bits_per_pixel(surface)); } if (guest_screen != NULL) { SDL_FreeSurface(guest_screen); } #ifdef DEBUG_SDL printf("SDL: Creating surface with masks: %08x %08x %08x %08x\n", pf.rmask, pf.gmask, pf.bmask, pf.amask); #endif guest_screen = SDL_CreateRGBSurfaceFrom (surface_data(surface), surface_width(surface), surface_height(surface), surface_bits_per_pixel(surface), surface_stride(surface), pf.rmask, pf.gmask, pf.bmask, pf.amask); }
void surface_gl_update_texture(ConsoleGLState *gls, DisplaySurface *surface, int x, int y, int w, int h) { uint8_t *data = (void *)surface_data(surface); assert(gls); glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, surface_stride(surface) / surface_bytes_per_pixel(surface)); glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, surface->glformat, surface->gltype, data + surface_stride(surface) * y + surface_bytes_per_pixel(surface) * x); }
static void sdl_switch(DisplayChangeListener *dcl, DisplaySurface *new_surface) { /* temporary hack: allows to call sdl_switch to handle scaling changes */ if (new_surface) { surface = new_surface; } if (!scaling_active) { do_sdl_resize(surface_width(surface), surface_height(surface), 0); } else if (real_screen->format->BitsPerPixel != surface_bits_per_pixel(surface)) { do_sdl_resize(real_screen->w, real_screen->h, surface_bits_per_pixel(surface)); } if (guest_screen != NULL) { SDL_FreeSurface(guest_screen); } guest_screen = SDL_CreateRGBSurfaceFrom (surface_data(surface), surface_width(surface), surface_height(surface), surface_bits_per_pixel(surface), surface_stride(surface), surface->pf.rmask, surface->pf.gmask, surface->pf.bmask, surface->pf.amask); }
static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) { static const int blksize = 32; int blocks = (surface_width(ssd->ds) + blksize - 1) / blksize; int dirty_top[blocks]; int y, yoff, x, xoff, blk, bw; int bpp = surface_bytes_per_pixel(ssd->ds); uint8_t *guest, *mirror; if (qemu_spice_rect_is_empty(&ssd->dirty)) { return; }; if (ssd->surface == NULL) { ssd->surface = pixman_image_ref(ssd->ds->image); ssd->mirror = qemu_pixman_mirror_create(ssd->ds->format, ssd->ds->image); } for (blk = 0; blk < blocks; blk++) { dirty_top[blk] = -1; } guest = surface_data(ssd->ds); mirror = (void *)pixman_image_get_data(ssd->mirror); for (y = ssd->dirty.top; y < ssd->dirty.bottom; y++) { yoff = y * surface_stride(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; } } } }
void sdl2_2d_update(DisplayChangeListener *dcl, int x, int y, int w, int h) { struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); DisplaySurface *surf = qemu_console_surface(dcl->con); SDL_Rect rect; assert(!scon->opengl); if (!surf) { return; } if (!scon->texture) { return; } /* * SDL2 seems to do some double-buffering, and trying to only * update the changed areas results in only one of the two buffers * being updated. Which flickers alot. So lets not try to be * clever do a full update every time ... */ #if 0 rect.x = x; rect.y = y; rect.w = w; rect.h = h; #else rect.x = 0; rect.y = 0; rect.w = surface_width(surf); rect.h = surface_height(surf); #endif SDL_UpdateTexture(scon->texture, NULL, surface_data(surf), surface_stride(surf)); #if defined( __ANDROID__) && defined (__LIMBO_SDL_FORCE_HARDWARE_RENDERING__) //Android OPENGL ES needs full screen redraw SDL_SetRenderDrawColor( scon->real_renderer, 0, 0, 0, 255 ); SDL_RenderClear( scon->real_renderer ); SDL_RenderCopy(scon->real_renderer, scon->texture, NULL, NULL); #else SDL_RenderCopy(scon->real_renderer, scon->texture, &rect, &rect); #endif //__ANDROID__ SDL_RenderPresent(scon->real_renderer); }
static void jazz_led_update_display(void *opaque) { LedState *s = opaque; DisplaySurface *surface = qemu_console_surface(s->con); uint8_t *d1; uint32_t color_segment, color_led; int y, bpp; if (s->state & REDRAW_BACKGROUND) { /* clear screen */ bpp = (surface_bits_per_pixel(surface) + 7) >> 3; d1 = surface_data(surface); for (y = 0; y < surface_height(surface); y++) { memset(d1, 0x00, surface_width(surface) * bpp); d1 += surface_stride(surface); } }
static void tc6393xb_draw_blank(TC6393xbState *s, int full_update) { DisplaySurface *surface = qemu_console_surface(s->con); int i, w; uint8_t *d; if (!full_update) return; w = s->scr_width * surface_bytes_per_pixel(surface); d = surface_data(surface); for(i = 0; i < s->scr_height; i++) { memset(d, 0, w); d += surface_stride(surface); } dpy_gfx_update(s->con, 0, 0, s->scr_width, s->scr_height); }
static int goldfish_fb_load(QEMUFile* f, void* opaque, int version_id) { struct goldfish_fb_state* s = opaque; int ret = -1; int ds_w, ds_h, ds_pitch, ds_rot; if (version_id != GOLDFISH_FB_SAVE_VERSION) goto Exit; ds_w = qemu_get_be32(f); ds_h = qemu_get_be32(f); ds_pitch = qemu_get_be32(f); ds_rot = qemu_get_byte(f); DisplaySurface *ds = qemu_console_surface(s->con); if (surface_width(ds) != ds_w || surface_height(ds) != ds_h || surface_stride(ds) != ds_pitch || ds_rot != 0) { /* XXX: We should be able to force a resize/rotation from here ? */ fprintf(stderr, "%s: framebuffer dimensions mismatch\n", __FUNCTION__); goto Exit; } s->fb_base = qemu_get_be32(f); s->base_valid = qemu_get_byte(f); s->need_update = qemu_get_byte(f); s->need_int = qemu_get_byte(f); s->blank = qemu_get_byte(f); s->int_status = qemu_get_be32(f); s->int_enable = qemu_get_be32(f); s->rotation = qemu_get_be32(f); s->dpi = qemu_get_be32(f); s->format = qemu_get_be32(f); /* force a refresh */ s->need_update = 1; ret = 0; Exit: return ret; }
void sdl2_2d_update(DisplayChangeListener *dcl, int x, int y, int w, int h) { struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); DisplaySurface *surf = qemu_console_surface(dcl->con); SDL_Rect rect; assert(!scon->opengl); if (!surf) { return; } if (!scon->texture) { return; } /* * SDL2 seems to do some double-buffering, and trying to only * update the changed areas results in only one of the two buffers * being updated. Which flickers alot. So lets not try to be * clever do a full update every time ... */ #if 0 rect.x = x; rect.y = y; rect.w = w; rect.h = h; #else rect.x = 0; rect.y = 0; rect.w = surface_width(surf); rect.h = surface_height(surf); #endif SDL_UpdateTexture(scon->texture, NULL, surface_data(surf), surface_stride(surf)); SDL_RenderCopy(scon->real_renderer, scon->texture, &rect, &rect); SDL_RenderPresent(scon->real_renderer); }
static void goldfish_fb_save(QEMUFile* f, void* opaque) { struct goldfish_fb_state* s = opaque; DisplaySurface *ds = qemu_console_surface(s->con); qemu_put_be32(f, surface_width(ds)); qemu_put_be32(f, surface_height(ds)); qemu_put_be32(f, surface_stride(ds)); qemu_put_byte(f, 0); qemu_put_be32(f, s->fb_base); qemu_put_byte(f, s->base_valid); qemu_put_byte(f, s->need_update); qemu_put_byte(f, s->need_int); qemu_put_byte(f, s->blank); qemu_put_be32(f, s->int_status); qemu_put_be32(f, s->int_enable); qemu_put_be32(f, s->rotation); qemu_put_be32(f, s->dpi); qemu_put_be32(f, s->format); }
/* * 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) { DisplaySurface *surface = qemu_console_surface(xenfb->c.con); int line, oops = 0; int bpp = surface_bits_per_pixel(surface); int linesize = surface_stride(surface); uint8_t *data = surface_data(surface); if (!is_buffer_shared(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_gfx_update(xenfb->c.con, x, y, w, h); }
static void sdl_update(DisplayChangeListener *dcl, int x, int y, int w, int h) { struct sdl2_state *scon = container_of(dcl, struct sdl2_state, dcl); SDL_Rect rect; DisplaySurface *surf = qemu_console_surface(dcl->con); if (!surf) { return; } if (!scon->texture) { return; } rect.x = x; rect.y = y; rect.w = w; rect.h = h; SDL_UpdateTexture(scon->texture, NULL, surface_data(surf), surface_stride(surf)); SDL_RenderCopy(scon->real_renderer, scon->texture, &rect, &rect); SDL_RenderPresent(scon->real_renderer); }
static void tcx24_update_display(void *opaque) { TCXState *ts = opaque; DisplaySurface *surface = qemu_console_surface(ts->con); 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 (surface_bits_per_pixel(surface) != 32) { return; } page = 0; page24 = ts->vram24_offset; cpage = ts->cplane_offset; y_start = -1; page_min = -1; page_max = 0; d = surface_data(surface); s = ts->vram; s24 = ts->vram24; cptr = ts->cplane; dd = surface_stride(surface); 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_gfx_update(ts->con, 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_gfx_update(ts->con, 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); } }
static void goldfish_fb_update_display(void *opaque) { struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque; DisplaySurface *ds = qemu_console_surface(s->con); int full_update = 0; if (!s || !s->con || surface_bits_per_pixel(ds) == 0 || !s->fb_base) return; if((s->int_enable & FB_INT_VSYNC) && !(s->int_status & FB_INT_VSYNC)) { s->int_status |= FB_INT_VSYNC; qemu_irq_raise(s->irq); } if(s->need_update) { full_update = 1; if(s->need_int) { s->int_status |= FB_INT_BASE_UPDATE_DONE; if(s->int_enable & FB_INT_BASE_UPDATE_DONE) qemu_irq_raise(s->irq); } s->need_int = 0; s->need_update = 0; } int dest_width = surface_width(ds); int dest_height = surface_height(ds); int dest_pitch = surface_stride(ds); int ymin, ymax; #if STATS if (full_update) stats_full_updates += 1; if (++stats_counter == 120) { stats_total += stats_counter; stats_total_full_updates += stats_full_updates; trace_goldfish_fb_update_stats(stats_full_updates*100.0/stats_counter, stats_total_full_updates*100.0/stats_total ); stats_counter = 0; stats_full_updates = 0; } #endif /* STATS */ if (s->blank) { void *dst_line = surface_data(ds); memset( dst_line, 0, dest_height*dest_pitch ); ymin = 0; ymax = dest_height-1; } else { SysBusDevice *dev = SYS_BUS_DEVICE(opaque); MemoryRegion *address_space = sysbus_address_space(dev); int src_width, src_height; int dest_row_pitch, dest_col_pitch; drawfn fn; /* The source framebuffer is always read in a linear fashion, * we achieve rotation by altering the destination * step-per-pixel. */ switch (s->rotation) { case 0: /* Normal, native landscape view */ src_width = dest_width; src_height = dest_height; dest_row_pitch = surface_stride(ds); dest_col_pitch = surface_bytes_per_pixel(ds); break; case 1: /* 90 degree, portrait view */ src_width = dest_height; src_height = dest_width; dest_row_pitch = -surface_bytes_per_pixel(ds); dest_col_pitch = surface_stride(ds); break; case 2: /* 180 degree, inverted landscape view */ src_width = dest_width; src_height = dest_height; dest_row_pitch = -surface_stride(ds); dest_col_pitch = -surface_bytes_per_pixel(ds); break; case 3: /* 270 degree, mirror portrait view */ src_width = dest_height; src_height = dest_width; dest_row_pitch = surface_bytes_per_pixel(ds); dest_col_pitch = -surface_stride(ds); break; default: g_assert_not_reached(); } int source_bytes_per_pixel = 2; switch (s->format) { /* source format */ case HAL_PIXEL_FORMAT_RGB_565: source_bytes_per_pixel = 2; switch (surface_bits_per_pixel(ds)) { /* dest format */ case 8: fn = draw_line_16_8; break; case 15: fn = draw_line_16_15; break; case 16: fn = draw_line_16_16; break; case 24: fn = draw_line_16_24; break; case 32: fn = draw_line_16_32; break; default: hw_error("goldfish_fb: bad dest color depth\n"); return; } break; case HAL_PIXEL_FORMAT_RGBX_8888: source_bytes_per_pixel = 4; switch (surface_bits_per_pixel(ds)) { /* dest format */ case 8: fn = draw_line_32_8; break; case 15: fn = draw_line_32_15; break; case 16: fn = draw_line_32_16; break; case 24: fn = draw_line_32_24; break; case 32: fn = draw_line_32_32; break; default: hw_error("goldfish_fb: bad dest color depth\n"); return; } break; default: hw_error("goldfish_fb: bad source color format\n"); return; } ymin = 0; framebuffer_update_display(ds, address_space, s->fb_base, src_width, src_height, src_width * source_bytes_per_pixel, dest_row_pitch, dest_col_pitch, full_update, fn, ds, &ymin, &ymax); } ymax += 1; if (ymin >= 0) { if (s->rotation % 2) { /* In portrait mode we are drawing "sideways" so always * need to update the whole screen */ trace_goldfish_fb_update_display(0, dest_height, 0, dest_width); dpy_gfx_update(s->con, 0, 0, dest_width, dest_height); } else { trace_goldfish_fb_update_display(ymin, ymax-ymin, 0, dest_width); dpy_gfx_update(s->con, 0, ymin, dest_width, ymax-ymin); } } }
/* Fixed line length 1024 allows us to do nice tricks not possible on VGA... */ static void tcx_update_display(void *opaque) { TCXState *ts = opaque; DisplaySurface *surface = qemu_console_surface(ts->con); 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 (surface_bits_per_pixel(surface) == 0) { return; } page = 0; y_start = -1; page_min = -1; page_max = 0; d = surface_data(surface); s = ts->vram; dd = surface_stride(surface); ds = 1024; switch (surface_bits_per_pixel(surface)) { 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_gfx_update(ts->con, 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_gfx_update(ts->con, 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 - page_min) + TARGET_PAGE_SIZE, DIRTY_MEMORY_VGA); } }