[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