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; } }
static void egl_scanout_flush(DisplayChangeListener *dcl, uint32_t x, uint32_t y, uint32_t w, uint32_t h) { egl_dpy *edpy = container_of(dcl, egl_dpy, dcl); if (!edpy->guest_fb.texture || !edpy->ds) { return; } assert(surface_width(edpy->ds) == edpy->guest_fb.width); assert(surface_height(edpy->ds) == edpy->guest_fb.height); assert(surface_format(edpy->ds) == PIXMAN_x8r8g8b8); if (edpy->cursor_fb.texture) { /* have cursor -> render using textures */ egl_texture_blit(edpy->gls, &edpy->blit_fb, &edpy->guest_fb, !edpy->y_0_top); egl_texture_blend(edpy->gls, &edpy->blit_fb, &edpy->cursor_fb, !edpy->y_0_top, edpy->pos_x, edpy->pos_y); } else { /* no cursor -> use simple framebuffer blit */ egl_fb_blit(&edpy->blit_fb, &edpy->guest_fb, edpy->y_0_top); } egl_fb_read(surface_data(edpy->ds), &edpy->blit_fb); dpy_gfx_update(edpy->dcl.con, x, y, w, h); }
static void vigs_hw_update(void *opaque) { VIGSState *s = opaque; DisplaySurface *ds = qemu_console_surface(s->con); if (!surface_data(ds)) { return; } if (vigs_server_update_display(s->server, s->invalidate_cnt)) { /* * 'vigs_server_update_display' could have updated the surface, * so fetch it again. */ ds = qemu_console_surface(s->con); dpy_gfx_update(s->con, 0, 0, surface_width(ds), surface_height(ds)); } if (s->invalidate_cnt > 0) { s->invalidate_cnt--; } if (s->reg_con & VIGS_REG_CON_VBLANK_ENABLE) { s->reg_int |= VIGS_REG_INT_VBLANK_PENDING; vigs_update_irq(s); } }
static uint8_t *vigs_dpy_get_data(void *user_data) { VIGSState *s = user_data; DisplaySurface *ds = qemu_console_surface(s->con); return surface_data(ds); }
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 qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) { DisplaySurface *surface = qemu_console_surface(qxl->vga.con); uint8_t *dst = surface_data(surface); uint8_t *src; int len, i; if (is_buffer_shared(surface)) { return; } 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_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); }
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 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 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 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 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); } }
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 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); }
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); }
/* * 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 setsurf( void ) { DNA_SURFACE *sdata; LWSurfaceID sid; double color[ 3 ]; const char *objname; int i; objname = mgGetCurrentObject(); if ( !objname ) return; for ( i = 0; i < 11; i++ ) { sdata = surface_data( i ); sid = mgCreateSurface( objname, sdata->name ); csSetSurfEdSurface( sdata->name, objname ); color[ 0 ] = ( double ) sdata->colr[ 0 ]; color[ 1 ] = ( double ) sdata->colr[ 1 ]; color[ 2 ] = ( double ) sdata->colr[ 2 ]; csSetSurfaceColor( SURF_COLR, color ); csSetSurfaceFlt( SURF_DIFF, sdata->diff ); csSetSurfaceFlt( SURF_SPEC, sdata->spec ); csSetSurfaceFlt( SURF_GLOS, sdata->glos ); if ( sdata->sman > 0.0 ) csSetSurfaceFlt( SURF_SMAN, sdata->sman ); if ( sdata->tran > 0.0 ) { csSetSurfaceFlt( SURF_TRAN, sdata->tran ); csSetSurfaceFlt( SURF_RIND, sdata->rind ); } csSetSurfaceInt( SURF_SIDE, sdata->side ); } }
static void cg3_update_display(void *opaque) { CG3State *s = opaque; DisplaySurface *surface = qemu_console_surface(s->con); const uint8_t *pix; uint32_t *data; uint32_t dval; int x, y, y_start; unsigned int width, height; ram_addr_t page, page_min, page_max; if (surface_bits_per_pixel(surface) != 32) { return; } width = s->width; height = s->height; y_start = -1; page_min = -1; page_max = 0; page = 0; pix = memory_region_get_ram_ptr(&s->vram_mem); data = (uint32_t *)surface_data(surface); for (y = 0; y < height; y++) { int update = s->full_update; page = (y * width) & TARGET_PAGE_MASK; update |= memory_region_get_dirty(&s->vram_mem, page, page + width, DIRTY_MEMORY_VGA); if (update) { if (y_start < 0) { y_start = y; } if (page < page_min) { page_min = page; } if (page > page_max) { page_max = page; } for (x = 0; x < width; x++) { dval = *pix++; dval = (s->r[dval] << 16) | (s->g[dval] << 8) | s->b[dval]; *data++ = dval; } } else { if (y_start >= 0) { dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start); y_start = -1; } pix += width; data += width; } } s->full_update = 0; if (y_start >= 0) { dpy_gfx_update(s->con, 0, y_start, s->width, y - y_start); } if (page_max >= page_min) { memory_region_reset_dirty(&s->vram_mem, page_min, page_max - page_min + TARGET_PAGE_SIZE, DIRTY_MEMORY_VGA); } /* vsync interrupt? */ if (s->regs[0] & CG3_CR_ENABLE_INTS) { s->regs[1] |= CG3_SR_PENDING_INT; qemu_irq_raise(s->irq); } }
/* 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); } }
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); } } }
void framebuffer_update_display( DisplaySurface *ds, MemoryRegion *address_space, hwaddr 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 */) { hwaddr 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); mem = mem_section.mr; if (int128_get64(mem_section.size) != src_len || !memory_region_is_ram(mem_section.mr)) { goto out; } assert(mem); assert(mem_section.offset_within_address_space == base); memory_region_sync_dirty_bitmap(mem); if (!memory_region_is_logging(mem, DIRTY_MEMORY_VGA)) { invalidate = true; } 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) goto out; if (src_len != src_width * rows) { cpu_physical_memory_unmap(src_base, src_len, 0, 0); goto out; } src = src_base; dest = surface_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) { goto out; } memory_region_reset_dirty(mem, mem_section.offset_within_region, src_len, DIRTY_MEMORY_VGA); *first_row = first; *last_row = last; out: memory_region_unref(mem); }
static void cg3_update_display(void *opaque) { CG3State *s = opaque; DisplaySurface *surface = qemu_console_surface(s->con); const uint8_t *pix; uint32_t *data; uint32_t dval; int x, y, y_start; unsigned int width, height; ram_addr_t page; DirtyBitmapSnapshot *snap = NULL; if (surface_bits_per_pixel(surface) != 32) { return; } width = s->width; height = s->height; y_start = -1; pix = memory_region_get_ram_ptr(&s->vram_mem); data = (uint32_t *)surface_data(surface); if (!s->full_update) { memory_region_sync_dirty_bitmap(&s->vram_mem); snap = memory_region_snapshot_and_clear_dirty(&s->vram_mem, 0x0, memory_region_size(&s->vram_mem), DIRTY_MEMORY_VGA); } for (y = 0; y < height; y++) { int update; page = (ram_addr_t)y * width; if (s->full_update) { update = 1; } else { update = memory_region_snapshot_get_dirty(&s->vram_mem, snap, page, width); } if (update) { if (y_start < 0) { y_start = y; } for (x = 0; x < width; x++) { dval = *pix++; dval = (s->r[dval] << 16) | (s->g[dval] << 8) | s->b[dval]; *data++ = dval; } } else { if (y_start >= 0) { dpy_gfx_update(s->con, 0, y_start, width, y - y_start); y_start = -1; } pix += width; data += width; } } s->full_update = 0; if (y_start >= 0) { dpy_gfx_update(s->con, 0, y_start, width, y - y_start); } /* vsync interrupt? */ if (s->regs[0] & CG3_CR_ENABLE_INTS) { s->regs[1] |= CG3_SR_PENDING_INT; qemu_irq_raise(s->irq); } g_free(snap); }
static void sm_lcd_update_display(void *arg) { lcd_state *s = arg; uint8_t *d; uint32_t colour_on, colour_off, colour; int x, y, bpp; DisplaySurface *surface = qemu_console_surface(s->con); bpp = surface_bits_per_pixel(surface); d = surface_data(surface); // If vibrate is on, simply jiggle the display if (s->vibrate_on) { if (s->vibrate_offset == 0) { s->vibrate_offset = 2; } int bytes_per_pixel; switch (bpp) { case 8: bytes_per_pixel = 1; break; case 15: case 16: bytes_per_pixel = 2; break; case 32: bytes_per_pixel = 4; break; default: abort(); } int total_bytes = NUM_ROWS * NUM_COLS * bytes_per_pixel - abs(s->vibrate_offset) * bytes_per_pixel; if (s->vibrate_offset > 0) { memmove(d, d + s->vibrate_offset * bytes_per_pixel, total_bytes); } else { memmove(d - s->vibrate_offset * bytes_per_pixel, d, total_bytes); } s->vibrate_offset *= -1; dpy_gfx_update(s->con, 0, 0, NUM_COLS, NUM_ROWS); return; } if (!s->redraw) { return; } // Adjust the white level to compensate for the set brightness. // brightness = 0: 255 in maps to 170 out // brightness = 1.0: 255 in maps to 255 out float brightness = s->backlight_enabled ? s->brightness : 0.0; int max_val = 170 + (255 - 170) * brightness; /* set colours according to bpp */ switch (bpp) { case 8: colour_on = rgb_to_pixel8(max_val, max_val, max_val); colour_off = rgb_to_pixel8(0x00, 0x00, 0x00); break; case 15: colour_on = rgb_to_pixel15(max_val, max_val, max_val); colour_off = rgb_to_pixel15(0x00, 0x00, 0x00); break; case 16: colour_on = rgb_to_pixel16(max_val, max_val, max_val); colour_off = rgb_to_pixel16(0x00, 0x00, 0x00); case 24: colour_on = rgb_to_pixel24(max_val, max_val, max_val); colour_off = rgb_to_pixel24(0x00, 0x00, 0x00); break; case 32: colour_on = rgb_to_pixel32(max_val, max_val, max_val); colour_off = rgb_to_pixel32(0x00, 0x00, 0x00); break; default: return; } for (y = 0; y < NUM_ROWS; y++) { for (x = 0; x < NUM_COLS; x++) { /* Rotate display - installed 'upside-down' in pebble. */ int xr = NUM_COLS - 1 - x; int yr = NUM_ROWS - 1 - y; bool on = s->framebuffer[yr * NUM_COL_BYTES + xr / 8] & 1 << (xr % 8); colour = on ? colour_on : colour_off; switch(bpp) { case 8: *((uint8_t *)d) = colour; d++; break; case 15: case 16: *((uint16_t *)d) = colour; d += 2; break; case 24: abort(); case 32: *((uint32_t *)d) = colour; d += 4; break; } } } dpy_gfx_update(s->con, 0, 0, NUM_COLS, NUM_ROWS); s->redraw = false; }