mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 04:38: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
|
||||
// kWholeBuffer for the non-Range entry points, which attach the buffer as it grows rather
|
||||
// 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,
|
||||
GLenum internalformat, GLuint buffer, GLintptr offset, SizeT size,
|
||||
const char* caller) {
|
||||
using MG_State::GLState::TextureObjectBuffer;
|
||||
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;
|
||||
|
||||
auto& bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
|
||||
@@ -2056,8 +2108,10 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
}
|
||||
if (!TextureImpl::ValidateTextureObject(textureObject)) return;
|
||||
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(
|
||||
ErrorCode::InvalidEnum,
|
||||
ErrorCode::InvalidOperation,
|
||||
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||
"The effective target of `texture` is not `GL_TEXTURE_BUFFER`."));
|
||||
return;
|
||||
@@ -2086,6 +2140,15 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
"offset is not a multiple of GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT."));
|
||||
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());
|
||||
|
||||
Reference in New Issue
Block a user