Commit f548cc3e authored by Jeremy White's avatar Jeremy White
Browse files

Initial set of revisions to the dummy driver to add DRI and Present.

This makes the dummy driver similar to the mode setting driver.

This work was done by Henri Verbeet, which was in turn based heavily on
the Xorg modesetting driver.
parent 475c51bd
config.h
config.h.in
libtool
ltmain.sh
stamp-h1
src/.libs
*.o
*.lo
*.la
xf86-video-dummy - virtual/offscreen frame buffer driver for the Xorg X server
spice-video-dummy - virtual/offscreen frame buffer driver for the Xorg X server
------------------------------------------------------------------------------
All questions regarding this software should be directed at the
Xorg mailing list:
spice-devel mailing list:
https://lists.x.org/mailman/listinfo/xorg
https://lists.freedesktop.org/mailman/listinfo/spice-devel
The master development code repository can be found at:
This driver originated with the dummy driver from:
https://gitlab.freedesktop.org/xorg/driver/xf86-video-dummy
Please submit bug reports and requests to merge patches there.
For patch submission instructions, see:
https://www.x.org/wiki/Development/Documentation/SubmittingPatches
and modified to be similar to the mode setting driver:
https://gitlab.freedesktop.org/xorg/xserver/tree/master/hw/xfree86/drivers/modesetting
......@@ -22,10 +22,10 @@
# Initialize Autoconf
AC_PREREQ([2.60])
AC_INIT([xf86-video-dummy],
[0.3.8],
[https://gitlab.freedesktop.org/xorg/driver/xf86-video-dummy/issues],
[xf86-video-dummy])
AC_INIT([spice-video-dummy],
[1.1],
[https://gitlab.freedesktop.org/spice/x11spice/issues],
[spice-video-dummy])
AC_CONFIG_SRCDIR([Makefile.am])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_AUX_DIR(.)
......@@ -61,10 +61,6 @@ PKG_CHECK_MODULES(XORG, [xorg-server >= 1.4.99.901] xproto fontsproto $REQUIRED_
# Checks for libraries.
DRIVER_NAME=dummy
AC_SUBST([DRIVER_NAME])
AC_CONFIG_FILES([
Makefile
src/Makefile
......
Section "Device"
Identifier "SpiceDummy"
Driver "spicedummy"
# The SWcursor option enables a software cursor. Default false.
#Option "SWcursor" "false"
# AccelMethod can be glamor (the default), or none.
#Option "AccelMethod" "glamor"
# kmsdev specifies which framebuffer device to use, default /dev/dri/renderD128
#Option "kmsdev" "/dev/dri/renderD128"
VideoRam 16384
EndSection
Section "InputDevice"
Identifier "dummy_mouse"
Option "CorePointer" "true"
Driver "void"
EndSection
Section "InputDevice"
Identifier "dummy_keyboard"
Option "CoreKeyboard" "true"
Driver "void"
EndSection
Section "Screen"
Identifier "SpiceDummy"
SubSection "Display"
Virtual 1920 1200
EndSubSection
EndSection
......@@ -27,13 +27,15 @@
AM_CFLAGS = $(XORG_CFLAGS) $(PCIACCESS_CFLAGS)
dummy_drv_la_LTLIBRARIES = dummy_drv.la
dummy_drv_la_LDFLAGS = -module -avoid-version
dummy_drv_la_LIBADD = $(XORG_LIBS)
dummy_drv_ladir = @moduledir@/drivers
spicedummy_drv_la_LTLIBRARIES = spicedummy_drv.la
spicedummy_drv_la_LDFLAGS = -module -avoid-version
spicedummy_drv_la_LIBADD = $(XORG_LIBS)
spicedummy_drv_ladir = @moduledir@/drivers
dummy_drv_la_SOURCES = \
spicedummy_drv_la_SOURCES = \
compat-api.h \
dri2.c \
dummy_cursor.c \
dummy_driver.c \
dummy.h
spicedummy_driver.c \
dummy.h \
present.c
/*
* Copyright 2019 Henri Verbeet
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "dummy.h"
#include "dri2.h"
#include "xf86drm.h"
struct dummy_dri2_buffer_private {
PixmapRec *pixmap;
};
static PixmapRec *
dummy_get_drawable_pixmap(DrawableRec * drawable)
{
const ScreenRec *screen = drawable->pScreen;
if (drawable->type == DRAWABLE_PIXMAP) {
return (PixmapRec *) drawable;
}
return screen->GetWindowPixmap((WindowRec *) drawable);
}
static DRI2Buffer2Rec *
dummy_dri2_create_buffer2(ScreenRec * screen,
DrawableRec * drawable, unsigned int attachment, unsigned int format)
{
const ScrnInfoRec *scrn = xf86ScreenToScrn(screen);
struct dummy_dri2_buffer_private *private;
DRI2Buffer2Rec *buffer;
PixmapRec *pixmap;
CARD16 pitch;
CARD32 size;
if (!(buffer = calloc(1, sizeof(*buffer)))) {
return NULL;
}
if (!(private = calloc(1, sizeof(*private)))) {
free(buffer);
return NULL;
}
pixmap = NULL;
if (attachment == DRI2BufferFrontLeft) {
pixmap = dummy_get_drawable_pixmap(drawable);
if (pixmap && pixmap->drawable.pScreen != screen) {
pixmap = NULL;
}
if (pixmap) {
++pixmap->refcnt;
}
}
if (!pixmap) {
switch (attachment) {
case DRI2BufferAccum:
case DRI2BufferBackLeft:
case DRI2BufferBackRight:
case DRI2BufferFakeFrontLeft:
case DRI2BufferFakeFrontRight:
case DRI2BufferFrontLeft:
case DRI2BufferFrontRight:
break;
case DRI2BufferStencil:
case DRI2BufferDepth:
case DRI2BufferDepthStencil:
case DRI2BufferHiz:
default:
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"Request for DRI2 buffer attachment %#x unsupported.\n", attachment);
free(private);
free(buffer);
return NULL;
}
if (!(pixmap = screen->CreatePixmap(screen, drawable->width,
drawable->height, format ? format : drawable->depth,
0))) {
free(private);
free(buffer);
return NULL;
}
}
buffer->attachment = attachment;
buffer->cpp = pixmap->drawable.bitsPerPixel / 8;
buffer->format = format;
buffer->flags = 0;
buffer->name = glamor_name_from_pixmap(pixmap, &pitch, &size);
buffer->pitch = pitch;
if (buffer->name == -1) {
xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to get DRI2 name for pixmap.\n");
screen->DestroyPixmap(pixmap);
free(private);
free(buffer);
return NULL;
}
buffer->driverPrivate = private;
private->pixmap = pixmap;
return buffer;
}
static DRI2Buffer2Rec *
dummy_dri2_create_buffer(DrawableRec * drawable, unsigned int attachment, unsigned int format)
{
return dummy_dri2_create_buffer2(drawable->pScreen, drawable, attachment, format);
}
static void
dummy_dri2_destroy_buffer2(ScreenRec * unused, DrawableRec * unused2, DRI2Buffer2Rec * buffer)
{
struct dummy_dri2_buffer_private *private;
const ScreenRec *screen;
if (!buffer) {
return;
}
if (!(private = buffer->driverPrivate)) {
free(buffer);
return;
}
screen = private->pixmap->drawable.pScreen;
screen->DestroyPixmap(private->pixmap);
free(private);
free(buffer);
}
static void
dummy_dri2_destroy_buffer(DrawableRec * drawable, DRI2Buffer2Rec * buffer)
{
dummy_dri2_destroy_buffer2(NULL, drawable, buffer);
}
static void
dummy_dri2_copy_region2(ScreenRec * screen, DrawableRec * drawable,
RegionRec * region, DRI2BufferRec * dst_buffer, DRI2BufferRec * src_buffer)
{
const struct dummy_dri2_buffer_private *src_priv = src_buffer->driverPrivate;
const struct dummy_dri2_buffer_private *dst_priv = dst_buffer->driverPrivate;
int off_x = 0, off_y = 0;
Bool translate = FALSE;
DrawableRec *src, *dst;
RegionRec *clip_region;
GC *gc;
src = (src_buffer->attachment == DRI2BufferFrontLeft) ? drawable : &src_priv->pixmap->drawable;
dst = (dst_buffer->attachment == DRI2BufferFrontLeft) ? drawable : &dst_priv->pixmap->drawable;
if (dst_buffer->attachment == DRI2BufferFrontLeft && drawable->pScreen != screen) {
if (!(dst = DRI2UpdatePrime(drawable, dst_buffer))) {
return;
}
if (dst != drawable) {
translate = TRUE;
}
}
if (translate && drawable->type == DRAWABLE_WINDOW) {
const PixmapRec *pixmap = dummy_get_drawable_pixmap(drawable);
off_x = -pixmap->screen_x;
off_y = -pixmap->screen_y;
off_x += drawable->x;
off_y += drawable->y;
}
if (!(gc = GetScratchGC(dst->depth, screen))) {
return;
}
clip_region = REGION_CREATE(screen, NULL, 0);
REGION_COPY(screen, clip_region, region);
if (translate) {
REGION_TRANSLATE(screen, clip_region, off_x, off_y);
}
gc->funcs->ChangeClip(gc, CT_REGION, clip_region, 0);
ValidateGC(dst, gc);
gc->ops->CopyArea(src, dst, gc, 0, 0, drawable->width, drawable->height, off_x, off_y);
FreeScratchGC(gc);
}
static void
dummy_dri2_copy_region(DrawableRec * drawable, RegionRec * region,
DRI2BufferRec * dst_buffer, DRI2BufferRec * src_buffer)
{
dummy_dri2_copy_region2(drawable->pScreen, drawable, region, dst_buffer, src_buffer);
}
static int
dummy_dri2_get_msc(DrawableRec * drawable, CARD64 * ust, CARD64 * msc)
{
*ust = dummy_gettime_us();
*msc = 0;
return TRUE;
}
static int
dummy_dri2_schedule_wait_msc(ClientRec * client, DrawableRec * drawable,
CARD64 target_msc, CARD64 divisor, CARD64 remainder)
{
DRI2WaitMSCComplete(client, drawable, target_msc, 0, 0);
return TRUE;
}
static int
dummy_dri2_schedule_swap(ClientRec * client, DrawableRec * drawable,
DRI2BufferRec * front, DRI2BufferRec * back,
CARD64 * target_msc, CARD64 divisor, CARD64 remainder,
DRI2SwapEventPtr func, void *data)
{
RegionRec region;
BoxRec box;
box.x1 = 0;
box.y1 = 0;
box.x2 = drawable->width;
box.y2 = drawable->height;
RegionInit(&region, &box, 0);
dummy_dri2_copy_region(drawable, &region, front, back);
DRI2SwapComplete(client, drawable, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
*target_msc = 0;
return TRUE;
}
Bool
dummy_dri2_screen_init(ScreenRec * screen)
{
const ScrnInfoRec *scrn = xf86ScreenToScrn(screen);
const DUMMYRec *dummy = scrn->driverPrivate;
DRI2InfoRec info;
if (!glamor_supports_pixmap_import_export(screen)) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"DRI2: glamor lacks support for pixmap import/export\n");
}
if (!xf86LoaderCheckSymbol("DRI2Version")) {
return FALSE;
}
memset(&info, 0, sizeof(info));
info.fd = dummy->fd;
info.driverName = NULL;
info.deviceName = drmGetDeviceNameFromFd2(dummy->fd);
info.version = 9;
info.CreateBuffer = dummy_dri2_create_buffer;
info.DestroyBuffer = dummy_dri2_destroy_buffer;
info.CopyRegion = dummy_dri2_copy_region;
info.ScheduleSwap = dummy_dri2_schedule_swap;
info.GetMSC = dummy_dri2_get_msc;
info.ScheduleWaitMSC = dummy_dri2_schedule_wait_msc;
info.CreateBuffer2 = dummy_dri2_create_buffer2;
info.DestroyBuffer2 = dummy_dri2_destroy_buffer2;
info.CopyRegion2 = dummy_dri2_copy_region2;
info.numDrivers = 0;
info.driverNames = NULL;
return DRI2ScreenInit(screen, &info);
}
void
dummy_dri2_close_screen(ScreenRec * screen)
{
DRI2CloseScreen(screen);
}
......@@ -13,6 +13,9 @@
#include "compat-api.h"
#define GLAMOR_FOR_XORG 1
#include "glamor.h"
/* Supported chipsets */
typedef enum {
DUMMY_CHIP
......@@ -28,6 +31,10 @@ extern Bool DUMMYCursorInit(ScreenPtr pScrn);
extern void DUMMYShowCursor(ScrnInfoPtr pScrn);
extern void DUMMYHideCursor(ScrnInfoPtr pScrn);
void dummy_dri2_close_screen(ScreenRec * screen);
Bool dummy_dri2_screen_init(ScreenRec * screen);
Bool dummy_present_screen_init(ScreenRec * screen);
/* globals */
typedef struct _color {
int red;
......@@ -50,7 +57,22 @@ typedef struct dummyRec {
dummy_colors colors[1024];
Bool (*CreateWindow)(); /* wrapped CreateWindow */
Bool prop;
Bool glamor;
int fd;
} DUMMYRec, *DUMMYPtr;
/* The privates of the DUMMY driver */
#define DUMMYPTR(p) ((DUMMYPtr)((p)->driverPrivate))
static inline uint64_t
dummy_gettime_us(void)
{
struct timespec tv;
if (clock_gettime(CLOCK_MONOTONIC, &tv)) {
return 0;
}
return (uint64_t) tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
}
/*
* Copyright 2019 Henri Verbeet
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "dummy.h"
#include "present.h"
static RRCrtcRec *
dummy_present_get_crtc(WindowRec * window)
{
return NULL;
}
static int
dummy_present_get_ust_msc(RRCrtcRec * crtc, CARD64 * ust, CARD64 * msc)
{
*ust = dummy_gettime_us();
*msc = 0;
return Success;
}
static int
dummy_present_queue_vblank(RRCrtcRec * crtc, uint64_t event_id, uint64_t msc)
{
present_event_notify(event_id, dummy_gettime_us(), msc);
return Success;
}
static void
dummy_present_abort_vblank(RRCrtcRec * crtc, uint64_t event_id, uint64_t msc)
{
}
static void
dummy_present_flush(WindowRec * window)
{
glamor_block_handler(window->drawable.pScreen);
}
static Bool
dummy_present_check_flip(RRCrtcRec * crtc, WindowRec * window, PixmapRec * pixmap, Bool sync_flip)
{
return FALSE;
}
static Bool
dummy_present_flip(RRCrtcRec * crtc, uint64_t event_id,
uint64_t target_msc, PixmapRec * pixmap, Bool sync_flip)
{
return FALSE;
}
static void
dummy_present_unflip(ScreenRec * screen, uint64_t event_id)
{
present_event_notify(event_id, 0, 0);
}
Bool
dummy_present_screen_init(ScreenRec * screen)
{
static struct present_screen_info present_screen_info = {
.version = PRESENT_SCREEN_INFO_VERSION,
.get_crtc = dummy_present_get_crtc,
.get_ust_msc = dummy_present_get_ust_msc,
.queue_vblank = dummy_present_queue_vblank,
.abort_vblank = dummy_present_abort_vblank,
.flush = dummy_present_flush,
.capabilities = PresentCapabilityNone,
.check_flip = dummy_present_check_flip,
.flip = dummy_present_flip,
.unflip = dummy_present_unflip,
};
return present_screen_init(screen, &present_screen_info);
}
......@@ -33,6 +33,8 @@
* Driver data structures.
*/
#include "dummy.h"
#include <fcntl.h>
#include <errno.h>
/* These need to be checked */
#include <X11/X.h>
......@@ -62,8 +64,8 @@ static Bool dummyDriverFunc(ScrnInfoPtr pScrn, xorgDriverFuncOp op, pointer ptr)
/* int PowerManagementMode, int flags); */
#define DUMMY_VERSION 4000
#define DUMMY_NAME "DUMMY"
#define DUMMY_DRIVER_NAME "dummy"
#define DUMMY_NAME "SPICEDUMMY"
#define DUMMY_DRIVER_NAME "spicedummy"
#define DUMMY_MAJOR_VERSION PACKAGE_VERSION_MAJOR
#define DUMMY_MINOR_VERSION PACKAGE_VERSION_MINOR
......@@ -99,16 +101,20 @@ _X_EXPORT DriverRec DUMMY = {
};
static SymTabRec DUMMYChipsets[] = {
{DUMMY_CHIP, "dummy"},
{DUMMY_CHIP, "spicedummy"},
{-1, NULL}
};
typedef enum {
OPTION_SW_CURSOR
OPTION_SW_CURSOR,
OPTION_DEVICE_PATH,
OPTION_ACCEL_METHOD,
} DUMMYOpts;
static const OptionInfoRec DUMMYOptions[] = {
{OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_DEVICE_PATH, "kmsdev", OPTV_STRING, {0}, FALSE},
{OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE},
{-1, NULL, OPTV_NONE, {0}, FALSE}
};
......@@ -117,7 +123,7 @@ static const OptionInfoRec DUMMYOptions[] = {
static MODULESETUPPROTO(dummySetup);
static XF86ModuleVersionInfo dummyVersRec = {
"dummy",
"spicedummy",
MODULEVENDORSTRING,
MODINFOSTRING1,
MODINFOSTRING2,
......@@ -133,7 +139,7 @@ static XF86ModuleVersionInfo dummyVersRec = {
* This is the module init data.
* Its name has to be the driver name followed by ModuleData
*/
_X_EXPORT XF86ModuleData dummyModuleData = { &dummyVersRec, dummySetup, NULL };
_X_EXPORT XF86ModuleData spicedummyModuleData = { &dummyVersRec, dummySetup, NULL };