[RFC] Server side glvnd
Kyle Brenneman
kbrenneman at nvidia.com
Tue Jul 18 17:19:02 UTC 2017
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
More information about the xorg-devel
mailing list