diff options
author | Søren Sandmann Pedersen <ssp@redhat.com> | 2011-03-20 14:15:07 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <ssp@redhat.com> | 2011-03-20 16:21:00 -0400 |
commit | 9ae9a238584574295624282f01dca03c6692ada7 (patch) | |
tree | 889aad2720746f76da0e3238bfb8e28113ee99ed | |
parent | ef8d84434f659c9504bd413f51dedc1ccd6cb7a8 (diff) |
- Surfaces need to be evacuated before switching VT
- The device must be reset
- Framebuffer access must be turned off
- Pixmaps created while switched away must be created in host memory.
- Pixmaps that are being destroyed while switched away should be marked
as not needing to be replaced.
-rw-r--r-- | src/qxl.h | 5 | ||||
-rw-r--r-- | src/qxl_driver.c | 51 | ||||
-rw-r--r-- | src/qxl_surface.c | 73 | ||||
-rw-r--r-- | src/uxa/uxa.c | 7 | ||||
-rw-r--r-- | src/uxa/uxa.h | 1 |
5 files changed, 106 insertions, 31 deletions
@@ -693,6 +693,9 @@ struct _qxl_screen_t uint8_t vram_mem_slot; surface_cache_t * surface_cache; + + /* Evacuated surfaces are stored here during VT switches */ + void * vt_surfaces; }; static inline uint64_t @@ -766,6 +769,8 @@ void * qxl_surface_cache_evacuate_all (surface_cache_t *qxl); void qxl_surface_cache_replace_all (surface_cache_t *qxl, void *data); +void +qxl_surface_kill_evacuated (PixmapPtr pixmap, void *data); void qxl_surface_set_pixmap (qxl_surface_t *surface, PixmapPtr pixmap); diff --git a/src/qxl_driver.c b/src/qxl_driver.c index 305648f..7701ad0 100644 --- a/src/qxl_driver.c +++ b/src/qxl_driver.c @@ -678,6 +678,9 @@ qxl_create_pixmap (ScreenPtr screen, int w, int h, int depth, unsigned usage) #if 0 ErrorF ("Create pixmap: %d %d @ %d (usage: %d)\n", w, h, depth, usage); #endif + + if (uxa_swapped_out (screen)) + goto fallback; surface = qxl_surface_create (qxl->surface_cache, w, h, depth); @@ -705,13 +708,13 @@ qxl_create_pixmap (ScreenPtr screen, int w, int h, int depth, unsigned usage) ErrorF (" Couldn't allocate %d x %d @ %d surface in video memory\n", w, h, depth); #endif - + fallback: pixmap = fbCreatePixmap (screen, w, h, depth, usage); #if 0 ErrorF ("Create pixmap %p without surface\n", pixmap); #endif -} + } return pixmap; } @@ -728,18 +731,23 @@ qxl_destroy_pixmap (PixmapPtr pixmap) if (pixmap->refcnt == 1) { - surface = get_surface (pixmap); - + if (uxa_swapped_out (screen)) + { + qxl_surface_kill_evacuated (pixmap, qxl->vt_surfaces); + } + else + { + surface = get_surface (pixmap); #if 0 - ErrorF ("- Destroy %p (had surface %p)\n", pixmap, surface); + ErrorF ("- Destroy %p (had surface %p)\n", pixmap, surface); #endif - - if (surface) - { - qxl_surface_kill (surface); - set_surface (pixmap, NULL); - - qxl_surface_cache_sanity_check (qxl->surface_cache); + if (surface) + { + qxl_surface_kill (surface); + set_surface (pixmap, NULL); + + qxl_surface_cache_sanity_check (qxl->surface_cache); + } } } @@ -963,10 +971,20 @@ static Bool qxl_enter_vt(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; - + qxl_screen_t *qxl = pScrn->driverPrivate; + qxl_save_state(pScrn); qxl_switch_mode(scrnIndex, pScrn->currentMode, 0); + if (qxl->vt_surfaces) + { + qxl_surface_cache_replace_all (qxl->surface_cache, qxl->vt_surfaces); + + qxl->vt_surfaces = NULL; + } + + pScrn->EnableDisableFBAccess (scrnIndex, TRUE); + return TRUE; } @@ -974,7 +992,14 @@ static void qxl_leave_vt(int scrnIndex, int flags) { ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; + qxl_screen_t *qxl = pScrn->driverPrivate; + pScrn->EnableDisableFBAccess (scrnIndex, FALSE); + + qxl->vt_surfaces = qxl_surface_cache_evacuate_all (qxl->surface_cache); + + outb(qxl->io_base + QXL_IO_RESET, 0); + qxl_restore_state(pScrn); } diff --git a/src/qxl_surface.c b/src/qxl_surface.c index 4642b6a..0c29c20 100644 --- a/src/qxl_surface.c +++ b/src/qxl_surface.c @@ -1161,9 +1161,11 @@ qxl_surface_cache_evacuate_all (surface_cache_t *cache) evacuated->image = s->host_image; evacuated->pixmap = s->pixmap; - - assert (get_surface (evacuated->pixmap) == s); + assert (get_surface (evacuated->pixmap) == s); + + set_surface (evacuated->pixmap, (qxl_surface_t *)evacuated); + #if 0 ErrorF ("Evacuated %d => %p\n", s->id, evacuated->pixmap); #endif @@ -1189,6 +1191,36 @@ qxl_surface_cache_evacuate_all (surface_cache_t *cache) } void +qxl_surface_kill_evacuated (PixmapPtr pixmap, void *data) +{ + evacuated_surface_t *ev; + evacuated_surface_t *pix_ev = + (evacuated_surface_t *)get_surface (pixmap); + + if (pix_ev) + { + /* Sometimes we will be asked to destroy a pixmap while + * we are switched away. We rely on such pixmaps + * having a pointer to the evacuated surface. This + * is taken care of in evacuate_all(). + */ + for (ev = data; ev != NULL; ev = ev->next) + { + if (ev == pix_ev) + { + /* In replace_all(), if the pixmap of an + * evacuated surface is NULL, it won't + * be replaced + */ + ev->pixmap = NULL; + set_surface (pixmap, NULL); + break; + } + } + } +} + +void qxl_surface_cache_replace_all (surface_cache_t *cache, void *data) { evacuated_surface_t *ev; @@ -1213,31 +1245,36 @@ qxl_surface_cache_replace_all (surface_cache_t *cache, void *data) int height = pixman_image_get_height (ev->image); qxl_surface_t *surface; - surface = qxl_surface_create (cache, width, height, ev->bpp); + if (ev->pixmap) + { + surface = qxl_surface_create (cache, width, height, ev->bpp); #if 0 - ErrorF ("recreated %d\n", surface->id); - ErrorF ("%d => %p\n", surface->id, ev->pixmap); + ErrorF ("recreated %d\n", surface->id); + ErrorF ("%d => %p\n", surface->id, ev->pixmap); #endif + + assert (surface->host_image); + assert (surface->dev_image); + + pixman_image_unref (surface->host_image); + surface->host_image = ev->image; + + upload_box (surface, 0, 0, width, height); + + set_surface (ev->pixmap, surface); - assert (surface->host_image); - assert (surface->dev_image); - - pixman_image_unref (surface->host_image); - surface->host_image = ev->image; - - upload_box (surface, 0, 0, width, height); - - set_surface (ev->pixmap, surface); - - qxl_surface_set_pixmap (surface, ev->pixmap); + qxl_surface_set_pixmap (surface, ev->pixmap); + } + else + { + pixman_image_unref (ev->image); + } free (ev); - ev = next; } qxl_surface_cache_sanity_check (cache); - } static void diff --git a/src/uxa/uxa.c b/src/uxa/uxa.c index 71609fa..83e06cc 100644 --- a/src/uxa/uxa.c +++ b/src/uxa/uxa.c @@ -391,6 +391,13 @@ void uxa_set_force_fallback(ScreenPtr screen, Bool value) uxa_screen->force_fallback = value; } +Bool uxa_swapped_out(ScreenPtr screen) +{ + uxa_screen_t *uxa_screen = uxa_get_screen (screen); + + return uxa_screen->swappedOut; +} + /** * uxa_close_screen() unwraps its wrapped screen functions and tears down UXA's * screen private, before calling down to the next CloseSccreen. diff --git a/src/uxa/uxa.h b/src/uxa/uxa.h index 379d384..2eb4041 100644 --- a/src/uxa/uxa.h +++ b/src/uxa/uxa.h @@ -572,6 +572,7 @@ uxa_get_color_for_pixmap (PixmapPtr pixmap, void uxa_set_fallback_debug(ScreenPtr screen, Bool enable); void uxa_set_force_fallback(ScreenPtr screen, Bool enable); +Bool uxa_swapped_out (ScreenPtr screen); /** * Returns TRUE if the given planemask covers all the significant bits in the |