[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, 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_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_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, FramebufferParameteri, GLenum target, GLenum pname, GLint param) DECLARE_GL_FUNCTION_END_NO_RETURN(void, FramebufferParameteri, target, pname, param)
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(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)
@@ -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, 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_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, 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)
@@ -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, 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_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, 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)
@@ -8,6 +8,7 @@
#include "GL_Framebuffer.h"
#include "Validators.h"
#include <MG_Util/Texture/TextureFormatProcessor.h>
#include "Config.h"
#include <MG_Backend/BackendObjects.h>
#include <MG_Util/Metrics/TextureMetrics.h>
@@ -2131,6 +2132,124 @@ namespace MobileGL::MG_Impl::GLImpl {
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(
const SharedPtr<MG_State::GLState::FramebufferObject>& framebufferObject, GLenum attachment, GLenum pname,
GLint* params, const char* caller) {
@@ -2250,6 +2369,54 @@ namespace MobileGL::MG_Impl::GLImpl {
"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,
GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter) {
@@ -2896,6 +3063,22 @@ namespace MobileGL::MG_Impl::GLImpl {
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) {
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 ClearNamedFramebufferuiv(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint* value);
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 BlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1,
GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
@@ -119,6 +119,58 @@ namespace MobileGL::MG_Impl::GLImpl::FramebufferImpl {
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) {
auto& framebufferObject =
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
// INVALID_OPERATION.
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
@@ -185,6 +185,20 @@ namespace MobileGL::MG_State::GLState {
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) {
++m_attachmentVersions[static_cast<SizeT>(type)];
++m_objectVersion;
@@ -129,6 +129,19 @@ namespace MobileGL {
void SetReadBuffer(FramebufferAttachmentType buf);
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 {
return m_attachmentVersions;
}
@@ -148,6 +161,12 @@ namespace MobileGL {
FramebufferAttachmentArray m_drawBuffers; // Probably no versioning needed for this, just check equality
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`)
Uint16 m_objectVersion = 0;
};