mirror of
https://gitlab.freedesktop.org/xorg/xserver.git
synced 2025-12-29 10:20:08 +01:00
This commit adds DRI3/glamor support, effectively translating into hardware GPU support. Theoretically it should be possible to use DRM/GPU drivers such as virtio or vgem, although only the intel i915 driver is currently tested. Since Xvfb does no modeset, it opens the render node. Currently that is fixed to "/dev/dri/renderD128" and will be tweaked with future commits. Specific use-cases are left for the reader - testing glamor, GL driver or others. v2: Drop GLAMOR_NO_XV, use GLAMOR_FOR_XORG instead (Michel Dänzer) v3: Fix build w/o glamor v4: - Split out glamor dependency patch for meson (Pekka) - Enhance commit message (Pekka) - Use O_CLOEXEC with open() (Pekka) - Enhance error path, memory leak comments (Pekka) Signed-off-by: Emil Velikov <emil.velikov@collabora.com>
1132 lines
31 KiB
C
1132 lines
31 KiB
C
/*
|
|
|
|
Copyright 1993, 1998 The Open Group
|
|
|
|
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.
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of The Open Group shall
|
|
not be used in advertising or otherwise to promote the sale, use or
|
|
other dealings in this Software without prior written authorization
|
|
from The Open Group.
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_DIX_CONFIG_H
|
|
#include <dix-config.h>
|
|
#endif
|
|
|
|
#if defined(WIN32)
|
|
#include <X11/Xwinsock.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <X11/X.h>
|
|
#include <X11/Xproto.h>
|
|
#include <X11/Xos.h>
|
|
#include "scrnintstr.h"
|
|
#include "servermd.h"
|
|
#define PSZ 8
|
|
#include "fb.h"
|
|
#include "colormapst.h"
|
|
#include "gcstruct.h"
|
|
#include "input.h"
|
|
#include "mipointer.h"
|
|
#include "micmap.h"
|
|
#include <sys/types.h>
|
|
#ifdef HAVE_MMAP
|
|
#include <sys/mman.h>
|
|
#ifndef MAP_FILE
|
|
#define MAP_FILE 0
|
|
#endif
|
|
#endif /* HAVE_MMAP */
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
#ifndef WIN32
|
|
#include <sys/param.h>
|
|
#endif
|
|
#include <X11/XWDFile.h>
|
|
#ifdef HAS_SHM
|
|
#include <sys/ipc.h>
|
|
#include <sys/shm.h>
|
|
#endif /* HAS_SHM */
|
|
#include "dix.h"
|
|
#include "miline.h"
|
|
#include "glx_extinit.h"
|
|
#include "randrstr.h"
|
|
|
|
#ifdef GLAMOR_HAS_GBM
|
|
#include <glamor.h>
|
|
#include <gbm.h>
|
|
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
#define VFB_DEFAULT_WIDTH 1280
|
|
#define VFB_DEFAULT_HEIGHT 1024
|
|
#define VFB_DEFAULT_DEPTH 24
|
|
#define VFB_DEFAULT_WHITEPIXEL 1
|
|
#define VFB_DEFAULT_BLACKPIXEL 0
|
|
#define VFB_DEFAULT_LINEBIAS 0
|
|
#define XWD_WINDOW_NAME_LEN 60
|
|
|
|
typedef struct {
|
|
int width;
|
|
int paddedBytesWidth;
|
|
int paddedWidth;
|
|
int height;
|
|
int depth;
|
|
int bitsPerPixel;
|
|
int sizeInBytes;
|
|
int ncolors;
|
|
char *pfbMemory;
|
|
XWDColor *pXWDCmap;
|
|
XWDFileHeader *pXWDHeader;
|
|
Pixel blackPixel;
|
|
Pixel whitePixel;
|
|
unsigned int lineBias;
|
|
CloseScreenProcPtr closeScreen;
|
|
|
|
#ifdef HAVE_MMAP
|
|
int mmap_fd;
|
|
char mmap_file[MAXPATHLEN];
|
|
#endif
|
|
|
|
#ifdef HAS_SHM
|
|
int shmid;
|
|
#endif
|
|
#ifdef GLAMOR_HAS_GBM
|
|
int fd;
|
|
CreateScreenResourcesProcPtr createScreenResources;
|
|
struct gbm_device *gbm;
|
|
struct gbm_bo *front_bo;
|
|
#endif
|
|
} vfbScreenInfo, *vfbScreenInfoPtr;
|
|
|
|
static int vfbNumScreens;
|
|
static vfbScreenInfo *vfbScreens;
|
|
|
|
static vfbScreenInfo defaultScreenInfo = {
|
|
.width = VFB_DEFAULT_WIDTH,
|
|
.height = VFB_DEFAULT_HEIGHT,
|
|
.depth = VFB_DEFAULT_DEPTH,
|
|
.blackPixel = VFB_DEFAULT_BLACKPIXEL,
|
|
.whitePixel = VFB_DEFAULT_WHITEPIXEL,
|
|
.lineBias = VFB_DEFAULT_LINEBIAS,
|
|
};
|
|
|
|
static Bool vfbPixmapDepths[33];
|
|
|
|
#ifdef HAVE_MMAP
|
|
static char *pfbdir = NULL;
|
|
#endif
|
|
typedef enum { NORMAL_MEMORY_FB, SHARED_MEMORY_FB, MMAPPED_FILE_FB } fbMemType;
|
|
static fbMemType fbmemtype = NORMAL_MEMORY_FB;
|
|
static char needswap = 0;
|
|
static Bool Render = TRUE;
|
|
|
|
#define swapcopy16(_dst, _src) \
|
|
if (needswap) { CARD16 _s = _src; cpswaps(_s, _dst); } \
|
|
else _dst = _src;
|
|
|
|
#define swapcopy32(_dst, _src) \
|
|
if (needswap) { CARD32 _s = _src; cpswapl(_s, _dst); } \
|
|
else _dst = _src;
|
|
|
|
static void
|
|
vfbInitializePixmapDepths(void)
|
|
{
|
|
int i;
|
|
|
|
vfbPixmapDepths[1] = TRUE; /* always need bitmaps */
|
|
for (i = 2; i <= 32; i++)
|
|
vfbPixmapDepths[i] = FALSE;
|
|
}
|
|
|
|
static int
|
|
vfbBitsPerPixel(int depth)
|
|
{
|
|
if (depth == 1)
|
|
return 1;
|
|
else if (depth <= 8)
|
|
return 8;
|
|
else if (depth <= 16)
|
|
return 16;
|
|
else
|
|
return 32;
|
|
}
|
|
|
|
static void
|
|
freeScreenInfo(vfbScreenInfoPtr pvfb)
|
|
{
|
|
switch (fbmemtype) {
|
|
#ifdef HAVE_MMAP
|
|
case MMAPPED_FILE_FB:
|
|
if (-1 == unlink(pvfb->mmap_file)) {
|
|
perror("unlink");
|
|
ErrorF("unlink %s failed, %s",
|
|
pvfb->mmap_file, strerror(errno));
|
|
}
|
|
break;
|
|
#else /* HAVE_MMAP */
|
|
case MMAPPED_FILE_FB:
|
|
break;
|
|
#endif /* HAVE_MMAP */
|
|
|
|
#ifdef HAS_SHM
|
|
case SHARED_MEMORY_FB:
|
|
if (-1 == shmdt((char *) pvfb->pXWDHeader)) {
|
|
perror("shmdt");
|
|
ErrorF("shmdt failed, %s", strerror(errno));
|
|
}
|
|
break;
|
|
#else /* HAS_SHM */
|
|
case SHARED_MEMORY_FB:
|
|
break;
|
|
#endif /* HAS_SHM */
|
|
|
|
case NORMAL_MEMORY_FB:
|
|
free(pvfb->pXWDHeader);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
ddxGiveUp(enum ExitCode error)
|
|
{
|
|
int i;
|
|
|
|
/* clean up the framebuffers */
|
|
for (i = 0; i < vfbNumScreens; i++) {
|
|
freeScreenInfo(&vfbScreens[i]);
|
|
}
|
|
}
|
|
|
|
#ifdef __APPLE__
|
|
void
|
|
DarwinHandleGUI(int argc, char *argv[])
|
|
{
|
|
}
|
|
#endif
|
|
|
|
void
|
|
OsVendorInit(void)
|
|
{
|
|
}
|
|
|
|
void
|
|
OsVendorFatalError(const char *f, va_list args)
|
|
{
|
|
}
|
|
|
|
#if defined(DDXBEFORERESET)
|
|
void
|
|
ddxBeforeReset(void)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
#if INPUTTHREAD
|
|
/** This function is called in Xserver/os/inputthread.c when starting
|
|
the input thread. */
|
|
void
|
|
ddxInputThreadInit(void)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
void
|
|
ddxUseMsg(void)
|
|
{
|
|
ErrorF("-screen scrn WxHxD set screen's width, height, depth\n");
|
|
ErrorF("-pixdepths list-of-int support given pixmap depths\n");
|
|
ErrorF("+/-render turn on/off RENDER extension support"
|
|
"(default on)\n");
|
|
ErrorF("-linebias n adjust thin line pixelization\n");
|
|
ErrorF("-blackpixel n pixel value for black\n");
|
|
ErrorF("-whitepixel n pixel value for white\n");
|
|
|
|
#ifdef HAVE_MMAP
|
|
ErrorF
|
|
("-fbdir directory put framebuffers in mmap'ed files in directory\n");
|
|
#endif
|
|
|
|
#ifdef HAS_SHM
|
|
ErrorF("-shmem put framebuffers in shared memory\n");
|
|
#endif
|
|
}
|
|
|
|
int
|
|
ddxProcessArgument(int argc, char *argv[], int i)
|
|
{
|
|
static Bool firstTime = TRUE;
|
|
static int lastScreen = -1;
|
|
vfbScreenInfo *currentScreen;
|
|
|
|
if (firstTime) {
|
|
vfbInitializePixmapDepths();
|
|
firstTime = FALSE;
|
|
}
|
|
|
|
if (lastScreen == -1)
|
|
currentScreen = &defaultScreenInfo;
|
|
else
|
|
currentScreen = &vfbScreens[lastScreen];
|
|
|
|
if (strcmp(argv[i], "-screen") == 0) { /* -screen n WxHxD */
|
|
int screenNum;
|
|
|
|
CHECK_FOR_REQUIRED_ARGUMENTS(2);
|
|
screenNum = atoi(argv[i + 1]);
|
|
/* The protocol only has a CARD8 for number of screens in the
|
|
connection setup block, so don't allow more than that. */
|
|
if ((screenNum < 0) || (screenNum >= 255)) {
|
|
ErrorF("Invalid screen number %d\n", screenNum);
|
|
UseMsg();
|
|
FatalError("Invalid screen number %d passed to -screen\n",
|
|
screenNum);
|
|
}
|
|
|
|
if (vfbNumScreens <= screenNum) {
|
|
vfbScreens =
|
|
reallocarray(vfbScreens, screenNum + 1, sizeof(*vfbScreens));
|
|
if (!vfbScreens)
|
|
FatalError("Not enough memory for screen %d\n", screenNum);
|
|
for (; vfbNumScreens <= screenNum; ++vfbNumScreens)
|
|
vfbScreens[vfbNumScreens] = defaultScreenInfo;
|
|
}
|
|
|
|
if (3 != sscanf(argv[i + 2], "%dx%dx%d",
|
|
&vfbScreens[screenNum].width,
|
|
&vfbScreens[screenNum].height,
|
|
&vfbScreens[screenNum].depth)) {
|
|
ErrorF("Invalid screen configuration %s\n", argv[i + 2]);
|
|
UseMsg();
|
|
FatalError("Invalid screen configuration %s for -screen %d\n",
|
|
argv[i + 2], screenNum);
|
|
}
|
|
|
|
lastScreen = screenNum;
|
|
return 3;
|
|
}
|
|
|
|
if (strcmp(argv[i], "-pixdepths") == 0) { /* -pixdepths list-of-depth */
|
|
int depth, ret = 1;
|
|
|
|
CHECK_FOR_REQUIRED_ARGUMENTS(1);
|
|
while ((++i < argc) && (depth = atoi(argv[i])) != 0) {
|
|
if (depth < 0 || depth > 32) {
|
|
ErrorF("Invalid pixmap depth %d\n", depth);
|
|
UseMsg();
|
|
FatalError("Invalid pixmap depth %d passed to -pixdepths\n",
|
|
depth);
|
|
}
|
|
vfbPixmapDepths[depth] = TRUE;
|
|
ret++;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
if (strcmp(argv[i], "+render") == 0) { /* +render */
|
|
Render = TRUE;
|
|
return 1;
|
|
}
|
|
|
|
if (strcmp(argv[i], "-render") == 0) { /* -render */
|
|
Render = FALSE;
|
|
#ifdef COMPOSITE
|
|
noCompositeExtension = TRUE;
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
if (strcmp(argv[i], "-blackpixel") == 0) { /* -blackpixel n */
|
|
CHECK_FOR_REQUIRED_ARGUMENTS(1);
|
|
currentScreen->blackPixel = atoi(argv[++i]);
|
|
return 2;
|
|
}
|
|
|
|
if (strcmp(argv[i], "-whitepixel") == 0) { /* -whitepixel n */
|
|
CHECK_FOR_REQUIRED_ARGUMENTS(1);
|
|
currentScreen->whitePixel = atoi(argv[++i]);
|
|
return 2;
|
|
}
|
|
|
|
if (strcmp(argv[i], "-linebias") == 0) { /* -linebias n */
|
|
CHECK_FOR_REQUIRED_ARGUMENTS(1);
|
|
currentScreen->lineBias = atoi(argv[++i]);
|
|
return 2;
|
|
}
|
|
|
|
#ifdef HAVE_MMAP
|
|
if (strcmp(argv[i], "-fbdir") == 0) { /* -fbdir directory */
|
|
CHECK_FOR_REQUIRED_ARGUMENTS(1);
|
|
pfbdir = argv[++i];
|
|
fbmemtype = MMAPPED_FILE_FB;
|
|
return 2;
|
|
}
|
|
#endif /* HAVE_MMAP */
|
|
|
|
#ifdef HAS_SHM
|
|
if (strcmp(argv[i], "-shmem") == 0) { /* -shmem */
|
|
fbmemtype = SHARED_MEMORY_FB;
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
vfbInstallColormap(ColormapPtr pmap)
|
|
{
|
|
ColormapPtr oldpmap = GetInstalledmiColormap(pmap->pScreen);
|
|
|
|
if (pmap != oldpmap) {
|
|
int entries;
|
|
XWDFileHeader *pXWDHeader;
|
|
VisualPtr pVisual;
|
|
Pixel *ppix;
|
|
xrgb *prgb;
|
|
xColorItem *defs;
|
|
int i;
|
|
|
|
miInstallColormap(pmap);
|
|
|
|
entries = pmap->pVisual->ColormapEntries;
|
|
pXWDHeader = vfbScreens[pmap->pScreen->myNum].pXWDHeader;
|
|
pVisual = pmap->pVisual;
|
|
|
|
swapcopy32(pXWDHeader->visual_class, pVisual->class);
|
|
swapcopy32(pXWDHeader->red_mask, pVisual->redMask);
|
|
swapcopy32(pXWDHeader->green_mask, pVisual->greenMask);
|
|
swapcopy32(pXWDHeader->blue_mask, pVisual->blueMask);
|
|
swapcopy32(pXWDHeader->bits_per_rgb, pVisual->bitsPerRGBValue);
|
|
swapcopy32(pXWDHeader->colormap_entries, pVisual->ColormapEntries);
|
|
|
|
ppix = xallocarray(entries, sizeof(Pixel));
|
|
prgb = xallocarray(entries, sizeof(xrgb));
|
|
defs = xallocarray(entries, sizeof(xColorItem));
|
|
|
|
for (i = 0; i < entries; i++)
|
|
ppix[i] = i;
|
|
/* XXX truecolor */
|
|
QueryColors(pmap, entries, ppix, prgb, serverClient);
|
|
|
|
for (i = 0; i < entries; i++) { /* convert xrgbs to xColorItems */
|
|
defs[i].pixel = ppix[i] & 0xff; /* change pixel to index */
|
|
defs[i].red = prgb[i].red;
|
|
defs[i].green = prgb[i].green;
|
|
defs[i].blue = prgb[i].blue;
|
|
defs[i].flags = DoRed | DoGreen | DoBlue;
|
|
}
|
|
(*pmap->pScreen->StoreColors) (pmap, entries, defs);
|
|
|
|
free(ppix);
|
|
free(prgb);
|
|
free(defs);
|
|
}
|
|
}
|
|
|
|
static void
|
|
vfbStoreColors(ColormapPtr pmap, int ndef, xColorItem * pdefs)
|
|
{
|
|
XWDColor *pXWDCmap;
|
|
int i;
|
|
|
|
if (pmap != GetInstalledmiColormap(pmap->pScreen)) {
|
|
return;
|
|
}
|
|
|
|
pXWDCmap = vfbScreens[pmap->pScreen->myNum].pXWDCmap;
|
|
|
|
if ((pmap->pVisual->class | DynamicClass) == DirectColor) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < ndef; i++) {
|
|
if (pdefs[i].flags & DoRed) {
|
|
swapcopy16(pXWDCmap[pdefs[i].pixel].red, pdefs[i].red);
|
|
}
|
|
if (pdefs[i].flags & DoGreen) {
|
|
swapcopy16(pXWDCmap[pdefs[i].pixel].green, pdefs[i].green);
|
|
}
|
|
if (pdefs[i].flags & DoBlue) {
|
|
swapcopy16(pXWDCmap[pdefs[i].pixel].blue, pdefs[i].blue);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_MMAP
|
|
|
|
/* this flushes any changes to the screens out to the mmapped file */
|
|
static void
|
|
vfbBlockHandler(void *blockData, void *timeout)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < vfbNumScreens; i++) {
|
|
#ifdef MS_ASYNC
|
|
if (-1 == msync((caddr_t) vfbScreens[i].pXWDHeader,
|
|
(size_t) vfbScreens[i].sizeInBytes, MS_ASYNC))
|
|
#else
|
|
/* silly NetBSD and who else? */
|
|
if (-1 == msync((caddr_t) vfbScreens[i].pXWDHeader,
|
|
(size_t) vfbScreens[i].sizeInBytes))
|
|
#endif
|
|
{
|
|
perror("msync");
|
|
ErrorF("msync failed, %s", strerror(errno));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
vfbWakeupHandler(void *blockData, int result)
|
|
{
|
|
}
|
|
|
|
static void
|
|
vfbAllocateMmappedFramebuffer(vfbScreenInfoPtr pvfb)
|
|
{
|
|
#define DUMMY_BUFFER_SIZE 65536
|
|
char dummyBuffer[DUMMY_BUFFER_SIZE];
|
|
int currentFileSize, writeThisTime;
|
|
|
|
snprintf(pvfb->mmap_file, sizeof(pvfb->mmap_file), "%s/Xvfb_screen%d",
|
|
pfbdir, (int) (pvfb - vfbScreens));
|
|
if (-1 == (pvfb->mmap_fd = open(pvfb->mmap_file, O_CREAT | O_RDWR, 0666))) {
|
|
perror("open");
|
|
ErrorF("open %s failed, %s", pvfb->mmap_file, strerror(errno));
|
|
return;
|
|
}
|
|
|
|
/* Extend the file to be the proper size */
|
|
|
|
memset(dummyBuffer, 0, DUMMY_BUFFER_SIZE);
|
|
for (currentFileSize = 0;
|
|
currentFileSize < pvfb->sizeInBytes;
|
|
currentFileSize += writeThisTime) {
|
|
writeThisTime = min(DUMMY_BUFFER_SIZE,
|
|
pvfb->sizeInBytes - currentFileSize);
|
|
if (-1 == write(pvfb->mmap_fd, dummyBuffer, writeThisTime)) {
|
|
perror("write");
|
|
ErrorF("write %s failed, %s", pvfb->mmap_file, strerror(errno));
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* try to mmap the file */
|
|
|
|
pvfb->pXWDHeader = (XWDFileHeader *) mmap((caddr_t) NULL, pvfb->sizeInBytes,
|
|
PROT_READ | PROT_WRITE,
|
|
MAP_FILE | MAP_SHARED,
|
|
pvfb->mmap_fd, 0);
|
|
if (-1 == (long) pvfb->pXWDHeader) {
|
|
perror("mmap");
|
|
ErrorF("mmap %s failed, %s", pvfb->mmap_file, strerror(errno));
|
|
pvfb->pXWDHeader = NULL;
|
|
return;
|
|
}
|
|
|
|
if (!RegisterBlockAndWakeupHandlers(vfbBlockHandler, vfbWakeupHandler,
|
|
NULL)) {
|
|
pvfb->pXWDHeader = NULL;
|
|
}
|
|
}
|
|
#endif /* HAVE_MMAP */
|
|
|
|
#ifdef HAS_SHM
|
|
static void
|
|
vfbAllocateSharedMemoryFramebuffer(vfbScreenInfoPtr pvfb)
|
|
{
|
|
/* create the shared memory segment */
|
|
|
|
pvfb->shmid = shmget(IPC_PRIVATE, pvfb->sizeInBytes, IPC_CREAT | 0777);
|
|
if (pvfb->shmid < 0) {
|
|
perror("shmget");
|
|
ErrorF("shmget %d bytes failed, %s", pvfb->sizeInBytes,
|
|
strerror(errno));
|
|
return;
|
|
}
|
|
|
|
/* try to attach it */
|
|
|
|
pvfb->pXWDHeader = (XWDFileHeader *) shmat(pvfb->shmid, 0, 0);
|
|
if (-1 == (long) pvfb->pXWDHeader) {
|
|
perror("shmat");
|
|
ErrorF("shmat failed, %s", strerror(errno));
|
|
pvfb->pXWDHeader = NULL;
|
|
return;
|
|
}
|
|
|
|
ErrorF("screen %d shmid %d\n", (int) (pvfb - vfbScreens), pvfb->shmid);
|
|
}
|
|
#endif /* HAS_SHM */
|
|
|
|
static char *
|
|
vfbAllocateFramebufferMemory(vfbScreenInfoPtr pvfb)
|
|
{
|
|
if (pvfb->pfbMemory)
|
|
return pvfb->pfbMemory; /* already done */
|
|
|
|
pvfb->sizeInBytes = pvfb->paddedBytesWidth * pvfb->height;
|
|
|
|
/* Calculate how many entries in colormap. This is rather bogus, because
|
|
* the visuals haven't even been set up yet, but we need to know because we
|
|
* have to allocate space in the file for the colormap. The number 10
|
|
* below comes from the MAX_PSEUDO_DEPTH define in cfbcmap.c.
|
|
*/
|
|
|
|
if (pvfb->depth <= 10) { /* single index colormaps */
|
|
pvfb->ncolors = 1 << pvfb->depth;
|
|
}
|
|
else { /* decomposed colormaps */
|
|
int nplanes_per_color_component = pvfb->depth / 3;
|
|
|
|
if (pvfb->depth % 3)
|
|
nplanes_per_color_component++;
|
|
pvfb->ncolors = 1 << nplanes_per_color_component;
|
|
}
|
|
|
|
/* add extra bytes for XWDFileHeader, window name, and colormap */
|
|
|
|
pvfb->sizeInBytes += SIZEOF(XWDheader) + XWD_WINDOW_NAME_LEN +
|
|
pvfb->ncolors * SIZEOF(XWDColor);
|
|
|
|
pvfb->pXWDHeader = NULL;
|
|
switch (fbmemtype) {
|
|
#ifdef HAVE_MMAP
|
|
case MMAPPED_FILE_FB:
|
|
vfbAllocateMmappedFramebuffer(pvfb);
|
|
break;
|
|
#else
|
|
case MMAPPED_FILE_FB:
|
|
break;
|
|
#endif
|
|
|
|
#ifdef HAS_SHM
|
|
case SHARED_MEMORY_FB:
|
|
vfbAllocateSharedMemoryFramebuffer(pvfb);
|
|
break;
|
|
#else
|
|
case SHARED_MEMORY_FB:
|
|
break;
|
|
#endif
|
|
|
|
case NORMAL_MEMORY_FB:
|
|
pvfb->pXWDHeader = (XWDFileHeader *) malloc(pvfb->sizeInBytes);
|
|
break;
|
|
}
|
|
|
|
if (pvfb->pXWDHeader) {
|
|
pvfb->pXWDCmap = (XWDColor *) ((char *) pvfb->pXWDHeader
|
|
+ SIZEOF(XWDheader) +
|
|
XWD_WINDOW_NAME_LEN);
|
|
pvfb->pfbMemory = (char *) (pvfb->pXWDCmap + pvfb->ncolors);
|
|
|
|
return pvfb->pfbMemory;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
vfbWriteXWDFileHeader(ScreenPtr pScreen)
|
|
{
|
|
vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
|
|
XWDFileHeader *pXWDHeader = pvfb->pXWDHeader;
|
|
char hostname[XWD_WINDOW_NAME_LEN];
|
|
unsigned long swaptest = 1;
|
|
int i;
|
|
|
|
needswap = *(char *) &swaptest;
|
|
|
|
pXWDHeader->header_size =
|
|
(char *) pvfb->pXWDCmap - (char *) pvfb->pXWDHeader;
|
|
pXWDHeader->file_version = XWD_FILE_VERSION;
|
|
|
|
pXWDHeader->pixmap_format = ZPixmap;
|
|
pXWDHeader->pixmap_depth = pvfb->depth;
|
|
pXWDHeader->pixmap_height = pXWDHeader->window_height = pvfb->height;
|
|
pXWDHeader->xoffset = 0;
|
|
pXWDHeader->byte_order = IMAGE_BYTE_ORDER;
|
|
pXWDHeader->bitmap_bit_order = BITMAP_BIT_ORDER;
|
|
#ifndef INTERNAL_VS_EXTERNAL_PADDING
|
|
pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->width;
|
|
pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT;
|
|
pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD;
|
|
#else
|
|
pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->paddedWidth;
|
|
pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT_PROTO;
|
|
pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD_PROTO;
|
|
#endif
|
|
pXWDHeader->bits_per_pixel = pvfb->bitsPerPixel;
|
|
pXWDHeader->bytes_per_line = pvfb->paddedBytesWidth;
|
|
pXWDHeader->ncolors = pvfb->ncolors;
|
|
|
|
/* visual related fields are written when colormap is installed */
|
|
|
|
pXWDHeader->window_x = pXWDHeader->window_y = 0;
|
|
pXWDHeader->window_bdrwidth = 0;
|
|
|
|
/* write xwd "window" name: Xvfb hostname:server.screen */
|
|
|
|
if (-1 == gethostname(hostname, sizeof(hostname)))
|
|
hostname[0] = 0;
|
|
else
|
|
hostname[XWD_WINDOW_NAME_LEN - 1] = 0;
|
|
sprintf((char *) (pXWDHeader + 1), "Xvfb %s:%s.%d", hostname, display,
|
|
pScreen->myNum);
|
|
|
|
/* write colormap pixel slot values */
|
|
|
|
for (i = 0; i < pvfb->ncolors; i++) {
|
|
pvfb->pXWDCmap[i].pixel = i;
|
|
}
|
|
|
|
/* byte swap to most significant byte first */
|
|
|
|
if (needswap) {
|
|
SwapLongs((CARD32 *) pXWDHeader, SIZEOF(XWDheader) / 4);
|
|
for (i = 0; i < pvfb->ncolors; i++) {
|
|
swapl(&pvfb->pXWDCmap[i].pixel);
|
|
}
|
|
}
|
|
}
|
|
|
|
static Bool
|
|
vfbCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
vfbCrossScreen(ScreenPtr pScreen, Bool entering)
|
|
{
|
|
}
|
|
|
|
static miPointerScreenFuncRec vfbPointerCursorFuncs = {
|
|
vfbCursorOffScreen,
|
|
vfbCrossScreen,
|
|
miPointerWarpCursor
|
|
};
|
|
|
|
static Bool
|
|
vfbCloseScreen(ScreenPtr pScreen)
|
|
{
|
|
vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
|
|
|
|
pScreen->CloseScreen = pvfb->closeScreen;
|
|
|
|
/*
|
|
* fb overwrites miCloseScreen, so do this here
|
|
*/
|
|
if (pScreen->devPrivate)
|
|
(*pScreen->DestroyPixmap) (pScreen->devPrivate);
|
|
pScreen->devPrivate = NULL;
|
|
#ifdef GLAMOR_HAS_GBM
|
|
if (pvfb->fd >= 0) {
|
|
if (pvfb->front_bo) {
|
|
gbm_bo_destroy(pvfb->front_bo);
|
|
pvfb->front_bo = NULL;
|
|
}
|
|
close(pvfb->fd);
|
|
pvfb->fd = -1;
|
|
}
|
|
#endif
|
|
/*
|
|
* XXX: There is an existing vfbScreens leak. Should we free() it directly
|
|
* or otherwise - input welcome.
|
|
*/
|
|
|
|
return pScreen->CloseScreen(pScreen);
|
|
}
|
|
|
|
#ifdef GLAMOR_HAS_GBM
|
|
static Bool
|
|
vfbCreateScreenResources(ScreenPtr pScreen)
|
|
{
|
|
vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
|
|
PixmapPtr pixmap;
|
|
Bool ret;
|
|
|
|
pScreen->CreateScreenResources = pvfb->createScreenResources;
|
|
ret = pScreen->CreateScreenResources(pScreen);
|
|
pScreen->CreateScreenResources = vfbCreateScreenResources;
|
|
|
|
if (!ret)
|
|
return FALSE;
|
|
|
|
pixmap = pScreen->GetScreenPixmap(pScreen);
|
|
/* TODO: add support for modifiers at some point */
|
|
if (!glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, pvfb->front_bo,
|
|
FALSE)) {
|
|
LogMessage(X_ERROR, "glamor_egl_create_textured_pixmap() failed\n");
|
|
/* TODO: plug the leak, aka undo the CreateScreenResources() call above. */
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
vfbDRIInit(ScreenPtr pScreen)
|
|
{
|
|
vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
|
|
/* TODO: don't hardcode the node name */
|
|
const char *node_name = "/dev/dri/renderD128";
|
|
const char *error_msg;
|
|
|
|
pvfb->fd = open(node_name, O_RDWR | O_CLOEXEC);
|
|
if (pvfb->fd < 0) {
|
|
error_msg = "Failed to open device node";
|
|
goto out;
|
|
}
|
|
|
|
if (!glamor_egl_init(pScreen, pvfb->fd)) {
|
|
error_msg = "Failed to initialize glamor";
|
|
goto close_fd;
|
|
}
|
|
|
|
pvfb->gbm = glamor_egl_get_gbm_device(pScreen);
|
|
if (!pvfb->gbm) {
|
|
error_msg = "Failed to get gbm device";
|
|
goto egl_fini;
|
|
}
|
|
pvfb->front_bo = gbm_bo_create(pvfb->gbm,
|
|
pScreen->width, pScreen->height,
|
|
GBM_FORMAT_ARGB8888,
|
|
GBM_BO_USE_RENDERING);
|
|
if (!pvfb->front_bo) {
|
|
error_msg = "Failed to create front buffer";
|
|
goto egl_fini;
|
|
}
|
|
|
|
if (!glamor_init(pScreen, GLAMOR_USE_EGL_SCREEN)) {
|
|
error_msg = "Failed to initialize glamor at ScreenInit() time";
|
|
goto destroy_bo;
|
|
}
|
|
|
|
pvfb->createScreenResources = pScreen->CreateScreenResources;
|
|
pScreen->CreateScreenResources = vfbCreateScreenResources;
|
|
return;
|
|
|
|
destroy_bo:
|
|
gbm_bo_destroy(pvfb->front_bo);
|
|
egl_fini:
|
|
/* TODO: There's no glamor_egl_fini just yet */
|
|
close_fd:
|
|
close(pvfb->fd);
|
|
out:
|
|
LogMessage(X_ERROR, "%s. Disabling GLAMOR/DRI3.\n", error_msg);
|
|
return;
|
|
}
|
|
#else
|
|
static void
|
|
vfbDRIInit(ScreenPtr pScreen)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
static Bool
|
|
vfbRROutputValidateMode(ScreenPtr pScreen,
|
|
RROutputPtr output,
|
|
RRModePtr mode)
|
|
{
|
|
rrScrPriv(pScreen);
|
|
|
|
if (pScrPriv->minWidth <= mode->mode.width &&
|
|
pScrPriv->maxWidth >= mode->mode.width &&
|
|
pScrPriv->minHeight <= mode->mode.height &&
|
|
pScrPriv->maxHeight >= mode->mode.height)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static Bool
|
|
vfbRRScreenSetSize(ScreenPtr pScreen,
|
|
CARD16 width,
|
|
CARD16 height,
|
|
CARD32 mmWidth,
|
|
CARD32 mmHeight)
|
|
{
|
|
// Prevent screen updates while we change things around
|
|
SetRootClip(pScreen, ROOT_CLIP_NONE);
|
|
|
|
pScreen->width = width;
|
|
pScreen->height = height;
|
|
pScreen->mmWidth = mmWidth;
|
|
pScreen->mmHeight = mmHeight;
|
|
|
|
// Restore the ability to update screen, now with new dimensions
|
|
SetRootClip(pScreen, ROOT_CLIP_FULL);
|
|
|
|
RRScreenSizeNotify (pScreen);
|
|
RRTellChanged(pScreen);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
vfbRRCrtcSet(ScreenPtr pScreen,
|
|
RRCrtcPtr crtc,
|
|
RRModePtr mode,
|
|
int x,
|
|
int y,
|
|
Rotation rotation,
|
|
int numOutput,
|
|
RROutputPtr *outputs)
|
|
{
|
|
return RRCrtcNotify(crtc, mode, x, y, rotation, NULL, numOutput, outputs);
|
|
}
|
|
|
|
static Bool
|
|
vfbRRGetInfo(ScreenPtr pScreen, Rotation *rotations)
|
|
{
|
|
/* Don't support rotations */
|
|
*rotations = RR_Rotate_0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
vfbRandRInit(ScreenPtr pScreen)
|
|
{
|
|
rrScrPrivPtr pScrPriv;
|
|
#if RANDR_12_INTERFACE
|
|
RRModePtr mode;
|
|
RRCrtcPtr crtc;
|
|
RROutputPtr output;
|
|
xRRModeInfo modeInfo;
|
|
char name[64];
|
|
#endif
|
|
|
|
if (!RRScreenInit (pScreen))
|
|
return FALSE;
|
|
pScrPriv = rrGetScrPriv(pScreen);
|
|
pScrPriv->rrGetInfo = vfbRRGetInfo;
|
|
#if RANDR_12_INTERFACE
|
|
pScrPriv->rrCrtcSet = vfbRRCrtcSet;
|
|
pScrPriv->rrScreenSetSize = vfbRRScreenSetSize;
|
|
pScrPriv->rrOutputSetProperty = NULL;
|
|
#if RANDR_13_INTERFACE
|
|
pScrPriv->rrOutputGetProperty = NULL;
|
|
#endif
|
|
pScrPriv->rrOutputValidateMode = vfbRROutputValidateMode;
|
|
pScrPriv->rrModeDestroy = NULL;
|
|
|
|
RRScreenSetSizeRange (pScreen,
|
|
1, 1,
|
|
pScreen->width, pScreen->height);
|
|
|
|
sprintf (name, "%dx%d", pScreen->width, pScreen->height);
|
|
memset (&modeInfo, '\0', sizeof (modeInfo));
|
|
modeInfo.width = pScreen->width;
|
|
modeInfo.height = pScreen->height;
|
|
modeInfo.nameLength = strlen (name);
|
|
|
|
mode = RRModeGet (&modeInfo, name);
|
|
if (!mode)
|
|
return FALSE;
|
|
|
|
crtc = RRCrtcCreate (pScreen, NULL);
|
|
if (!crtc)
|
|
return FALSE;
|
|
|
|
/* This is to avoid xrandr to complain about the gamma missing */
|
|
RRCrtcGammaSetSize (crtc, 256);
|
|
|
|
output = RROutputCreate (pScreen, "screen", 6, NULL);
|
|
if (!output)
|
|
return FALSE;
|
|
if (!RROutputSetClones (output, NULL, 0))
|
|
return FALSE;
|
|
if (!RROutputSetModes (output, &mode, 1, 0))
|
|
return FALSE;
|
|
if (!RROutputSetCrtcs (output, &crtc, 1))
|
|
return FALSE;
|
|
if (!RROutputSetConnection (output, RR_Connected))
|
|
return FALSE;
|
|
RRCrtcNotify (crtc, mode, 0, 0, RR_Rotate_0, NULL, 1, &output);
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
vfbScreenInit(ScreenPtr pScreen, int argc, char **argv)
|
|
{
|
|
vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
|
|
int dpix = monitorResolution, dpiy = monitorResolution;
|
|
int ret;
|
|
char *pbits;
|
|
|
|
if (dpix == 0)
|
|
dpix = 100;
|
|
|
|
if (dpiy == 0)
|
|
dpiy = 100;
|
|
|
|
pvfb->paddedBytesWidth = PixmapBytePad(pvfb->width, pvfb->depth);
|
|
pvfb->bitsPerPixel = vfbBitsPerPixel(pvfb->depth);
|
|
if (pvfb->bitsPerPixel >= 8)
|
|
pvfb->paddedWidth = pvfb->paddedBytesWidth / (pvfb->bitsPerPixel / 8);
|
|
else
|
|
pvfb->paddedWidth = pvfb->paddedBytesWidth * 8;
|
|
pbits = vfbAllocateFramebufferMemory(pvfb);
|
|
if (!pbits)
|
|
return FALSE;
|
|
|
|
switch (pvfb->depth) {
|
|
case 8:
|
|
miSetVisualTypesAndMasks(8,
|
|
((1 << StaticGray) |
|
|
(1 << GrayScale) |
|
|
(1 << StaticColor) |
|
|
(1 << PseudoColor) |
|
|
(1 << TrueColor) |
|
|
(1 << DirectColor)), 8, PseudoColor, 0, 0, 0);
|
|
break;
|
|
case 15:
|
|
miSetVisualTypesAndMasks(15,
|
|
((1 << TrueColor) |
|
|
(1 << DirectColor)),
|
|
8, TrueColor, 0x7c00, 0x03e0, 0x001f);
|
|
break;
|
|
case 16:
|
|
miSetVisualTypesAndMasks(16,
|
|
((1 << TrueColor) |
|
|
(1 << DirectColor)),
|
|
8, TrueColor, 0xf800, 0x07e0, 0x001f);
|
|
break;
|
|
case 24:
|
|
miSetVisualTypesAndMasks(24,
|
|
((1 << TrueColor) |
|
|
(1 << DirectColor)),
|
|
8, TrueColor, 0xff0000, 0x00ff00, 0x0000ff);
|
|
break;
|
|
case 30:
|
|
miSetVisualTypesAndMasks(30,
|
|
((1 << TrueColor) |
|
|
(1 << DirectColor)),
|
|
10, TrueColor, 0x3ff00000, 0x000ffc00,
|
|
0x000003ff);
|
|
break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
miSetPixmapDepths();
|
|
|
|
ret = fbScreenInit(pScreen, pbits, pvfb->width, pvfb->height,
|
|
dpix, dpiy, pvfb->paddedWidth, pvfb->bitsPerPixel);
|
|
if (!ret)
|
|
return FALSE;
|
|
|
|
if (Render) {
|
|
fbPictureInit(pScreen, 0, 0);
|
|
vfbDRIInit(pScreen);
|
|
}
|
|
|
|
if (!vfbRandRInit(pScreen))
|
|
return FALSE;
|
|
|
|
pScreen->InstallColormap = vfbInstallColormap;
|
|
pScreen->StoreColors = vfbStoreColors;
|
|
|
|
miDCInitialize(pScreen, &vfbPointerCursorFuncs);
|
|
|
|
vfbWriteXWDFileHeader(pScreen);
|
|
|
|
pScreen->blackPixel = pvfb->blackPixel;
|
|
pScreen->whitePixel = pvfb->whitePixel;
|
|
|
|
ret = fbCreateDefColormap(pScreen);
|
|
|
|
miSetZeroLineBias(pScreen, pvfb->lineBias);
|
|
|
|
pvfb->closeScreen = pScreen->CloseScreen;
|
|
pScreen->CloseScreen = vfbCloseScreen;
|
|
|
|
return ret;
|
|
|
|
} /* end vfbScreenInit */
|
|
|
|
void
|
|
InitOutput(ScreenInfo * screen_info, int argc, char **argv)
|
|
{
|
|
int i;
|
|
int NumFormats = 0;
|
|
|
|
/* initialize pixmap formats */
|
|
|
|
/* must have a pixmap depth to match every screen depth */
|
|
for (i = 0; i < vfbNumScreens; i++) {
|
|
vfbPixmapDepths[vfbScreens[i].depth] = TRUE;
|
|
}
|
|
|
|
/* RENDER needs a good set of pixmaps. */
|
|
if (Render) {
|
|
vfbPixmapDepths[1] = TRUE;
|
|
vfbPixmapDepths[4] = TRUE;
|
|
vfbPixmapDepths[8] = TRUE;
|
|
#if 0
|
|
vfbPixmapDepths[12] = TRUE;
|
|
#endif
|
|
/* vfbPixmapDepths[15] = TRUE; */
|
|
vfbPixmapDepths[16] = TRUE;
|
|
vfbPixmapDepths[24] = TRUE;
|
|
#if 0
|
|
vfbPixmapDepths[30] = TRUE;
|
|
#endif
|
|
vfbPixmapDepths[32] = TRUE;
|
|
}
|
|
|
|
xorgGlxCreateVendor();
|
|
|
|
for (i = 1; i <= 32; i++) {
|
|
if (vfbPixmapDepths[i]) {
|
|
if (NumFormats >= MAXFORMATS)
|
|
FatalError("MAXFORMATS is too small for this server\n");
|
|
screen_info->formats[NumFormats].depth = i;
|
|
screen_info->formats[NumFormats].bitsPerPixel = vfbBitsPerPixel(i);
|
|
screen_info->formats[NumFormats].scanlinePad = BITMAP_SCANLINE_PAD;
|
|
NumFormats++;
|
|
}
|
|
}
|
|
|
|
screen_info->imageByteOrder = IMAGE_BYTE_ORDER;
|
|
screen_info->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT;
|
|
screen_info->bitmapScanlinePad = BITMAP_SCANLINE_PAD;
|
|
screen_info->bitmapBitOrder = BITMAP_BIT_ORDER;
|
|
screen_info->numPixmapFormats = NumFormats;
|
|
|
|
/* initialize screens */
|
|
|
|
if (vfbNumScreens < 1) {
|
|
vfbScreens = &defaultScreenInfo;
|
|
vfbNumScreens = 1;
|
|
}
|
|
for (i = 0; i < vfbNumScreens; i++) {
|
|
if (-1 == AddScreen(vfbScreenInit, argc, argv)) {
|
|
FatalError("Couldn't add screen %d", i);
|
|
}
|
|
}
|
|
|
|
} /* end InitOutput */
|