summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Jackson <ajax@redhat.com>2017-05-10 11:54:40 -0400
committerAdam Jackson <ajax@redhat.com>2017-06-16 15:47:57 -0400
commite93c950ed7adc5fefb9dbe09798b6e3e885a69c6 (patch)
tree60f8024a86ff766e9afd06df1c89a6cf22ae20f7
parent5d49af3c0306fe2f9141c7970b316fc2adc572a9 (diff)
glx: Add dispatch frontend
This allows multiple GLX backends to coexist within a single server. There are three categories of requests. QueryVersion is just hardwired to return 1.4. The client info requests are dispatched to every backend, because it is needed when computing GetString replies and the BE is better positioned to do that intersection than the FE. For all other requests, we establish a mapping between the XID/tag and the backend as they are created. For XIDs we set up a mirror resource (with the same XID) that points to the backend, which makes lifetime management easy. Tags are trickier. XXX and in fact don't work yet. The plan is to create a fake (client-namespace) XID for the tag, but the tag ID itself is only mentioned in the MakeCurrent reply, so the backends will need to call up; and with that in mind, we may as well just allocate the tags in the FE. This effectively maps tags into the XID space. Signed-off-by: Adam Jackson <ajax@redhat.com>
-rw-r--r--glx/glxfe.c790
-rw-r--r--glx/glxfe.h106
-rw-r--r--glx/meson.build15
3 files changed, 911 insertions, 0 deletions
diff --git a/glx/glxfe.c b/glx/glxfe.c
new file mode 100644
index 000000000..4ead55e69
--- /dev/null
+++ b/glx/glxfe.c
@@ -0,0 +1,790 @@
+/*
+ * Copyright © 2017 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ * Adam Jackson <ajax@redhat.com>
+ */
+
+/*
+ * Notes:
+ *
+ * This code requires that the context tags returned by the backends not
+ * collide. XXX Can we just be the tag tracker ourselves instead?
+ *
+ * MakeCurrent will notice when the old and new contexts share a backend
+ * and only call the backend once if so.
+ *
+ * Nothing is setting up vendor private dispatch yet.
+ *
+ * Need to handle swapping here! But just the screen/xid/tag field so really
+ * we can swap when looking up the backend. Enhance: can keep two vtables
+ * for swapped or not! That could be a cool optimization later, swap first
+ * then call in? Except for replies.
+ */
+
+#include <dix-config.h>
+#include "glxfe.h"
+#include "hashtable.h"
+#include "glxserver.h"
+#include "privates.h"
+#include "protocol-versions.h"
+#include "windowstr.h"
+
+/* variables */
+
+RESTYPE GlxFEXID;
+
+ExtensionEntry *GlxExtension;
+
+static HashTable fe_vop_hash;
+
+static const HtGenericHashSetupRec hashSetup = {
+ .keySize = 4
+};
+
+static int
+GlxFeHashSetup(void)
+{
+ fe_vop_hash = ht_create(sizeof(int), sizeof(struct GlxVop),
+ ht_generic_hash, ht_generic_compare, &hashSetup);
+ return !!fe_vop_hash;
+}
+
+static DevPrivateKeyRec GlxFEPrivateKeyRec;
+
+static int
+DeleteXID(void *value, XID id)
+{
+ /* this is just a shallow pointer to the backend, nothing to do here */
+ return 0;
+}
+
+static int
+CreateXID(void *be, XID id)
+{
+ if (!AddResource(id, GlxFEXID, be)) {
+ FreeResource(id , RT_NONE);
+ return BadAlloc;
+ }
+ return Success;
+}
+
+static GlxBackend *
+backendForScreen(int screen)
+{
+ ScreenPtr pScreen;
+
+ if (screen < 0 || screen > screenInfo.numScreens)
+ return NULL;
+
+ pScreen = screenInfo.screens[screen];
+ return dixLookupPrivate(&pScreen->devPrivates, &GlxFEPrivateKeyRec);
+}
+
+static GlxBackend *
+backendForXID(XID xid)
+{
+ void *ret = NULL;
+ dixLookupResourceByType(&ret, xid, GlxFEXID, NULL, 0);
+ return ret;
+}
+
+static GlxBackend *
+backendForGLXDrawable(XID xid)
+{
+ GlxBackend *be = backendForXID(xid);
+
+ if (!be) {
+ WindowPtr pWin;
+
+ if (dixLookupWindow(&pWin, xid, NULL, 0) == Success)
+ be = backendForScreen(pWin->drawable.pScreen->myNum);
+ }
+ return be;
+}
+
+/*
+ * Tag tracking. This is "broken" for the moment, it assumes Xorg's
+ * "the tag is the XID" implementation. I'm not sure how I want to handle
+ * this in the general case yet, but right now I just need to get things
+ * standing up.
+ */
+static GlxBackend *
+backendForTag(GLXContextTag tag)
+{
+ return backendForXID(tag);
+}
+
+void
+GlxSetBackend(ScreenPtr pScreen, GlxBackend *backend)
+{
+ dixSetPrivate(&pScreen->devPrivates, &GlxFEPrivateKeyRec, backend);
+}
+
+static GlxVop *
+glxVop(int op)
+{
+ return ht_find(fe_vop_hash, (void *)(uintptr_t)op);
+}
+
+static int
+ProcGLXRender(ClientPtr client)
+{
+ REQUEST(xGLXSingleReq);
+ GlxBackend *be = backendForTag(stuff->contextTag);
+ if (!be)
+ return __glXError(GLXBadContextTag);
+ return be->Render(client);
+}
+
+static int
+ProcGLXRenderLarge(ClientPtr client)
+{
+ REQUEST(xGLXSingleReq);
+ GlxBackend *be = backendForTag(stuff->contextTag);
+ if (!be)
+ return __glXError(GLXBadContextTag);
+ return be->RenderLarge(client);
+}
+
+static int
+ProcGLXCreateContext(ClientPtr client)
+{
+ REQUEST(xGLXCreateContextReq);
+ GlxBackend *be = backendForScreen(stuff->screen);
+ int ret;
+
+ if (!be)
+ return BadValue;
+
+ ret = be->CreateContext(client);
+ if (ret == Success)
+ return CreateXID(be, stuff->context);
+
+ return ret;
+}
+
+static int
+ProcGLXDestroyContext(ClientPtr client)
+{
+ REQUEST(xGLXDestroyContextReq);
+ GlxBackend *be = backendForXID(stuff->context);
+
+ if (!be)
+ return __glXError(GLXBadContext);
+
+ return be->DestroyContext(client);
+}
+
+static int
+ProcGLXMakeCurrent(ClientPtr client)
+{
+ REQUEST(xGLXMakeCurrentReq);
+ GlxBackend *nbe = backendForXID(stuff->context);
+ GlxBackend *obe = NULL;
+ int ret;
+
+ if (!nbe)
+ return __glXError(GLXBadContext);
+
+ if (stuff->oldContextTag)
+ obe = backendForTag(stuff->oldContextTag);
+
+ if (obe && obe != nbe) {
+ int newctx = stuff->context;
+
+ /* no need to swap because 0 is a fixed point */
+ stuff->context = None;
+ ret = obe->MakeCurrent(client);
+ if (ret != Success)
+ return ret;
+
+ stuff->oldContextTag = None;
+ stuff->context = newctx;
+ }
+
+ ret = nbe->MakeCurrent(client);
+ if (ret == Success && stuff->drawable != None)
+ if (backendForXID(stuff->drawable) != nbe)
+ return CreateXID(nbe, stuff->drawable);
+
+ return ret;
+}
+
+static int
+ProcGLXIsDirect(ClientPtr client)
+{
+ REQUEST(xGLXIsDirectReq);
+ GlxBackend *be = backendForXID(stuff->context);
+ if (!be)
+ return __glXError(GLXBadContext);
+ return be->IsDirect(client);
+}
+
+static int
+ProcGLXQueryVersion(ClientPtr client)
+{
+ xGLXQueryVersionReply reply;
+
+ REQUEST_SIZE_MATCH(xGLXQueryVersionReq);
+
+ /*
+ ** Server should take into consideration the version numbers sent by the
+ ** client if it wants to work with older clients; however, in this
+ ** implementation the server just returns its version number.
+ */
+ reply = (xGLXQueryVersionReply) {
+ .type = X_Reply,
+ .sequenceNumber = client->sequence,
+ .length = 0,
+ .majorVersion = SERVER_GLX_MAJOR_VERSION,
+ .minorVersion = SERVER_GLX_MINOR_VERSION
+ };
+
+ if (client->swapped) {
+ swaps(&reply.sequenceNumber);
+ swapl(&reply.length);
+ swapl(&reply.majorVersion);
+ swapl(&reply.minorVersion);
+ }
+ WriteToClient(client, sz_xGLXQueryVersionReply, &reply);
+ return Success;
+}
+
+static int
+ProcGLXWaitGL(ClientPtr client)
+{
+ REQUEST(xGLXSingleReq);
+ GlxBackend *be = backendForTag(stuff->contextTag);
+ if (!be)
+ return __glXError(GLXBadContextTag);
+ return be->WaitGL(client);
+}
+
+static int
+ProcGLXWaitX(ClientPtr client)
+{
+ REQUEST(xGLXSingleReq);
+ GlxBackend *be = backendForTag(stuff->contextTag);
+ if (!be)
+ return __glXError(GLXBadContextTag);
+ return be->WaitX(client);
+}
+
+/*
+ * The source backend is responsible for verifying that the source context
+ * and tag refer to the same context.
+ */
+static int
+ProcGLXCopyContext(ClientPtr client)
+{
+ REQUEST(xGLXCopyContextReq);
+ GlxBackend *sbe = backendForXID(stuff->source);
+ GlxBackend *dbe = backendForXID(stuff->dest);
+
+ if (!sbe || !dbe)
+ return __glXError(GLXBadContext);
+ if (sbe != dbe)
+ return BadMatch;
+
+ return sbe->CopyContext(client);
+}
+
+/*
+ * Note that the backend is responsible for handling tag == 0.
+ */
+static int
+ProcGLXSwapBuffers(ClientPtr client)
+{
+ REQUEST(xGLXSwapBuffersReq);
+ GlxBackend *be = backendForGLXDrawable(stuff->drawable);
+
+ if (!be)
+ return __glXError(GLXBadDrawable);
+
+ return be->SwapBuffers(client);
+}
+
+static int
+ProcGLXUseXFont(ClientPtr client)
+{
+ REQUEST(xGLXSingleReq);
+ GlxBackend *be = backendForTag(stuff->contextTag);
+ if (!be)
+ return __glXError(GLXBadContextTag);
+ return be->UseXFont(client);
+}
+
+static int
+ProcGLXCreateGLXPixmap(ClientPtr client)
+{
+ REQUEST(xGLXCreateGLXPixmapReq);
+ GlxBackend *be = backendForScreen(stuff->screen);
+ int ret;
+
+ if (!be)
+ return BadValue;
+
+ ret = be->CreateGLXPixmap(client);
+ if (ret == Success)
+ return CreateXID(be, stuff->glxpixmap);
+
+ return ret;
+}
+
+static int
+ProcGLXGetVisualConfigs(ClientPtr client)
+{
+ REQUEST(xGLXGetVisualConfigsReq);
+ GlxBackend *be = backendForScreen(stuff->screen);
+ if (!be)
+ return BadValue;
+ return be->GetVisualConfigs(client);
+}
+
+static int
+ProcGLXDestroyGLXPixmap(ClientPtr client)
+{
+ REQUEST(xGLXDestroyGLXPixmapReq);
+ GlxBackend *be = backendForXID(stuff->glxpixmap);
+ int ret;
+ if (!be)
+ return BadValue;
+ ret = be->DestroyGLXPixmap(client);
+ return ret;
+}
+
+/* negative values are GLX errors, positive are core */
+static int
+translateError(int error)
+{
+ if (error < 0)
+ return __glXError(-error);
+ return error;
+}
+
+/*
+ * The same code and data are used for VendorPrivate and ...WithReply. If
+ * the backend wants to distinguish, it certainly may.
+ */
+static int
+ProcGLXVendorPrivate(ClientPtr client)
+{
+ REQUEST(xGLXVendorPrivateReq);
+ char *buf = (void *)stuff;
+ GlxVop *vop = glxVop(stuff->vendorCode);
+ GlxBackend *be;
+ int object;
+
+ if (!vop)
+ return BadRequest;
+
+ object = *(int *)(buf + vop->offset);
+
+ if (vop->object == GLXFE_SCREEN)
+ be = backendForScreen(object);
+ else if (vop->object == GLXFE_TAG)
+ be = backendForTag(object);
+ else if (vop->object == GLXFE_XID)
+ be = backendForXID(object);
+ else
+ return BadImplementation;
+
+ if (!be)
+ return translateError(vop->error);
+
+ return be->VendorPrivate(client);
+}
+
+static int
+ProcGLXQueryExtensionsString(ClientPtr client)
+{
+ REQUEST(xGLXQueryExtensionsStringReq);
+ GlxBackend *be = backendForScreen(stuff->screen);
+ if (!be)
+ return BadValue;
+ return be->QueryExtensionsString(client);
+}
+
+static int
+ProcGLXQueryServerString(ClientPtr client)
+{
+ REQUEST(xGLXQueryServerStringReq);
+ GlxBackend *be = backendForScreen(stuff->screen);
+ if (!be)
+ return BadValue;
+ return be->QueryServerString(client);
+}
+
+static int
+ProcGLXClientInfo(ClientPtr client)
+{
+ int i, ret = BadImplementation;
+
+ for (i = 0; i < screenInfo.numScreens; i++) {
+ GlxBackend *be = backendForScreen(i);
+ if (be) {
+ ret = be->ClientInfo(client);
+ if (ret != Success)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int
+ProcGLXGetFBConfigs(ClientPtr client)
+{
+ REQUEST(xGLXGetFBConfigsReq);
+ GlxBackend *be = backendForScreen(stuff->screen);
+ if (!be)
+ return BadValue;
+ return be->GetFBConfigs(client);
+}
+
+static int
+ProcGLXCreatePixmap(ClientPtr client)
+{
+ REQUEST(xGLXCreatePixmapReq);
+ GlxBackend *be = backendForScreen(stuff->screen);
+ int ret;
+
+ if (!be)
+ return BadValue;
+
+ ret = be->CreatePixmap(client);
+ if (ret == Success)
+ return CreateXID(be, stuff->glxpixmap);
+
+ return ret;
+}
+
+static int
+ProcGLXDestroyPixmap(ClientPtr client)
+{
+ REQUEST(xGLXDestroyPixmapReq);
+ GlxBackend *be = backendForXID(stuff->glxpixmap);
+ int ret;
+ if (!be)
+ return BadValue;
+ ret = be->DestroyPixmap(client);
+ return ret;
+}
+
+static int
+ProcGLXCreateNewContext(ClientPtr client)
+{
+ REQUEST(xGLXCreateNewContextReq);
+ GlxBackend *be = backendForScreen(stuff->screen);
+ int ret;
+
+ if (!be)
+ return BadValue;
+
+ ret = be->CreateNewContext(client);
+ if (ret == Success)
+ return CreateXID(be, stuff->context);
+
+ return ret;
+}
+
+static int
+ProcGLXQueryContext(ClientPtr client)
+{
+ REQUEST(xGLXQueryContextReq);
+ GlxBackend *be = backendForXID(stuff->context);
+ if (!be)
+ return BadValue;
+ return be->QueryContext(client);
+}
+
+static int
+ProcGLXMakeContextCurrent(ClientPtr client)
+{
+ REQUEST(xGLXMakeContextCurrentReq);
+ GlxBackend *nbe = backendForXID(stuff->context);
+ GlxBackend *obe = NULL;
+ XID draw = stuff->drawable, read = stuff->readdrawable;
+ int ret;
+
+ if (!nbe)
+ return __glXError(GLXBadContext);
+
+ if (stuff->oldContextTag)
+ obe = backendForXID(stuff->oldContextTag);
+
+ if (obe && obe != nbe) {
+ int newctx = stuff->context;
+
+ /* no need to swap because 0 is a fixed point */
+ stuff->context = None;
+ ret = obe->MakeCurrent(client);
+ if (ret != Success)
+ return ret;
+
+ stuff->oldContextTag = None;
+ stuff->context = newctx;
+ }
+
+ ret = nbe->MakeContextCurrent(client);
+ if (ret == Success && draw != None && read != None) {
+ GlxBackend *dbe = backendForXID(draw);
+ GlxBackend *rbe = backendForXID(read);
+
+ if (dbe == NULL && CreateXID(dbe, draw) != Success)
+ return BadAlloc;
+
+ if (rbe == NULL && CreateXID(rbe, read) != Success)
+ return BadAlloc;
+ }
+
+ return ret;
+}
+
+static int
+ProcGLXCreatePbuffer(ClientPtr client)
+{
+ REQUEST(xGLXCreatePbufferReq);
+ GlxBackend *be = backendForScreen(stuff->screen);
+ int ret;
+
+ if (!be)
+ return BadValue;
+
+ ret = be->CreatePbuffer(client);
+ if (ret == Success)
+ return CreateXID(be, stuff->pbuffer);
+
+ return ret;
+}
+
+static int
+ProcGLXDestroyPbuffer(ClientPtr client)
+{
+ REQUEST(xGLXDestroyPbufferReq);
+ GlxBackend *be = backendForXID(stuff->pbuffer);
+ int ret;
+ if (!be)
+ return BadValue;
+ ret = be->DestroyPbuffer(client);
+ return ret;
+}
+
+static int
+ProcGLXGetDrawableAttributes(ClientPtr client)
+{
+ REQUEST(xGLXGetDrawableAttributesReq);
+ GlxBackend *be = backendForGLXDrawable(stuff->drawable);
+
+ if (!be)
+ return __glXError(GLXBadDrawable);
+
+ return be->GetDrawableAttributes(client);
+}
+
+static int
+ProcGLXChangeDrawableAttributes(ClientPtr client)
+{
+ REQUEST(xGLXChangeDrawableAttributesReq);
+ GlxBackend *be = backendForGLXDrawable(stuff->drawable);
+ if (!be)
+ return __glXError(GLXBadDrawable);
+
+ return be->ChangeDrawableAttributes(client);
+}
+
+static int
+ProcGLXCreateWindow(ClientPtr client)
+{
+ REQUEST(xGLXCreateWindowReq);
+ GlxBackend *be = backendForScreen(stuff->screen);
+ int ret;
+
+ if (!be)
+ return BadValue;
+
+ ret = be->CreateWindow(client);
+ if (ret == Success)
+ return CreateXID(be, stuff->glxwindow);
+
+ return ret;
+}
+
+static int
+ProcGLXDestroyWindow(ClientPtr client)
+{
+ REQUEST(xGLXDestroyWindowReq);
+ GlxBackend *be = backendForXID(stuff->glxwindow);
+ int ret;
+ if (!be)
+ return BadValue;
+ ret = be->DestroyWindow(client);
+ return ret;
+}
+
+static int
+ProcGLXSetClientInfoARB(ClientPtr client)
+{
+ int i, ret = BadImplementation;
+
+ for (i = 0; i < screenInfo.numScreens; i++) {
+ GlxBackend *be = backendForScreen(i);
+ if (be) {
+ ret = be->SetClientInfoARB(client);
+ if (ret != Success)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int
+ProcGLXCreateContextAttribsARB(ClientPtr client)
+{
+ REQUEST(xGLXCreateContextAttribsARBReq);
+ GlxBackend *be = backendForScreen(stuff->screen);
+ int ret;
+
+ if (!be)
+ return BadValue;
+
+ ret = be->CreateContextAttribsARB(client);
+ if (ret == Success)
+ return CreateXID(be, stuff->context);
+
+ return ret;
+}
+
+static int
+ProcGLXSetClientInfo2ARB(ClientPtr client)
+{
+ int i, ret = BadImplementation;
+
+ for (i = 0; i < screenInfo.numScreens; i++) {
+ GlxBackend *be = backendForScreen(i);
+ if (be) {
+ ret = be->SetClientInfo2ARB(client);
+ if (ret != Success)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int
+ProcGLXSingle(ClientPtr client)
+{
+ REQUEST(xGLXSingleReq);
+ GlxBackend *be = backendForTag(stuff->contextTag);
+ if (!be)
+ return __glXError(GLXBadContextTag);
+ return be->Single(client);
+}
+
+int
+ProcGLXDispatch(ClientPtr client)
+{
+ REQUEST(xGLXSingleReq);
+ CARD8 opcode = stuff->glxCode;
+
+ ErrorF("glx op %d\n", opcode);
+
+ int (*glxprocs[36])(ClientPtr) = {
+ NULL,
+ ProcGLXRender, // 1
+ ProcGLXRenderLarge, // 2
+ ProcGLXCreateContext, // 3
+ ProcGLXDestroyContext, // 4
+ ProcGLXMakeCurrent, // 5
+ ProcGLXIsDirect, // 6
+ ProcGLXQueryVersion, // 7
+ ProcGLXWaitGL, // 8
+ ProcGLXWaitX, // 9
+ ProcGLXCopyContext, // 10
+ ProcGLXSwapBuffers, // 11
+ ProcGLXUseXFont, // 12
+ ProcGLXCreateGLXPixmap, // 13
+ ProcGLXGetVisualConfigs, // 14
+ ProcGLXDestroyGLXPixmap, // 15
+ ProcGLXVendorPrivate, // 16
+ ProcGLXVendorPrivate, // 17 ... WithReply
+ ProcGLXQueryExtensionsString, // 18
+ ProcGLXQueryServerString, // 19
+ ProcGLXClientInfo, // 20
+ ProcGLXGetFBConfigs, // 21
+ ProcGLXCreatePixmap, // 22
+ ProcGLXDestroyPixmap, // 23
+ ProcGLXCreateNewContext, // 24
+ ProcGLXQueryContext, // 25
+ ProcGLXMakeContextCurrent, // 26
+ ProcGLXCreatePbuffer, // 27
+ ProcGLXDestroyPbuffer, // 28
+ ProcGLXGetDrawableAttributes, // 29
+ ProcGLXChangeDrawableAttributes, // 30
+ ProcGLXCreateWindow, // 31
+ ProcGLXDestroyWindow, // 32
+ ProcGLXSetClientInfoARB, // 33
+ ProcGLXCreateContextAttribsARB, // 34
+ ProcGLXSetClientInfo2ARB, // 35
+ };
+
+ if (opcode >= X_GLsop_NewList)
+ return ProcGLXSingle(client);
+
+ if (opcode <= X_GLXSetClientInfo2ARB && glxprocs[opcode])
+ return glxprocs[opcode](client);
+
+ return BadRequest;
+}
+
+static void
+ResetGLXFE(ExtensionEntry *extEntry)
+{
+ ht_destroy(fe_vop_hash);
+}
+
+void
+GlxExtensionInit(void)
+{
+ GlxFEXID = CreateNewResourceType(DeleteXID, "GlxFEXID");
+
+ if (!GlxFEXID)
+ return;
+
+ if (!GlxFeHashSetup())
+ return;
+
+ if (!dixRegisterPrivateKey(&GlxFEPrivateKeyRec, PRIVATE_SCREEN, 0))
+ return;
+
+ GlxBackendInit();
+
+ GlxExtension = AddExtension(GLX_EXTENSION_NAME, __GLX_NUMBER_EVENTS,
+ __GLX_NUMBER_ERRORS, ProcGLXDispatch,
+ ProcGLXDispatch, ResetGLXFE,
+ StandardMinorOpcode);
+ if (!GlxExtension)
+ return;
+}
diff --git a/glx/glxfe.h b/glx/glxfe.h
new file mode 100644
index 000000000..f72c38813
--- /dev/null
+++ b/glx/glxfe.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright © 2017 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) 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 AUTHORS OR COPYRIGHT HOLDERS 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.
+ *
+ * Authors:
+ * Adam Jackson <ajax@redhat.com>
+ */
+
+#ifndef _GLXFE_H
+#define _GLXFE_H
+
+#include <dix-config.h>
+#include <X11/Xmd.h>
+#include <GL/glxproto.h>
+#include "dixstruct.h"
+#include "extnsionst.h"
+
+/* shitty hacks */
+#ifndef X_GLXSetClientInfo2ARB
+#define X_GLXSetClientInfo2ARB 35
+#endif
+
+/* types */
+typedef struct GlxBackend {
+ /* Dispatched to every backend */
+ int (*ClientInfo)(ClientPtr client);
+ int (*SetClientInfoARB)(ClientPtr client);
+ int (*SetClientInfo2ARB)(ClientPtr client);
+
+ /* Dispatched to one backend */
+ int (*Render)(ClientPtr client);
+ int (*RenderLarge)(ClientPtr client);
+ int (*CreateContext)(ClientPtr client);
+ int (*DestroyContext)(ClientPtr client);
+ int (*MakeCurrent)(ClientPtr client);
+ int (*IsDirect)(ClientPtr client);
+ int (*WaitGL)(ClientPtr client);
+ int (*WaitX)(ClientPtr client);
+ int (*CopyContext)(ClientPtr client);
+ int (*SwapBuffers)(ClientPtr client);
+ int (*UseXFont)(ClientPtr client);
+ int (*CreateGLXPixmap)(ClientPtr client);
+ int (*GetVisualConfigs)(ClientPtr client);
+ int (*DestroyGLXPixmap)(ClientPtr client);
+ int (*VendorPrivate)(ClientPtr client);
+ int (*QueryExtensionsString)(ClientPtr client);
+ int (*QueryServerString)(ClientPtr client);
+ int (*GetFBConfigs)(ClientPtr client);
+ int (*CreatePixmap)(ClientPtr client);
+ int (*DestroyPixmap)(ClientPtr client);
+ int (*CreateNewContext)(ClientPtr client);
+ int (*QueryContext)(ClientPtr client);
+ int (*MakeContextCurrent)(ClientPtr client);
+ int (*CreatePbuffer)(ClientPtr client);
+ int (*DestroyPbuffer)(ClientPtr client);
+ int (*GetDrawableAttributes)(ClientPtr client);
+ int (*ChangeDrawableAttributes)(ClientPtr client);
+ int (*CreateWindow)(ClientPtr client);
+ int (*DestroyWindow)(ClientPtr client);
+ int (*CreateContextAttribsARB)(ClientPtr client);
+ int (*Single)(ClientPtr client);
+} GlxBackend;
+
+typedef struct GlxFrontend {
+ int (*AddTag)(void);
+ int (*AddVop)(void);
+} GlxFrontend;
+
+struct TagState {
+ GlxBackend *be;
+ XID track_id;
+};
+
+#define GLXFE_SCREEN 0
+#define GLXFE_TAG 1
+#define GLXFE_XID 2
+
+typedef struct GlxVop {
+ int object;
+ int offset;
+ int error;
+} GlxVop;
+
+extern ExtensionEntry *GlxExtension;
+
+extern _X_EXPORT void GlxSetBackend(ScreenPtr pScreen, GlxBackend *backend);
+
+#endif
diff --git a/glx/meson.build b/glx/meson.build
index a4af2b846..198819d89 100644
--- a/glx/meson.build
+++ b/glx/meson.build
@@ -53,3 +53,18 @@ srcs_glxdri2 = []
if build_dri2 or build_dri3
srcs_glxdri2 = files('glxdri2.c')
endif
+
+srcs_glxfe = [
+ 'glxfe.c',
+]
+
+libglxfe = static_library('libglxfe',
+ srcs_glxfe,
+ include_directories: inc,
+ dependencies: [
+ common_dep,
+ dl_dep,
+ dependency('glproto', version: '>= 1.4.17'),
+ dependency('gl', version: '>= 9.2.0'),
+ ],
+)