[Feat] (MG_Impl, MG_State): implement the framebuffer parameter getters and setters

glFramebufferParameteri, glGetFramebufferParameteriv and their two by-name
siblings were all export stubs - the GL_ARB_framebuffer_no_attachments entry
points. The stub raises no error and writes nothing, so
direct_state_access.framebuffers_get_parameter_errors saw GL_NO_ERROR for all
three conditions it checks.

FramebufferObject gains the five DEFAULT_* parameters as real state, initialised
to GL 4.6 core table 23.24 and bumping the object version on a write like the
read buffer does. The getter answers those plus the six derived names -
GL_SAMPLES and GL_SAMPLE_BUFFERS from the attachments' sample counts,
GL_IMPLEMENTATION_COLOR_READ_FORMAT/_TYPE from the read buffer's internal format,
GL_DOUBLEBUFFER true only for the window-system framebuffer, GL_STEREO false
because stereo surfaces are not exposed - which is what glGetIntegerv already
reports for the bound framebuffer.

The pname rules live in ValidateFramebufferParameterPname, and their ORDER is
load-bearing: a name outside the table is INVALID_ENUM, and only a name that IS
in the table but that the default framebuffer cannot answer is INVALID_OPERATION.
Testing the framebuffer kind first would answer INVALID_ENUM for
GL_FRAMEBUFFER_DEFAULT_WIDTH on framebuffer zero, which is exactly the third
thing the case checks. The by-name forms take zero as the default framebuffer,
like the other DSA framebuffer entry points.

Rendering to a framebuffer with no attachments is deliberately NOT enabled by
this: CheckCompleteness still reports INCOMPLETE_MISSING_ATTACHMENT, because no
backend can rasterize one. The state is real and the queries are honest; the
draw path is a separate piece of work.

Takes framebuffers_get_parameter_errors from failing to passing on both backends,
with framebuffers_get_parameters - which passed only because both getters were
stubs leaving the CTS's zero-initialised comparands untouched - still passing.
This commit is contained in:
BZLZHH
2026-08-05 05:33:31 -04:00
parent 817091641c
commit 1f1a331a44
7 changed files with 282 additions and 4 deletions
@@ -310,8 +310,8 @@ DECLARE_GL_FUNCTION_HEAD(void, DispatchCompute, GLuint num_groups_x, GLuint num_
DECLARE_GL_FUNCTION_HEAD(void, DispatchComputeIndirect, GLintptr indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DispatchComputeIndirect, indirect) DECLARE_GL_FUNCTION_HEAD(void, DispatchComputeIndirect, GLintptr indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DispatchComputeIndirect, indirect)
DECLARE_GL_FUNCTION_HEAD(void, DrawArraysIndirect, GLenum mode, const void* indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawArraysIndirect, mode, indirect) DECLARE_GL_FUNCTION_HEAD(void, DrawArraysIndirect, GLenum mode, const void* indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawArraysIndirect, mode, indirect)
DECLARE_GL_FUNCTION_HEAD(void, DrawElementsIndirect, GLenum mode, GLenum type, const void* indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsIndirect, mode, type, indirect) DECLARE_GL_FUNCTION_HEAD(void, DrawElementsIndirect, GLenum mode, GLenum type, const void* indirect) DECLARE_GL_FUNCTION_END_NO_RETURN(void, DrawElementsIndirect, mode, type, indirect)
DECLARE_GL_FUNCTION_STUB_HEAD(void, FramebufferParameteri, GLenum target, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, FramebufferParameteri, target, pname, param) DECLARE_GL_FUNCTION_HEAD(void, FramebufferParameteri, GLenum target, GLenum pname, GLint param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferParameteri, target, pname, param)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetFramebufferParameteriv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetFramebufferParameteriv, target, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetFramebufferParameteriv, GLenum target, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetFramebufferParameteriv, target, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, GetProgramInterfaceiv, GLuint program, GLenum programInterface, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetProgramInterfaceiv, program, programInterface, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetProgramInterfaceiv, GLuint program, GLenum programInterface, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetProgramInterfaceiv, program, programInterface, pname, params)
DECLARE_GL_FUNCTION_HEAD(GLuint, GetProgramResourceIndex, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_END(GLuint, GetProgramResourceIndex, program, programInterface, name) DECLARE_GL_FUNCTION_HEAD(GLuint, GetProgramResourceIndex, GLuint program, GLenum programInterface, const GLchar* name) DECLARE_GL_FUNCTION_END(GLuint, GetProgramResourceIndex, program, programInterface, name)
DECLARE_GL_FUNCTION_HEAD(void, GetProgramResourceName, GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei* length, GLchar* name) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetProgramResourceName, program, programInterface, index, bufSize, length, name) DECLARE_GL_FUNCTION_HEAD(void, GetProgramResourceName, GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei* length, GLchar* name) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetProgramResourceName, program, programInterface, index, bufSize, length, name)
@@ -1028,7 +1028,7 @@ DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferPointerv, GLuint buffer, GLenum pna
DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferSubData, buffer, offset, size, data) DECLARE_GL_FUNCTION_HEAD(void, GetNamedBufferSubData, GLuint buffer, GLintptr offset, GLsizeiptr size, void* data) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedBufferSubData, buffer, offset, size, data)
DECLARE_GL_FUNCTION_HEAD(void, CreateFramebuffers, GLsizei n, GLuint* framebuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateFramebuffers, n, framebuffers) DECLARE_GL_FUNCTION_HEAD(void, CreateFramebuffers, GLsizei n, GLuint* framebuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateFramebuffers, n, framebuffers)
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferRenderbuffer, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferRenderbuffer, framebuffer, attachment, renderbuffertarget, renderbuffer) DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferRenderbuffer, GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferRenderbuffer, framebuffer, attachment, renderbuffertarget, renderbuffer)
DECLARE_GL_FUNCTION_STUB_HEAD(void, NamedFramebufferParameteri, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, NamedFramebufferParameteri, framebuffer, pname, param) DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferParameteri, GLuint framebuffer, GLenum pname, GLint param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferParameteri, framebuffer, pname, param)
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferTexture, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferTexture, framebuffer, attachment, texture, level) DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferTexture, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferTexture, framebuffer, attachment, texture, level)
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferTextureLayer, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferTextureLayer, framebuffer, attachment, texture, level, layer) DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferTextureLayer, GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferTextureLayer, framebuffer, attachment, texture, level, layer)
DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferDrawBuffer, GLuint framebuffer, GLenum buf) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferDrawBuffer, framebuffer, buf) DECLARE_GL_FUNCTION_HEAD(void, NamedFramebufferDrawBuffer, GLuint framebuffer, GLenum buf) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedFramebufferDrawBuffer, framebuffer, buf)
@@ -1042,7 +1042,7 @@ DECLARE_GL_FUNCTION_HEAD(void, ClearNamedFramebufferfv, GLuint framebuffer, GLen
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)
DECLARE_GL_FUNCTION_HEAD(GLenum, CheckNamedFramebufferStatus, GLuint framebuffer, GLenum target) DECLARE_GL_FUNCTION_END(GLenum, CheckNamedFramebufferStatus, framebuffer, target) DECLARE_GL_FUNCTION_HEAD(GLenum, CheckNamedFramebufferStatus, GLuint framebuffer, GLenum target) DECLARE_GL_FUNCTION_END(GLenum, CheckNamedFramebufferStatus, framebuffer, target)
DECLARE_GL_FUNCTION_STUB_HEAD(void, GetNamedFramebufferParameteriv, GLuint framebuffer, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, GetNamedFramebufferParameteriv, framebuffer, pname, param) DECLARE_GL_FUNCTION_HEAD(void, GetNamedFramebufferParameteriv, GLuint framebuffer, GLenum pname, GLint* param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedFramebufferParameteriv, framebuffer, pname, param)
DECLARE_GL_FUNCTION_HEAD(void, GetNamedFramebufferAttachmentParameteriv, GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedFramebufferAttachmentParameteriv, framebuffer, attachment, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetNamedFramebufferAttachmentParameteriv, GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedFramebufferAttachmentParameteriv, framebuffer, attachment, pname, params)
DECLARE_GL_FUNCTION_HEAD(void, CreateRenderbuffers, GLsizei n, GLuint* renderbuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateRenderbuffers, n, renderbuffers) DECLARE_GL_FUNCTION_HEAD(void, CreateRenderbuffers, GLsizei n, GLuint* renderbuffers) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateRenderbuffers, n, renderbuffers)
DECLARE_GL_FUNCTION_HEAD(void, NamedRenderbufferStorage, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedRenderbufferStorage, renderbuffer, internalformat, width, height) DECLARE_GL_FUNCTION_HEAD(void, NamedRenderbufferStorage, GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedRenderbufferStorage, renderbuffer, internalformat, width, height)
@@ -8,6 +8,7 @@
#include "GL_Framebuffer.h" #include "GL_Framebuffer.h"
#include "Validators.h" #include "Validators.h"
#include <MG_Util/Texture/TextureFormatProcessor.h>
#include "Config.h" #include "Config.h"
#include <MG_Backend/BackendObjects.h> #include <MG_Backend/BackendObjects.h>
#include <MG_Util/Metrics/TextureMetrics.h> #include <MG_Util/Metrics/TextureMetrics.h>
@@ -2131,6 +2132,124 @@ namespace MobileGL::MG_Impl::GLImpl {
return GL_FRAMEBUFFER_COMPLETE; return GL_FRAMEBUFFER_COMPLETE;
} }
// GL_ARB_framebuffer_no_attachments plus the queryable framebuffer state of GL 4.6 core 9.2.3.
// The DEFAULT_* half is real state on the framebuffer object; the rest is derived from the
// attachments, and matches what glGetIntegerv answers for the bound framebuffer.
void GetFramebufferParameteriv_Object(const SharedPtr<MG_State::GLState::FramebufferObject>& framebufferObject,
GLenum pname, GLint* params, const char* caller) {
if (params == nullptr) return;
if (!FramebufferImpl::ValidateFramebufferParameterPname(pname, framebufferObject->IsDefaultFramebuffer(),
/*forSetter=*/false, caller)) {
return;
}
const auto resolveSampleCount = [&]() {
GLint maxSamples = 0;
for (const auto& attachment : framebufferObject->GetAllAttachmentObjects()) {
if (attachment.IsRenderbuffer() && attachment.GetRenderbuffer()) {
maxSamples = std::max(maxSamples, static_cast<GLint>(attachment.GetRenderbuffer()->GetSamples()));
} else if (attachment.IsTexture() && attachment.GetTexture()) {
maxSamples = std::max(maxSamples, static_cast<GLint>(attachment.GetTexture()->GetSamples()));
}
}
return maxSamples;
};
switch (pname) {
case GL_FRAMEBUFFER_DEFAULT_WIDTH:
*params = framebufferObject->GetDefaultWidth();
break;
case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
*params = framebufferObject->GetDefaultHeight();
break;
case GL_FRAMEBUFFER_DEFAULT_LAYERS:
*params = framebufferObject->GetDefaultLayers();
break;
case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
*params = framebufferObject->GetDefaultSamples();
break;
case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
*params = framebufferObject->GetDefaultFixedSampleLocations() ? GL_TRUE : GL_FALSE;
break;
case GL_SAMPLES:
*params = resolveSampleCount();
break;
case GL_SAMPLE_BUFFERS:
*params = resolveSampleCount() > 0 ? 1 : 0;
break;
case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
case GL_IMPLEMENTATION_COLOR_READ_TYPE: {
const auto readBuffer = framebufferObject->GetReadBuffer();
TextureInternalFormat internalFormat = TextureInternalFormat::Unknown;
if (readBuffer != FramebufferAttachmentType::None) {
const auto& attachment = framebufferObject->GetAttachment(readBuffer);
if (attachment.IsTexture() && attachment.GetTexture()) {
internalFormat = attachment.GetTexture()->GetFormat();
} else if (attachment.IsRenderbuffer() && attachment.GetRenderbuffer()) {
internalFormat = attachment.GetRenderbuffer()->GetInternalFormat();
}
}
if (internalFormat == TextureInternalFormat::Unknown) {
*params = 0;
break;
}
const GLenum glInternalFormat = MG_Util::ConvertTextureInternalFormatToGLEnum(internalFormat);
GLenum normalizedInternalFormat = glInternalFormat;
GLenum format = GL_RGBA;
GLenum type = GL_UNSIGNED_BYTE;
MG_Util::TextureFormatProcessor::NormalizePixelFormat(glInternalFormat, PixelFormatNormalizeOptionBit::None,
&normalizedInternalFormat, &format, &type);
*params = static_cast<GLint>(pname == GL_IMPLEMENTATION_COLOR_READ_FORMAT ? format : type);
break;
}
case GL_DOUBLEBUFFER:
// Only the window-system surface is ever double buffered; a framebuffer object never is.
*params = framebufferObject->IsDefaultFramebuffer() ? GL_TRUE : GL_FALSE;
break;
case GL_STEREO:
// Stereo surfaces are not exposed, matching what glGetIntegerv reports.
*params = GL_FALSE;
break;
default:
break;
}
}
void FramebufferParameteri_Object(const SharedPtr<MG_State::GLState::FramebufferObject>& framebufferObject,
GLenum pname, GLint param, const char* caller) {
if (!FramebufferImpl::ValidateFramebufferParameterPname(pname, framebufferObject->IsDefaultFramebuffer(),
/*forSetter=*/true, caller)) {
return;
}
if (pname != GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS && param < 0) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
"Framebuffer default parameters must be non-negative."));
return;
}
switch (pname) {
case GL_FRAMEBUFFER_DEFAULT_WIDTH:
framebufferObject->SetDefaultWidth(param);
break;
case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
framebufferObject->SetDefaultHeight(param);
break;
case GL_FRAMEBUFFER_DEFAULT_LAYERS:
framebufferObject->SetDefaultLayers(param);
break;
case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
framebufferObject->SetDefaultSamples(param);
break;
case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
framebufferObject->SetDefaultFixedSampleLocations(param != GL_FALSE);
break;
default:
break;
}
}
void GetFramebufferAttachmentParameteriv_Object( void GetFramebufferAttachmentParameteriv_Object(
const SharedPtr<MG_State::GLState::FramebufferObject>& framebufferObject, GLenum attachment, GLenum pname, const SharedPtr<MG_State::GLState::FramebufferObject>& framebufferObject, GLenum attachment, GLenum pname,
GLint* params, const char* caller) { GLint* params, const char* caller) {
@@ -2250,6 +2369,54 @@ namespace MobileGL::MG_Impl::GLImpl {
"GetNamedFramebufferAttachmentParameteriv_State"); "GetNamedFramebufferAttachmentParameteriv_State");
} }
// The by-target forms resolve the binding; the by-name forms take zero as the default
// framebuffer, exactly as the other DSA framebuffer entry points do (GL 4.6 core 9.2.3).
void GetFramebufferParameteriv_State(GLenum target, GLenum pname, GLint* params) {
if (target == GL_FRAMEBUFFER) target = GL_DRAW_FRAMEBUFFER;
const auto framebufferTarget = MG_Util::ConvertGLEnumToFramebufferTarget(target);
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return;
auto& framebufferObject = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget).GetBoundObject();
if (!framebufferObject) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "GetFramebufferParameteriv_State",
"Framebuffer target is bound to no framebuffer object."));
return;
}
GetFramebufferParameteriv_Object(framebufferObject, pname, params, "GetFramebufferParameteriv_State");
}
void FramebufferParameteri_State(GLenum target, GLenum pname, GLint param) {
if (target == GL_FRAMEBUFFER) target = GL_DRAW_FRAMEBUFFER;
const auto framebufferTarget = MG_Util::ConvertGLEnumToFramebufferTarget(target);
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return;
auto& framebufferObject = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget).GetBoundObject();
if (!framebufferObject) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "FramebufferParameteri_State",
"Framebuffer target is bound to no framebuffer object."));
return;
}
FramebufferParameteri_Object(framebufferObject, pname, param, "FramebufferParameteri_State");
}
void GetNamedFramebufferParameteriv_State(GLuint framebuffer, GLenum pname, GLint* params) {
auto framebufferObject = framebuffer == 0
? FramebufferImpl::pDefaultFramebufferInfo->defaultFBO
: GetNamedFramebufferObject_State(framebuffer, "GetNamedFramebufferParameteriv_State");
if (!framebufferObject) return;
GetFramebufferParameteriv_Object(framebufferObject, pname, params, "GetNamedFramebufferParameteriv_State");
}
void NamedFramebufferParameteri_State(GLuint framebuffer, GLenum pname, GLint param) {
auto framebufferObject = framebuffer == 0
? FramebufferImpl::pDefaultFramebufferInfo->defaultFBO
: GetNamedFramebufferObject_State(framebuffer, "NamedFramebufferParameteri_State");
if (!framebufferObject) return;
FramebufferParameteri_Object(framebufferObject, pname, param, "NamedFramebufferParameteri_State");
}
void BlitNamedFramebuffer_State(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, void BlitNamedFramebuffer_State(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0,
GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter) { GLbitfield mask, GLenum filter) {
@@ -2896,6 +3063,22 @@ namespace MobileGL::MG_Impl::GLImpl {
return CheckNamedFramebufferStatus_State(framebuffer, target); return CheckNamedFramebufferStatus_State(framebuffer, target);
} }
void GetFramebufferParameteriv(GLenum target, GLenum pname, GLint* params) {
GetFramebufferParameteriv_State(target, pname, params);
}
void FramebufferParameteri(GLenum target, GLenum pname, GLint param) {
FramebufferParameteri_State(target, pname, param);
}
void GetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname, GLint* params) {
GetNamedFramebufferParameteriv_State(framebuffer, pname, params);
}
void NamedFramebufferParameteri(GLuint framebuffer, GLenum pname, GLint param) {
NamedFramebufferParameteri_State(framebuffer, pname, param);
}
void GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) { void GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params) {
GetNamedFramebufferAttachmentParameteriv_State(framebuffer, attachment, pname, params); GetNamedFramebufferAttachmentParameteriv_State(framebuffer, attachment, pname, params);
} }
@@ -67,6 +67,10 @@ namespace MobileGL::MG_Impl::GLImpl {
void ClearNamedFramebufferiv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value); void ClearNamedFramebufferiv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint* value);
void ClearNamedFramebufferuiv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* 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 GetFramebufferParameteriv(GLenum target, GLenum pname, GLint* params);
void FramebufferParameteri(GLenum target, GLenum pname, GLint param);
void GetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname, GLint* params);
void NamedFramebufferParameteri(GLuint framebuffer, GLenum pname, GLint param);
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,
GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
@@ -119,6 +119,58 @@ namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
return false; return false;
} }
Bool ValidateFramebufferParameterPname(GLenum pname, Bool isDefaultFramebuffer, Bool forSetter,
const char* caller) {
Bool isDefaultParameter = false;
switch (pname) {
case GL_FRAMEBUFFER_DEFAULT_WIDTH:
case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
case GL_FRAMEBUFFER_DEFAULT_LAYERS:
case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
isDefaultParameter = true;
break;
case GL_DOUBLEBUFFER:
case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
case GL_IMPLEMENTATION_COLOR_READ_TYPE:
case GL_SAMPLES:
case GL_SAMPLE_BUFFERS:
case GL_STEREO:
// Queryable only; glFramebufferParameteri sets none of these.
if (forSetter) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl/FramebufferImpl", caller,
std::format("pname {} is not settable on a framebuffer.",
MG_Util::ConvertGLEnumToString(pname))));
return false;
}
break;
default:
MG_State::pGLContext->RecordError(
ErrorCode::InvalidEnum,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl/FramebufferImpl", caller,
std::format("pname {} is not a framebuffer parameter.",
MG_Util::ConvertGLEnumToString(pname))));
return false;
}
// The default framebuffer has no DEFAULT_* state of its own - its shape comes from the
// surface - so those names are accepted enums it simply cannot answer or accept.
if (isDefaultFramebuffer && isDefaultParameter) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>(
"MG_Impl/GLImpl/FramebufferImpl", caller,
std::format("pname {} does not apply to the default framebuffer.",
MG_Util::ConvertGLEnumToString(pname))));
return false;
}
return true;
}
Bool ValidateReadFramebufferForCopy(const char* caller) { Bool ValidateReadFramebufferForCopy(const char* caller) {
auto& framebufferObject = auto& framebufferObject =
MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject(); MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read).GetBoundObject();
@@ -25,4 +25,10 @@ namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
// not be multisampled. Incompleteness is INVALID_FRAMEBUFFER_OPERATION, the other two are // not be multisampled. Incompleteness is INVALID_FRAMEBUFFER_OPERATION, the other two are
// INVALID_OPERATION. // INVALID_OPERATION.
Bool ValidateReadFramebufferForCopy(const char* caller); Bool ValidateReadFramebufferForCopy(const char* caller);
// The pname sets of glGet/FramebufferParameteri (GL 4.6 core 9.2.3). Order matters and is part
// of the contract: a name outside the table is INVALID_ENUM, and only then is a name that the
// DEFAULT framebuffer does not answer INVALID_OPERATION. Testing the framebuffer kind first
// would turn GL_FRAMEBUFFER_DEFAULT_WIDTH on framebuffer zero into the wrong error.
Bool ValidateFramebufferParameterPname(GLenum pname, Bool isDefaultFramebuffer, Bool forSetter,
const char* caller);
} // namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl } // namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl
@@ -185,6 +185,20 @@ namespace MobileGL::MG_State::GLState {
return m_externalIndex; return m_externalIndex;
} }
#define MOBILEGL_DEFINE_FRAMEBUFFER_DEFAULT_SETTER(name, member, type) \
void FramebufferObject::Set##name(type value) { \
if (member == value) return; \
member = value; \
++m_objectVersion; \
}
MOBILEGL_DEFINE_FRAMEBUFFER_DEFAULT_SETTER(DefaultWidth, m_defaultWidth, Int)
MOBILEGL_DEFINE_FRAMEBUFFER_DEFAULT_SETTER(DefaultHeight, m_defaultHeight, Int)
MOBILEGL_DEFINE_FRAMEBUFFER_DEFAULT_SETTER(DefaultLayers, m_defaultLayers, Int)
MOBILEGL_DEFINE_FRAMEBUFFER_DEFAULT_SETTER(DefaultSamples, m_defaultSamples, Int)
MOBILEGL_DEFINE_FRAMEBUFFER_DEFAULT_SETTER(DefaultFixedSampleLocations, m_defaultFixedSampleLocations, Bool)
#undef MOBILEGL_DEFINE_FRAMEBUFFER_DEFAULT_SETTER
void FramebufferObject::BumpAttachmentVersion(FramebufferAttachmentType type) { void FramebufferObject::BumpAttachmentVersion(FramebufferAttachmentType type) {
++m_attachmentVersions[static_cast<SizeT>(type)]; ++m_attachmentVersions[static_cast<SizeT>(type)];
++m_objectVersion; ++m_objectVersion;
@@ -129,6 +129,19 @@ namespace MobileGL {
void SetReadBuffer(FramebufferAttachmentType buf); void SetReadBuffer(FramebufferAttachmentType buf);
FramebufferAttachmentType GetReadBuffer() const { return m_readBuffer; } FramebufferAttachmentType GetReadBuffer() const { return m_readBuffer; }
// GL_ARB_framebuffer_no_attachments state (GL 4.6 core table 23.24). The shape a
// framebuffer with no attachments would rasterize at; all zero / FALSE until set.
Int GetDefaultWidth() const { return m_defaultWidth; }
Int GetDefaultHeight() const { return m_defaultHeight; }
Int GetDefaultLayers() const { return m_defaultLayers; }
Int GetDefaultSamples() const { return m_defaultSamples; }
Bool GetDefaultFixedSampleLocations() const { return m_defaultFixedSampleLocations; }
void SetDefaultWidth(Int value);
void SetDefaultHeight(Int value);
void SetDefaultLayers(Int value);
void SetDefaultSamples(Int value);
void SetDefaultFixedSampleLocations(Bool value);
FramebufferAttachmentVersionArray GetAllFramebufferAttachmentVersions() const { FramebufferAttachmentVersionArray GetAllFramebufferAttachmentVersions() const {
return m_attachmentVersions; return m_attachmentVersions;
} }
@@ -148,6 +161,12 @@ namespace MobileGL {
FramebufferAttachmentArray m_drawBuffers; // Probably no versioning needed for this, just check equality FramebufferAttachmentArray m_drawBuffers; // Probably no versioning needed for this, just check equality
FramebufferAttachmentType m_readBuffer = FramebufferAttachmentType::None; FramebufferAttachmentType m_readBuffer = FramebufferAttachmentType::None;
Int m_defaultWidth = 0;
Int m_defaultHeight = 0;
Int m_defaultLayers = 0;
Int m_defaultSamples = 0;
Bool m_defaultFixedSampleLocations = false;
// This version will bump when draw/read buffer changes (by `glDrawBuffer(s)`/`glReadBuffer`) // This version will bump when draw/read buffer changes (by `glDrawBuffer(s)`/`glReadBuffer`)
Uint16 m_objectVersion = 0; Uint16 m_objectVersion = 0;
}; };