Nice summary, John!

John Dennis wrote:
| * The assertion that function pointers returned by a GetProcAddress
|   call are context specfic and the application needs to manage these
|   on a per-context basis is entirely correct, BUT I believe a bit
|   pedantic, is not what application developers want/need and contrary
|   to the overarching design of OpenGL. ...
|                                                           ... Yes,
|   applications will need be aware of constraints a specfic context may
|   have (e.g. absent extensions), but why demand they also modify how
|   they call the grahics API for a minor subset of entry points? ...

Very well said.

I might add that one of the reasons people like using OpenGL is that
the interface model is significantly simpler than that of COM.  Sure,
we could adopt a COM-like notion of runtime separation of interface
and implementation, by demanding that apps keep separate function
pointers for all contexts they use.  But I, too, feel that's contrary
to the OpenGL design.

As a practical matter, some applications already take the address of
OpenGL functions (in order to avoid some DSO calling overhead, or to
pass them to commands like gluTessCallback).  If there are cases in
which such actions are performed in libraries, the libraries might
well break if we decide that the function addresses are
context-specific.  The same concerns would apply to extension
functions as well as core functions.

|                                      ... In my view it makes little
| difference whether the index into the dispatch table is computed by
| the compiler (e.g. table->foo) and is static or whether the index is
| contained in a variable (e.g. table[fooIndex]) and is dynamic. In
| the former case its a "move immediate" into the offset register, in
| the latter case its a "move memory" into the offset register. The
| cycle count difference for this one instruction hardly seems worth
| worrying about.

I'll defer to the consensus view on this matter, but my preference
is for the static offsets.

First, the business of maintaining universal indices for the dispatch
table seems quite manageable to me, and in fact is essentially
identical to the process we already use for ensuring that new OpenGL
enumerants are unique.

Second, I'd quibble with John's cost estimates.  Granted that it's
machine-dependent, but I'd expect the static-offset case to boil down
to something like the following pseudo-assembly code:

        glFunc:
                load    RX, perThreadDataArea+dispatchTable
                load    RY, offset_glFunc(RX)   ; use indexed load
                                                ;   to fetch driver func
                                                ;   addr
                jump    (RY)                    ; indirect jump to driver

whereas the dynamic-offset case might look something like:

        glFunc:
                load    RX, perThreadDataArea+dispatchTable
                load    RZ, index_glFunc        ; get actual offset of
                                                ;   function
                load    RY, (RX+RZ)             ; use double-indexed
                                                ;   mode, if available,
                                                ;   to fetch driver func
                                                ;   addr; otherwise, must
                                                ;   use separate ADD and
                                                ;   LOAD
                jump    (RY)

I'm willing to pay the extra one or two instructions, one extra memory
reference, and possible extra register spill code in the case of new
extensions that were added since libGL was compiled, but I'm more
reluctant to pay that cost for core routines or well-known extensions. 
And I don't see all that much benefit for making everything dynamic,
since managing a consistent set of function offsets seems relatively
easy to me.

As I said, although I prefer the static offset implementation, I'll
honor the consensus if it goes the other way.  But I think it's pretty
important to preserve the ``one function address works everywhere''
semantic in either case.

|              ... The primary benefit is ALL extension entry points
| across all drivers share the same dynamically allocated index. ...

But you do complicate the drivers and make updating the dispatch table
more expensive in order to get this benefit, so it isn't an
unqualified win.

| I believe these concepts borrow heavily on concepts presented earlier
| by others and credit is due to them. I'm just trying to bring together
| the concepts in a unified fashion that solves all the perceived
| goals.

Thanks -- I definitely found it helpful, and I expect others did, too.

Allen

Reply via email to