glClearNamedFramebufferfi documentation mismatches and errors.

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 glClearBuffer - OpenGL 4 Reference Pages desn’t have any drawbuffer argument passed to the function :wink: 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.

The reference page, the XML registry and the header file all disagree with the specification (§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.

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 ( clear.c\main\mesa\src - mesa/mesa - The Mesa 3D Graphics Library (mirrored from https://gitlab.freedesktop.org/mesa/mesa) ) 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);
}

:wink:

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, who will fix it… eventually. I guess.

I’m not talking about how function works, but that the driver side code expects 5 arguments on the stack after the call happens.

That what I’m talking about - someone just made a silly mistake that propagates on headers.

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 :wink:

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) 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.