Brett Johnson wrote:
> Bob Beretta wrote:
> >
> > Hi All,
> >
> > Arguments *for* context-specific function pointers from glGetProcAddress:
> > (possibly MacOS specific, but maybe not...)
> >
> > 1) On the Macintosh, the link library (libGL.so equivalent) manages multiple
> > graphics devices with independent drivers in a way that is transparent to the
> > application. It does this by exporting a wrapper layer that may redirect the
> > OpenGL commands from one driver to another, or to multiple drivers
> > simultaneously, depending on the configuration of the screens and the
> > current location of the application window. In general, an application
> > may bypass the overhead of the wrapper layer by accessing the *real* GL
> > entry points that are stored in the context.
>
> What are the *real* entrypoints? Are these pointers to the actual driver
> functions? Or are they just another (less expensive) wrapper? I'm not very
> familiar with Apple/Conix's implementation.
On a single-screen context, these *real* entrypoints are pointers to the actual
driver functions. On a multi-screen context, it depends whether the context is
in execute mode or display-list-compile mode. In execute mode, most of the
entrypoints still point to the driver, but a few are wrappers that redirect to all
drivers. In compile mode, most entries are wrappers that redirect to all drivers
so that display lists are kept synchronized. Non-listable functions such as
glGet* are still not wrapped.
> > When an app calls glGetProcAddress, what is really returned is a pointer
> > to a function that is generated at run-time - a wrapper for the real pointer(s)
> > returned from the driver. The problem is that two contexts may very well
> > be attached to two entirely different drivers, making the *real* proc pointer
> > for one context useless for another. Or, one context may be attached to a
> > single driver while the other is attached to multiple drivers, making the
> > wrapper function itself inappropriate for use with the wrong context.
>
> What happens when the user moves the window to a monitor controlled by another
> driver (or worse, the window spans two monitors)? Doesn't this present the
> same problem (suddenly the *real* function pointer isn't valid anymore)?
When a window moves so as to change what driver we must hook to, we have the
appropriate driver copy all of its function pointers into the current top-level
dispatch
table. To avoid extra indirection, we pay for a big copy when windows move
between screens.
> > The only way I can see to code my way around this is to A) ignore the
> > wrapper function issue and accept the logic overhead of a generic wrapper
> > AND B) keep track of all calls to glGetProcAddress in the link library
> > and have the library internally extract all the previously requested function
> > pointers from each driver whenever a new context is created AND C) go
> > back and "fix up" all existing contexts with each new call to
> > glGetProcAddress so a procedure may be used with a context that was
> > created previously. What a pain!
>
> I don't see that it has to be _that_ difficult. If I were architecting the
> implementation, I'd have the drivers "register" all of their entrypoints with
> the link library at context creation time. If a particular driver registered
> an entrypoint that I hadn't seen before, I'd simply put it in the next available
> slot in the jump table. Contexts created previously could easily be updated
> at MakeCurrent time if necessary.
It's not a show-stopper, which is why I noted the existance of a solution. The
question is "what's right". We move lots of function pointers and state around
as it is to hide the existance of multiple drivers from the app. Currently,
*everything* we do is confined to a particular context - *nothing* moves
between contexts. If we implemented my B) and C) steps, above, it would
be the first occurence of moving GL state between contexts.
Maybe I'm taking a very abstract view here, but glGetProcAddress returns
a pointer to data. It came from a particular context and it should not survive
that context. In the case of our particular implementation, this abstraction is
very real - I allocated the data and wrote instructions into it. When I delete
the context, I free the data - the procedure is gone.
It seems to me that the only way it would be appropriate for the proc to survive
is if the proc is formal shared state between two shared contexts.
> > It seems to me that any X implementation for Linux that tries to tackle the
> > multi-screen problem in a generic way (like Conix/Apple did) will run into
> > similar difficulties, so I think it would be prudent to leave the per-context
> > pointers in the spec.
>
> Maybe I'm missing something, but I don't see that making the pointer context
> specific solves any of the problems you've brought up.
The problem that it solves is just the issue of cross-context book keeping of
function pointers.
> As you've pointed out,
> the actual driver routine that needs to be called isn't just a function of
> which context is current. It always depends on the current pipeline state,
> but in a heterogeneous multi-headed environment, it also depends on the position
> of the rendering view (i.e. the device that's being rendered on can change
> dynamically as the window is moved).
>
> Multi-head OpenGL is already a tough problem, and making it heterogeneous, and
> transparent to the app is a **really-really** tough problem! If you guys can
> solve it in any fashion, context specific pointers or no, you have my respect
> and admiration!
Well, thanks. We've been shipping this system for a couple years now (6
months for Apple) and it seems to work pretty well in real life. There are
some small holes in the driver synchronization scheme where a driver switch in
a very particular state will cause some state to be lost to the new active driver.
But, I've never seen a real app fall into these holes, only my own test cases.
There's some overhead for a multi-head context, but none for a single-head,
so an app can pretty much have whatever it's willing to pay for.
You might be interested in this: eXodusPowerPC is an X server for the Mac.
Running on Apple OpenGL with the GLX extension enabled and the root
window stretched across multiple screens with HW acceleration, it is a
multi-headed, heterogeneous, accelerated GLX X server.
> > 2) Further, one context may support the extension of which the function
> > pointer is a part and another context may not, making the pointer useless
> > for the second context.
>
> This is a good point. It does seem kind of funny for GetProcAddress to return
> a pointer that is callable, but does nothing. It's also a little fuzzy what
> GetProcAddress should return if it gets a request for a function that it the
> dispatcher hasn't seen before. My instinct is that it should go ahead and assign
> a dispatch table entry to the name and return a valid pointer, but maybe set
> some kind of glError.
>
> > glGetString may return different extension strings
> > for different contexts in a multiple-graphics-device environment, so it
> > follows semantically that glGetAnythingEXT must return context
> > specific information.
>
> This idea gets really weird in a heterogeneous environment like you're describing
> though, because even the results from glGetString can't be counted on to remain
> valid once the window is moved. If the user moves the window from a device which
> supports glWizBang3fvEXT, to a device that doesn't, what happens?
That's a fact. On a Mac, the return values of all glGet* functions may change when
the window is moved between screens. If the app cares, it must take steps to find
the return values from all drivers associated with that context. We provide a routine
to allow the app to explicitely switch between drivers without actually moving the
window. Thus, the app can step through all the drivers durings its context
initialization
and do whatever glGet* operations it must. In the case of extension strings, the app
must either take the intersection of the extension strings from all drivers, or be
able to
switch paths on the fly in response to a driver change.
> The problems you've pointed out are certainly valid problems, and I'm not sure
> what the best way to solve them is. However, I don't see how specifying
> GetProcAddress to return context specific pointers will help with the solution.
>
> Cheers!
I guess it comes down to this: I concede that the spec can be implemented on a Mac
with context-independent pointers, and it wouldn't be all that hard.
What I think I have shown is that the proc pointers *really* are context-specific.
Therefore the entire discussion of making the spec context-independent is for the
sole purpose of hiding this fact from the app. Why?
It's a pointer. It came from the context. It dies with the context. Isn't that how
it
should be, in a proper OpenGL sense? Maybe my thread is hung on this one.
Best Regards,
Bob Beretta