PDA

View Full Version : glClearNamedFramebufferfi documentation mismatches and errors.



Sagaceil
09-28-2015, 02:18 AM
Hi !

I'm doing depth-stencil clearing using glClearNamedFramebufferfi :



// f is depth ClearValue - 1.0 , s is stencilClearValue - 0x00, fbo is valid, completness-checked framebuffer
if( depthBufferFormat == GpuApi::ETF_Depth24Stencil8 )
{
glClearNamedFramebufferfi( fbo, GL_DEPTH_STENCIL, f, s );
}


What'im getting is : GL_INVALID_VALUE error generated. Invalid draw buffer.

Documentation https://www.opengl.org/sdk/docs/man/html/glClearBuffer.xhtml desn't have any drawbuffer argument passed to the function ;) What make thing more interesting is the signature of the function:


typedef void (GLAPIENTRY * PFNGLCLEARNAMEDFRAMEBUFFERFIPROC) (GLuint framebuffer, GLenum buffer, GLfloat depth, GLint stencil);

If I change signature to the function to pass drawbuffer beetwen buffer and depth:


typedef void (GLAPIENTRY * PFNGLCLEARNAMEDFRAMEBUFFERFIPROC) (GLuint framebuffer, GLenum buffer,GLint drawbuffer, GLfloat depth, GLint stencil);

Suddenly clearing starts working perfectly fine w/o any error or warning messages. It seems that somehow documentation is wrong and all the WGL stuff follows that wrong doc or I'm missing something.

// Clearing depth and stencil using separate functions works fine.

GClements
09-28-2015, 04:22 AM
It seems that somehow documentation is wrong and all the WGL stuff follows that wrong doc or I'm missing something.
The reference page (https://www.opengl.org/sdk/docs/man4/html/glClearBuffer.xhtml), the XML registry (https://cvs.khronos.org/svn/repos/ogl/trunk/doc/registry/public/api/gl.xml) and the header file (https://www.opengl.org/registry/api/GL/glext.h) all disagree with the specification (https://www.opengl.org/registry/doc/glspec45.core.pdf) (17.4.3.1), which has:



void ClearNamedFramebufferfi( uint framebuffer, enum buffer, int drawbuffer, float depth, int stencil );

IOW, the "fi" versions have one more parameter than the others; they retain the drawbuffer parameter while having two parameters for the depth and stencil values rather than a single parameter for the value.

Sagaceil
09-28-2015, 05:41 AM
IOW, the "fi" versions have one more parameter than the others; they retain the drawbuffer parameter while having two parameters for the depth and stencil values rather than a single parameter for the value.
It's a known fact. But its super wierd, that doing this:


typedef void (WINAPI * FUNC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
FUNC hack_glClearNamedFramebufferfi = (FUNC)(glClearNamedFramebufferfi);
hack_glClearNamedFramebufferfi( fbo, GL_DEPTH_STENCIL, 0, f, s );

Actually does the job. So the signature is wrong, but function hiding under that exact adress expects 5 arguments. Tested it on AMD and nVidia. I checked MESA driver source ( http://cgit.freedesktop.org/mesa/mesa/tree/src/mesa/main/clear.c ) and at the very bottom on the file, there is:



/**
* The ClearBuffer framework is so complicated and so riddled with the
* assumption that the framebuffer is bound that, for now, we will just fake
* direct state access clearing for the user.
*/
void GLAPIENTRY
_mesa_ClearNamedFramebufferfi(GLuint framebuffer, GLenum buffer,
GLfloat depth, GLint stencil)
{
GLint oldfb;

_mesa_GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldfb);
_mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer);
_mesa_ClearBufferfi(buffer, 0, depth, stencil);
_mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, (GLuint) oldfb);
}

;)

Alfonse Reinheart
09-28-2015, 06:05 AM
Actually does the job. So the signature is wrong, but function hiding under that exact adress expects 5 arguments.

Why is that weird? That's how function pointers work. The pointer is just an address. And the number of parameters is not encoded in that address. The number of parameters is used by the compiler only to figure out how to communicate with the code at that address. How to encode parameters in registers/on the stack, how to receive parameters, etc.

That's why it's so important when dealing with DLLs to always cast pointers to the exact correct function type. Because there's no safety net if you get it wrong; nobody can know what was actually intended.


I checked MESA driver source ( http://cgit.freedesktop.org/mesa/mes...a/main/clear.c ) and at the very bottom on the file, there is:

I'd suggest filing a bug with MESA on that. Not so much for the lack of true DSA, but the incorrect function signature.

I've already filed a bug with Khronos (https://www.khronos.org/bugzilla/show_bug.cgi?id=1394), who will fix it... eventually. I guess.

Sagaceil
09-28-2015, 06:35 AM
Why is that weird? That's how function pointers work. The pointer is just an address. And the number of parameters is not encoded in that address. The number of parameters is used by the compiler only to figure out how to communicate with the code at that address. How to encode parameters in registers/on the stack, how to receive parameters, etc.
I'm not talking about how function works, but that the driver side code expects 5 arguments on the stack after the call happens.


I've already filed a bug with Khronos (https://www.khronos.org/bugzilla/show_bug.cgi?id=1394), who will fix it... eventually. I guess.
That what I'm talking about - someone just made a silly mistake that propagates on headers.

Alfonse Reinheart
09-28-2015, 07:55 AM
I'm not talking about how function works, but that the driver side code expects 5 arguments on the stack after the call happens.

But that's not weird; that's what the specification says. So that's what ought to happen.

Then again, I guess it is weird that AMD actually got it right ;)

What's much weirder is that... this bug in the XML files (the source of which is probably the ARB_direct_state_access extension specification (https://www.opengl.org/registry/specs/ARB/direct_state_access.txt)) has been around for over a year, since the release of ARB_DSA and OpenGL 4.5. This was long enough for it to propagate into MESA. Literally every OpenGL loading library incorporates this mistake.

Yet you're the first person who actually noticed it.