Yes, it's possible to create multiple OpenGL contexts within the same
application.  For example, this is how Qt renders an opengl widget to
an image (see 
http://qt-project.org/doc/qt-5.0/qtopengl/qglwidget.html#renderPixmap)

However, I'm pretty sure the opengl function pointers don't depend on
the context per se, they're only to do with the particular opengl
library you've linked to, so they're valid between contexts in the
same application.  (Unless you dlopen()ed multiple OpenGL libraries I
guess, though not sure why you'd want to do that!)

~Chris

On Thu, Apr 3, 2014 at 9:51 PM, Tobias Knopp
<[email protected]> wrote:
> Is it really possible to switch contexts in OpenGL at runtime? As far as I
> understand it one does not have "handles" to some OpenGL context but the
> state is defined globally in the driver. The dynamic nature OpenGL is more
> to check whether certain features are implemented by the driver or not.
>
> Am Donnerstag, 3. April 2014 13:33:10 UTC+2 schrieb Toivo Henningsson:
>>
>> If the function pointer depends on the context, shouldn't it be
>> stored/cached in the context, rather than globally?
>>
>> On Thursday, 3 April 2014 11:23:30 UTC+2, Simon Danisch wrote:
>>>
>>> By the way, this solution doesn't deal with the problem, that the OpenGl
>>> package needs to expose different sets of functions depending on the OpenGl
>>> version, which can be only determined after the context creation.
>>> Or is this bad style and one should just include all functions, leaving
>>> unsupported function with C_NULL? But it would be a difference of a couple
>>> of thousand lines of code.
>>>
>>> Its actually not trivial, as a package that doesn't create an opengl
>>> context might include a particular version, independent of the version that
>>> is actually used by the package, that deals with creating the opengl
>>> context.
>>>
>>> Also, if we already start sacrificing performance, we could just go back
>>> to the trivial solution, which is to put the getprocaddress into the ccall.
>>> This at least guarantees, that one always gets the right pointer, even if
>>> the context gets switched, destroyed or changed...
>>>
>>> On Apr 3, 2014 10:48 AM, "Mike Innes" <[email protected]> wrote:
>>> >
>>> > Ok, that's interesting. This is obviously a pretty clever macro,
>>> > because it's not at all obvious that it should run as quickly as it does.
>>> >
>>> > But, I'm still not sure I understand why that solution is necessarily
>>> > the least brittle and most correct. As I see it, we have three potential
>>> > solutions here, which in order of most elegant / least performant are (1)
>>> > getFuncPointerM memoization, (2) @getFunctionPointer memoization, (3) 
>>> > @eval
>>> > inlining. (1) and (2) are exactly the same amount of typing, (3) a few
>>> > characters more. (3), I would argue, is more clear about what it does and
>>> > why it's fast, but perhaps your opinion will differ.
>>> >
>>> > Without clear reasoning, drawing a line of "correctness" between (2)
>>> > and (3) seems pretty arbitrary. I can see why you might argue that only 
>>> > (1)
>>> > is correct, since it's evidently easier to understand and maintain. But 
>>> > what
>>> > exactly makes (3) so much worse than (2), objectively speaking?
>>> >
>>> >
>>> > On 3 April 2014 09:21, Simon Danisch <[email protected]> wrote:
>>> >>
>>> >> Can someone explain me what exactly is brittle about it?
>>> >> I don't like the solution too much myself, as it disguises things a
>>> >> little.
>>> >>
>>> >> But I don't know Julia ( or macros and programming concepts in
>>> >> general) well enough to see the bad side effects.
>>> >> At least it gets the job done, which is to generate a function body
>>> >> that only consists of a ccall with an inlined function ptr.
>>> >>
>>> >> Or is this not desirable?
>>> >>
>>> >> On Apr 3, 2014 5:19 AM, "Jameson Nash" <[email protected]> wrote:
>>> >>>
>>> >>> As I indicated, I used the macro to make the code look neater. I
>>> >>> could
>>> >>> have expanded it (see below). But just as functions help DRY code,
>>> >>> macros help DRY typing. Memoizing using a dict isn't much better than
>>> >>> calling dlsym, which is also some form of dict (and may even benefit
>>> >>> from better memory localization). I am doing almost the same (using
>>> >>> the module global namespace as a dictionary), but I am cheat because
>>> >>> I
>>> >>> can inform the compiler that the result of this dictionary lookup is
>>> >>> static, which lets it emit a direct entry into the module global
>>> >>> lookup table, at essentially negligible runtime performance impact
>>> >>> (one mov and one jmp instruction more than directly ccall'ing a
>>> >>> pointer).
>>> >>>
>>> >>> Using eval to do inlining is a brittle usage of both eval and
>>> >>> inlining. it is nice to have the computer run things fast, but it is
>>> >>> better have it do them right :)
>>> >>>
>>> >>> const glGetString_func_pointer = C_NULL
>>> >>> function glGetString(name::Uint16)
>>> >>>     global glGetString_func_pointer
>>> >>>     if glGetString_func_pointer::Ptr{Void} == C_NULL
>>> >>>         glGetString_func_pointer::Ptr{Void} =
>>> >>> getFuncPointer("glGetString")
>>> >>>     end
>>> >>>     ccall(glGetString_func_pointer::Ptr{Void}, Ptr{Cchar}, (Uint16,),
>>> >>> name)
>>> >>> end
>>> >>>
>>> >>> On Wed, Apr 2, 2014 at 9:59 PM, Mike Innes <[email protected]>
>>> >>> wrote:
>>> >>> > I agree entirely that macros and eval should be avoided if possible
>>> >>> > - so why
>>> >>> > have you used them for memoization?
>>> >>> >
>>> >>> >
>>> >>> > const func_pointers = Dict{String, Ptr{Void}}()
>>> >>> >
>>> >>> >
>>> >>> > getFuncPointerM(name) =
>>> >>> >
>>> >>> >   haskey(func_pointers, name) ?
>>> >>> >
>>> >>> >     func_pointers[name] :
>>> >>> >
>>> >>> >     (func_pointers[name] = getFuncPointer(name))
>>> >>> >
>>> >>> >
>>> >>> > Perhaps I'm missing something, but that seems equivalent and a lot
>>> >>> > neater to
>>> >>> > me. The benefit to your macro is that it's faster, which is exactly
>>> >>> > the
>>> >>> > reason to use eval in Simon's case.
>>> >>> >
>>> >>> > If retrieving a pointer carries a significant overhead compared to
>>> >>> > inlining
>>> >>> > it (which may well be a concern in an OpenGL library), then using
>>> >>> > eval to do
>>> >>> > that inlining is perfectly justified.
>>> >>> >
>>> >>> >
>>> >>> > On 3 April 2014 02:13, Jameson Nash <[email protected]> wrote:
>>> >>> >>
>>> >>> >> A delayed macro is just a function call. Don't make you life
>>> >>> >> complicated by trying to use one in place of the other.
>>> >>> >>
>>> >>> >> Using macros and eval can get you into a lot of trouble by helping
>>> >>> >> you
>>> >>> >> write brittle code. They allow you to confuse compile and run
>>> >>> >> time,
>>> >>> >> even though Julia does make a strong distinction between them.
>>> >>> >> Avoid
>>> >>> >> using them.
>>> >>> >>
>>> >>> >> The correct way to write this is using memoization. We can use a
>>> >>> >> macro
>>> >>> >> to make this look neater. This one is copied from PyCall:
>>> >>> >>
>>> >>> >> macro getFuncPointer(func)
>>> >>> >>     z = gensym(string(func))
>>> >>> >>     @eval global $z = C_NULL
>>> >>> >>     quote begin
>>> >>> >>         global $z
>>> >>> >>         if $z::Ptr{Void} == C_NULL
>>> >>> >>             $z::Ptr{Void} = $(getFuncPointer(esc(func))))
>>> >>> >>         end
>>> >>> >>         $z::Ptr{Void}
>>> >>> >>     end end
>>> >>> >> end
>>> >>> >>
>>> >>> >> glGetString(name::GLenum) = ccall(@getFuncPointer("glGetString"),
>>> >>> >> ...., ...., name)
>>> >>> >>
>>> >>> >>
>>> >>> >> A good macro should be equivalent to a pure function: regardless
>>> >>> >> of
>>> >>> >> when or how it is run, or how the program state changes, it must
>>> >>> >> return the same result given the same inputs. In this case, it
>>> >>> >> returns
>>> >>> >> a static variable and a method of retrieving the actual function
>>> >>> >> pointer. Note that it does not actually look up the function
>>> >>> >> pointer
>>> >>> >> or return it -- that cannot be done until runtime.
>>> >>> >>
>>> >>> >> eval is actually just a macro call in disguise, so the same
>>> >>> >> guidelines
>>> >>> >> apply. This also happens to demonstrate an appropriate (safe) use
>>> >>> >> of
>>> >>> >> eval.
>>> >>> >>
>>> >>> >>
>>> >>> >> PS. this code should be causing a compile-time deprecation warning
>>> >>> >> (because of the constant there), I'll have to investigate why that
>>> >>> >> code is not working anymore:
>>> >>> >>         return top(ccall)(Ptr{Void}
>>> >>> >> @0x00007f402e6dadc0,Ptr{Int8},(Uint16,),name::Uint16,0)::Ptr{Int8}
>>> >>> >>
>>> >>> >> On Wed, Apr 2, 2014 at 11:56 AM, Isaiah Norton
>>> >>> >> <[email protected]>
>>> >>> >> wrote:
>>> >>> >> > I stand corrected.
>>> >>> >> >
>>> >>> >> > On Wed, Apr 2, 2014 at 9:50 AM, Simon Danisch
>>> >>> >> > <[email protected]>
>>> >>> >> > wrote:
>>> >>> >> >>
>>> >>> >> >> Ah, the links are all the same...
>>> >>> >> >> Output for Mikes solution:
>>> >>> >> >> native:
>>> >>> >> >> https://gist.github.com/SimonDanisch/6270c01a6ea881877c4f
>>> >>> >> >> llvm:
>>> >>> >> >> https://gist.github.com/SimonDanisch/612e8b08d915d188c4d5
>>> >>> >> >>
>>> >>> >> >>
>>> >>> >> >>
>>> >>> >> >>
>>> >>> >> >> 2014-04-02 15:46 GMT+02:00 Simon Danisch <[email protected]>:
>>> >>> >> >>
>>> >>> >> >>> @ Mike
>>> >>> >> >>> Good question. Well, I definitely would wish for a simpler
>>> >>> >> >>> solutions.
>>> >>> >> >>> But as far as I understand the situation, every video card
>>> >>> >> >>> vendor
>>> >>> >> >>> makes
>>> >>> >> >>> his own OpenGL implementation.
>>> >>> >> >>> Also, even on one computer, you can have more than one
>>> >>> >> >>> rendering
>>> >>> >> >>> context.
>>> >>> >> >>> This means, the correct function pointers can be just queried,
>>> >>> >> >>> after
>>> >>> >> >>> one
>>> >>> >> >>> creates a particular context.
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>> So I looked into the machine and llvm code and its pretty
>>> >>> >> >>> clear!
>>> >>> >> >>> The version inspired by Mike generates a lot shorter llvm and
>>> >>> >> >>> machine
>>> >>> >> >>> code.
>>> >>> >> >>> It also doesn't matter if I call glGetString before inspecting
>>> >>> >> >>> the
>>> >>> >> >>> machine code.
>>> >>> >> >>>
>>> >>> >> >>> My test program for Isaiah's solution:
>>> >>> >> >>>
>>> >>> >> >>> #glTest.jl
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>> using GLUT, OpenGL
>>> >>> >> >>>
>>> >>> >> >>> glutInit()
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>> glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA |
>>> >>> >> >>> GLUT_MULTISAMPLE | GLUT_ALPHA)
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>> glutInitWindowPosition(0, 0)
>>> >>> >> >>> glutInitWindowSize(1,1)
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>> window = glutCreateWindow("dummy")
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>> println(code_llvm(glGetString, (Uint16,)))
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>> println(bytestring(convert(Ptr{Uint8}, glGetString(0x1F02))))
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>> println(code_llvm(glGetString, (Uint16,)))
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>> #OpenGL.jl
>>> >>> >> >>> module OpenGL
>>> >>> >> >>>
>>> >>> >> >>> function getFuncPointer(name)
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>     ccall( (:glXGetProcAddress, "libGL"), Ptr{Void},
>>> >>> >> >>> (Ptr{Cchar},),
>>> >>> >> >>> name)
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>> end
>>> >>> >> >>> glGetString(name::Uint16) =
>>> >>> >> >>> ccall(getFuncPointer("glGetString"),
>>> >>> >> >>> Ptr{Cchar}, (Uint16,), name)
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>> export glGetString
>>> >>> >> >>> end
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>> Output:
>>> >>> >> >>> https://gist.github.com/SimonDanisch/777bfc7783f9e96818f4
>>> >>> >> >>>
>>> >>> >> >>> Output for Mikes solution:
>>> >>> >> >>> native:
>>> >>> >> >>> https://gist.github.com/SimonDanisch/777bfc7783f9e96818f4
>>> >>> >> >>> llvm:
>>> >>> >> >>> https://gist.github.com/SimonDanisch/777bfc7783f9e96818f4
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>> Am I missing something?
>>> >>> >> >>>
>>> >>> >> >>>
>>> >>> >> >>> Am Dienstag, 1. April 2014 14:30:12 UTC+2 schrieb Simon
>>> >>> >> >>> Danisch:
>>> >>> >> >>>>
>>> >>> >> >>>> Hi,
>>> >>> >> >>>> I'm working on the OpenGL package and I want to make it
>>> >>> >> >>>> finally
>>> >>> >> >>>> usable
>>> >>> >> >>>> in a nice and clean way on all platforms.
>>> >>> >> >>>> The problem is, that one needs pointer for the GL functions,
>>> >>> >> >>>> which
>>> >>> >> >>>> you
>>> >>> >> >>>> can only get, after initialization of the OpenGL context.
>>> >>> >> >>>> But initializing the context and creating a window shouldn't
>>> >>> >> >>>> be part
>>> >>> >> >>>> of
>>> >>> >> >>>> the OpenGL package.
>>> >>> >> >>>>
>>> >>> >> >>>> So I tried two different approaches, which both seem to have
>>> >>> >> >>>> their
>>> >>> >> >>>> downsides:
>>> >>> >> >>>>
>>> >>> >> >>>> 1.
>>> >>> >> >>>> Initialize OpenGL context when including the OpenGL package
>>> >>> >> >>>> This is bad, because this makes the OpenGL package dependent
>>> >>> >> >>>> on some
>>> >>> >> >>>> third party OpenGL context creation library.
>>> >>> >> >>>>
>>> >>> >> >>>> 2.
>>> >>> >> >>>> Load the functions later with a loading Function.
>>> >>> >> >>>> Bad, because the function definitions are not visible for any
>>> >>> >> >>>> other
>>> >>> >> >>>> module, that relies on the OpenGL package.
>>> >>> >> >>>>
>>> >>> >> >>>> My ideal solution would be, to evaluate a macro when the
>>> >>> >> >>>> function is
>>> >>> >> >>>> called and not when the module is included.
>>> >>> >> >>>> Like this, I can define all the OpenGL functions already in
>>> >>> >> >>>> the
>>> >>> >> >>>> OpenGL
>>> >>> >> >>>> module, and when you call them the first time,
>>> >>> >> >>>> the right function ptr gets inserted into the ccall, or an
>>> >>> >> >>>> error is
>>> >>> >> >>>> raised, when OpenGL context is not initialized.
>>> >>> >> >>>>
>>> >>> >> >>>> this could look like this:
>>> >>> >> >>>>
>>> >>> >> >>>> module OpenGL
>>> >>> >> >>>>
>>> >>> >> >>>> macro getFuncPointer(name::ASCIIString)
>>> >>> >> >>>>    return getProcAddress(name)
>>> >>> >> >>>> end
>>> >>> >> >>>>
>>> >>> >> >>>> glGetString(name::GLenum) =
>>> >>> >> >>>> ccall(@getFuncPointer("glGetString"),
>>> >>> >> >>>> ....,
>>> >>> >> >>>> ...., name)
>>> >>> >> >>>> export glGetString
>>> >>> >> >>>> end
>>> >>> >> >>>>
>>> >>> >> >>>> using OpenGL
>>> >>> >> >>>> ...create OpenGL context
>>> >>> >> >>>> #define getProcAddress
>>> >>> >> >>>> global const getProcAddress = glutGetProcAddress # If using
>>> >>> >> >>>> GLUT for
>>> >>> >> >>>> GL
>>> >>> >> >>>> context creation
>>> >>> >> >>>> #call gl Functions
>>> >>> >> >>>> glGetString(GL_VERSION)
>>> >>> >> >>>>
>>> >>> >> >>>> Any ideas how to do this in a clean way?
>>> >>> >> >>>>
>>> >>> >> >>>>
>>> >>> >> >>>> Cheers,
>>> >>> >> >>>>
>>> >>> >> >>>> Simon
>>> >>> >> >>
>>> >>> >> >>
>>> >>> >> >
>>> >>> >
>>> >>> >
>>> >
>>> >

Reply via email to