mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
[Feat] (MG_Impl): complete the by-name framebuffer attachment and buffer-selection entry points
Four direct_state_access framebuffer cases failed on one shared cause and three local ones. The shared cause: every DSA framebuffer entry point resolved its name through GetNamedFramebufferObject_State, which rejects zero outright. But zero names the default framebuffer to these functions, so glGetNamedFramebufferAttachmentParameteriv, glNamedFramebufferDrawBuffer(s) and glNamedFramebufferReadBuffer answered INVALID_VALUE for every default-framebuffer query the CTS makes. They now resolve zero to the default framebuffer object and tell the two kinds apart explicitly, which is what the accepted-name rules key off anyway. Attachment queries: the accepted attachment names differ between the default framebuffer (FRONT/BACK variants, DEPTH, STENCIL) and a framebuffer object (COLOR_ATTACHMENTi, DEPTH/STENCIL/DEPTH_STENCIL_ATTACHMENT), and a name outside the relevant list is INVALID_ENUM. Both getters share ResolveAttachmentQueryName for that, so the by-target form no longer aliases GL_FRONT onto a framebuffer object's colour attachment 0. The TEXTURE_* parameters are also rejected with INVALID_ENUM when the attached object is a renderbuffer. Buffer selection: naming a buffer that belongs to the other kind of framebuffer is INVALID_OPERATION, not INVALID_ENUM - the enum is accepted, the framebuffer just has no such buffer. glDrawBuffers additionally rejects the multi-buffer names (FRONT, LEFT, RIGHT, FRONT_AND_BACK) with INVALID_ENUM on both kinds, takes BACK only when n is one, and glReadBuffer treats the multi-buffer names as accepted-but-unselectable. Both colour-attachment range checks now go through ValidateColorAttachmentInRange instead of comparing against MAX_DRAW_BUFFERS with an off-by-one. NamedFramebufferTextureLayer was a stub that reported "not represented by the current framebuffer attachment model" for every call, even though the attachment model stores a layer and the by-target glFramebufferTextureLayer already uses it. It is implemented against the same model, with the per-target layer limits and the INVALID_OPERATION-for-a-bad-name rule that separates it from NamedFramebufferTexture. NamedFramebufferTexture itself gained the two checks it lacked: colour attachment range, and a negative level. Takes framebuffers_get_attachment_parameters, framebuffers_get_attachment_parameter_errors, framebuffers_texture_attachment_errors and framebuffers_draw_read_buffers_errors from failing to passing on both backends.
This commit is contained in:
@@ -258,6 +258,86 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
}
|
||||
|
||||
// GL 4.6 core 9.2.3: which attachment names an attachment query accepts depends on whether
|
||||
// it is looking at the default framebuffer or at a framebuffer object, and a name outside
|
||||
// its list is INVALID_ENUM - not the INVALID_OPERATION that a well-formed but unattachable
|
||||
// name gets. On success the default framebuffer's names are rewritten to the attachment
|
||||
// point that backs them.
|
||||
Bool ResolveAttachmentQueryName(Bool isDefaultFramebuffer, GLenum& attachment, const char* caller) {
|
||||
const auto reject = [&]() {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", caller,
|
||||
std::format("Attachment {} is not queryable on this framebuffer.",
|
||||
MG_Util::ConvertGLEnumToString(attachment))));
|
||||
return false;
|
||||
};
|
||||
|
||||
if (isDefaultFramebuffer) {
|
||||
switch (attachment) {
|
||||
case GL_FRONT:
|
||||
case GL_FRONT_LEFT:
|
||||
case GL_FRONT_RIGHT:
|
||||
case GL_BACK:
|
||||
case GL_BACK_LEFT:
|
||||
case GL_BACK_RIGHT:
|
||||
attachment = GL_COLOR_ATTACHMENT0;
|
||||
return true;
|
||||
case GL_DEPTH:
|
||||
attachment = GL_DEPTH_ATTACHMENT;
|
||||
return true;
|
||||
case GL_STENCIL:
|
||||
attachment = GL_STENCIL_ATTACHMENT;
|
||||
return true;
|
||||
default:
|
||||
return reject();
|
||||
}
|
||||
}
|
||||
|
||||
switch (attachment) {
|
||||
case GL_DEPTH_ATTACHMENT:
|
||||
case GL_STENCIL_ATTACHMENT:
|
||||
case GL_DEPTH_STENCIL_ATTACHMENT:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// Every COLOR_ATTACHMENTi token is a name; one past MAX_COLOR_ATTACHMENTS is a
|
||||
// well-formed name that this framebuffer has no point for, which is INVALID_OPERATION
|
||||
// and is left to the attachment-point lookup below.
|
||||
if (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT31) return true;
|
||||
return reject();
|
||||
}
|
||||
|
||||
// The TEXTURE_* parameters only exist while the attached object is a texture (GL 4.6 core
|
||||
// 9.2.3); asking for one of them about a renderbuffer is INVALID_ENUM. An empty attachment
|
||||
// point is a different rule and is deliberately passed through here.
|
||||
Bool ValidateAttachmentQueryPname(const MG_State::GLState::FramebufferAttachmentObject* attachmentObject,
|
||||
GLenum pname, const char* caller) {
|
||||
switch (pname) {
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_LAYERED:
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
const Bool nothingAttached =
|
||||
attachmentObject == nullptr || attachmentObject->IsEmpty() || !attachmentObject->IsValid();
|
||||
if (nothingAttached || attachmentObject->IsTexture()) return true;
|
||||
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", caller,
|
||||
std::format("pname {} is only defined for a texture attachment.",
|
||||
MG_Util::ConvertGLEnumToString(pname))));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handles the format-derived pnames shared by GetFramebufferAttachmentParameteriv
|
||||
// and its DSA variant. Returns true when pname was one of them.
|
||||
Bool TryAnswerAttachmentFormatQuery(const MG_State::GLState::FramebufferAttachmentObject* attachmentObject,
|
||||
@@ -623,33 +703,6 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
FramebufferTarget framebufferTarget = MG_Util::ConvertGLEnumToFramebufferTarget(target);
|
||||
if (!FramebufferImpl::ValidateFramebufferTarget(framebufferTarget)) return;
|
||||
|
||||
// Default-framebuffer attachment names (GL_DEPTH, GL_STENCIL, GL_FRONT/GL_BACK
|
||||
// variants) alias onto the equivalent attachment points.
|
||||
switch (attachment) {
|
||||
case GL_DEPTH:
|
||||
attachment = GL_DEPTH_ATTACHMENT;
|
||||
break;
|
||||
case GL_STENCIL:
|
||||
attachment = GL_STENCIL_ATTACHMENT;
|
||||
break;
|
||||
case GL_FRONT:
|
||||
case GL_FRONT_LEFT:
|
||||
case GL_FRONT_RIGHT:
|
||||
case GL_BACK:
|
||||
case GL_BACK_LEFT:
|
||||
case GL_BACK_RIGHT:
|
||||
attachment = GL_COLOR_ATTACHMENT0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const Bool depthStencilAlias = attachment == GL_DEPTH_STENCIL_ATTACHMENT;
|
||||
FramebufferAttachmentType attachmentType = depthStencilAlias
|
||||
? FramebufferAttachmentType::Depth
|
||||
: MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment);
|
||||
if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return;
|
||||
|
||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(framebufferTarget);
|
||||
auto& framebufferObject = bindingSlot.GetBoundObject();
|
||||
if (!framebufferObject) {
|
||||
@@ -660,6 +713,17 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ResolveAttachmentQueryName(framebufferObject->IsDefaultFramebuffer(), attachment,
|
||||
"GetFramebufferAttachmentParameteriv_State")) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Bool depthStencilAlias = attachment == GL_DEPTH_STENCIL_ATTACHMENT;
|
||||
FramebufferAttachmentType attachmentType = depthStencilAlias
|
||||
? FramebufferAttachmentType::Depth
|
||||
: MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment);
|
||||
if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return;
|
||||
|
||||
Bool depthStencilMismatch = false;
|
||||
const auto* attachmentObject = [&]() -> const MG_State::GLState::FramebufferAttachmentObject* {
|
||||
if (!depthStencilAlias) {
|
||||
@@ -694,6 +758,8 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateAttachmentQueryPname(attachmentObject, pname, "GetFramebufferAttachmentParameteriv_State")) return;
|
||||
|
||||
switch (pname) {
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
|
||||
if (attachmentObject == nullptr || attachmentObject->IsEmpty() || !attachmentObject->IsValid()) {
|
||||
@@ -1119,6 +1185,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
|
||||
FramebufferAttachmentType attachmentType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment);
|
||||
if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return;
|
||||
if (!FramebufferImpl::ValidateColorAttachmentInRange(attachmentType, "NamedFramebufferTexture_State")) return;
|
||||
if (!TextureImpl::ValidateTextureName(texture, true)) return;
|
||||
|
||||
if (texture == 0) {
|
||||
@@ -1134,6 +1201,13 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
std::format("Texture object {} is not valid.", texture)));
|
||||
return;
|
||||
}
|
||||
if (level < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "NamedFramebufferTexture_State",
|
||||
"Texture level must be non-negative."));
|
||||
return;
|
||||
}
|
||||
|
||||
TextureUploadTarget textureUploadTarget = TextureUploadTarget::Unknown;
|
||||
Bool layered = false;
|
||||
@@ -1234,14 +1308,98 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
|
||||
void NamedFramebufferTextureLayer_State(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level,
|
||||
GLint layer) {
|
||||
static_cast<void>(framebuffer);
|
||||
static_cast<void>(attachment);
|
||||
static_cast<void>(texture);
|
||||
static_cast<void>(level);
|
||||
static_cast<void>(layer);
|
||||
RecordUnsupportedFramebufferTextureAttachmentError(
|
||||
__func__,
|
||||
"Layered framebuffer texture attachments are not represented by the current framebuffer attachment model.");
|
||||
if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
|
||||
NamedFramebufferTextureLayer_State(framebuffer, GL_DEPTH_ATTACHMENT, texture, level, layer);
|
||||
NamedFramebufferTextureLayer_State(framebuffer, GL_STENCIL_ATTACHMENT, texture, level, layer);
|
||||
return;
|
||||
}
|
||||
|
||||
auto framebufferObject = GetNamedFramebufferObject_State(framebuffer, __func__);
|
||||
if (!framebufferObject) return;
|
||||
|
||||
const FramebufferAttachmentType attachmentType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(attachment);
|
||||
if (!FramebufferImpl::ValidateFramebufferAttachmentType(attachmentType)) return;
|
||||
if (!FramebufferImpl::ValidateColorAttachmentInRange(attachmentType, __func__)) return;
|
||||
|
||||
if (texture == 0) {
|
||||
framebufferObject->Detach(attachmentType);
|
||||
return;
|
||||
}
|
||||
|
||||
// Unlike NamedFramebufferTexture, this entry point answers INVALID_OPERATION - not
|
||||
// INVALID_VALUE - for a name that is not a texture, so the name check below is the object
|
||||
// lookup rather than TextureImpl::ValidateTextureName.
|
||||
auto& textureObject = MG_State::pGLContext->GetTextureObject(texture);
|
||||
if (!textureObject) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
std::format("Texture object {} is not valid.", texture)));
|
||||
return;
|
||||
}
|
||||
if (level < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Texture level must be non-negative."));
|
||||
return;
|
||||
}
|
||||
if (layer < 0) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "Layer must be non-negative."));
|
||||
return;
|
||||
}
|
||||
|
||||
// GL 4.6 core 9.2.8: only the layered targets have layers to select, and the largest layer
|
||||
// each one admits comes from a different implementation limit.
|
||||
const auto& limits = MG_Backend::pActiveBackendObject
|
||||
? MG_Backend::pActiveBackendObject->GetDynamicParameters()
|
||||
: MG_Backend::DynamicBackendParameters{};
|
||||
TextureUploadTarget textureUploadTarget = TextureUploadTarget::Unknown;
|
||||
Int layerLimit = 0;
|
||||
switch (textureObject->GetTarget()) {
|
||||
case TextureTarget::Texture3D:
|
||||
textureUploadTarget = TextureUploadTarget::Texture3D;
|
||||
layerLimit = limits.Max3DTextureSize;
|
||||
break;
|
||||
case TextureTarget::Texture1DArray:
|
||||
textureUploadTarget = TextureUploadTarget::Texture1DArray;
|
||||
layerLimit = limits.MaxArrayTextureLayers;
|
||||
break;
|
||||
case TextureTarget::Texture2DArray:
|
||||
textureUploadTarget = TextureUploadTarget::Texture2DArray;
|
||||
layerLimit = limits.MaxArrayTextureLayers;
|
||||
break;
|
||||
case TextureTarget::Texture2DMultisampleArray:
|
||||
textureUploadTarget = TextureUploadTarget::Texture2DMultisampleArray;
|
||||
layerLimit = limits.MaxArrayTextureLayers;
|
||||
break;
|
||||
case TextureTarget::TextureCubeMapArray:
|
||||
textureUploadTarget = TextureUploadTarget::CubeMapArray;
|
||||
// A cube map array is an array texture whose layers happen to be cube faces, so its
|
||||
// layer index is bounded by GL_MAX_ARRAY_TEXTURE_LAYERS like any other array's.
|
||||
layerLimit = limits.MaxArrayTextureLayers;
|
||||
break;
|
||||
default:
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"NamedFramebufferTextureLayer requires a 3D, array, 2D multisample "
|
||||
"array, or cube map array texture."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (layer >= layerLimit) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidValue,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
std::format("Layer {} is beyond the limit ({}) for this texture target.",
|
||||
layer, layerLimit)));
|
||||
return;
|
||||
}
|
||||
|
||||
framebufferObject->AttachTexture(attachmentType, textureObject, textureUploadTarget, level, layer,
|
||||
/*layered=*/false);
|
||||
}
|
||||
|
||||
void FramebufferRenderbuffer_State(GLenum target, GLenum attachment, GLenum renderbuffertarget,
|
||||
@@ -1345,13 +1503,30 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
static int existenceMap[(SizeT)FramebufferAttachmentType::FramebufferAttachmentTypeCount] = {-1};
|
||||
std::fill(existenceMap, existenceMap + (SizeT)FramebufferAttachmentType::FramebufferAttachmentTypeCount, -1);
|
||||
|
||||
// GL 4.6 core 17.4.1: BACK names both back buffers at once, so DrawBuffers only takes it as
|
||||
// the whole list. DrawBuffer, which names one buffer, is exempt.
|
||||
if (!allowDefaultFBOAliases && n != 1) {
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
if (bufs[i] != GL_BACK) continue;
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
"GL_BACK may only appear in bufs when n is one."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (GLsizei i = 0; i < n; ++i) {
|
||||
if (isDefaultFBO && !allowDefaultFBOAliases && (bufs[i] == GL_FRONT || bufs[i] == GL_BACK)) {
|
||||
// FRONT, LEFT, RIGHT and FRONT_AND_BACK each stand for more than one buffer, so
|
||||
// DrawBuffers rejects them outright - on a framebuffer object as well as on the default
|
||||
// framebuffer. LEFT, RIGHT and FRONT_AND_BACK are not attachment names at all and fall
|
||||
// out of the conversion below; only FRONT needs saying here.
|
||||
if (!allowDefaultFBOAliases && bufs[i] == GL_FRONT) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", __func__,
|
||||
std::format("glDrawBuffers cannot use default framebuffer alias {}.",
|
||||
std::format("glDrawBuffers cannot use the multi-buffer name {}.",
|
||||
MG_Util::ConvertGLEnumToString(bufs[i]))));
|
||||
return;
|
||||
}
|
||||
@@ -1368,10 +1543,13 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
return;
|
||||
}
|
||||
|
||||
// A name that is well formed but belongs to the other kind of framebuffer is
|
||||
// INVALID_OPERATION, not INVALID_ENUM: the enum is accepted, this framebuffer just has
|
||||
// no such buffer.
|
||||
if (isDefaultFBO && attType != FramebufferAttachmentType::None &&
|
||||
(attType < FramebufferAttachmentType::FrontLeft || attType > FramebufferAttachmentType::BackRight)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", __func__,
|
||||
std::format("FBO is default FBO, but bufs[{}] = {} is not `GL_NONE` or one of the default "
|
||||
@@ -1383,7 +1561,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
if (!isDefaultFBO && attType != FramebufferAttachmentType::None &&
|
||||
(attType < FramebufferAttachmentType::Color0 || attType > FramebufferAttachmentType::Color31)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", __func__,
|
||||
std::format("FBO is not default FBO, but bufs[{}] = {} is anything other than `GL_NONE` or "
|
||||
@@ -1405,16 +1583,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
|
||||
existenceMap[(SizeT)attType] = i;
|
||||
|
||||
if ((SizeT)attType >
|
||||
(SizeT)FramebufferAttachmentType::Color0 + MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
std::format("bufs[{}] == {} indicates a color buffer that does "
|
||||
"not exist in the current GL context.",
|
||||
i, MG_Util::ConvertGLEnumToString(bufs[i]))));
|
||||
return;
|
||||
}
|
||||
if (!FramebufferImpl::ValidateColorAttachmentInRange(attType, __func__)) return;
|
||||
// ------------------------- Check validity end ----------------------------------
|
||||
fbo->SetDrawBuffer(i, attType);
|
||||
}
|
||||
@@ -1442,91 +1611,95 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
}
|
||||
|
||||
void ReadBuffer_State(GLenum mode) {
|
||||
auto attType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(mode);
|
||||
void ReadBufferForFramebuffer_State(const SharedPtr<MG_State::GLState::FramebufferObject>& fbo, Bool isDefaultFBO,
|
||||
GLenum src, const char* caller) {
|
||||
auto attType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(src);
|
||||
|
||||
// ------------------- Check validity begin ------------------------
|
||||
if (attType == FramebufferAttachmentType::Unknown) {
|
||||
// LEFT, RIGHT and FRONT_AND_BACK are table 17.4 names - accepted enums - that stand for
|
||||
// more than one buffer, so ReadBuffer cannot select them. That makes them
|
||||
// INVALID_OPERATION rather than the INVALID_ENUM a name outside the table gets.
|
||||
const Bool isMultiBufferName = src == GL_LEFT || src == GL_RIGHT || src == GL_FRONT_AND_BACK;
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
isMultiBufferName ? ErrorCode::InvalidOperation : ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", __func__,
|
||||
std::format("`mode` = {} is not an accepted value.", MG_Util::ConvertGLEnumToString(mode))));
|
||||
"MG_Impl/GLImpl", caller,
|
||||
std::format("`src` = {} does not name a single readable colour buffer.",
|
||||
MG_Util::ConvertGLEnumToString(src))));
|
||||
return;
|
||||
}
|
||||
|
||||
// Get bound framebuffer
|
||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
|
||||
auto& fbo = bindingSlot.GetBoundObject();
|
||||
if (!fbo) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__, "No framebuffer bound to read target."));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller, "No framebuffer bound to read target."));
|
||||
return;
|
||||
}
|
||||
const Bool isDefaultFBO = (fbo == FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
|
||||
|
||||
// Naming a buffer the other kind of framebuffer has is INVALID_OPERATION rather than
|
||||
// INVALID_ENUM (GL 4.6 core 17.4.1) - the name is accepted, this framebuffer just has no
|
||||
// such colour buffer.
|
||||
if (isDefaultFBO && attType != FramebufferAttachmentType::None &&
|
||||
(attType < FramebufferAttachmentType::FrontLeft || attType > FramebufferAttachmentType::BackRight)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", __func__,
|
||||
std::format("Default framebuffer read buffer {} is not valid.", MG_Util::ConvertGLEnumToString(mode))));
|
||||
"MG_Impl/GLImpl", caller,
|
||||
std::format("Default framebuffer read buffer {} is not valid.", MG_Util::ConvertGLEnumToString(src))));
|
||||
return;
|
||||
}
|
||||
if (!isDefaultFBO && attType != FramebufferAttachmentType::None &&
|
||||
(attType < FramebufferAttachmentType::Color0 || attType > FramebufferAttachmentType::Color31)) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
std::format("Framebuffer object read buffer {} is not valid.",
|
||||
MG_Util::ConvertGLEnumToString(mode))));
|
||||
return;
|
||||
}
|
||||
if (!isDefaultFBO &&
|
||||
static_cast<SizeT>(attType) >
|
||||
static_cast<SizeT>(FramebufferAttachmentType::Color0) +
|
||||
MG_State::GLState::FramebufferObject::MAX_DRAW_BUFFERS) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", __func__,
|
||||
std::format("Read buffer {} indicates a color buffer that does not exist "
|
||||
"in the current GL context.",
|
||||
MG_Util::ConvertGLEnumToString(mode))));
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||
std::format("Framebuffer object read buffer {} is not valid.",
|
||||
MG_Util::ConvertGLEnumToString(src))));
|
||||
return;
|
||||
}
|
||||
if (!isDefaultFBO && !FramebufferImpl::ValidateColorAttachmentInRange(attType, caller)) return;
|
||||
fbo->SetReadBuffer(attType);
|
||||
}
|
||||
|
||||
void ReadBuffer_State(GLenum mode) {
|
||||
auto& bindingSlot = MG_State::pGLContext->GetFramebufferBindingSlot(FramebufferTarget::Read);
|
||||
auto& fbo = bindingSlot.GetBoundObject();
|
||||
const Bool isDefaultFBO = (fbo == FramebufferImpl::pDefaultFramebufferInfo->defaultFBO);
|
||||
ReadBufferForFramebuffer_State(fbo, isDefaultFBO, mode, __func__);
|
||||
}
|
||||
|
||||
void NamedFramebufferDrawBuffers_State(GLuint framebuffer, GLsizei n, const GLenum* bufs) {
|
||||
auto framebufferObject = GetNamedFramebufferObject_State(framebuffer, "NamedFramebufferDrawBuffers_State");
|
||||
// Zero names the default framebuffer, whose accepted buffer names are a different set - so
|
||||
// it cannot go through the framebuffer-object lookup, which rejects the name outright.
|
||||
auto framebufferObject = framebuffer == 0
|
||||
? FramebufferImpl::pDefaultFramebufferInfo->defaultFBO
|
||||
: GetNamedFramebufferObject_State(framebuffer, "NamedFramebufferDrawBuffers_State");
|
||||
if (!framebufferObject) return;
|
||||
DrawBuffersForFramebuffer_State(framebufferObject, false, n, bufs, false);
|
||||
DrawBuffersForFramebuffer_State(framebufferObject, framebuffer == 0, n, bufs, false);
|
||||
}
|
||||
|
||||
void NamedFramebufferDrawBuffer_State(GLuint framebuffer, GLenum buf) {
|
||||
auto framebufferObject = framebuffer == 0
|
||||
? FramebufferImpl::pDefaultFramebufferInfo->defaultFBO
|
||||
: GetNamedFramebufferObject_State(framebuffer, "NamedFramebufferDrawBuffer_State");
|
||||
if (!framebufferObject) return;
|
||||
|
||||
if (buf == GL_NONE) {
|
||||
NamedFramebufferDrawBuffers_State(framebuffer, 0, nullptr);
|
||||
DrawBuffersForFramebuffer_State(framebufferObject, framebuffer == 0, 0, nullptr, true);
|
||||
} else {
|
||||
GLenum bufs[] = {buf};
|
||||
NamedFramebufferDrawBuffers_State(framebuffer, 1, bufs);
|
||||
const GLenum bufs[] = {buf};
|
||||
DrawBuffersForFramebuffer_State(framebufferObject, framebuffer == 0, 1, bufs, true);
|
||||
}
|
||||
}
|
||||
|
||||
void NamedFramebufferReadBuffer_State(GLuint framebuffer, GLenum src) {
|
||||
auto framebufferObject = GetNamedFramebufferObject_State(framebuffer, "NamedFramebufferReadBuffer_State");
|
||||
auto framebufferObject = framebuffer == 0
|
||||
? FramebufferImpl::pDefaultFramebufferInfo->defaultFBO
|
||||
: GetNamedFramebufferObject_State(framebuffer, "NamedFramebufferReadBuffer_State");
|
||||
if (!framebufferObject) return;
|
||||
|
||||
auto attType = MG_Util::ConvertGLEnumToFramebufferAttachmentType(src);
|
||||
if (attType == FramebufferAttachmentType::Unknown) {
|
||||
MG_State::pGLContext->RecordError(
|
||||
ErrorCode::InvalidEnum,
|
||||
MakeUnique<GenericErrorInfo>(
|
||||
"MG_Impl/GLImpl", "NamedFramebufferReadBuffer_State",
|
||||
std::format("`src` = {} is not an accepted value.", MG_Util::ConvertGLEnumToString(src))));
|
||||
return;
|
||||
}
|
||||
framebufferObject->SetReadBuffer(attType);
|
||||
ReadBufferForFramebuffer_State(framebufferObject, framebuffer == 0, src,
|
||||
"NamedFramebufferReadBuffer_State");
|
||||
}
|
||||
|
||||
SharedPtr<MG_State::GLState::FramebufferObject> GetFramebufferObjectForNamedClear(GLuint framebuffer,
|
||||
@@ -1919,6 +2092,8 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
GLint* params, const char* caller) {
|
||||
if (params == nullptr) return;
|
||||
|
||||
if (!ResolveAttachmentQueryName(framebufferObject->IsDefaultFramebuffer(), attachment, caller)) return;
|
||||
|
||||
const Bool depthStencilAlias = attachment == GL_DEPTH_STENCIL_ATTACHMENT;
|
||||
FramebufferAttachmentType attachmentType = depthStencilAlias
|
||||
? FramebufferAttachmentType::Depth
|
||||
@@ -1959,6 +2134,8 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateAttachmentQueryPname(attachmentObject, pname, caller)) return;
|
||||
|
||||
switch (pname) {
|
||||
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
|
||||
if (attachmentObject == nullptr || attachmentObject->IsEmpty() || !attachmentObject->IsValid()) {
|
||||
@@ -2019,8 +2196,11 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
|
||||
void GetNamedFramebufferAttachmentParameteriv_State(GLuint framebuffer, GLenum attachment, GLenum pname,
|
||||
GLint* params) {
|
||||
auto framebufferObject =
|
||||
GetNamedFramebufferObject_State(framebuffer, "GetNamedFramebufferAttachmentParameteriv_State");
|
||||
// Zero names the default framebuffer here rather than being rejected: the DSA queries take
|
||||
// it in place of a binding (GL 4.6 core 9.2.3).
|
||||
auto framebufferObject = framebuffer == 0
|
||||
? FramebufferImpl::pDefaultFramebufferInfo->defaultFBO
|
||||
: GetNamedFramebufferObject_State(framebuffer, "GetNamedFramebufferAttachmentParameteriv_State");
|
||||
if (!framebufferObject) return;
|
||||
GetFramebufferAttachmentParameteriv_Object(framebufferObject, attachment, pname, params,
|
||||
"GetNamedFramebufferAttachmentParameteriv_State");
|
||||
|
||||
Reference in New Issue
Block a user