[Feat] (MG_Impl, MG_Backend): implement the integer direct state access framebuffer clears

glClearNamedFramebufferiv and glClearNamedFramebufferuiv were stubs, so a clear through
them was silently dropped and the attachment kept whatever it held. Their float siblings
were already implemented, which is what made the gap look like a rendering bug rather than
a missing entry point.

Which buffers they accept is narrower than glClearNamedFramebufferfv and differs between
the two: signed values clear COLOR or STENCIL, unsigned only COLOR (GL 4.6 core 17.4.3.1).
Only the colour buffer is indexed, so a stencil clear naming any drawbuffer other than 0 is
INVALID_VALUE rather than merely ignored, and anything else is INVALID_ENUM. Resolving the
framebuffer by name goes through the same helper the float forms use, which is what reports
INVALID_OPERATION for a name that is neither zero nor an existing framebuffer.

Both backends express them the way they already express the float forms: DirectGLES binds
the named framebuffer and forwards to glClearBuffer*, Magma queues the payload against the
named framebuffer rather than the bound one.

direct_state_access.framebuffers_clear_errors passes on both backends, and
framebuffers_clear passes on Espryt. Magma still fails that one, for a separate reason on
the materialization side rather than in these entry points.
This commit is contained in:
BZLZHH
2026-08-04 23:41:28 -04:00
parent 1011d9fea1
commit 19932f9e49
12 changed files with 200 additions and 2 deletions
+4
View File
@@ -145,6 +145,10 @@ namespace MobileGL {
GLenum buffer, GLint drawbuffer, const GLfloat* value); GLenum buffer, GLint drawbuffer, const GLfloat* value);
void (*ClearNamedFramebufferfi)(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, void (*ClearNamedFramebufferfi)(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
void (*ClearNamedFramebufferiv)(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLint* value);
void (*ClearNamedFramebufferuiv)(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLuint* value);
void (*BlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, void (*BlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0,
GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
void (*BlitNamedFramebuffer)(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer, void (*BlitNamedFramebuffer)(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
@@ -988,6 +988,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
funcsTable.GL.ClearBufferuiv = ClearBufferuiv; funcsTable.GL.ClearBufferuiv = ClearBufferuiv;
funcsTable.GL.ClearBufferiv = ClearBufferiv; funcsTable.GL.ClearBufferiv = ClearBufferiv;
funcsTable.GL.ClearNamedFramebufferfv = ClearNamedFramebufferfv; funcsTable.GL.ClearNamedFramebufferfv = ClearNamedFramebufferfv;
funcsTable.GL.ClearNamedFramebufferiv = ClearNamedFramebufferiv;
funcsTable.GL.ClearNamedFramebufferuiv = ClearNamedFramebufferuiv;
funcsTable.GL.ClearNamedFramebufferfi = ClearNamedFramebufferfi; funcsTable.GL.ClearNamedFramebufferfi = ClearNamedFramebufferfi;
funcsTable.GL.BlitFramebuffer = BlitFramebuffer; funcsTable.GL.BlitFramebuffer = BlitFramebuffer;
funcsTable.GL.BlitNamedFramebuffer = BlitNamedFramebuffer; funcsTable.GL.BlitNamedFramebuffer = BlitNamedFramebuffer;
@@ -4431,6 +4431,40 @@ namespace MobileGL::MG_Backend::DirectGLES {
ForceBindCurrentFBO(FramebufferTarget::Draw); ForceBindCurrentFBO(FramebufferTarget::Draw);
} }
void ClearNamedFramebufferiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLint* value) {
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER
DebugImpl::OpenGLScopeMarker marker(__func__);
#endif
TextureImpl::SyncNeccessaryTextures();
RenderStateImpl::SyncRenderState();
SyncAndBindFramebufferObject(framebuffer, FramebufferTarget::Draw, true);
g_GLESFuncs.glClearBufferiv(buffer, drawbuffer, value);
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
});
ForceBindCurrentFBO(FramebufferTarget::Draw);
}
void ClearNamedFramebufferuiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLuint* value) {
#if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG && MOBILEGL_ENABLE_SCOPE_MARKER
DebugImpl::OpenGLScopeMarker marker(__func__);
#endif
TextureImpl::SyncNeccessaryTextures();
RenderStateImpl::SyncRenderState();
SyncAndBindFramebufferObject(framebuffer, FramebufferTarget::Draw, true);
g_GLESFuncs.glClearBufferuiv(buffer, drawbuffer, value);
DebugImpl::ErrorLopper::Loop([file = __FILE__, line = __LINE__](auto err) {
MGLOG_D("ES error (%s:%d): %s", file, line, MG_Util::ConvertGLEnumToString(err).c_str());
});
ForceBindCurrentFBO(FramebufferTarget::Draw);
}
static SizeT AlignPixelRow(SizeT rowBytes, Int alignment) { static SizeT AlignPixelRow(SizeT rowBytes, Int alignment) {
const SizeT resolvedAlignment = static_cast<SizeT>(std::max(alignment, 1)); const SizeT resolvedAlignment = static_cast<SizeT>(std::max(alignment, 1));
return (rowBytes + resolvedAlignment - 1) & ~(resolvedAlignment - 1); return (rowBytes + resolvedAlignment - 1) & ~(resolvedAlignment - 1);
@@ -59,6 +59,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
GLenum buffer, GLint drawbuffer, const GLfloat* value); GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
void ClearNamedFramebufferiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLint* value);
void ClearNamedFramebufferuiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLuint* value);
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1,
GLint dstY1, GLbitfield mask, GLenum filter); GLint dstY1, GLbitfield mask, GLenum filter);
void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer, void BlitNamedFramebuffer(const SharedPtr<MG_State::GLState::FramebufferObject>& readFramebuffer,
@@ -597,6 +597,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
funcsTable.GL.ClearBufferiv = ClearBufferiv; funcsTable.GL.ClearBufferiv = ClearBufferiv;
funcsTable.GL.ClearNamedFramebufferfv = ClearNamedFramebufferfv; funcsTable.GL.ClearNamedFramebufferfv = ClearNamedFramebufferfv;
funcsTable.GL.ClearNamedFramebufferfi = ClearNamedFramebufferfi; funcsTable.GL.ClearNamedFramebufferfi = ClearNamedFramebufferfi;
funcsTable.GL.ClearNamedFramebufferiv = ClearNamedFramebufferiv;
funcsTable.GL.ClearNamedFramebufferuiv = ClearNamedFramebufferuiv;
funcsTable.GL.BlitFramebuffer = BlitFramebuffer; funcsTable.GL.BlitFramebuffer = BlitFramebuffer;
funcsTable.GL.BlitNamedFramebuffer = BlitNamedFramebuffer; funcsTable.GL.BlitNamedFramebuffer = BlitNamedFramebuffer;
funcsTable.GL.CopyTexImage2D = CopyTexImage2D; funcsTable.GL.CopyTexImage2D = CopyTexImage2D;
@@ -440,6 +440,20 @@ namespace MobileGL::MG_Backend::DirectVulkan {
pVulkanRenderer->ClearNamedFramebufferfv(framebuffer, buffer, drawbuffer, value); pVulkanRenderer->ClearNamedFramebufferfv(framebuffer, buffer, drawbuffer, value);
} }
void ClearNamedFramebufferiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, const GLint* value) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferiv called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearNamedFramebufferiv called with null GL context");
pVulkanRenderer->ClearNamedFramebufferiv(framebuffer, buffer, drawbuffer, value);
}
void ClearNamedFramebufferuiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, const GLuint* value) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferuiv called with null VulkanRenderer");
MOBILEGL_ASSERT(MG_State::pGLContext, "DirectVulkan::ClearNamedFramebufferuiv called with null GL context");
pVulkanRenderer->ClearNamedFramebufferuiv(framebuffer, buffer, drawbuffer, value);
}
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer, void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, GLfloat depth, GLint stencil) { GLint drawbuffer, GLfloat depth, GLint stencil) {
MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferfi called with null VulkanRenderer"); MOBILEGL_ASSERT(pVulkanRenderer, "DirectVulkan::ClearNamedFramebufferfi called with null VulkanRenderer");
@@ -35,6 +35,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value); void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer, void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, const GLfloat* value); GLint drawbuffer, const GLfloat* value);
void ClearNamedFramebufferiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, const GLint* value);
void ClearNamedFramebufferuiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, const GLuint* value);
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer, void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer,
GLint drawbuffer, GLfloat depth, GLint stencil); GLint drawbuffer, GLfloat depth, GLint stencil);
void Clear(GLbitfield mask); void Clear(GLbitfield mask);
@@ -5771,6 +5771,46 @@ void main() {
QueueClearBufferPayloadForFramebuffer(*framebuffer, buffer, drawbuffer, payload); QueueClearBufferPayloadForFramebuffer(*framebuffer, buffer, drawbuffer, payload);
} }
// The integer clears carry the same payload as their target-based siblings; only the
// destination differs, so they queue against the named framebuffer rather than the bound one.
void VulkanRenderer::ClearNamedFramebufferiv(
const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer, GLint drawbuffer,
const GLint* value) {
if (!framebuffer || value == nullptr) {
return;
}
ClearAttachmentPayload payload{};
switch (buffer) {
case GL_COLOR:
payload.mask = GL_COLOR_BUFFER_BIT;
payload.color = FloatVec4(static_cast<Float>(value[0]), static_cast<Float>(value[1]),
static_cast<Float>(value[2]), static_cast<Float>(value[3]));
break;
case GL_STENCIL:
payload.mask = GL_STENCIL_BUFFER_BIT;
payload.stencil = static_cast<Uint32>(std::max(value[0], 0));
break;
default:
break;
}
QueueClearBufferPayloadForFramebuffer(*framebuffer, buffer, drawbuffer, payload);
}
void VulkanRenderer::ClearNamedFramebufferuiv(
const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer, GLint drawbuffer,
const GLuint* value) {
if (!framebuffer || value == nullptr) {
return;
}
ClearAttachmentPayload payload{};
if (buffer == GL_COLOR) {
payload.mask = GL_COLOR_BUFFER_BIT;
payload.color = FloatVec4(static_cast<Float>(value[0]), static_cast<Float>(value[1]),
static_cast<Float>(value[2]), static_cast<Float>(value[3]));
}
QueueClearBufferPayloadForFramebuffer(*framebuffer, buffer, drawbuffer, payload);
}
void VulkanRenderer::ClearNamedFramebufferfi( void VulkanRenderer::ClearNamedFramebufferfi(
const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer, GLint drawbuffer, const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, GLenum buffer, GLint drawbuffer,
GLfloat depth, GLint stencil) { GLfloat depth, GLint stencil) {
@@ -181,6 +181,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value); void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value);
void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, void ClearNamedFramebufferfv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLfloat* value); GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearNamedFramebufferiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLint* value);
void ClearNamedFramebufferuiv(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLuint* value);
void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer, void ClearNamedFramebufferfi(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
@@ -1036,8 +1036,8 @@ DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferDrawBuffers, GLuint framebuffer,
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferReadBuffer, GLuint framebuffer, GLenum src) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferReadBuffer, framebuffer, src) DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferReadBuffer, GLuint framebuffer, GLenum src) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferReadBuffer, framebuffer, src)
DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferData, framebuffer, numAttachments, attachments) DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferData, framebuffer, numAttachments, attachments)
DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferSubData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferSubData, framebuffer, numAttachments, attachments, x, y, width, height) DECLARE_GL_FUNCTION_STUB_HEAD(void, InvalidateNamedFramebufferSubData, GLuint framebuffer, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, InvalidateNamedFramebufferSubData, framebuffer, numAttachments, attachments, x, y, width, height)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferiv, framebuffer, buffer, drawbuffer, value) DECLARE_GL_FUNCTION_HEAD(void, ClearNamedFramebufferiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedFramebufferiv, framebuffer, buffer, drawbuffer, value)
DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearNamedFramebufferuiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* value) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearNamedFramebufferuiv, framebuffer, buffer, drawbuffer, value) DECLARE_GL_FUNCTION_HEAD(void, ClearNamedFramebufferuiv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedFramebufferuiv, framebuffer, buffer, drawbuffer, value)
DECLARE_GL_FUNCTION_HEAD(void, ClearNamedFramebufferfv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedFramebufferfv, framebuffer, buffer, drawbuffer, value) DECLARE_GL_FUNCTION_HEAD(void, ClearNamedFramebufferfv, GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedFramebufferfv, framebuffer, buffer, drawbuffer, value)
DECLARE_GL_FUNCTION_HEAD(void, ClearNamedFramebufferfi, GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedFramebufferfi, framebuffer, buffer, drawbuffer, depth, stencil) DECLARE_GL_FUNCTION_HEAD(void, ClearNamedFramebufferfi, GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) DECLARE_GL_FUNCTION_END_NO_RETURN(void, ClearNamedFramebufferfi, framebuffer, buffer, drawbuffer, depth, stencil)
DECLARE_GL_FUNCTION_HEAD(void, BlitNamedFramebuffer, GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlitNamedFramebuffer, readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) DECLARE_GL_FUNCTION_HEAD(void, BlitNamedFramebuffer, GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) DECLARE_GL_FUNCTION_END_NO_RETURN(void, BlitNamedFramebuffer, readFramebuffer, drawFramebuffer, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter)
@@ -467,6 +467,26 @@ namespace MobileGL::MG_Impl::GLImpl {
clearNamedFramebufferfi(framebuffer, buffer, drawbuffer, depth, stencil); clearNamedFramebufferfi(framebuffer, buffer, drawbuffer, depth, stencil);
} }
void ClearNamedFramebufferiv_Backend(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLint* value) {
auto clearNamedFramebufferiv = MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferiv;
if (!clearNamedFramebufferiv) {
MGLOG_E("glClearNamedFramebufferiv skipped: backend does not implement explicit framebuffer clear.");
return;
}
clearNamedFramebufferiv(framebuffer, buffer, drawbuffer, value);
}
void ClearNamedFramebufferuiv_Backend(const SharedPtr<MG_State::GLState::FramebufferObject>& framebuffer,
GLenum buffer, GLint drawbuffer, const GLuint* value) {
auto clearNamedFramebufferuiv = MG_Backend::gBackendFunctionsTable.GL.ClearNamedFramebufferuiv;
if (!clearNamedFramebufferuiv) {
MGLOG_E("glClearNamedFramebufferuiv skipped: backend does not implement explicit framebuffer clear.");
return;
}
clearNamedFramebufferuiv(framebuffer, buffer, drawbuffer, value);
}
void SampleMaski_State(GLuint maskNumber, GLbitfield mask) { void SampleMaski_State(GLuint maskNumber, GLbitfield mask) {
if (maskNumber != 0) { if (maskNumber != 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
@@ -1586,6 +1606,66 @@ namespace MobileGL::MG_Impl::GLImpl {
ClearNamedFramebufferfi_Backend(framebufferObject, buffer, drawbuffer, depth, stencil); ClearNamedFramebufferfi_Backend(framebufferObject, buffer, drawbuffer, depth, stencil);
} }
// Which buffers the integer clears accept is narrower than the float one, and differs between
// them: signed values can clear COLOR or STENCIL, unsigned only COLOR (GL 4.6 core 17.4.3.1).
// Only the colour buffer is indexed; a stencil clear names the single stencil buffer, so any
// drawbuffer other than 0 is out of range rather than merely unused.
Bool ValidateNamedClearIntegerv_State(GLenum buffer, GLint drawbuffer, const void* value, Bool allowStencil,
const char* caller) {
if (!value) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "value pointer cannot be null."));
return false;
}
if (buffer == GL_COLOR) {
if (drawbuffer < 0 ||
drawbuffer >= static_cast<GLint>(MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "color drawbuffer index is out of range."));
return false;
}
return true;
}
if (buffer == GL_STENCIL && allowStencil) {
if (drawbuffer != 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "stencil clear requires drawbuffer 0."));
return false;
}
return true;
}
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl", caller,
std::format("buffer {} is not accepted for this clear.", MG_Util::ConvertGLEnumToString(buffer))));
return false;
}
void ClearNamedFramebufferiv_State(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value) {
auto framebufferObject = GetFramebufferObjectForNamedClear(framebuffer, "ClearNamedFramebufferiv_State");
if (!framebufferObject) return;
if (!ValidateNamedClearIntegerv_State(buffer, drawbuffer, value, true, "ClearNamedFramebufferiv_State")) {
return;
}
ClearNamedFramebufferiv_Backend(framebufferObject, buffer, drawbuffer, value);
}
void ClearNamedFramebufferuiv_State(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* value) {
auto framebufferObject = GetFramebufferObjectForNamedClear(framebuffer, "ClearNamedFramebufferuiv_State");
if (!framebufferObject) return;
if (!ValidateNamedClearIntegerv_State(buffer, drawbuffer, value, false, "ClearNamedFramebufferuiv_State")) {
return;
}
ClearNamedFramebufferuiv_Backend(framebufferObject, buffer, drawbuffer, value);
}
void DeleteRenderbuffers_State(GLsizei n, const GLuint* renderbuffers) { void DeleteRenderbuffers_State(GLsizei n, const GLuint* renderbuffers) {
if (n < 0) { if (n < 0) {
MG_State::pGLContext->RecordError( MG_State::pGLContext->RecordError(
@@ -2273,6 +2353,14 @@ namespace MobileGL::MG_Impl::GLImpl {
ClearBufferiv_Backend(buffer, drawbuffer, value); ClearBufferiv_Backend(buffer, drawbuffer, value);
} }
void ClearNamedFramebufferiv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value) {
ClearNamedFramebufferiv_State(framebuffer, buffer, drawbuffer, value);
}
void ClearNamedFramebufferuiv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* value) {
ClearNamedFramebufferuiv_State(framebuffer, buffer, drawbuffer, value);
}
void SampleMaski(GLuint maskNumber, GLbitfield mask) { void SampleMaski(GLuint maskNumber, GLbitfield mask) {
SampleMaski_State(maskNumber, mask); SampleMaski_State(maskNumber, mask);
} }
@@ -58,6 +58,8 @@ namespace MobileGL::MG_Impl::GLImpl {
void NamedFramebufferReadBuffer(GLuint framebuffer, GLenum src); void NamedFramebufferReadBuffer(GLuint framebuffer, GLenum src);
void ClearNamedFramebufferfv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value); void ClearNamedFramebufferfv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat* value);
void ClearNamedFramebufferfi(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); void ClearNamedFramebufferfi(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
void ClearNamedFramebufferiv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value);
void ClearNamedFramebufferuiv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* value);
GLenum CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target); GLenum CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target);
void GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params); void GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params);
void BlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, void BlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1,