When Does Opengl Get Finished with Pointers in Functions

When does OpenGL get finished with pointers in functions?

All OpenGL functions, with the exception noted below, will be finished with any pointer you give it upon that function's return. So glReadPixels will have finished all pixel reading and format conversion upon its return. This is why asynchronous pixel transfer is so important for reading operations. It allows OpenGL to not do that, to not synchronize with the GPU.

The only exception to this rule is every function that ends in the word "Pointer". Things like glVertexAttribPointer, glTexCoordPointer, and the like. When you use client-side memory with these functions (no longer legal in core profile OpenGL 3.2+), these functions store a pointer to that memory. Therefore, you must ensure that this pointer is valid for as long as you intend to render with those vertex attributes.

After each rendering call using client-memory, OpenGL requires that the implementation have finished reading from client memory by the time the rendering function returns. So you can call glDrawArrays, then delete the pointers in question. And as long as you don't make another draw call until you've changed those pointers, you're fine. This means OpenGL has to have copied out all relevant vertex data by the time the rendering call returns (one of the reasons why using buffer objects is faster).

How does the OpenGL function loading mechanism work?

  1. Who implements this magical get-function?

That one is actually a bit tricky, since this function is not part of OpenGL, but of the plattform-specific OpenGL binding library. For example, you have wglGetProcAddress on Win32/wgl, glxGetProcAddress on X11, elgGetProcAddress on EGL (multi-platform, more modern and flexible alternative).

On Linux, the EGL and glX implementations are part of the OpenGL implementation (for example mesa, but nivida's proprietary driver comes with its own glX and egl libs), so the answer to your question is "the opengl implementor".

On windows, the answer is "Microsoft" but that is a meaningless answer as the microsoft function basically only calls some implementor-specific function in the OpenGL ICD (installable client driver), which does the real work, and that one comes from the opengl implementor of cousre (intel, nvidia, AMD typically, but you could even run mesa software rasterizer on windows).


  1. Who implements the function (pointers) it returns?

The OpenGL implementor. Typically, the OpenGL implementation is part of the graphics driver.

My understanding right now is that it's Mesa3D that provides the get-function via libgl.so and gl.h, and it only operates in userspace. It's also Mesa3D that implements the userspace-side of the functions returned by the get-function, the kernel side is implemented by the GPU driver. Is this correct?

Mesa3D is a bit a special case as it is a multi-vendor OpenGL implementation. Actually, mesa consists of some shared frontend (which forms the outer interface of the libGL and others) and utility functionality, and some vendor-specific backends. Those mesa backends are actually considered part of the graphics driver, the driver is not just the kernel module to which mesa talks to. A very big deal of the graphics APIs (especially in the GL) is implemented in user space, and that is still highly device-specific.

This would imply that (in this example) a loading library like glad/glew/gl3w sits directly above Mesa3D and talks to no one other than Mesa3D?

More or less. The truth is a bit more complex and ugly. There are some platforms where the extension function pointer query function is not required to return pointers for functions which are in OpenGL 1.1 core, so most loaders work around this by resorting to GetProcAddress (win32) or dlsym to query those symbols at runtime, so they typically they might use libdl.so on Linux, too (and dlopen the GL lib behind your back). Note that this also means that when you use a GL loader like GLAD, you do not have to (and actually should not) manually link to libGL.so at all in your project - it is completely loaded at runtime anyway, and you program could also bail out nicely if no GL lib is available on the user's system, instead of the binary not even starting due to missing libs.

Also, modern Linux distributions use the libgvnd vendor neutral GL dispatch scheme, which means that even when you use Mesa3D, the GL loader would actually talk to the GLvnd stub, which internally would route the requests to the implementaition you use (mesa3d in your case).

Is there a way to tell whether an OpenGL operation is finished?

Yes, there is. Assuming you have access to OpenGL 3.2+ or the ARB_sync extension.

If you want to know when a particular command has finished, you can insert a "fence" sync object into the command stream immediately after issuing that command. This is done with the glFenceSync function.

You must store the pointer returned by this function. With that pointer in hand, you can query whether the fence has completed by checking whether the fence is signaled with the glGetSync function. Like this:

GLint isSignaled = 0;
glGetSync(syncObj, GL_SYNC_STATUS, 1, NULL, &isSignaled);

if(isSignaled == GL_SIGNALED)
{
//Prior commands have completed.
}
else
{
//Not done yet.
}

If you run out of other stuff to do, you don't need to wait for the sync object to finish; you can just do whatever OpenGL process you wanted to do. That will induce the CPU block for you.

Once you're finished with the sync object, you must delete it. Use the glDeleteSync function to do so.

When is data sent to the GPU with openGL

1: glCreateVertexArrays doesn't have anything to do with buffer objects or GPU memory (of that kind), so it's kinda irrelevant.

As for the rest, when OpenGL decides to allocate actual GPU memory is up to the OpenGL implementation. It can defer the actual allocation as long as it wants.

If you're asking about when your data is uploaded to OpenGL, OpenGL will always be finished with any pointer you pass it when that function call returns. So the implementation will either copy the data to the GPU-accessible memory within the call itself, or it will allocate some CPU memory and copy your data into that, scheduling the transfer to the actual GPU storage for later.

As a matter of practicality, you should assume that copying to the buffer doesn't happen immediately. This is because DMAs usually require certain memory alignment, and the pointer you pass may not have that alignment.

But usually, you shouldn't care. Let the implementation do its job.

2: Like the above, the implementation can do whatever it wants when you map memory. It might give you a genuine pointer to GPU-accessible memory. Or it might just allocate a block of CPU memory and DMA it up when you unmap the memory.

The only exception to this is persistent mapping. That feature requires that OpenGL give you an actual pointer to the actual GPU-accessible memory that the buffer resides in. This is because you never actually tell the implementation when you're finished writing to/reading from the memory.

This is also (part of) why OpenGL requires you to allocate buffer storage immutably to be able to use persistent mapping.

3: It is copied whenever the implementation feels that it needs to be.

OpenGL implementations are a black box. What they do is more-or-less up to them. The only requirement the specification makes is that their behavior act "as if" it were doing things the way the specification says. As such, the data can be copied whenever the implementation feels like copying it, so long as everything still works "as if" it had copied it immediately.

Making a draw call does not require that any buffer DMAs that this draw command relies on have completed at that time. It merely requires that those DMAs will happen before the GPU actually executes that drawing command. The implementation could do that by blocking in the glDraw* call until the DMAs have completed. But it can also use internal GPU synchronization mechanisms to tie the drawing command being issued to the completion of the DMA operation(s).

The only thing that will guarantee that the upload has actually completed is to call a function that will cause the GPU to access the buffer, then synchronizing the CPU with that command. Synchronizing after only the upload doesn't guarantee anything. The upload itself is not observable behavior, so synchronizing there may not have an effect.

Then again, it might. That's the point; you cannot know.

When does glBufferSubData return?

OpenGL doesn't define how glBufferSubData has to be implemented: It can either copy the data immediately to GPU memory or it may defer the copy operation to a later point.

What OpenGL guarantees (OpenGL 4.5 Specification, Section 5.3) is that one can assume a call to glBufferSubData to be completed when the method returns. This means that every implementation that defers the CPU->GPU copy operation has to make sure that the CPU memory is copied before returning.

In conclusion: You can change the content of the pointer immediately after the glBufferSubData returns without modifying/destroying the buffers content.

OpenGL loader Reason to #define function pointer

This is done to avoid namespace collisions. The names specified by OpenGL and the OpenGL extensions are reserved for the use by OpenGL implementations. Later versions of the various operating systems OpenGL standard ABI^1 may suddenly expose symbols in that namespace, which would break programs being linked with libraries, that also define these symbols.

An extension loader library is not an OpenGL implementation, but a 3rd party library. As such it is good practice not tread into the namespace reserved to OpenGL, i.e. symbols beginning with gl…. Instead such extension loaders load the symbols into their own namespace, like _ptrc_glew… and use some preprocessor macro trickery to transparently "rename" symbol references in code that uses that library.


1: ABI = specifications on what a certain API has to provide and how the interface is done on the lower level.

How does OpenGL function loading work?

Where are the functions actually located?

This is implementation dependent. I'd wager that they're stored in a hash table of function names to function pointers. They're still in the shared library, but usually don't have their symbols exposed.

How are they retrieved?

glXGetProcAddress or wglGetProcAddress, depending on the platform. Most libraries that create OpenGL windows (GLFW, SDL) have their own, cross-platform function that uses the above.

Why is it done this way?

I can think of a few reasons: implementations can change what extensions are available without breaking ABI compatibility, and what functions you have access to may depend on the type or version of context you request (ex. for Mesa, post OpenGL 3.1 extensions are only available in a 3.1+ context, not in anything lower).

Are OpenGL functions actually context-specific?

Technically yes: function pointers retrieved from an OpenGL context are valid only for that specific context. However, for most practical purposes, you can ignore this. If two contexts can share objects, then they almost certainly share function pointers.

If you want to account for those cases where function pointers can't be shared across contexts, the best option is to write a loader specifically for dealing with that eventuality. You could for example modify GLAD to put OpenGL functions in a struct and then load the functions into different structs for different contexts.

why pass window pointer in callback function opengl

This is done because GLFW is written in C, not C++. Therefore, there's not so much ways to distinguish one window from another. Also, it's not us who pass info to callbacks, it's GLFW that executes callbacks from its code. It specifies window handle so that you can choose the window for which this callback is meant to be called. When you have only one window, this argument can be left unused. But when you create multiple windows, and you have all window handles, you can choose a window object with the handle passed in callback and execute a method on only one exact window object.

Note that you can specify different callbacks for different windows.



Related Topics



Leave a reply



Submit