mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +09:00
[Fix] (MG_Impl): apply the buffer texture's own format and range rules
glTextureBuffer and glTextureBufferRange took any internal format the texture enum converter recognised. A buffer texture accepts a much shorter list than a sampled or a renderable texture does (GL 4.6 core table 8.16), and it cannot be inferred from either, so a format like GL_RGB8 was accepted and produced a texture nothing could read. Two error codes were wrong as well. A texture whose effective target is not GL_TEXTURE_BUFFER is the wrong object rather than the wrong token, so it is INVALID_OPERATION. And the range form never checked its range against the buffer it was attaching, so a size past the end of the buffer was accepted and left the texture addressing memory the buffer does not own. Fixes direct_state_access.textures_buffer_errors and textures_buffer_range_errors on both backends.
This commit is contained in:
@@ -2039,11 +2039,63 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// resolved - by binding for the target forms, by name for the DSA ones. `size` is
|
// resolved - by binding for the target forms, by name for the DSA ones. `size` is
|
||||||
// kWholeBuffer for the non-Range entry points, which attach the buffer as it grows rather
|
// kWholeBuffer for the non-Range entry points, which attach the buffer as it grows rather
|
||||||
// than freezing the size it happens to have now.
|
// than freezing the size it happens to have now.
|
||||||
|
// The sized internal formats a buffer texture accepts (GL 4.6 core table 8.16). This is a much
|
||||||
|
// shorter list than the renderable or texturable formats, so it cannot be inferred from either.
|
||||||
|
static Bool IsBufferTextureInternalFormat(GLenum internalformat) {
|
||||||
|
switch (internalformat) {
|
||||||
|
case GL_R8:
|
||||||
|
case GL_R16:
|
||||||
|
case GL_R16F:
|
||||||
|
case GL_R32F:
|
||||||
|
case GL_R8I:
|
||||||
|
case GL_R16I:
|
||||||
|
case GL_R32I:
|
||||||
|
case GL_R8UI:
|
||||||
|
case GL_R16UI:
|
||||||
|
case GL_R32UI:
|
||||||
|
case GL_RG8:
|
||||||
|
case GL_RG16:
|
||||||
|
case GL_RG16F:
|
||||||
|
case GL_RG32F:
|
||||||
|
case GL_RG8I:
|
||||||
|
case GL_RG16I:
|
||||||
|
case GL_RG32I:
|
||||||
|
case GL_RG8UI:
|
||||||
|
case GL_RG16UI:
|
||||||
|
case GL_RG32UI:
|
||||||
|
case GL_RGB32F:
|
||||||
|
case GL_RGB32I:
|
||||||
|
case GL_RGB32UI:
|
||||||
|
case GL_RGBA8:
|
||||||
|
case GL_RGBA16:
|
||||||
|
case GL_RGBA16F:
|
||||||
|
case GL_RGBA32F:
|
||||||
|
case GL_RGBA8I:
|
||||||
|
case GL_RGBA16I:
|
||||||
|
case GL_RGBA32I:
|
||||||
|
case GL_RGBA8UI:
|
||||||
|
case GL_RGBA16UI:
|
||||||
|
case GL_RGBA32UI:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void AttachBufferToTexture(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
|
static void AttachBufferToTexture(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
|
||||||
GLenum internalformat, GLuint buffer, GLintptr offset, SizeT size,
|
GLenum internalformat, GLuint buffer, GLintptr offset, SizeT size,
|
||||||
const char* caller) {
|
const char* caller) {
|
||||||
using MG_State::GLState::TextureObjectBuffer;
|
using MG_State::GLState::TextureObjectBuffer;
|
||||||
TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
|
TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat);
|
||||||
|
if (!IsBufferTextureInternalFormat(internalformat)) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidEnum,
|
||||||
|
MakeUnique<GenericErrorInfo>(
|
||||||
|
"MG_Impl/GLImpl", caller,
|
||||||
|
std::format("internalformat 0x{:X} is not one of the sized formats a buffer texture accepts.",
|
||||||
|
internalformat)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!TextureImpl::ValidateTextureInternalFormat(textureInternalFormat)) return;
|
if (!TextureImpl::ValidateTextureInternalFormat(textureInternalFormat)) return;
|
||||||
|
|
||||||
auto& bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
|
auto& bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
|
||||||
@@ -2056,8 +2108,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
}
|
}
|
||||||
if (!TextureImpl::ValidateTextureObject(textureObject)) return;
|
if (!TextureImpl::ValidateTextureObject(textureObject)) return;
|
||||||
if (textureObject->GetStorageType() != TextureStorageType::Buffer) {
|
if (textureObject->GetStorageType() != TextureStorageType::Buffer) {
|
||||||
|
// A texture whose target is something else is a wrong object, not a wrong token
|
||||||
|
// (GL 4.6 core 8.9).
|
||||||
MG_State::pGLContext->RecordError(
|
MG_State::pGLContext->RecordError(
|
||||||
ErrorCode::InvalidEnum,
|
ErrorCode::InvalidOperation,
|
||||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||||
"The effective target of `texture` is not `GL_TEXTURE_BUFFER`."));
|
"The effective target of `texture` is not `GL_TEXTURE_BUFFER`."));
|
||||||
return;
|
return;
|
||||||
@@ -2086,6 +2140,15 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
"offset is not a multiple of GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT."));
|
"offset is not a multiple of GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// The range has to lie inside the buffer that is being attached. Detaching (buffer
|
||||||
|
// zero) carries no range to check.
|
||||||
|
if (bufferObject && static_cast<SizeT>(offset) + size > bufferObject->GetSize()) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||||
|
"offset + size is greater than the buffer object's GL_BUFFER_SIZE."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* texBufferObject = static_cast<TextureObjectBuffer*>(textureObject.get());
|
auto* texBufferObject = static_cast<TextureObjectBuffer*>(textureObject.get());
|
||||||
|
|||||||
Reference in New Issue
Block a user