summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <ssp@redhat.com>2011-03-20 14:15:07 -0400
committerSøren Sandmann Pedersen <ssp@redhat.com>2011-03-20 16:21:00 -0400
commit9ae9a238584574295624282f01dca03c6692ada7 (patch)
tree889aad2720746f76da0e3238bfb8e28113ee99ed
parentef8d84434f659c9504bd413f51dedc1ccd6cb7a8 (diff)
Fix VT switchingrhel-6.1rhel6
- 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.h5
-rw-r--r--src/qxl_driver.c51
-rw-r--r--src/qxl_surface.c73
-rw-r--r--src/uxa/uxa.c7
-rw-r--r--src/uxa/uxa.h1
5 files changed, 106 insertions, 31 deletions
diff --git a/src/qxl.h b/src/qxl.h
index 801fe77..e7620b5 100644
--- a/src/qxl.h
+++ b/src/qxl.h
@@ -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