[Spice-devel] [PATCH xf86-qxl 18/27] qxl_driver: add infra for surface0 resizing
Marc-André Lureau
marcandre.lureau at gmail.com
Mon Jul 16 08:38:42 PDT 2012
From: Alon Levy <alevy at redhat.com>
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).
---
src/qxl.h | 1 +
src/qxl_driver.c | 189 +++++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 152 insertions(+), 38 deletions(-)
diff --git a/src/qxl.h b/src/qxl.h
index ccbe007..1d9ca75 100644
--- a/src/qxl.h
+++ b/src/qxl.h
@@ -156,6 +156,7 @@ struct _qxl_screen_t
void * surface0_area;
long surface0_size;
long vram_size;
+ long ram_size;
DisplayModePtr x_modes;
diff --git a/src/qxl_driver.c b/src/qxl_driver.c
index e4d1bbe..dd97a21 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)
{
@@ -408,6 +436,7 @@ static void
map_memory_helper(qxl_screen_t *qxl)
{
qxl->ram = malloc(RAM_SIZE);
+ qxl->ram_size = RAM_SIZE;
qxl->ram_physical = qxl->ram;
qxl->vram = malloc(VRAM_SIZE);
qxl->vram_size = VRAM_SIZE;
@@ -446,6 +475,7 @@ map_memory_helper(qxl_screen_t *qxl)
PCI_DEV_MAP_FLAG_WRITABLE | PCI_DEV_MAP_FLAG_WRITE_COMBINE,
&qxl->ram);
qxl->ram_physical = u64_to_pointer (qxl->pci->regions[0].base_addr);
+ qxl->ram_size = qxl->pci->regions[0].size;
pci_device_map_range(qxl->pci, qxl->pci->regions[1].base_addr,
qxl->pci->regions[1].size,
@@ -518,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)
{
@@ -538,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);
@@ -749,23 +847,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);
}
@@ -796,9 +904,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;
@@ -807,9 +916,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
@@ -820,9 +929,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
@@ -1410,7 +1517,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()
@@ -1436,7 +1545,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)
{
@@ -1775,7 +1886,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);
--
1.7.10.4
More information about the Spice-devel
mailing list