summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Levy <alevy@redhat.com>2012-04-30 18:35:59 +0300
committerMarc-André Lureau <marcandre.lureau@gmail.com>2012-07-15 19:21:33 +0200
commitf106ea65cde61c8f3cf5819d8c127fb7912ec067 (patch)
tree237eed5af7a2fb307c4749882d92705dc2b273b5 /src
parent21e5719f74749fa6187539dc0805cb12759d66da (diff)
qxl_driver: implement randr, arbitrary resolution, multiple monitors (big dump)
Send a MonitorsUpdate - this should definitely be split into it's own patch. Require revision 4 - this is needed just for MonitorsUpdate, should go with it. Adds new config: OPTION_NUM_HEADS, defaults to 4.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/qxl.h21
-rw-r--r--src/qxl_driver.c614
-rw-r--r--src/qxl_surface.c22
4 files changed, 534 insertions, 125 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 79ea3cc..9d9e965 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -48,6 +48,8 @@ qxl_drv_la_SOURCES = \
murmurhash3.c \
murmurhash3.h \
qxl_cursor.c \
+ qxl_option_helpers.c \
+ qxl_option_helpers.h \
compat-api.h
endif
diff --git a/src/qxl.h b/src/qxl.h
index c2d2369..6c97f1f 100644
--- a/src/qxl.h
+++ b/src/qxl.h
@@ -38,6 +38,7 @@
#include "xf86Cursor.h"
#include "xf86_OSproc.h"
#include "xf86xv.h"
+#include "xf86Crtc.h"
#include "shadow.h"
#include "micmap.h"
#include "uxa/uxa.h"
@@ -100,6 +101,7 @@ enum {
OPTION_ENABLE_IMAGE_CACHE = 0,
OPTION_ENABLE_FALLBACK_CACHE,
OPTION_ENABLE_SURFACES,
+ OPTION_NUM_HEADS,
#ifdef XSPICE
OPTION_SPICE_PORT,
OPTION_SPICE_TLS_PORT,
@@ -155,11 +157,19 @@ struct _qxl_screen_t
long surface0_size;
long vram_size;
+ DisplayModePtr x_modes;
+
int virtual_x;
int virtual_y;
void * fb;
- struct QXLMode * current_mode;
+
+ /* not the same as the heads mode for #head > 1 or virtual != head size */
+ struct QXLMode primary_mode;
qxl_surface_t * primary;
+
+ struct QXLMonitorsConfig *monitors_config;
+ int monitors_config_size;
+ int mem_size;
int bytes_per_pixel;
@@ -171,6 +181,10 @@ struct _qxl_screen_t
EntityInfoPtr entity;
+ int num_heads;
+ xf86CrtcPtr * crtcs;
+ xf86OutputPtr * outputs;
+
#ifndef XSPICE
void * io_pages;
void * io_pages_physical;
@@ -247,6 +261,11 @@ struct _qxl_screen_t
#endif /* XSPICE */
};
+typedef struct qxl_output_private {
+ qxl_screen_t *qxl;
+ int head;
+} qxl_output_private;
+
static inline uint64_t
physical_address (qxl_screen_t *qxl, void *virtual, uint8_t slot_id)
{
diff --git a/src/qxl_driver.c b/src/qxl_driver.c
index b0967dc..280aa70 100644
--- a/src/qxl_driver.c
+++ b/src/qxl_driver.c
@@ -42,6 +42,7 @@
#include <xf86Crtc.h>
#include "mspace.h"
+
#include "qxl.h"
#include "assert.h"
#include "qxl_option_helpers.h"
@@ -69,6 +70,8 @@ const OptionInfoRec DefaultOptions[] = {
"EnableFallbackCache", OPTV_BOOLEAN, { 0 }, TRUE },
{ OPTION_ENABLE_SURFACES,
"EnableSurfaces", OPTV_BOOLEAN, { 0 }, TRUE },
+ { OPTION_NUM_HEADS,
+ "NumHeads", OPTV_INTEGER, { 4 }, FALSE },
#ifdef XSPICE
{ OPTION_SPICE_PORT,
"SpicePort", OPTV_INTEGER, {5900}, FALSE },
@@ -214,6 +217,40 @@ void qxl_io_flush_surfaces(qxl_screen_t *qxl)
#endif
}
+static void qxl_io_monitors_config_async(qxl_screen_t *qxl)
+{
+#ifndef XSPICE
+ if (qxl->pci->revision < 4) {
+ return;
+ }
+ ioport_write(qxl, QXL_IO_MONITORS_CONFIG_ASYNC, 0);
+ qxl_wait_for_io_command(qxl);
+#else
+ fprintf(stderr, "UNIMPLEMENTED!\n");
+#endif
+}
+
+/* Having a single monitors config struct allocated on the device avoids any
+ *
+ * possible fragmentation. Since X is single threaded there is no danger
+ * in us changing it between issuing the io and getting the interrupt to signal
+ * spice-server is done reading it. */
+#define MAX_MONITORS_NUM 16
+
+static void
+qxl_allocate_monitors_config(qxl_screen_t *qxl)
+{
+ int size = sizeof(QXLMonitorsConfig) + sizeof(QXLHead) * MAX_MONITORS_NUM;
+
+ if (qxl->monitors_config) {
+ return;
+ }
+ qxl->monitors_config = (QXLMonitorsConfig *)(void *)(
+ (unsigned long)qxl->ram + qxl->rom->ram_header_offset
+ - qxl->monitors_config_size);
+ memset(qxl->monitors_config, 0, size);
+}
+
int
qxl_garbage_collect (qxl_screen_t *qxl)
{
@@ -452,6 +489,13 @@ qxl_unmap_memory(qxl_screen_t *qxl)
qxl->worker_running = FALSE;
}
#endif
+ if (qxl->mem)
+ {
+ qxl_mem_free_all (qxl->mem);
+ qxl_drop_image_cache (qxl);
+ }
+ if (qxl->surf_mem)
+ qxl_mem_free_all (qxl->surf_mem);
unmap_memory_helper(qxl);
qxl->ram = qxl->ram_physical = qxl->vram = qxl->rom = NULL;
@@ -499,10 +543,18 @@ qxl_map_memory(qxl_screen_t *qxl, int scrnIndex)
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.
+ */
+ 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->rom->num_pages * getpagesize() - qxl->surface0_size);
+ qxl->mem_size);
qxl->surf_mem = qxl_mem_create ((void *)((unsigned long)qxl->vram), qxl->vram_size);
-
qxl_allocate_monitors_config(qxl);
return TRUE;
@@ -593,9 +645,11 @@ qxl_reset_and_create_mem_slots (qxl_screen_t *qxl)
#else /* QXL */
qxl->main_mem_slot = setup_slot(qxl, 0,
(unsigned long)qxl->ram_physical,
- (unsigned long)qxl->ram_physical + (unsigned long)qxl->rom->num_pages * getpagesize(),
+ (unsigned long)qxl->ram_physical + qxl->surface0_size +
+ (unsigned long)qxl->rom->num_pages * getpagesize(),
(uint64_t)(uintptr_t)qxl->ram,
- (uint64_t)(uintptr_t)qxl->ram + (unsigned long)qxl->rom->num_pages * getpagesize()
+ (uint64_t)(uintptr_t)qxl->ram + qxl->surface0_size +
+ (unsigned long)qxl->rom->num_pages * getpagesize()
);
qxl->vram_mem_slot = setup_slot(qxl, 1,
(unsigned long)qxl->vram_physical,
@@ -676,7 +730,9 @@ set_screen_pixmap_header (ScreenPtr pScreen)
qxl_screen_t *qxl = pScrn->driverPrivate;
PixmapPtr pPixmap = pScreen->GetScreenPixmap(pScreen);
- if (pPixmap && qxl->current_mode)
+ // TODO: don't ModifyPixmapHeader too early?
+
+ if (pPixmap)
{
ErrorF ("new stride: %d (display width: %d, bpp: %d)\n",
qxl->pScrn->displayWidth * qxl->bytes_per_pixel,
@@ -684,24 +740,28 @@ set_screen_pixmap_header (ScreenPtr pScreen)
pScreen->ModifyPixmapHeader(
pPixmap,
- qxl->current_mode->x_res, qxl->current_mode->y_res,
+ qxl->primary_mode.x_res, qxl->primary_mode.y_res,
-1, -1,
qxl->pScrn->displayWidth * qxl->bytes_per_pixel,
NULL);
}
else
- ErrorF ("pix: %p; mode: %p\n", pPixmap, qxl->current_mode);
+ ErrorF ("pix: %p;\n", pPixmap);
}
-static Bool
-qxl_switch_mode(SWITCH_MODE_ARGS_DECL)
+static void
+qxl_resize_primary_to_virtual(qxl_screen_t *qxl)
{
- SCRN_INFO_PTR(arg);
- qxl_screen_t *qxl = pScrn->driverPrivate;
- int mode_index = (int)(unsigned long)mode->Private;
- struct QXLMode *m = qxl->modes + mode_index;
ScreenPtr pScreen;
+ 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;
+ }
+
+ ErrorF ("resizing primary to %dx%d\n", qxl->virtual_x, qxl->virtual_y);
+
if (qxl->primary)
{
qxl_surface_kill (qxl->primary);
@@ -709,8 +769,18 @@ qxl_switch_mode(SWITCH_MODE_ARGS_DECL)
qxl_io_destroy_primary(qxl);
}
- qxl->primary = qxl_surface_cache_create_primary (qxl->surface_cache, m);
- qxl->current_mode = m;
+ {
+ struct QXLMode *pm = &qxl->primary_mode;
+ pm->id = 0x4242;
+ pm->x_res = qxl->virtual_x;
+ pm->y_res = qxl->virtual_y;
+ pm->bits = qxl->pScrn->bitsPerPixel;
+ pm->stride = qxl->virtual_x * pm->bits / 8;
+ pm->x_mili = 0; // TODO
+ pm->y_mili = 0; // TODO
+ pm->orientation = 0; // ? supported by us for single head usage? more TODO
+ }
+ qxl->primary = qxl_surface_cache_create_primary (qxl->surface_cache, &qxl->primary_mode);
qxl->bytes_per_pixel = (qxl->pScrn->bitsPerPixel + 7) / 8;
pScreen = qxl->pScrn->pScreen;
@@ -725,6 +795,33 @@ qxl_switch_mode(SWITCH_MODE_ARGS_DECL)
set_surface (root, qxl->primary);
}
+ ErrorF ("primary is %p\n", qxl->primary);
+}
+
+static void
+qxl_resize_primary(qxl_screen_t *qxl, uint32_t width, uint32_t height)
+{
+ qxl->virtual_x = width;
+ qxl->virtual_y = height;
+
+ if (qxl->vt_surfaces) {
+ ErrorF("%s: ignoring resize due to not being in control of VT\n",
+ __FUNCTION__);
+ return;
+ }
+ qxl_resize_primary_to_virtual(qxl);
+}
+
+static Bool
+qxl_switch_mode(SWITCH_MODE_ARGS_DECL)
+{
+ SCRN_INFO_PTR(arg);
+ qxl_screen_t *qxl = pScrn->driverPrivate;
+
+ ErrorF ("Ignoring display mode, ensuring recreation of primary\n");
+
+ qxl_resize_primary_to_virtual(qxl);
+
return TRUE;
}
@@ -743,6 +840,61 @@ enum ROPDescriptor
ROPD_INVERS_RES = (1 <<10),
};
+static void
+qxl_update_monitors_config(qxl_screen_t *qxl)
+{
+ int i;
+ QXLHead *head;
+ xf86CrtcPtr crtc;
+ QXLRam *ram = get_ram_header(qxl);
+
+ qxl->monitors_config->count = 0;
+ qxl->monitors_config->max_allowed = qxl->num_heads;
+ for (i = 0 ; i < qxl->num_heads; ++i) {
+ head = &qxl->monitors_config->heads[qxl->monitors_config->count];
+ crtc = qxl->crtcs[i];
+ head->id = i;
+ head->surface_id = 0;
+ head->flags = 0;
+ if (!crtc->enabled || crtc->mode.CrtcHDisplay == 0 ||
+ crtc->mode.CrtcVDisplay == 0) {
+ head->width = head->height = head->x = head->y = 0;
+ head->height = 0;
+ } else {
+ head->width = crtc->mode.CrtcHDisplay;
+ head->height = crtc->mode.CrtcVDisplay;
+ head->x = crtc->x;
+ head->y = crtc->y;
+ qxl->monitors_config->count++;
+ }
+ }
+ /* initialize when actually used, memslots should be initialized by now */
+ if (ram->monitors_config == 0) {
+ ram->monitors_config = physical_address (qxl, qxl->monitors_config,
+ qxl->main_mem_slot);
+ }
+ qxl_io_monitors_config_async(qxl);
+}
+
+static Bool
+qxl_create_desired_modes(qxl_screen_t *qxl)
+{
+ int i;
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(qxl->pScrn);
+
+ for (i = 0 ; i < config->num_crtc; ++i) {
+ xf86CrtcPtr crtc = config->crtc[i];
+ if (!crtc->enabled) {
+ continue;
+ }
+ if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation,
+ crtc->desiredX, crtc->desiredY))
+ return FALSE;
+ }
+ qxl_update_monitors_config(qxl);
+ return TRUE;
+}
+
static Bool
qxl_create_screen_resources(ScreenPtr pScreen)
{
@@ -751,6 +903,7 @@ qxl_create_screen_resources(ScreenPtr pScreen)
Bool ret;
PixmapPtr pPixmap;
qxl_surface_t *surf;
+ int i;
pScreen->CreateScreenResources = qxl->create_screen_resources;
ret = pScreen->CreateScreenResources (pScreen);
@@ -767,7 +920,14 @@ qxl_create_screen_resources(ScreenPtr pScreen)
qxl_surface_kill (surf);
set_surface (pPixmap, qxl->primary);
-
+
+ /* HACK - I don't want to enable any crtcs other then the first at the beginning */
+ for (i = 1; i < qxl->num_heads; ++i) {
+ qxl->crtcs[i]->enabled = 0;
+ }
+
+ qxl_create_desired_modes(qxl);
+
return TRUE;
}
@@ -1096,6 +1256,27 @@ spiceqxl_screen_init(ScrnInfoPtr pScrn, qxl_screen_t *qxl)
#endif
static Bool
+qxl_fb_init(qxl_screen_t *qxl, ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = qxl->pScrn;
+
+#if 0
+ ErrorF ("allocated %d x %d %p\n", pScrn->virtualX, pScrn->virtualY, qxl->fb);
+#endif
+
+ if (!fbScreenInit(pScreen, NULL,
+ pScrn->virtualX, pScrn->virtualY,
+ pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth,
+ pScrn->bitsPerPixel))
+ {
+ return FALSE;
+ }
+
+ fbPictureInit(pScreen, NULL, 0);
+ return TRUE;
+}
+
+static Bool
qxl_screen_init(SCREEN_INIT_ARGS_DECL)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
@@ -1105,7 +1286,7 @@ qxl_screen_init(SCREEN_INIT_ARGS_DECL)
CHECK_POINT();
- qxl->pScrn = pScrn;
+ assert(qxl->pScrn == pScrn);
if (!qxl_map_memory(qxl, pScrn->scrnIndex))
return FALSE;
@@ -1127,10 +1308,6 @@ qxl_screen_init(SCREEN_INIT_ARGS_DECL)
goto out;
if (!miSetPixmapDepths())
goto out;
-
- qxl->virtual_x = pScrn->virtualX;
- qxl->virtual_y = pScrn->virtualY;
-
pScrn->displayWidth = pScrn->virtualX;
qxl->fb = calloc (pScrn->virtualY * pScrn->displayWidth, 4);
@@ -1144,13 +1321,8 @@ qxl_screen_init(SCREEN_INIT_ARGS_DECL)
pScrn->virtualX = pScrn->currentMode->HDisplay;
pScrn->virtualY = pScrn->currentMode->VDisplay;
- if (!fbScreenInit(pScreen, qxl->fb,
- pScrn->virtualX, pScrn->virtualY,
- pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth,
- pScrn->bitsPerPixel))
- {
- goto out;
- }
+ if (!qxl_fb_init(qxl, pScreen))
+ goto out;
visual = pScreen->visuals + pScreen->numVisuals;
while (--visual >= pScreen->visuals)
@@ -1166,8 +1338,6 @@ qxl_screen_init(SCREEN_INIT_ARGS_DECL)
}
}
- fbPictureInit(pScreen, NULL, 0);
-
qxl->uxa = uxa_driver_alloc ();
/* Set up resources */
@@ -1220,7 +1390,11 @@ qxl_screen_init(SCREEN_INIT_ARGS_DECL)
pScreen->width = pScrn->currentMode->HDisplay;
pScreen->height = pScrn->currentMode->VDisplay;
- qxl_switch_mode(SWITCH_MODE_ARGS(pScrn, pScrn->currentMode));
+ if (!xf86CrtcScreenInit(pScreen)) {
+ return FALSE;
+ }
+
+ qxl_resize_primary_to_virtual(qxl);
/* Note: this must be done after DamageSetup() because it calls
* _dixInitPrivates. And if that has been called, DamageSetup()
@@ -1246,7 +1420,7 @@ qxl_enter_vt(VT_FUNC_ARGS_DECL)
qxl_reset_and_create_mem_slots (qxl);
- qxl_switch_mode(SWITCH_MODE_ARGS(pScrn, pScrn->currentMode));
+ qxl_resize_primary_to_virtual(qxl);
if (qxl->mem)
{
@@ -1264,6 +1438,8 @@ qxl_enter_vt(VT_FUNC_ARGS_DECL)
qxl->vt_surfaces = NULL;
}
+ qxl_create_desired_modes(qxl);
+
pScrn->EnableDisableFBAccess (XF86_SCRN_ARG(pScrn), TRUE);
return TRUE;
@@ -1373,80 +1549,11 @@ qxl_check_device(ScrnInfoPtr pScrn, qxl_screen_t *qxl)
}
#endif /* !XSPICE */
-static int
-qxl_find_native_mode(ScrnInfoPtr pScrn, DisplayModePtr p)
-{
- int i;
- qxl_screen_t *qxl = pScrn->driverPrivate;
-
- CHECK_POINT();
-
- for (i = 0; i < qxl->num_modes; i++)
- {
- struct QXLMode *m = qxl->modes + i;
-
- if (m->x_res == p->HDisplay &&
- m->y_res == p->VDisplay &&
- m->bits == pScrn->bitsPerPixel)
- {
- if (m->bits == 16)
- {
- /* What QXL calls 16 bit is actually x1r5g5b515 */
- if (pScrn->depth == 15)
- return i;
- }
- else if (m->bits == 32)
- {
- /* What QXL calls 32 bit is actually x8r8g8b8 */
- if (pScrn->depth == 24)
- return i;
- }
- }
- }
-
- return -1;
-}
-
-static ModeStatus
-qxl_valid_mode(SCRN_ARG_TYPE arg, DisplayModePtr p, Bool flag, int pass)
-{
- SCRN_INFO_PTR(arg);
- int scrnIndex = pScrn->scrnIndex;
- qxl_screen_t *qxl = pScrn->driverPrivate;
- int bpp = pScrn->bitsPerPixel;
- int mode_idx;
-
- /* FIXME: I don't think this is necessary now that we report the
- * correct amount of video ram?
- */
- if (p->HDisplay * p->VDisplay * (bpp/8) > qxl->surface0_size)
- {
- xf86DrvMsg(scrnIndex, X_INFO, "rejecting mode %d x %d: insufficient memory\n", p->HDisplay, p->VDisplay);
- return MODE_MEM;
- }
-
- mode_idx = qxl_find_native_mode (pScrn, p);
- if (mode_idx == -1)
- {
- xf86DrvMsg(scrnIndex, X_INFO, "rejecting unknown mode %d x %d\n", p->HDisplay, p->VDisplay);
- return MODE_NOMODE;
- }
- p->Private = (void *)(unsigned long)mode_idx;
-
- xf86DrvMsg (scrnIndex, X_INFO, "accepting %d x %d\n", p->HDisplay, p->VDisplay);
-
- return MODE_OK;
-}
-
-static void qxl_add_mode(ScrnInfoPtr pScrn, int width, int height, int type)
+static DisplayModePtr qxl_add_mode(qxl_screen_t *qxl, ScrnInfoPtr pScrn,
+ int width, int height, int type)
{
DisplayModePtr mode;
- /* Skip already present modes */
- for (mode = pScrn->monitor->Modes; mode; mode = mode->next)
- if (mode->HDisplay == width && mode->VDisplay == height)
- return;
-
mode = xnfcalloc(1, sizeof(DisplayModeRec));
mode->status = MODE_OK;
@@ -1463,22 +1570,284 @@ static void qxl_add_mode(ScrnInfoPtr pScrn, int width, int height, int type)
mode->Flags = V_NHSYNC | V_PVSYNC;
xf86SetModeDefaultName(mode);
- xf86ModesAdd(pScrn->monitor->Modes, mode);
+ xf86SetModeCrtc(mode, pScrn->adjustFlags); /* needed? xf86-video-modesetting does this */
+ qxl->x_modes = xf86ModesAdd(qxl->x_modes, mode);
+ return mode;
+}
+
+static DisplayModePtr
+qxl_output_get_modes(xf86OutputPtr output)
+{
+ qxl_output_private *qxl_output = output->driver_private;
+
+ /* xf86ProbeOutputModes owns this memory */
+ return xf86DuplicateModes(qxl_output->qxl->pScrn, qxl_output->qxl->x_modes);
+}
+
+static void
+qxl_output_destroy(xf86OutputPtr output)
+{
+ qxl_output_private *qxl_output = output->driver_private;
+
+ xf86DrvMsg(qxl_output->qxl->pScrn->scrnIndex, X_INFO,
+ "%s", __func__);
+}
+
+static void
+qxl_output_dpms(xf86OutputPtr output, int mode)
+{
+}
+
+static void
+qxl_output_create_resources(xf86OutputPtr output)
+{
+}
+
+static Bool
+qxl_output_set_property(xf86OutputPtr output, Atom property,
+ RRPropertyValuePtr value)
+{
+ return FALSE;
+}
+
+static Bool
+qxl_output_get_property(xf86OutputPtr output, Atom property)
+{
+ return TRUE;
+}
+
+static xf86OutputStatus
+qxl_output_detect(xf86OutputPtr output)
+{
+ // TODO - how do I query this? do I add fields and let the host set this instead
+ // of the guest agent? or can I set this via the guest agent? I could just check
+ // some files / anything in userspace, settable by the guest agent. dbus even.
+ return XF86OutputStatusConnected;
+}
+
+static Bool
+qxl_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
+{
+ return MODE_OK;
+}
+
+static const xf86OutputFuncsRec qxl_output_funcs = {
+ .dpms = qxl_output_dpms,
+ .create_resources = qxl_output_create_resources,
+#ifdef RANDR_12_INTERFACE
+ .set_property = qxl_output_set_property,
+ .get_property = qxl_output_get_property,
+#endif
+ .detect = qxl_output_detect,
+ .mode_valid = qxl_output_mode_valid,
+
+ .get_modes = qxl_output_get_modes,
+ .destroy = qxl_output_destroy
+};
+
+static void
+qxl_crtc_dpms(xf86CrtcPtr crtc, int mode)
+{
+}
+
+static Bool
+qxl_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
+ Rotation rotation, int x, int y)
+{
+ qxl_screen_t *qxl = crtc->driver_private;
+
+ crtc->mode = *mode;
+ crtc->x = x;
+ crtc->y = y;
+ crtc->rotation = rotation;
+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,5,99,0,0)
+ crtc->transformPresent = FALSE;
+#endif
+ qxl_update_monitors_config(qxl);
+ return TRUE;
+}
+
+static void
+qxl_crtc_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
+{
+}
+
+static void
+qxl_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
+{
+}
+
+static void
+qxl_crtc_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
+{
+}
+
+static void
+qxl_crtc_hide_cursor (xf86CrtcPtr crtc)
+{
+}
+
+static void
+qxl_crtc_show_cursor (xf86CrtcPtr crtc)
+{
+}
+
+static void
+qxl_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
+ uint16_t *blue, int size)
+{
+}
+
+static void
+qxl_crtc_destroy (xf86CrtcPtr crtc)
+{
+ qxl_screen_t *qxl = crtc->driver_private;
+
+ xf86DrvMsg(qxl->pScrn->scrnIndex, X_INFO, "%s\n", __func__);
+}
+
+static Bool
+qxl_crtc_lock (xf86CrtcPtr crtc)
+{
+ qxl_screen_t *qxl = crtc->driver_private;
+
+ xf86DrvMsg(qxl->pScrn->scrnIndex, X_INFO, "%s\n", __func__);
+ return TRUE;
+}
+
+static void
+qxl_crtc_unlock (xf86CrtcPtr crtc)
+{
+ qxl_screen_t *qxl = crtc->driver_private;
+
+ xf86DrvMsg(qxl->pScrn->scrnIndex, X_INFO, "%s\n", __func__);
+ qxl_update_monitors_config(qxl);
+}
+
+static const xf86CrtcFuncsRec qxl_crtc_funcs = {
+ .dpms = qxl_crtc_dpms,
+ .set_mode_major = qxl_crtc_set_mode_major,
+ .set_cursor_colors = qxl_crtc_set_cursor_colors,
+ .set_cursor_position = qxl_crtc_set_cursor_position,
+ .show_cursor = qxl_crtc_show_cursor,
+ .hide_cursor = qxl_crtc_hide_cursor,
+ .load_cursor_argb = qxl_crtc_load_cursor_argb,
+ .lock = qxl_crtc_lock,
+ .unlock = qxl_crtc_unlock,
+
+ .gamma_set = qxl_crtc_gamma_set,
+ .destroy = qxl_crtc_destroy,
+};
+
+static Bool
+qxl_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
+{
+ qxl_screen_t *qxl = scrn->driverPrivate;
+
+ xf86DrvMsg(scrn->scrnIndex, X_INFO, "%s: Placeholder resize %dx%d\n",
+ __func__, width, height);
+ qxl_resize_primary(qxl, width, height);
+ scrn->virtualX = width;
+ scrn->virtualY = height;
+ qxl_update_monitors_config(qxl);
+ return TRUE;
}
static const xf86CrtcConfigFuncsRec qxl_xf86crtc_config_funcs = {
- NULL
+ qxl_xf86crtc_resize
};
+static void
+qxl_init_randr(ScrnInfoPtr pScrn, qxl_screen_t *qxl)
+{
+ char name[32];
+ qxl_output_private *qxl_output;
+ int i;
+ xf86OutputPtr output;
+ int maxWidth;
+ int maxHeight;
+
+ /* TODO: Hack */
+ switch (qxl->num_heads) {
+ case 1:
+ maxWidth = 1024;
+ maxHeight = 768;
+ break;
+ case 2:
+ maxWidth = 2048;
+ maxHeight = 1024;
+ default:
+ maxWidth = (qxl->num_heads > 4 ? 4 : qxl->num_heads) * 1280;
+ maxHeight = 1024;
+ }
+
+ xf86CrtcConfigInit(pScrn, &qxl_xf86crtc_config_funcs);
+
+ /* This is actually redundant, it's overwritten by a later call via
+ * xf86InitialConfiguration */
+ xf86CrtcSetSizeRange(pScrn, 320, 200, maxWidth, maxHeight);
+
+ qxl->crtcs = xnfcalloc(sizeof(xf86CrtcPtr), qxl->num_heads);
+ qxl->outputs = xnfcalloc(sizeof(xf86OutputPtr), qxl->num_heads);
+ for (i = 0 ; i < qxl->num_heads; ++i) {
+ qxl->crtcs[i] = xf86CrtcCreate(pScrn, &qxl_crtc_funcs);
+ if (!qxl->crtcs[i]) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "failed to create Crtc %d",
+ i);
+ }
+ qxl->crtcs[i]->driver_private = qxl;
+ snprintf(name, sizeof(name), "qxl-%d", i);
+ qxl->outputs[i] = output = xf86OutputCreate(pScrn, &qxl_output_funcs, name);
+ if (!output) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "failed to create Output %d",
+ i);
+ }
+ output->possible_crtcs = (1 << i); /* bitrange of allowed outputs - do a 1:1 */
+ output->possible_clones = 0; /* TODO: not? */
+ qxl_output = xnfcalloc(sizeof(qxl_output_private), 1);
+ output->driver_private = qxl_output;
+ qxl_output->head = i;
+ qxl_output->qxl = qxl;
+ }
+
+ qxl->virtual_x = 1024;
+ qxl->virtual_y = 768;
+
+ pScrn->display->virtualX = qxl->virtual_x;
+ pScrn->display->virtualY = qxl->virtual_y;
+
+ xf86InitialConfiguration(pScrn, TRUE);
+}
+
+static void
+qxl_initialize_x_modes(qxl_screen_t *qxl, ScrnInfoPtr pScrn,
+ unsigned int *max_x, unsigned int *max_y)
+{
+ int i;
+
+ *max_x = *max_y = 0;
+ /* Create a list of modes used by the qxl_output_get_modes */
+ for (i = 0; i < qxl->num_modes; i++) {
+ if (qxl->modes[i].orientation == 0) {
+ qxl_add_mode(qxl, pScrn, qxl->modes[i].x_res, qxl->modes[i].y_res,
+ M_T_DRIVER);
+ if (qxl->modes[i].x_res > *max_x)
+ *max_x = qxl->modes[i].x_res;
+ if (qxl->modes[i].y_res > *max_y)
+ *max_y = qxl->modes[i].y_res;
+ }
+ }
+}
+
static Bool
qxl_pre_init(ScrnInfoPtr pScrn, int flags)
{
- int i, scrnIndex = pScrn->scrnIndex;
+ int scrnIndex = pScrn->scrnIndex;
qxl_screen_t *qxl = NULL;
ClockRangePtr clockRanges = NULL;
- int *linePitches = NULL;
- DisplayModePtr mode;
- unsigned int max_x = 0, max_y = 0;
+ //int *linePitches = NULL;
+ //DisplayModePtr mode;
+ unsigned int max_x, max_y;
/* In X server 1.7.5, Xorg -configure will cause this
* function to get called without a confScreen.
@@ -1502,6 +1871,8 @@ qxl_pre_init(ScrnInfoPtr pScrn, int flags)
qxl = pScrn->driverPrivate;
memset(qxl, 0, sizeof(qxl));
qxl->device_primary = QXL_DEVICE_PRIMARY_UNDEFINED;
+ qxl->pScrn = pScrn;
+ qxl->x_modes = NULL;
qxl->entity = xf86GetEntityInfo(pScrn->entityList[0]);
@@ -1528,6 +1899,8 @@ qxl_pre_init(ScrnInfoPtr pScrn, int flags)
xf86ReturnOptValBool (qxl->options, OPTION_ENABLE_FALLBACK_CACHE, TRUE);
qxl->enable_surfaces =
xf86ReturnOptValBool (qxl->options, OPTION_ENABLE_SURFACES, TRUE);
+ qxl->num_heads =
+ get_int_option (qxl->options, OPTION_NUM_HEADS, "QXL_NUM_HEADS");
xf86DrvMsg(scrnIndex, X_INFO, "Offscreen Surfaces: %s\n",
qxl->enable_surfaces? "Enabled" : "Disabled");
@@ -1572,17 +1945,9 @@ qxl_pre_init(ScrnInfoPtr pScrn, int flags)
pScrn->monitor->nVrefresh = 1;
}
- /* Add any modes not in xorg's default mode list */
- for (i = 0; i < qxl->num_modes; i++)
- if (qxl->modes[i].orientation == 0) {
- qxl_add_mode(pScrn, qxl->modes[i].x_res, qxl->modes[i].y_res,
- M_T_DRIVER);
- if (qxl->modes[i].x_res > max_x)
- max_x = qxl->modes[i].x_res;
- if (qxl->modes[i].y_res > max_y)
- max_y = qxl->modes[i].y_res;
- }
+ qxl_initialize_x_modes(qxl, pScrn, &max_x, &max_y);
+#if 0
if (pScrn->display->virtualX == 0 && pScrn->display->virtualY == 0) {
/* It is possible for the largest x + largest y size combined leading
to a virtual size which will not fit into the framebuffer when this
@@ -1604,14 +1969,14 @@ qxl_pre_init(ScrnInfoPtr pScrn, int flags)
pScrn->display->virtualY,
128 * 1024 * 1024, LOOKUP_BEST_REFRESH))
goto out;
+#endif
CHECK_POINT();
- xf86CrtcConfigInit(pScrn, &qxl_xf86crtc_config_funcs);
-
xf86PruneDriverModes(pScrn);
- pScrn->currentMode = pScrn->modes;
+ qxl_init_randr(pScrn, qxl);
+#if 0
/* If no modes are specified in xorg.conf, default to 1024x768 */
if (pScrn->display->modes == NULL || pScrn->display->modes[0] == NULL)
for (mode = pScrn->modes; mode; mode = mode->next)
@@ -1619,8 +1984,9 @@ qxl_pre_init(ScrnInfoPtr pScrn, int flags)
pScrn->currentMode = mode;
break;
}
+#endif
- xf86PrintModes(pScrn);
+ //xf86PrintModes(pScrn);
xf86SetDpi(pScrn, 0, 0);
if (!xf86LoadSubModule(pScrn, "fb")
@@ -1714,7 +2080,7 @@ qxl_init_scrn(ScrnInfoPtr pScrn)
pScrn->PreInit = qxl_pre_init;
pScrn->ScreenInit = qxl_screen_init;
pScrn->SwitchMode = qxl_switch_mode;
- pScrn->ValidMode = qxl_valid_mode;
+ pScrn->ValidMode = NULL,
pScrn->EnterVT = qxl_enter_vt;
pScrn->LeaveVT = qxl_leave_vt;
}
diff --git a/src/qxl_surface.c b/src/qxl_surface.c
index a5f8c9e..387a183 100644
--- a/src/qxl_surface.c
+++ b/src/qxl_surface.c
@@ -343,6 +343,12 @@ qxl_surface_recycle (surface_cache_t *cache, uint32_t id)
cache->free_surfaces = surface;
}
+/*
+ * mode is used for the whole virtual screen, not for a specific head.
+ * For a single head where virtual size is equal to the head size, they are
+ * equal. For multiple heads this mode will not match any existing heads and
+ * will be the containing virtual size.
+ */
qxl_surface_t *
qxl_surface_cache_create_primary (surface_cache_t *cache,
struct QXLMode *mode)
@@ -387,9 +393,24 @@ qxl_surface_cache_create_primary (surface_cache_t *cache,
dev_image = pixman_image_create_bits (format, mode->x_res, mode->y_res,
(uint32_t *)dev_addr, -mode->stride);
+ if (qxl->fb != NULL)
+ free(qxl->fb);
+ qxl->fb = calloc (qxl->virtual_x * qxl->virtual_y, 4);
+ if (!qxl->fb)
+ return NULL;
+
host_image = pixman_image_create_bits (format,
qxl->virtual_x, qxl->virtual_y,
qxl->fb, mode->stride);
+#if 0
+ xf86DrvMsg(cache->qxl->pScrn->scrnIndex, X_ERROR,
+ "testing dev_image memory (%d x %d)\n",
+ mode->x_res, mode->y_res);
+ memset(qxl->ram, 0, mode->stride * mode->y_res);
+ xf86DrvMsg(cache->qxl->pScrn->scrnIndex, X_ERROR,
+ "testing host_image memory\n");
+ memset(qxl->fb, 0, mode->stride * mode->y_res);
+#endif
surface = malloc (sizeof *surface);
surface->id = 0;
@@ -459,6 +480,7 @@ make_drawable (qxl_screen_t *qxl, int surface, uint8_t type,
int i;
drawable = qxl_allocnf (qxl, sizeof *drawable);
+ assert(drawable);
drawable->release_info.id = pointer_to_u64 (drawable);