I was actually just getting ready to send this out. This is what I've come up with for a server-side GLVND-like interface:
https://github.com/kbrenneman/libglvnd/tree/server-libglx

What I've got there is a proof-of-concept GLX server module that can dispatch to multiple vendor libraries based on screen. The interface is defined in include/glvnd/glxserverabi.h, and the implementation is in src/glxserver.

There's still more to do, but I've been able to get the NVIDIA driver and GLX module running on one screen, and the Xorg dummy video driver and GLX module running on a second, and I can create and use direct and indirect contexts on both screens from a single client.


Dispatching works similarly to the client libraries. Each GLX request has a dispatch stub which looks up a vendor based on something in the request (tag, screen number, or XID), and it then forwards the request to that vendor. The vast majority of dispatch stubs can be generated by a script.

As with the client libraries, I set it up so that each vendor can provide dispatch stubs to handle any extension requests, including VendorPrivate requests. In addition, since requests that create or destroy resources include the XID in the request, the dispatch stubs can handle updating the (XID -> vendor) mapping. That way, you don't have to modify a vendor's existing request handlers.


MakeCurrent requests require a fair amount of special handling, so I defined a separate callback function for them. That way, if it's switching between different vendors, it can call each vendor's MakeCurrent callback.

Context tags are, as you note, pretty ugly. In order to avoid conflicts between multiple vendors, the GLVND layer has to create and assign tags. To make that easier to deal with, the MakeCurrent callback lets the vendor library provide a (void *) pointer for each tag that can be used for arbitrary private data. Xorg's GLX module doesn't especially depend on how the tag value is assigned, it just needs to be able to look up a context from a tag, so changing it to go through that GLVND pointer isn't too hard (unless I missed something in my testing, which is entirely possible).

Alternately, a vendor library could use the pointer that GLVND maintains to store whatever context tag value it would have used.

As a side note, the implementation that I've got uses array indexes for context tags instead of XID's.

For SwapBuffers or any other request that can take an optional context tag, the dispatch stub dispatches by the context tag if the request has one, and the drawable if it doesn't. Dispatching based only on the drawable could cause problems if they map to different vendors, because then a vendor might try to look up (and dereference) the private data from another vendor.


The part that's the most different from the client library is how I set up vendor selection. Instead of GLVND trying to query or otherwise figure out which vendor to use for each screen, the display driver simply assigns a vendor library to use:

- In the PreInit callback, the driver calls into GLVND to create an opaque vendor handle. At that point, the driver provides an initialization callback function. - When the GLX extension is initialized, it calls the initialization callback for each vendor handle. In that callback, the vendor fills in a function table. This part is analogous to the __glx_Main and __egl_Main functions exported from the EGL and GLX client vendor libraries. - Then, in the CreateScreenResoruces callback, the driver assigns a vendor handle to each screen.

Since a display driver can reasonably be expected to know what GLX implementation will work, that lets it piggyback on the server's existing driver selection capability.


I haven't addressed Prime or yet, because I'm still trying to figure out how it works. But, we could probably set it up to use a separate (screen -> vendor) mapping for each client. Maybe a new GLX extension to let the client send some additional data to the server at the beginning, which the server could then use to decide what mapping to set up.

As for Xinerama, I think it would largely be orthogonal to the GLVND layer. But, if you've got two screens that both use the same vendor library, then it shouldn't look any different from the vendor library's perspective than the non-GLVND case would. Xinerama between different vendor libraries would be a lot harder, though.

Anyway, I'd like to hear what people think about it. Comments and questions are all welcome.

-Kyle

On 07/18/2017 10:20 AM, Aaron Plattner wrote:
Adding Kyle to To -- he's been working on something similar.

On 07/18/2017 08:43 AM, Adam Jackson wrote:
I've been thinking about how to get multiple GL stacks to coexist
within the server, along the lines of libglvnd on the client side. This
is a bit of a brain dump, the intrepid can find some work in progress
along these lines here:

https://cgit.freedesktop.org/~ajax/xserver/log/?h=glxfe

The basic approach I've been taking is: how little does the GLX
provider's dispatch code need to be modified?

For QueryVersion, we can just return 1.4. For the ClientInfo requests,
we have to dispatch them to every backend. For every other request, we
need to inspect some key element of the request and use that to map to
a backend. There are only three kinds of objects for this purpose:
screen numbers (sigh), XIDs, and context tags. The screen mapping is
straightforward. For XIDs we can set up a mapping on creation:
GLXCreateWindow is dispatched to a backend (by screen number), on
success we create a shadow resource with the same XID whose value
points to the backend that created it.

Tags are uglier because tags are ugly [1]. The code I currently have
for this simply treats tags as XIDs because in Xorg's GLX they are. But
tags are assigned by the backend, not the client: they're in the reply
to MakeCurrent. So the backend's MakeCurrent hook will need to be
different from a non-glvnded version, allocating the tag from the
frontend.

The other quirk with MakeCurrent is, when switching between contexts on
different backends, one must first detach the old context and then
attach the new. But that's two backend calls, and MakeCurrent as a
protocol request wants to emit a reply, and libGL is absolutely not
prepared to hear two replies to a single request. So the backend vtable
probably also needs a LoseCurrent hook. (I tried to hide this detail in
the frontend via ReplyCallback, and I was not very pleased with myself
afterwards.)

SwapBuffers has to dispatch based on the drawable, not the context tag,
because the tag may be None. Thanks SGI.

GLX requests with opcode >= 101 are "single" requests corresponding to
GL API calls that don't fit in a Render request; they are dispatched
relative to a context tag, so the backend vfunc can simply be int
(*Single)(ClientPtr client). Requests from 1 to 35 are GLX API calls,
and have a mostly static dispatch setup. The exceptions are
VendorPrivate and VendorPrivateWithReply. For these I imagine the
backend will register a list of { vop, object, offset, error } tuples
for each request it supports.

VendorPrivate requests are also tricky because, being GLX API, they can
also create and destroy objects. The shadow resource trick (above)
makes destruction lifetime simple, but the frontend will need to expose
methods to allow e.g. glXCreateGLXPbufferSGIX to register its XID. (In
principle GLX extensions could also create named objects on which one
should dispatch that are not XIDs. I'm not aware of any extensions like
that at the moment, and I kind of want not to support anyone making
that mistake.)

In principle, the above is enough in a Zaphod Xorg configuration to
have heterogeneous GLX providers on different ScreenRecs. It would also
make it easy, in a single ScreenRec case, to determine the GLX provider
based on the DDX driver in use (e.g., I updated my kernel but not my
NVIDIA driver, nouveau wants Xorg's GLX not NVIDIA's). For homogeneous
Xinerama-enabled GLX this should not lose any functionality, since the
backend can simply be the same for all objects.

Open questions:

- What more is needed for Prime setups? For direct contexts, I don't
think much. For indirect contexts presumably you'd want a way to
communicate the desired GPU when you create the GLX drawable and have
that determine the screen you dispatch to.

- What more is needed for Xinerama+GLX with the open driver stack? We
have some flexibility here, GLX_EXT_glvnd lets us name whatever client-
side library we want, so we can ask for a new Mesa target that knows
how to be multi-GPU aware.

- What more is needed for credible GLX on non-xfree86 servers, in
particular Xwayland? I think, if the pig is given enough thrust, it
would be possible to build accelerated GLX atop just about arbitrary
EGL stacks; in that sense it'd be cool if Xwayland could do reasonable
amounts of GLX accel with the stock backend. But I don't think that's
going to get feature or performance parity with xfree86 on its own, if
nothing else the open stack doesn't have stereo support.

- What else am I missing?

[1] - The GLX spec describes context tags as _not_ being the same as
the context XID, with the explanation that the context may be destroyed
but still be current to a client. Yes, and? You can prevent the client
from reusing the XID by simply not freeing it, the client is going to
ask XC-MISC for free IDs when it needs to start reusing them. I _think_
this is because GLX 1.0 predates XC-MISC, but 1994 was a long time ago
so maybe we can assume it's there now.

- ajax

_______________________________________________
xorg-devel@lists.x.org: X.Org development
Archives: http://lists.x.org/archives/xorg-devel
Info: https://lists.x.org/mailman/listinfo/xorg-devel

Reply via email to