diff --git a/MobileGL/MG_Backend/BackendObject.h b/MobileGL/MG_Backend/BackendObject.h index 0c135b56..5285cd3c 100644 --- a/MobileGL/MG_Backend/BackendObject.h +++ b/MobileGL/MG_Backend/BackendObject.h @@ -315,6 +315,8 @@ namespace MobileGL { Int MaxComputeWorkGroupInvocations = 128; Int MaxShaderStorageBufferBindings = 8; Int MaxTextureBufferSize = 65536; + // GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT; 1 means the offset is unconstrained. + Int TextureBufferOffsetAlignment = 1; Int MaxUniformBufferBindings = 24; Int MaxUniformBlockSize = 16384; Int MaxImageUnits = 8; diff --git a/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp index 20070ff9..90cd66fd 100644 --- a/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp @@ -1112,6 +1112,7 @@ namespace MobileGL::MG_Backend::DirectGLES { m_dynamicParameters.MaxComputeWorkGroupInvocations = m_GLESCapabilities.MaxComputeWorkGroupInvocations; m_dynamicParameters.MaxShaderStorageBufferBindings = m_GLESCapabilities.MaxShaderStorageBufferBindings; m_dynamicParameters.MaxTextureBufferSize = m_GLESCapabilities.MaxTextureBufferSize; + m_dynamicParameters.TextureBufferOffsetAlignment = m_GLESCapabilities.TextureBufferOffsetAlignment; m_dynamicParameters.MaxUniformBufferBindings = m_GLESCapabilities.MaxUniformBufferBindings; m_dynamicParameters.MaxUniformBlockSize = m_GLESCapabilities.MaxUniformBlockSize; const Int maxSupportedTextureUnits = diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp index 1dd07706..14a5eecc 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -2232,7 +2232,24 @@ namespace MobileGL::MG_Backend::DirectGLES { "ID: %u, buffer ID: %u, buffer size: %zu, format: %s", m_backendTextureId, backendId, buffer->GetSize(), MG_Util::ConvertGLEnumToString(glInternalFormat).c_str()); - g_GLESFuncs.glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId); + // A texture that names a window of the buffer needs the range form; the + // whole-buffer forms report offset 0 and the buffer's current size, which + // glTexBuffer expresses more directly (and works where the range entry point + // is absent). + const SizeT rangeOffset = textureBufferObject->GetBufferRangeOffset(); + const SizeT rangeSize = textureBufferObject->GetBufferRangeSizeInBytes(); + if (rangeOffset == 0 && rangeSize == buffer->GetSize()) { + g_GLESFuncs.glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId); + } else if (g_GLESFuncs.glTexBufferRange != nullptr) { + g_GLESFuncs.glTexBufferRange(GL_TEXTURE_BUFFER, glInternalFormat, backendId, + static_cast(rangeOffset), + static_cast(rangeSize)); + } else { + MGLOG_E("Texture buffer %u names a sub-range but the driver has no " + "glTexBufferRange; binding the whole buffer instead", + stateTextureObject->GetExternalIndex()); + g_GLESFuncs.glTexBuffer(GL_TEXTURE_BUFFER, glInternalFormat, backendId); + } DebugImpl::ErrorLopper::Loop( [file = __FILE__, line = __LINE__, func = __func__, glInternalFormat, backendId](GLenum err) { MGLOG_D("%s(%s:%d) glTexBuffer(format=%s, buffer=%u) ES error: %s", diff --git a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp index ef45fbcd..97cf6949 100644 --- a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp @@ -780,6 +780,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { m_dynamicParameters.MaxComputeWorkGroupInvocations = m_vulkanCaps.MaxComputeWorkGroupInvocations; m_dynamicParameters.MaxShaderStorageBufferBindings = m_vulkanCaps.MaxShaderStorageBufferBindings; m_dynamicParameters.MaxTextureBufferSize = m_vulkanCaps.MaxTextureBufferSize; + m_dynamicParameters.TextureBufferOffsetAlignment = m_vulkanCaps.TextureBufferOffsetAlignment; m_dynamicParameters.MaxUniformBufferBindings = m_vulkanCaps.MaxUniformBufferBindings; m_dynamicParameters.MaxUniformBlockSize = m_vulkanCaps.MaxUniformBlockSize; m_dynamicParameters.MaxImageUnits = diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp index 2259577e..5d47bf7b 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp @@ -600,7 +600,11 @@ namespace MobileGL::MG_Backend::DirectVulkan { const VkDeviceSize texelSize = static_cast(MG_Util::GetSizedInternalFormatSizeInBytes(internalFormat)); - VkDeviceSize viewRange = slice.size; + // glTextureBufferRange addresses a window of the buffer, not all of it; the whole-buffer + // forms report the buffer's current size here, so both go through the same clamp. + const VkDeviceSize rangeOffset = static_cast(textureBuffer->GetBufferRangeOffset()); + const VkDeviceSize rangeSize = static_cast(textureBuffer->GetBufferRangeSizeInBytes()); + VkDeviceSize viewRange = std::min(rangeSize, slice.size > rangeOffset ? slice.size - rangeOffset : 0); if (texelSize > 0) { viewRange = (viewRange / texelSize) * texelSize; } @@ -613,7 +617,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { viewInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO; viewInfo.buffer = slice.buffer; viewInfo.format = vkFormat; - viewInfo.offset = slice.offset; + viewInfo.offset = slice.offset + rangeOffset; viewInfo.range = viewRange; VkBufferView bufferView = VK_NULL_HANDLE; diff --git a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp index f8dfe687..e3ca2e2e 100644 --- a/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp +++ b/MobileGL/MG_Impl/GLImpl/Exporting/Definitions.cpp @@ -434,7 +434,7 @@ DECLARE_GL_FUNCTION_HEAD(void, SamplerParameterIuiv, GLuint sampler, GLenum pnam DECLARE_GL_FUNCTION_HEAD(void, GetSamplerParameterIiv, GLuint sampler, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetSamplerParameterIiv, sampler, pname, params) DECLARE_GL_FUNCTION_HEAD(void, GetSamplerParameterIuiv, GLuint sampler, GLenum pname, GLuint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetSamplerParameterIuiv, sampler, pname, params) DECLARE_GL_FUNCTION_HEAD(void, TexBuffer, GLenum target, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexBuffer, target, internalformat, buffer) -DECLARE_GL_FUNCTION_STUB_HEAD(void, TexBufferRange, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TexBufferRange, target, internalformat, buffer, offset, size) +DECLARE_GL_FUNCTION_HEAD(void, TexBufferRange, GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexBufferRange, target, internalformat, buffer, offset, size) DECLARE_GL_FUNCTION_HEAD(void, TexStorage3DMultisample, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TexStorage3DMultisample, target, samples, internalformat, width, height, depth, fixedsamplelocations) DECLARE_GL_FUNCTION_HEAD(void*, MapBufferRange, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) DECLARE_GL_FUNCTION_END(void*, MapBufferRange, target, offset, length, access) DECLARE_GL_FUNCTION_STUB_HEAD(void, ClearIndex, GLfloat c) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, ClearIndex, c) @@ -1049,8 +1049,8 @@ DECLARE_GL_FUNCTION_HEAD(void, NamedRenderbufferStorage, GLuint renderbuffer, GL DECLARE_GL_FUNCTION_HEAD(void, NamedRenderbufferStorageMultisample, GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, NamedRenderbufferStorageMultisample, renderbuffer, samples, internalformat, width, height) DECLARE_GL_FUNCTION_HEAD(void, GetNamedRenderbufferParameteriv, GLuint renderbuffer, GLenum pname, GLint* params) DECLARE_GL_FUNCTION_END_NO_RETURN(void, GetNamedRenderbufferParameteriv, renderbuffer, pname, params) DECLARE_GL_FUNCTION_HEAD(void, CreateTextures, GLenum target, GLsizei n, GLuint* textures) DECLARE_GL_FUNCTION_END_NO_RETURN(void, CreateTextures, target, n, textures) -DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBuffer, GLuint texture, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBuffer, texture, internalformat, buffer) -DECLARE_GL_FUNCTION_STUB_HEAD(void, TextureBufferRange, GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) DECLARE_GL_FUNCTION_STUB_END_NO_RETURN(void, TextureBufferRange, texture, internalformat, buffer, offset, size) +DECLARE_GL_FUNCTION_HEAD(void, TextureBuffer, GLuint texture, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureBuffer, texture, internalformat, buffer) +DECLARE_GL_FUNCTION_HEAD(void, TextureBufferRange, GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureBufferRange, texture, internalformat, buffer, offset, size) DECLARE_GL_FUNCTION_HEAD(void, TextureStorage1D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureStorage1D, texture, levels, internalformat, width) DECLARE_GL_FUNCTION_HEAD(void, TextureStorage2D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureStorage2D, texture, levels, internalformat, width, height) DECLARE_GL_FUNCTION_HEAD(void, TextureStorage3D, GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) DECLARE_GL_FUNCTION_END_NO_RETURN(void, TextureStorage3D, texture, levels, internalformat, width, height, depth) diff --git a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp index e74dfd29..c88f89e0 100644 --- a/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp +++ b/MobileGL/MG_Impl/GLImpl/Getter/GL_Getter.cpp @@ -1669,7 +1669,7 @@ namespace MobileGL::MG_Impl::GLImpl { *params = static_cast(MG_State::pGLContext->GetHint(pname)); return; case GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT: - *params = 0; // texture-buffer range entrypoints are stubbed + *params = MG_Backend::pActiveBackendObject->GetDynamicParameters().TextureBufferOffsetAlignment; return; case GL_TIMESTAMP: { Int64 timestamp = 0; diff --git a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp index a2f2a335..5a27020a 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp +++ b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.cpp @@ -2035,6 +2035,65 @@ namespace MobileGL::MG_Impl::GLImpl { MaybeAutoGenerateMipmap(target, textureObject, isProxy, level); } + // The work glTexBuffer[Range] and glTextureBuffer[Range] all share once the texture has been + // 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. + static void AttachBufferToTexture(const SharedPtr& textureObject, + GLenum internalformat, GLuint buffer, GLintptr offset, SizeT size, + const char* caller) { + using MG_State::GLState::TextureObjectBuffer; + TextureInternalFormat textureInternalFormat = MG_Util::ConvertGLEnumToTextureInternalFormat(internalformat); + if (!TextureImpl::ValidateTextureInternalFormat(textureInternalFormat)) return; + + auto& bufferObject = MG_State::pGLContext->GetBufferObject(buffer); + if (buffer != 0 && !bufferObject) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidOperation, + MakeUnique("MG_Impl/GLImpl", caller, + "`buffer` is not zero and is not the name of an existing buffer object.")); + return; + } + if (!TextureImpl::ValidateTextureObject(textureObject)) return; + if (textureObject->GetStorageType() != TextureStorageType::Buffer) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidEnum, + MakeUnique("MG_Impl/GLImpl", caller, + "The effective target of `texture` is not `GL_TEXTURE_BUFFER`.")); + return; + } + if (size != TextureObjectBuffer::kWholeBuffer) { + // GL 4.6 core 8.9: offset must be non-negative and aligned to + // GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, and size must be positive. + if (offset < 0) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", caller, "offset must be non-negative.")); + return; + } + if (size == 0) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", caller, "size must be greater than zero.")); + return; + } + const Int alignment = std::max( + 1, MG_Backend::pActiveBackendObject->GetDynamicParameters().TextureBufferOffsetAlignment); + if (offset % alignment != 0) { + MG_State::pGLContext->RecordError( + ErrorCode::InvalidValue, + MakeUnique("MG_Impl/GLImpl", caller, + "offset is not a multiple of GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT.")); + return; + } + } + + auto* texBufferObject = static_cast(textureObject.get()); + texBufferObject->GetBufferBindingSlot().Bind(bufferObject); + texBufferObject->SetBufferRange(static_cast(offset < 0 ? 0 : offset), size); + texBufferObject->SetInternalFormat(textureInternalFormat); + } + void TexBuffer_State(GLenum target, GLenum internalformat, GLuint buffer) { // ======================= Converting ================================ TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target); @@ -2081,6 +2140,7 @@ namespace MobileGL::MG_Impl::GLImpl { auto& bufferSlot = texBufferObject->GetBufferBindingSlot(); bufferSlot.Bind(bufferObject); + texBufferObject->SetBufferRange(0, MG_State::GLState::TextureObjectBuffer::kWholeBuffer); texBufferObject->SetInternalFormat(textureInternalFormat); } @@ -4088,6 +4148,33 @@ namespace MobileGL::MG_Impl::GLImpl { TexBuffer_State(target, internalformat, buffer); } + // The buffer texture bound to `target` on the active unit - what the non-DSA range form + // operates on. Kept separate from TexBuffer_State because that one resolves the target + // itself and attaches the whole buffer. + static const SharedPtr& GetBoundBufferTexture(GLenum target, + const char* caller) { + TextureUploadTarget uploadTarget = MG_Util::ConvertGLEnumToTextureUploadTarget(target); + if (!TextureImpl::ValidateTextureUploadTarget(uploadTarget)) return nullTextureObject; + (void)caller; + auto& activeUnit = MG_State::pGLContext->GetTextureUnitObject(MG_State::pGLContext->GetActiveTextureUnit()); + return activeUnit.GetBindingSlot(MG_Util::ConvertGLEnumToTextureTarget(target)).GetBoundObject(); + } + + void TexBufferRange(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) { + AttachBufferToTexture(GetBoundBufferTexture(target, __func__), internalformat, buffer, offset, + static_cast(size < 0 ? 0 : size), __func__); + } + + void TextureBuffer(GLuint texture, GLenum internalformat, GLuint buffer) { + AttachBufferToTexture(GetTextureObjectByName(texture, __func__), internalformat, buffer, 0, + MG_State::GLState::TextureObjectBuffer::kWholeBuffer, __func__); + } + + void TextureBufferRange(GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size) { + AttachBufferToTexture(GetTextureObjectByName(texture, __func__), internalformat, buffer, offset, + static_cast(size < 0 ? 0 : size), __func__); + } + GLboolean IsTexture(GLuint texture) { return IsTexture_State(texture); } diff --git a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.h b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.h index 2b3c34a2..8811a404 100644 --- a/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.h +++ b/MobileGL/MG_Impl/GLImpl/Texture/GL_Texture.h @@ -42,6 +42,9 @@ namespace MobileGL::MG_Impl::GLImpl { void GenerateTextureMipmap(GLuint texture); void BindTextureUnit(GLuint unit, GLuint texture); void GetTextureImage(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels); + void TexBufferRange(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); + void TextureBuffer(GLuint texture, GLenum internalformat, GLuint buffer); + void TextureBufferRange(GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); void GetTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels); void GetTextureParameterfv(GLuint texture, GLenum pname, GLfloat* params); diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObjectBuffer.h b/MobileGL/MG_State/GLState/TextureState/TextureObjectBuffer.h index a2108c6a..9ecdec9c 100644 --- a/MobileGL/MG_State/GLState/TextureState/TextureObjectBuffer.h +++ b/MobileGL/MG_State/GLState/TextureState/TextureObjectBuffer.h @@ -21,10 +21,31 @@ namespace MobileGL { BindingSlot& GetBufferBindingSlot( TextureUploadTarget target = TextureUploadTarget::TextureBuffer); + // The window of the attached buffer the texture addresses. glTexBuffer attaches + // the whole buffer, which is expressed here as an offset of 0 and a size of + // kWholeBuffer so a later respecify of the buffer keeps being followed - a stored + // size would freeze the texture at the size the buffer happened to have. + static constexpr SizeT kWholeBuffer = ~static_cast(0); + void SetBufferRange(SizeT offset, SizeT size) { + m_bufferRangeOffset = offset; + m_bufferRangeSize = size; + } + SizeT GetBufferRangeOffset() const { return m_bufferRangeOffset; } + // Resolved against the buffer's current size, so kWholeBuffer tracks it. + SizeT GetBufferRangeSizeInBytes() const { + const auto& buffer = m_bufferBindingSlot.GetBoundObject(); + const SizeT bufferSize = buffer != nullptr ? buffer->GetSize() : 0; + if (m_bufferRangeSize == kWholeBuffer) return bufferSize; + const SizeT available = bufferSize > m_bufferRangeOffset ? bufferSize - m_bufferRangeOffset : 0; + return std::min(m_bufferRangeSize, available); + } + protected: Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const override; BindingSlot m_bufferBindingSlot = BindingSlot(BufferTarget::Texture); + SizeT m_bufferRangeOffset = 0; + SizeT m_bufferRangeSize = kWholeBuffer; const Vector m_uploadTargets{TextureUploadTarget::TextureBuffer}; }; } // namespace GLState diff --git a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp index cba00e44..41a85fc0 100644 --- a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp +++ b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.cpp @@ -1056,6 +1056,10 @@ namespace MobileGL::MG_Util::BackendLoader { caps.MaxComputeWorkGroupInvocations = maxComputeWorkGroupInvocations; caps.MaxShaderStorageBufferBindings = maxShaderStorageBufferBindings; caps.MaxTextureBufferSize = maxTextureBufferSize; + GLint textureBufferOffsetAlignment = 1; + glGetIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, &textureBufferOffsetAlignment); + while (glGetError() != GL_NO_ERROR) {} + caps.TextureBufferOffsetAlignment = std::max(1, textureBufferOffsetAlignment); caps.MaxUniformBufferBindings = maxUniformBufferBindings; caps.MaxUniformBlockSize = maxUniformBlockSize; caps.MaxImageUnits = maxImageUnits; diff --git a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h index 3986965d..3b9485cb 100644 --- a/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h +++ b/MobileGL/MG_Util/BackendLoaders/OpenGL/Loader.h @@ -1117,6 +1117,8 @@ namespace MobileGL { Int MaxComputeWorkGroupInvocations = 128; Int MaxShaderStorageBufferBindings = 8; Int MaxTextureBufferSize = 65536; + // GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT; 1 means the offset is unconstrained. + Int TextureBufferOffsetAlignment = 1; Int MaxUniformBufferBindings = 24; Int MaxUniformBlockSize = 16384; Int MaxImageUnits = 8; diff --git a/MobileGL/MG_Util/BackendLoaders/Vulkan/Loader.cpp b/MobileGL/MG_Util/BackendLoaders/Vulkan/Loader.cpp index be3e90d9..be80e933 100644 --- a/MobileGL/MG_Util/BackendLoaders/Vulkan/Loader.cpp +++ b/MobileGL/MG_Util/BackendLoaders/Vulkan/Loader.cpp @@ -177,6 +177,8 @@ namespace MobileGL::MG_Util::BackendLoader { caps.MaxComputeWorkGroupInvocations = static_cast(p.limits.maxComputeWorkGroupInvocations); caps.MaxShaderStorageBufferBindings = static_cast(p.limits.maxDescriptorSetStorageBuffers); caps.MaxTextureBufferSize = static_cast(p.limits.maxTexelBufferElements); + caps.TextureBufferOffsetAlignment = + static_cast(std::max(1, p.limits.minTexelBufferOffsetAlignment)); caps.MaxUniformBufferBindings = static_cast(p.limits.maxDescriptorSetUniformBuffers); caps.MaxUniformBlockSize = static_cast(p.limits.maxUniformBufferRange); caps.MaxImageUnits = static_cast(p.limits.maxPerStageDescriptorStorageImages); @@ -268,6 +270,8 @@ namespace MobileGL::MG_Util::BackendLoader { caps.MaxComputeWorkGroupInvocations = static_cast(properties.limits.maxComputeWorkGroupInvocations); caps.MaxShaderStorageBufferBindings = static_cast(properties.limits.maxDescriptorSetStorageBuffers); caps.MaxTextureBufferSize = static_cast(properties.limits.maxTexelBufferElements); + caps.TextureBufferOffsetAlignment = + static_cast(std::max(1, properties.limits.minTexelBufferOffsetAlignment)); caps.MaxUniformBufferBindings = static_cast(properties.limits.maxDescriptorSetUniformBuffers); caps.MaxUniformBlockSize = static_cast(properties.limits.maxUniformBufferRange); caps.MaxImageUnits = static_cast(properties.limits.maxPerStageDescriptorStorageImages); diff --git a/MobileGL/MG_Util/BackendLoaders/Vulkan/Loader.h b/MobileGL/MG_Util/BackendLoaders/Vulkan/Loader.h index fea97466..f731c558 100644 --- a/MobileGL/MG_Util/BackendLoaders/Vulkan/Loader.h +++ b/MobileGL/MG_Util/BackendLoaders/Vulkan/Loader.h @@ -54,6 +54,8 @@ namespace MobileGL { Int MaxComputeWorkGroupInvocations = 128; Int MaxShaderStorageBufferBindings = 8; Int MaxTextureBufferSize = 65536; + // GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT; 1 means the offset is unconstrained. + Int TextureBufferOffsetAlignment = 1; Int MaxUniformBufferBindings = 24; Int MaxUniformBlockSize = 16384; Int MaxImageUnits = 8;