void gd_gl_area_switch(DisplayChangeListener *dcl, DisplaySurface *surface) { VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); bool resized = true; trace_gd_switch(vc->label, surface_width(surface), surface_height(surface)); if (vc->gfx.ds && surface_width(vc->gfx.ds) == surface_width(surface) && surface_height(vc->gfx.ds) == surface_height(surface)) { resized = false; } if (vc->gfx.gls) { gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); surface_gl_destroy_texture(vc->gfx.gls, vc->gfx.ds); surface_gl_create_texture(vc->gfx.gls, surface); } vc->gfx.ds = surface; if (resized) { gd_update_windowsize(vc); } }
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 sdl2_gl_switch(DisplayChangeListener *dcl, DisplaySurface *new_surface) { struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); DisplaySurface *old_surface = scon->surface; assert(scon->opengl); SDL_GL_MakeCurrent(scon->real_window, scon->winctx); surface_gl_destroy_texture(scon->gls, scon->surface); scon->surface = new_surface; if (!new_surface) { console_gl_fini_context(scon->gls); scon->gls = NULL; sdl2_window_destroy(scon); return; } if (!scon->real_window) { sdl2_window_create(scon); scon->gls = console_gl_init_context(); } else if (old_surface && ((surface_width(old_surface) != surface_width(new_surface)) || (surface_height(old_surface) != surface_height(new_surface)))) { sdl2_window_resize(scon); } surface_gl_create_texture(scon->gls, scon->surface); }
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); }
void sdl2_2d_switch(DisplayChangeListener *dcl, DisplaySurface *new_surface) { struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl); DisplaySurface *old_surface = scon->surface; int format = 0; assert(!scon->opengl); scon->surface = new_surface; if (scon->texture) { SDL_DestroyTexture(scon->texture); scon->texture = NULL; } if (!new_surface) { sdl2_window_destroy(scon); return; } if (!scon->real_window) { sdl2_window_create(scon); } else if (old_surface && ((surface_width(old_surface) != surface_width(new_surface)) || (surface_height(old_surface) != surface_height(new_surface)))) { sdl2_window_resize(scon); } SDL_RenderSetLogicalSize(scon->real_renderer, surface_width(new_surface), surface_height(new_surface)); switch (surface_format(scon->surface)) { case PIXMAN_x1r5g5b5: format = SDL_PIXELFORMAT_ARGB1555; break; case PIXMAN_r5g6b5: format = SDL_PIXELFORMAT_RGB565; break; case PIXMAN_x8r8g8b8: format = SDL_PIXELFORMAT_ARGB8888; break; case PIXMAN_r8g8b8x8: format = SDL_PIXELFORMAT_RGBA8888; break; case PIXMAN_b8g8r8x8: format = SDL_PIXELFORMAT_BGRX8888; break; default: g_assert_not_reached(); } scon->texture = SDL_CreateTexture(scon->real_renderer, format, SDL_TEXTUREACCESS_STREAMING, surface_width(new_surface), surface_height(new_surface)); sdl2_2d_redraw(scon); }
/* * Send a mouse event from the client to the guest OS * * The QEMU mouse can be in either relative, or absolute mode. * Movement is sent separately from button state, which has to * be encoded as virtual key events. We also don't actually get * given any button up/down events, so have to track changes in * the button state. */ static void xenfb_mouse_event(void *opaque, int dx, int dy, int dz, int button_state) { struct XenInput *xenfb = opaque; DisplaySurface *surface = qemu_console_surface(xenfb->c.con); int dw = surface_width(surface); int dh = surface_height(surface); int i; trace_xenfb_mouse_event(opaque, dx, dy, dz, button_state, xenfb->abs_pointer_wanted); if (xenfb->abs_pointer_wanted) xenfb_send_position(xenfb, dx * (dw - 1) / 0x7fff, dy * (dh - 1) / 0x7fff, dz); else xenfb_send_motion(xenfb, dx, dy, dz); for (i = 0 ; i < 8 ; i++) { int lastDown = xenfb->button_state & (1 << i); int down = button_state & (1 << i); if (down == lastDown) continue; if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0) return; } xenfb->button_state = button_state; }
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); }
void sdl2_window_create(struct sdl2_console *scon) { int flags = 0; if (!scon->surface) { return; } assert(!scon->real_window); if (gui_fullscreen) { flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; } else { flags |= SDL_WINDOW_RESIZABLE; } if (scon->hidden) { flags |= SDL_WINDOW_HIDDEN; } scon->real_window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, surface_width(scon->surface), surface_height(scon->surface), flags); scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0); if (scon->opengl) { scon->winctx = SDL_GL_GetCurrentContext(); } sdl_update_caption(scon); }
void gd_egl_draw(VirtualConsole *vc) { GdkWindow *window; int ww, wh; if (!vc->gfx.gls) { return; } window = gtk_widget_get_window(vc->gfx.drawing_area); ww = gdk_window_get_width(window); wh = gdk_window_get_height(window); if (vc->gfx.scanout_mode) { gd_egl_scanout_flush(&vc->gfx.dcl, 0, 0, vc->gfx.w, vc->gfx.h); vc->gfx.scale_x = (double)ww / vc->gfx.w; vc->gfx.scale_y = (double)wh / vc->gfx.h; } else { if (!vc->gfx.ds) { return; } eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, vc->gfx.esurface, vc->gfx.ectx); surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh); surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds); eglSwapBuffers(qemu_egl_display, vc->gfx.esurface); vc->gfx.scale_x = (double)ww / surface_width(vc->gfx.ds); vc->gfx.scale_y = (double)wh / surface_height(vc->gfx.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 toggle_full_screen(void) { int width = surface_width(surface); int height = surface_height(surface); int bpp = surface_bits_per_pixel(surface); gui_fullscreen = !gui_fullscreen; if (gui_fullscreen) { gui_saved_width = real_screen->w; gui_saved_height = real_screen->h; gui_saved_scaling = scaling_active; do_sdl_resize(width, height, bpp); scaling_active = 0; gui_saved_grab = gui_grab; sdl_grab_start(); } else { if (gui_saved_scaling) { sdl_scale(gui_saved_width, gui_saved_height); } else { do_sdl_resize(width, height, 0); } if (!gui_saved_grab || !qemu_console_is_graphic(NULL)) { sdl_grab_end(); } } graphic_hw_invalidate(NULL); graphic_hw_update(NULL); }
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 void sdl_switch(DisplayChangeListener *dcl, DisplaySurface *new_surface) { struct sdl2_state *scon = container_of(dcl, struct sdl2_state, dcl); int format = 0; int idx = scon->idx; DisplaySurface *old_surface = scon->surface; /* temporary hack: allows to call sdl_switch to handle scaling changes */ if (new_surface) { scon->surface = new_surface; } if (!new_surface && idx > 0) { scon->surface = NULL; } if (new_surface == NULL) { do_sdl_resize(scon, 0, 0, 0); } else { do_sdl_resize(scon, surface_width(scon->surface), surface_height(scon->surface), 0); } if (old_surface && scon->texture) { SDL_DestroyTexture(scon->texture); scon->texture = NULL; } if (new_surface) { if (!scon->texture) { if (surface_bits_per_pixel(scon->surface) == 16) { format = SDL_PIXELFORMAT_RGB565; } else if (surface_bits_per_pixel(scon->surface) == 32) { format = SDL_PIXELFORMAT_ARGB8888; } scon->texture = SDL_CreateTexture(scon->real_renderer, format, SDL_TEXTUREACCESS_STREAMING, surface_width(new_surface), surface_height(new_surface)); } } }
void sdl2_window_resize(struct sdl2_console *scon) { if (!scon->real_window) { return; } SDL_SetWindowSize(scon->real_window, surface_width(scon->surface), surface_height(scon->surface)); }
void sdl2_2d_redraw(struct sdl2_console *scon) { assert(!scon->opengl); if (!scon->surface) { return; } sdl2_2d_update(&scon->dcl, 0, 0, surface_width(scon->surface), surface_height(scon->surface)); }
static void vigs_dpy_resize(void *user_data, uint32_t width, uint32_t height) { VIGSState *s = user_data; DisplaySurface *ds = qemu_console_surface(s->con); if ((width != surface_width(ds)) || (height != surface_height(ds))) { qemu_console_resize(s->con, width, height); } }
/* Console hooks */ void goldfish_fb_set_rotation(int rotation) { DeviceState *dev = qdev_find_recursive(sysbus_get_default(), TYPE_GOLDFISH_FB); if (dev) { struct goldfish_fb_state *s = GOLDFISH_FB(dev); DisplaySurface *ds = qemu_console_surface(s->con); s->rotation = rotation; s->need_update = 1; qemu_console_resize(s->con, surface_height(ds), surface_width(ds)); } else { fprintf(stderr,"%s: unable to find FB dev\n", __func__); } }
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; } } } }
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 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; }
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); }
void surface_gl_setup_viewport(ConsoleGLState *gls, DisplaySurface *surface, int ww, int wh) { int gw, gh, stripe; float sw, sh; assert(gls); gw = surface_width(surface); gh = surface_height(surface); sw = (float)ww/gw; sh = (float)wh/gh; if (sw < sh) { stripe = wh - wh*sw/sh; glViewport(0, stripe / 2, ww, wh - stripe); } else { stripe = ww - ww*sh/sw; glViewport(stripe / 2, 0, ww - stripe, wh); } }
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 tc6393xb_update_display(void *opaque) { TC6393xbState *s = opaque; DisplaySurface *surface = qemu_console_surface(s->con); int full_update; if (s->scr_width == 0 || s->scr_height == 0) return; full_update = 0; if (s->blanked != s->blank) { s->blanked = s->blank; full_update = 1; } if (s->scr_width != surface_width(surface) || s->scr_height != surface_height(surface)) { qemu_console_resize(s->con, s->scr_width, s->scr_height); full_update = 1; } if (s->blanked) tc6393xb_draw_blank(s, full_update); else tc6393xb_draw_graphic(s, full_update); }
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); } } }
static uint64_t goldfish_fb_read(void *opaque, hwaddr offset, unsigned size) { uint64_t ret = 0; struct goldfish_fb_state *s = opaque; DisplaySurface *ds = qemu_console_surface(s->con); #ifndef USE_ANDROID_EMU int android_display_bpp = surface_bits_per_pixel(ds); #endif switch(offset) { case FB_GET_WIDTH: ret = surface_width(ds); break; case FB_GET_HEIGHT: ret = surface_height(ds); break; case FB_INT_STATUS: ret = s->int_status & s->int_enable; if(ret) { s->int_status &= ~ret; qemu_irq_lower(s->irq); } break; case FB_GET_PHYS_WIDTH: ret = pixels_to_mm( surface_width(ds), s->dpi ); break; case FB_GET_PHYS_HEIGHT: ret = pixels_to_mm( surface_height(ds), s->dpi ); break; case FB_GET_FORMAT: /* A kernel making this query supports high color and true color */ switch (android_display_bpp) { /* hw.lcd.depth */ case 32: case 24: ret = HAL_PIXEL_FORMAT_RGBX_8888; break; case 16: ret = HAL_PIXEL_FORMAT_RGB_565; break; default: error_report("goldfish_fb_read: Bad android_display_bpp %d", android_display_bpp); break; } s->format = ret; break; default: error_report("goldfish_fb_read: Bad offset 0x" TARGET_FMT_plx, offset); break; } trace_goldfish_fb_memory_read(offset, ret); return ret; }
/* * Send a mouse event from the client to the guest OS * * The QEMU mouse can be in either relative, or absolute mode. * Movement is sent separately from button state, which has to * be encoded as virtual key events. We also don't actually get * given any button up/down events, so have to track changes in * the button state. */ static void xenfb_mouse_event(DeviceState *dev, QemuConsole *src, InputEvent *evt) { struct XenInput *xenfb = (struct XenInput *)dev; InputBtnEvent *btn; InputMoveEvent *move; QemuConsole *con; DisplaySurface *surface; int scale; switch (evt->type) { case INPUT_EVENT_KIND_BTN: btn = evt->u.btn.data; switch (btn->button) { case INPUT_BUTTON_LEFT: xenfb_send_key(xenfb, btn->down, BTN_LEFT); break; case INPUT_BUTTON_RIGHT: xenfb_send_key(xenfb, btn->down, BTN_LEFT + 1); break; case INPUT_BUTTON_MIDDLE: xenfb_send_key(xenfb, btn->down, BTN_LEFT + 2); break; case INPUT_BUTTON_WHEEL_UP: if (btn->down) { xenfb->wheel--; } break; case INPUT_BUTTON_WHEEL_DOWN: if (btn->down) { xenfb->wheel++; } break; default: break; } break; case INPUT_EVENT_KIND_ABS: move = evt->u.abs.data; if (xenfb->raw_pointer_wanted) { xenfb->axis[move->axis] = move->value; } else { con = qemu_console_lookup_by_index(0); if (!con) { xen_pv_printf(&xenfb->c.xendev, 0, "No QEMU console available"); return; } surface = qemu_console_surface(con); switch (move->axis) { case INPUT_AXIS_X: scale = surface_width(surface) - 1; break; case INPUT_AXIS_Y: scale = surface_height(surface) - 1; break; default: scale = 0x8000; break; } xenfb->axis[move->axis] = move->value * scale / 0x7fff; } break; case INPUT_EVENT_KIND_REL: move = evt->u.rel.data; xenfb->axis[move->axis] += move->value; break; default: break; } }
static void handle_keydown(SDL_Event *ev) { int mod_state; int keycode; if (alt_grab) { mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) == (gui_grab_code | KMOD_LSHIFT); } else if (ctrl_grab) { mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL; } else { mod_state = (SDL_GetModState() & gui_grab_code) == gui_grab_code; } gui_key_modifier_pressed = mod_state; if (gui_key_modifier_pressed) { keycode = sdl_keyevent_to_keycode(&ev->key); switch (keycode) { case 0x21: /* 'f' key on US keyboard */ toggle_full_screen(); gui_keysym = 1; break; case 0x16: /* 'u' key on US keyboard */ if (scaling_active) { scaling_active = 0; sdl_switch(dcl, NULL); graphic_hw_invalidate(NULL); graphic_hw_update(NULL); } gui_keysym = 1; break; case 0x02 ... 0x0a: /* '1' to '9' keys */ /* Reset the modifiers sent to the current console */ reset_keys(); console_select(keycode - 0x02); gui_keysym = 1; if (gui_fullscreen) { break; } if (!qemu_console_is_graphic(NULL)) { /* release grab if going to a text console */ if (gui_grab) { sdl_grab_end(); } else if (absolute_enabled) { sdl_show_cursor(); } } else if (absolute_enabled) { sdl_hide_cursor(); absolute_mouse_grab(); } break; case 0x1b: /* '+' */ case 0x35: /* '-' */ if (!gui_fullscreen) { int width = MAX(real_screen->w + (keycode == 0x1b ? 50 : -50), 160); int height = (surface_height(surface) * width) / surface_width(surface); sdl_scale(width, height); graphic_hw_invalidate(NULL); graphic_hw_update(NULL); gui_keysym = 1; } default: break; } } else if (!qemu_console_is_graphic(NULL)) {