summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Levy <alevy@redhat.com>2012-06-25 17:09:20 +0300
committerAlon Levy <alevy@redhat.com>2012-06-27 17:36:17 +0300
commitf09be971e891011a7c8af27d2728d6722cbcc5cd (patch)
tree4e39ba45e7720b58b369cff744dfcc877028eb61
parent94ec2918e17305a9f665b5be335ae2b37b6e734f (diff)
qxl_driver: add infra for surface0 resizing
Most importantly, don't allow randr resize if it is too large for the currently allocated mspace. Ifdeffed out almost working code for reallocating the primary mspace (qxl->mem).
-rw-r--r--src/qxl_driver.c187
1 files changed, 149 insertions, 38 deletions
diff --git a/src/qxl_driver.c b/src/qxl_driver.c
index a0bb7be..941d0d4 100644
--- a/src/qxl_driver.c
+++ b/src/qxl_driver.c
@@ -140,6 +140,19 @@ static void qxl_wait_for_io_command(qxl_screen_t *qxl)
}
ram_header->int_pending &= ~QXL_INTERRUPT_IO_CMD;
}
+
+#if 0
+static void qxl_wait_for_display_interrupt(qxl_screen_t *qxl)
+{
+ struct QXLRam *ram_header = (void *)(
+ (unsigned long)qxl->ram + qxl->rom->ram_header_offset);
+
+ while (!(ram_header->int_pending & QXL_INTERRUPT_DISPLAY)) {
+ usleep(1);
+ }
+ ram_header->int_pending &= ~QXL_INTERRUPT_DISPLAY;
+}
+#endif
#endif
void qxl_update_area(qxl_screen_t *qxl)
@@ -209,6 +222,7 @@ void qxl_io_notify_oom(qxl_screen_t *qxl)
void qxl_io_flush_surfaces(qxl_screen_t *qxl)
{
+ // FIXME: write individual update_area for revision < V10
#ifndef XSPICE
ioport_write(qxl, QXL_IO_FLUSH_SURFACES_ASYNC, 0);
qxl_wait_for_io_command(qxl);
@@ -217,6 +231,34 @@ void qxl_io_flush_surfaces(qxl_screen_t *qxl)
#endif
}
+static void
+qxl_usleep (int useconds)
+{
+ struct timespec t;
+
+ t.tv_sec = useconds / 1000000;
+ t.tv_nsec = (useconds - (t.tv_sec * 1000000)) * 1000;
+
+ errno = 0;
+ while (nanosleep (&t, &t) == -1 && errno == EINTR)
+ ;
+}
+
+#ifdef QXLDRV_RESIZABLE_SURFACE0
+static void qxl_io_flush_release(qxl_screen_t *qxl)
+{
+#ifndef XSPICE
+ int sum = 0;
+
+ sum += qxl_garbage_collect (qxl);
+ ioport_write(qxl, QXL_IO_FLUSH_RELEASE, 0);
+ sum += qxl_garbage_collect (qxl);
+ ErrorF("%s: collected %d\n", __func__, sum);
+#else
+#endif
+}
+#endif
+
static void qxl_io_monitors_config_async(qxl_screen_t *qxl)
{
#ifndef XSPICE
@@ -322,20 +364,6 @@ qxl_garbage_collect (qxl_screen_t *qxl)
return i;
}
-static void
-qxl_usleep (int useconds)
-{
- struct timespec t;
-
- t.tv_sec = useconds / 1000000;
- t.tv_nsec = (useconds - (t.tv_sec * 1000000)) * 1000;
-
- errno = 0;
- while (nanosleep (&t, &t) == -1 && errno == EINTR)
- ;
-
-}
-
int
qxl_handle_oom (qxl_screen_t *qxl)
{
@@ -520,6 +548,75 @@ qxl_mspace_print_func(void *user_data, const char *format, ...)
va_end(args);
}
+#ifdef QXLDRV_RESIZABLE_SURFACE0
+static void
+qxl_dump_ring_stat(qxl_screen_t *qxl)
+{
+ int cmd_prod, cursor_prod, cmd_cons, cursor_cons;
+ int release_prod, release_cons;
+
+ cmd_prod = qxl_ring_prod(qxl->command_ring);
+ cursor_prod = qxl_ring_prod(qxl->cursor_ring);
+ cmd_cons = qxl_ring_cons(qxl->command_ring);
+ cursor_cons = qxl_ring_cons(qxl->cursor_ring);
+ release_prod = qxl_ring_prod(qxl->release_ring);
+ release_cons = qxl_ring_cons(qxl->release_ring);
+
+ ErrorF("%s: Cmd %d/%d, Cur %d/%d, Rel %d/%d\n",
+ __func__, cmd_cons, cmd_prod, cursor_cons, cursor_prod,
+ release_cons, release_prod);
+}
+#endif
+
+/* To resize surface0 we need to ensure qxl->mem is empty. We can do that by:
+ * - fast:
+ * - ooming until command ring is empty.
+ * - flushing the release ring (>V10)
+ * - slow: calling update_area on all surfaces.
+ * This is done via already known code, so use that by default now.
+ */
+static int
+qxl_resize_surface0(qxl_screen_t *qxl, long surface0_size)
+{
+ long ram_header_size = qxl->ram_size - qxl->rom->ram_header_offset;
+ long new_mem_size = qxl->ram_size - surface0_size - ram_header_size
+ - qxl->monitors_config_size;
+
+ if (new_mem_size < 0) {
+ ErrorF ("cannot resize surface0 to %ld, does not fit in BAR 0\n",
+ surface0_size);
+ return 0;
+ }
+ ErrorF ("resizing surface0 to %ld\n", surface0_size);
+
+ if (qxl->mem)
+ {
+#ifdef QXLDRV_RESIZABLE_SURFACE0
+ void *surfaces;
+ qxl_dump_ring_stat(qxl);
+ qxl_io_flush_surfaces(qxl);
+ surfaces = qxl_surface_cache_evacuate_all (qxl->surface_cache);
+ qxl_io_destroy_all_surfaces(qxl); // redundant?
+ qxl_io_flush_release(qxl);
+ qxl_drop_image_cache (qxl);
+ qxl_dump_ring_stat(qxl);
+ qxl_surface_cache_replace_all (qxl->surface_cache, surfaces);
+#else
+ ErrorF ("resizing surface0 compiled out\n");
+ return 0;
+#endif
+ }
+
+ /* surface0_area is still fixed to start of ram BAR */
+ qxl->surface0_size = surface0_size;
+
+ qxl->mem_size = new_mem_size;
+ qxl->mem = qxl_mem_create ((void *)((unsigned long)qxl->surface0_area
+ + qxl->surface0_size),
+ qxl->mem_size);
+ return 1;
+}
+
static Bool
qxl_map_memory(qxl_screen_t *qxl, int scrnIndex)
{
@@ -540,22 +637,21 @@ qxl_map_memory(qxl_screen_t *qxl, int scrnIndex)
xf86DrvMsg(scrnIndex, X_INFO, "rom at %p\n", qxl->rom);
- qxl->num_modes = *(uint32_t *)((uint8_t *)qxl->rom + qxl->rom->modes_offset);
- qxl->modes = (struct QXLMode *)(((uint8_t *)qxl->rom) + qxl->rom->modes_offset + 4);
- qxl->surface0_area = qxl->ram;
- qxl->surface0_size = qxl->rom->surface0_area_size;
-
/*
- * We keep a hole for MonitorsConfig. This is not part of QXLRam to ensure
- * we, the driver, can change it without affecting the driver/device ABI.
+ * Keep a hole for MonitorsConfig. This is not part of QXLRam to ensure
+ * the driver can change it without affecting the driver/device ABI.
*/
qxl->monitors_config_size = (sizeof(QXLMonitorsConfig) +
sizeof(QXLHead) * MAX_MONITORS_NUM + getpagesize() - 1)
& ~(getpagesize() - 1);
- qxl->mem_size = qxl->rom->num_pages * getpagesize() - qxl->monitors_config_size;
-
- qxl->mem = qxl_mem_create ((void *)((unsigned long)qxl->ram + qxl->surface0_size),
- qxl->mem_size);
+ qxl->num_modes = *(uint32_t *)((uint8_t *)qxl->rom + qxl->rom->modes_offset);
+ qxl->modes = (struct QXLMode *)(((uint8_t *)qxl->rom) + qxl->rom->modes_offset + 4);
+ qxl->surface0_area = qxl->ram;
+ qxl->surface0_size = 0;
+ qxl->mem = NULL;
+ if (!qxl_resize_surface0(qxl, qxl->rom->surface0_area_size)) {
+ return FALSE;
+ }
qxl->surf_mem = qxl_mem_create ((void *)((unsigned long)qxl->vram), qxl->vram_size);
qxl_allocate_monitors_config(qxl);
@@ -752,23 +848,33 @@ set_screen_pixmap_header (ScreenPtr pScreen)
ErrorF ("pix: %p;\n", pPixmap);
}
-static void
+static Bool
qxl_resize_primary_to_virtual(qxl_screen_t *qxl)
{
ScreenPtr pScreen;
+ long new_surface0_size;
if ((qxl->primary_mode.x_res == qxl->virtual_x &&
qxl->primary_mode.y_res == qxl->virtual_y) &&
qxl->device_primary == QXL_DEVICE_PRIMARY_CREATED) {
- return;
+ return TRUE; /* empty Success */
}
ErrorF ("resizing primary to %dx%d\n", qxl->virtual_x, qxl->virtual_y);
+ new_surface0_size = qxl->virtual_x * qxl->pScrn->bitsPerPixel / 8
+ * qxl->virtual_y;
+ if (new_surface0_size > qxl->surface0_size)
+ {
+ if (!qxl_resize_surface0(qxl, new_surface0_size)) {
+ ErrorF("not resizing primary to virtual, leaving old virtual\n");
+ return FALSE;
+ }
+ }
if (qxl->primary)
{
- qxl_surface_kill (qxl->primary);
- qxl_surface_cache_sanity_check (qxl->surface_cache);
+ qxl_surface_kill (qxl->primary);
+ qxl_surface_cache_sanity_check (qxl->surface_cache);
qxl_io_destroy_primary(qxl);
}
@@ -799,9 +905,10 @@ qxl_resize_primary_to_virtual(qxl_screen_t *qxl)
}
ErrorF ("primary is %p\n", qxl->primary);
+ return TRUE;
}
-static void
+static Bool
qxl_resize_primary(qxl_screen_t *qxl, uint32_t width, uint32_t height)
{
qxl->virtual_x = width;
@@ -810,9 +917,9 @@ qxl_resize_primary(qxl_screen_t *qxl, uint32_t width, uint32_t height)
if (qxl->vt_surfaces) {
ErrorF("%s: ignoring resize due to not being in control of VT\n",
__FUNCTION__);
- return;
+ return FALSE;
}
- qxl_resize_primary_to_virtual(qxl);
+ return qxl_resize_primary_to_virtual(qxl);
}
static Bool
@@ -823,9 +930,7 @@ qxl_switch_mode(SWITCH_MODE_ARGS_DECL)
ErrorF ("Ignoring display mode, ensuring recreation of primary\n");
- qxl_resize_primary_to_virtual(qxl);
-
- return TRUE;
+ return qxl_resize_primary_to_virtual(qxl);
}
enum ROPDescriptor
@@ -1397,7 +1502,9 @@ qxl_screen_init(SCREEN_INIT_ARGS_DECL)
return FALSE;
}
- qxl_resize_primary_to_virtual(qxl);
+ if (!qxl_resize_primary_to_virtual(qxl)) {
+ return FALSE;
+ }
/* Note: this must be done after DamageSetup() because it calls
* _dixInitPrivates. And if that has been called, DamageSetup()
@@ -1423,7 +1530,9 @@ qxl_enter_vt(VT_FUNC_ARGS_DECL)
qxl_reset_and_create_mem_slots (qxl);
- qxl_resize_primary_to_virtual(qxl);
+ if (!qxl_resize_primary_to_virtual(qxl)) {
+ return FALSE;
+ }
if (qxl->mem)
{
@@ -1749,7 +1858,9 @@ qxl_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
xf86DrvMsg(scrn->scrnIndex, X_INFO, "%s: Placeholder resize %dx%d\n",
__func__, width, height);
- qxl_resize_primary(qxl, width, height);
+ if (!qxl_resize_primary(qxl, width, height)) {
+ return FALSE;
+ }
scrn->virtualX = width;
scrn->virtualY = height;
qxl_update_monitors_config(qxl);