mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-14 07:08:32 +09:00
[Feat] (MG_Impl, MG_State, MG_Util): attach a buffer texture to a range of its buffer
glTexBufferRange, glTextureBuffer and glTextureBufferRange were all stubs, so a buffer texture could only ever be attached through glTexBuffer -- by binding, and always to the whole buffer. Give the buffer texture the window it is supposed to address. The non-range forms record it as offset 0 with a whole-buffer sentinel rather than the size the buffer happens to have, so a later respecify keeps being followed instead of freezing the texture at yesterday's size. All four entry points now share one attach path, differing only in how they name the texture: by binding for the target forms, by name for the DSA ones. Both backends honour the window: DirectVulkan offsets and clamps the buffer view, DirectGLES uses glTexBufferRange when the texture names a sub-range and keeps plain glTexBuffer for the whole-buffer case, which also works on a driver without the range entry point. GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT reported 0 with a comment explaining that the range entry points were stubbed. It now reports what the device actually requires -- minTexelBufferOffsetAlignment on Vulkan, the driver's own value on GLES -- and the range entry points enforce it. Zero was never a legal answer; the minimum is 1, and an application that trusted it would have built unaligned offsets.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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<GLintptr>(rangeOffset),
|
||||
static_cast<GLsizeiptr>(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",
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -600,7 +600,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
const VkDeviceSize texelSize =
|
||||
static_cast<VkDeviceSize>(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<VkDeviceSize>(textureBuffer->GetBufferRangeOffset());
|
||||
const VkDeviceSize rangeSize = static_cast<VkDeviceSize>(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;
|
||||
|
||||
Reference in New Issue
Block a user