diff options
author | Alon Levy <alevy@redhat.com> | 2012-06-25 17:09:20 +0300 |
---|---|---|
committer | Marc-André Lureau <marcandre.lureau@gmail.com> | 2012-07-15 19:21:34 +0200 |
commit | f493653a5e09ae0e0fe1a5f70c3aba1dc9fe86fe (patch) | |
tree | 6d41ad47cf3713e8b17dc5584003b2c5e71340c2 /src | |
parent | 75619d076bb029b76bed7a885864e191c386aa23 (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).
Diffstat (limited to 'src')
-rw-r--r-- | src/qxl.h | 1 | ||||
-rw-r--r-- | src/qxl_driver.c | 189 |
2 files changed, 152 insertions, 38 deletions
@@ -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); |