[Fix] (DirectGLES, DirectVulkan): answer GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT with the storage limit, not the uniform one

This commit is contained in:
2026-08-25 05:21:42 -04:00
parent 5398fb4289
commit ebb8a4cebf
11 changed files with 86 additions and 6 deletions
@@ -1064,6 +1064,16 @@ namespace MobileGL::MG_Util::BackendLoader {
MGLOG_I("OpenGL ES capabilities:");
glesFuncs.glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &caps.UniformBufferOffsetAlignment);
MGLOG_I(" GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: %d", caps.UniformBufferOffsetAlignment);
// ES 3.1 core, so no extension gate - but a driver that somehow leaves it at zero would
// make every storage-range offset legal, so an unusable answer keeps the 256 default.
GLint shaderStorageOffsetAlignment = 0;
glesFuncs.glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &shaderStorageOffsetAlignment);
while (glesFuncs.glGetError() != GL_NO_ERROR) {
}
if (shaderStorageOffsetAlignment > 0) {
caps.ShaderStorageBufferOffsetAlignment = shaderStorageOffsetAlignment;
}
MGLOG_I(" GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT: %d", caps.ShaderStorageBufferOffsetAlignment);
GLfloat aliasedLineWidthRange[2] = {1.0f, 1.0f};
GLfloat smoothLineWidthRange[2] = {1.0f, 1.0f};
GLfloat smoothLineWidthGranularity = 1.0f;
@@ -1231,6 +1231,10 @@ namespace MobileGL {
// InstanceIndex, which includes firstInstance.
Bool IndirectDrawInstanceIdIncludesBaseInstance = false;
Int UniformBufferOffsetAlignment = 256;
// Its storage-buffer counterpart, queried separately because it is a separate limit:
// Adreno 830 answers 32 for GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT and 64 for
// GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT.
Int ShaderStorageBufferOffsetAlignment = 256;
Float AliasedLineWidthRangeMin = 1.0f;
Float AliasedLineWidthRangeMax = 1.0f;
Float SmoothLineWidthRangeMin = 1.0f;
@@ -154,6 +154,7 @@ namespace MobileGL::MG_Util::BackendLoader {
caps.DriverVersionString = DecodeDriverVersion(p.driverVersion);
caps.VendorId = p.vendorID;
caps.UniformBufferOffsetAlignment = static_cast<int>(p.limits.minUniformBufferOffsetAlignment);
caps.ShaderStorageBufferOffsetAlignment = static_cast<int>(p.limits.minStorageBufferOffsetAlignment);
caps.AliasedLineWidthRangeMin = p.limits.lineWidthRange[0];
caps.AliasedLineWidthRangeMax = p.limits.lineWidthRange[1];
caps.MaxSamplerAnisotropy = p.limits.maxSamplerAnisotropy;
@@ -272,6 +273,8 @@ namespace MobileGL::MG_Util::BackendLoader {
caps.DriverVersionString = DecodeDriverVersion(properties.driverVersion);
caps.VendorId = properties.vendorID;
caps.UniformBufferOffsetAlignment = static_cast<int>(properties.limits.minUniformBufferOffsetAlignment);
caps.ShaderStorageBufferOffsetAlignment =
static_cast<int>(properties.limits.minStorageBufferOffsetAlignment);
caps.AliasedLineWidthRangeMin = properties.limits.lineWidthRange[0];
caps.AliasedLineWidthRangeMax = properties.limits.lineWidthRange[1];
caps.MaxSamplerAnisotropy = properties.limits.maxSamplerAnisotropy;
@@ -18,6 +18,10 @@ namespace MobileGL {
// VkPhysicalDeviceProperties::vendorID, for device-quirk vendor gating.
Uint32 VendorId = 0;
Int UniformBufferOffsetAlignment = 256;
// VkPhysicalDeviceLimits::minStorageBufferOffsetAlignment. A separate limit from
// the uniform one on Vulkan too, and the one GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT
// has to answer with.
Int ShaderStorageBufferOffsetAlignment = 256;
Float AliasedLineWidthRangeMin = 1.0f;
Float AliasedLineWidthRangeMax = 1.0f;
// VkPhysicalDeviceLimits::maxSamplerAnisotropy. Whether it can be used at all depends on
@@ -44,9 +44,10 @@ namespace MobileGL {
//
// Why not simply rebase the offsets to zero and bind the buffer 8 bytes in: because
// glBindBufferRange's offset must be a multiple of
// GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, which the target device reports as 32.
// A byte offset of 8 cannot be expressed as a binding at all, so the correction has
// to live in the shader's indexing, where it costs nothing.
// GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, which is 64 on Adreno 830 and no smaller
// than 32 on the other targets. A byte offset of 8 cannot be expressed as a binding
// on any of them, so the correction has to live in the shader's indexing, where it
// costs nothing.
//
// A block that is ALREADY laid out naturally - which is every shader that omits the
// offset qualifier, and so very nearly all of them - is left byte-identical: the