mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-12 06:08:30 +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 MaxComputeWorkGroupInvocations = 128;
|
||||||
Int MaxShaderStorageBufferBindings = 8;
|
Int MaxShaderStorageBufferBindings = 8;
|
||||||
Int MaxTextureBufferSize = 65536;
|
Int MaxTextureBufferSize = 65536;
|
||||||
|
// GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT; 1 means the offset is unconstrained.
|
||||||
|
Int TextureBufferOffsetAlignment = 1;
|
||||||
Int MaxUniformBufferBindings = 24;
|
Int MaxUniformBufferBindings = 24;
|
||||||
Int MaxUniformBlockSize = 16384;
|
Int MaxUniformBlockSize = 16384;
|
||||||
Int MaxImageUnits = 8;
|
Int MaxImageUnits = 8;
|
||||||
|
|||||||
@@ -1112,6 +1112,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
m_dynamicParameters.MaxComputeWorkGroupInvocations = m_GLESCapabilities.MaxComputeWorkGroupInvocations;
|
m_dynamicParameters.MaxComputeWorkGroupInvocations = m_GLESCapabilities.MaxComputeWorkGroupInvocations;
|
||||||
m_dynamicParameters.MaxShaderStorageBufferBindings = m_GLESCapabilities.MaxShaderStorageBufferBindings;
|
m_dynamicParameters.MaxShaderStorageBufferBindings = m_GLESCapabilities.MaxShaderStorageBufferBindings;
|
||||||
m_dynamicParameters.MaxTextureBufferSize = m_GLESCapabilities.MaxTextureBufferSize;
|
m_dynamicParameters.MaxTextureBufferSize = m_GLESCapabilities.MaxTextureBufferSize;
|
||||||
|
m_dynamicParameters.TextureBufferOffsetAlignment = m_GLESCapabilities.TextureBufferOffsetAlignment;
|
||||||
m_dynamicParameters.MaxUniformBufferBindings = m_GLESCapabilities.MaxUniformBufferBindings;
|
m_dynamicParameters.MaxUniformBufferBindings = m_GLESCapabilities.MaxUniformBufferBindings;
|
||||||
m_dynamicParameters.MaxUniformBlockSize = m_GLESCapabilities.MaxUniformBlockSize;
|
m_dynamicParameters.MaxUniformBlockSize = m_GLESCapabilities.MaxUniformBlockSize;
|
||||||
const Int maxSupportedTextureUnits =
|
const Int maxSupportedTextureUnits =
|
||||||
|
|||||||
@@ -2232,7 +2232,24 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
"ID: %u, buffer ID: %u, buffer size: %zu, format: %s",
|
"ID: %u, buffer ID: %u, buffer size: %zu, format: %s",
|
||||||
m_backendTextureId, backendId, buffer->GetSize(),
|
m_backendTextureId, backendId, buffer->GetSize(),
|
||||||
MG_Util::ConvertGLEnumToString(glInternalFormat).c_str());
|
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(
|
DebugImpl::ErrorLopper::Loop(
|
||||||
[file = __FILE__, line = __LINE__, func = __func__, glInternalFormat, backendId](GLenum err) {
|
[file = __FILE__, line = __LINE__, func = __func__, glInternalFormat, backendId](GLenum err) {
|
||||||
MGLOG_D("%s(%s:%d) glTexBuffer(format=%s, buffer=%u) ES error: %s",
|
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.MaxComputeWorkGroupInvocations = m_vulkanCaps.MaxComputeWorkGroupInvocations;
|
||||||
m_dynamicParameters.MaxShaderStorageBufferBindings = m_vulkanCaps.MaxShaderStorageBufferBindings;
|
m_dynamicParameters.MaxShaderStorageBufferBindings = m_vulkanCaps.MaxShaderStorageBufferBindings;
|
||||||
m_dynamicParameters.MaxTextureBufferSize = m_vulkanCaps.MaxTextureBufferSize;
|
m_dynamicParameters.MaxTextureBufferSize = m_vulkanCaps.MaxTextureBufferSize;
|
||||||
|
m_dynamicParameters.TextureBufferOffsetAlignment = m_vulkanCaps.TextureBufferOffsetAlignment;
|
||||||
m_dynamicParameters.MaxUniformBufferBindings = m_vulkanCaps.MaxUniformBufferBindings;
|
m_dynamicParameters.MaxUniformBufferBindings = m_vulkanCaps.MaxUniformBufferBindings;
|
||||||
m_dynamicParameters.MaxUniformBlockSize = m_vulkanCaps.MaxUniformBlockSize;
|
m_dynamicParameters.MaxUniformBlockSize = m_vulkanCaps.MaxUniformBlockSize;
|
||||||
m_dynamicParameters.MaxImageUnits =
|
m_dynamicParameters.MaxImageUnits =
|
||||||
|
|||||||
@@ -600,7 +600,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
|
|
||||||
const VkDeviceSize texelSize =
|
const VkDeviceSize texelSize =
|
||||||
static_cast<VkDeviceSize>(MG_Util::GetSizedInternalFormatSizeInBytes(internalFormat));
|
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) {
|
if (texelSize > 0) {
|
||||||
viewRange = (viewRange / texelSize) * texelSize;
|
viewRange = (viewRange / texelSize) * texelSize;
|
||||||
}
|
}
|
||||||
@@ -613,7 +617,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
|||||||
viewInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
|
viewInfo.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
|
||||||
viewInfo.buffer = slice.buffer;
|
viewInfo.buffer = slice.buffer;
|
||||||
viewInfo.format = vkFormat;
|
viewInfo.format = vkFormat;
|
||||||
viewInfo.offset = slice.offset;
|
viewInfo.offset = slice.offset + rangeOffset;
|
||||||
viewInfo.range = viewRange;
|
viewInfo.range = viewRange;
|
||||||
|
|
||||||
VkBufferView bufferView = VK_NULL_HANDLE;
|
VkBufferView bufferView = VK_NULL_HANDLE;
|
||||||
|
|||||||
@@ -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, 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, 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_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, 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_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)
|
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, 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, 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_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_HEAD(void, TextureBuffer, GLuint texture, GLenum internalformat, GLuint buffer) DECLARE_GL_FUNCTION_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, 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, 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, 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)
|
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)
|
||||||
|
|||||||
@@ -1669,7 +1669,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
*params = static_cast<GLint>(MG_State::pGLContext->GetHint(pname));
|
*params = static_cast<GLint>(MG_State::pGLContext->GetHint(pname));
|
||||||
return;
|
return;
|
||||||
case GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT:
|
case GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT:
|
||||||
*params = 0; // texture-buffer range entrypoints are stubbed
|
*params = MG_Backend::pActiveBackendObject->GetDynamicParameters().TextureBufferOffsetAlignment;
|
||||||
return;
|
return;
|
||||||
case GL_TIMESTAMP: {
|
case GL_TIMESTAMP: {
|
||||||
Int64 timestamp = 0;
|
Int64 timestamp = 0;
|
||||||
|
|||||||
@@ -2035,6 +2035,65 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
MaybeAutoGenerateMipmap(target, textureObject, isProxy, level);
|
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<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 (!TextureImpl::ValidateTextureInternalFormat(textureInternalFormat)) return;
|
||||||
|
|
||||||
|
auto& bufferObject = MG_State::pGLContext->GetBufferObject(buffer);
|
||||||
|
if (buffer != 0 && !bufferObject) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidOperation,
|
||||||
|
MakeUnique<GenericErrorInfo>("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<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", caller, "offset must be non-negative."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (size == 0) {
|
||||||
|
MG_State::pGLContext->RecordError(
|
||||||
|
ErrorCode::InvalidValue,
|
||||||
|
MakeUnique<GenericErrorInfo>("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<GenericErrorInfo>("MG_Impl/GLImpl", caller,
|
||||||
|
"offset is not a multiple of GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* texBufferObject = static_cast<TextureObjectBuffer*>(textureObject.get());
|
||||||
|
texBufferObject->GetBufferBindingSlot().Bind(bufferObject);
|
||||||
|
texBufferObject->SetBufferRange(static_cast<SizeT>(offset < 0 ? 0 : offset), size);
|
||||||
|
texBufferObject->SetInternalFormat(textureInternalFormat);
|
||||||
|
}
|
||||||
|
|
||||||
void TexBuffer_State(GLenum target, GLenum internalformat, GLuint buffer) {
|
void TexBuffer_State(GLenum target, GLenum internalformat, GLuint buffer) {
|
||||||
// ======================= Converting ================================
|
// ======================= Converting ================================
|
||||||
TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
TextureTarget textureTarget = MG_Util::ConvertGLEnumToTextureTarget(target);
|
||||||
@@ -2081,6 +2140,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
auto& bufferSlot = texBufferObject->GetBufferBindingSlot();
|
auto& bufferSlot = texBufferObject->GetBufferBindingSlot();
|
||||||
bufferSlot.Bind(bufferObject);
|
bufferSlot.Bind(bufferObject);
|
||||||
|
|
||||||
|
texBufferObject->SetBufferRange(0, MG_State::GLState::TextureObjectBuffer::kWholeBuffer);
|
||||||
texBufferObject->SetInternalFormat(textureInternalFormat);
|
texBufferObject->SetInternalFormat(textureInternalFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4088,6 +4148,33 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
TexBuffer_State(target, internalformat, buffer);
|
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<MG_State::GLState::ITextureObject>& 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<SizeT>(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<SizeT>(size < 0 ? 0 : size), __func__);
|
||||||
|
}
|
||||||
|
|
||||||
GLboolean IsTexture(GLuint texture) {
|
GLboolean IsTexture(GLuint texture) {
|
||||||
return IsTexture_State(texture);
|
return IsTexture_State(texture);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
void GenerateTextureMipmap(GLuint texture);
|
void GenerateTextureMipmap(GLuint texture);
|
||||||
void BindTextureUnit(GLuint unit, GLuint texture);
|
void BindTextureUnit(GLuint unit, GLuint texture);
|
||||||
void GetTextureImage(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels);
|
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,
|
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);
|
GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void* pixels);
|
||||||
void GetTextureParameterfv(GLuint texture, GLenum pname, GLfloat* params);
|
void GetTextureParameterfv(GLuint texture, GLenum pname, GLfloat* params);
|
||||||
|
|||||||
@@ -21,10 +21,31 @@ namespace MobileGL {
|
|||||||
BindingSlot<BufferObject>& GetBufferBindingSlot(
|
BindingSlot<BufferObject>& GetBufferBindingSlot(
|
||||||
TextureUploadTarget target = TextureUploadTarget::TextureBuffer);
|
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<SizeT>(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:
|
protected:
|
||||||
Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const override;
|
Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const override;
|
||||||
|
|
||||||
BindingSlot<BufferObject> m_bufferBindingSlot = BindingSlot<BufferObject>(BufferTarget::Texture);
|
BindingSlot<BufferObject> m_bufferBindingSlot = BindingSlot<BufferObject>(BufferTarget::Texture);
|
||||||
|
SizeT m_bufferRangeOffset = 0;
|
||||||
|
SizeT m_bufferRangeSize = kWholeBuffer;
|
||||||
const Vector<TextureUploadTarget> m_uploadTargets{TextureUploadTarget::TextureBuffer};
|
const Vector<TextureUploadTarget> m_uploadTargets{TextureUploadTarget::TextureBuffer};
|
||||||
};
|
};
|
||||||
} // namespace GLState
|
} // namespace GLState
|
||||||
|
|||||||
@@ -1056,6 +1056,10 @@ namespace MobileGL::MG_Util::BackendLoader {
|
|||||||
caps.MaxComputeWorkGroupInvocations = maxComputeWorkGroupInvocations;
|
caps.MaxComputeWorkGroupInvocations = maxComputeWorkGroupInvocations;
|
||||||
caps.MaxShaderStorageBufferBindings = maxShaderStorageBufferBindings;
|
caps.MaxShaderStorageBufferBindings = maxShaderStorageBufferBindings;
|
||||||
caps.MaxTextureBufferSize = maxTextureBufferSize;
|
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.MaxUniformBufferBindings = maxUniformBufferBindings;
|
||||||
caps.MaxUniformBlockSize = maxUniformBlockSize;
|
caps.MaxUniformBlockSize = maxUniformBlockSize;
|
||||||
caps.MaxImageUnits = maxImageUnits;
|
caps.MaxImageUnits = maxImageUnits;
|
||||||
|
|||||||
@@ -1117,6 +1117,8 @@ namespace MobileGL {
|
|||||||
Int MaxComputeWorkGroupInvocations = 128;
|
Int MaxComputeWorkGroupInvocations = 128;
|
||||||
Int MaxShaderStorageBufferBindings = 8;
|
Int MaxShaderStorageBufferBindings = 8;
|
||||||
Int MaxTextureBufferSize = 65536;
|
Int MaxTextureBufferSize = 65536;
|
||||||
|
// GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT; 1 means the offset is unconstrained.
|
||||||
|
Int TextureBufferOffsetAlignment = 1;
|
||||||
Int MaxUniformBufferBindings = 24;
|
Int MaxUniformBufferBindings = 24;
|
||||||
Int MaxUniformBlockSize = 16384;
|
Int MaxUniformBlockSize = 16384;
|
||||||
Int MaxImageUnits = 8;
|
Int MaxImageUnits = 8;
|
||||||
|
|||||||
@@ -177,6 +177,8 @@ namespace MobileGL::MG_Util::BackendLoader {
|
|||||||
caps.MaxComputeWorkGroupInvocations = static_cast<Int>(p.limits.maxComputeWorkGroupInvocations);
|
caps.MaxComputeWorkGroupInvocations = static_cast<Int>(p.limits.maxComputeWorkGroupInvocations);
|
||||||
caps.MaxShaderStorageBufferBindings = static_cast<Int>(p.limits.maxDescriptorSetStorageBuffers);
|
caps.MaxShaderStorageBufferBindings = static_cast<Int>(p.limits.maxDescriptorSetStorageBuffers);
|
||||||
caps.MaxTextureBufferSize = static_cast<Int>(p.limits.maxTexelBufferElements);
|
caps.MaxTextureBufferSize = static_cast<Int>(p.limits.maxTexelBufferElements);
|
||||||
|
caps.TextureBufferOffsetAlignment =
|
||||||
|
static_cast<Int>(std::max<VkDeviceSize>(1, p.limits.minTexelBufferOffsetAlignment));
|
||||||
caps.MaxUniformBufferBindings = static_cast<Int>(p.limits.maxDescriptorSetUniformBuffers);
|
caps.MaxUniformBufferBindings = static_cast<Int>(p.limits.maxDescriptorSetUniformBuffers);
|
||||||
caps.MaxUniformBlockSize = static_cast<Int>(p.limits.maxUniformBufferRange);
|
caps.MaxUniformBlockSize = static_cast<Int>(p.limits.maxUniformBufferRange);
|
||||||
caps.MaxImageUnits = static_cast<Int>(p.limits.maxPerStageDescriptorStorageImages);
|
caps.MaxImageUnits = static_cast<Int>(p.limits.maxPerStageDescriptorStorageImages);
|
||||||
@@ -268,6 +270,8 @@ namespace MobileGL::MG_Util::BackendLoader {
|
|||||||
caps.MaxComputeWorkGroupInvocations = static_cast<Int>(properties.limits.maxComputeWorkGroupInvocations);
|
caps.MaxComputeWorkGroupInvocations = static_cast<Int>(properties.limits.maxComputeWorkGroupInvocations);
|
||||||
caps.MaxShaderStorageBufferBindings = static_cast<Int>(properties.limits.maxDescriptorSetStorageBuffers);
|
caps.MaxShaderStorageBufferBindings = static_cast<Int>(properties.limits.maxDescriptorSetStorageBuffers);
|
||||||
caps.MaxTextureBufferSize = static_cast<Int>(properties.limits.maxTexelBufferElements);
|
caps.MaxTextureBufferSize = static_cast<Int>(properties.limits.maxTexelBufferElements);
|
||||||
|
caps.TextureBufferOffsetAlignment =
|
||||||
|
static_cast<Int>(std::max<VkDeviceSize>(1, properties.limits.minTexelBufferOffsetAlignment));
|
||||||
caps.MaxUniformBufferBindings = static_cast<Int>(properties.limits.maxDescriptorSetUniformBuffers);
|
caps.MaxUniformBufferBindings = static_cast<Int>(properties.limits.maxDescriptorSetUniformBuffers);
|
||||||
caps.MaxUniformBlockSize = static_cast<Int>(properties.limits.maxUniformBufferRange);
|
caps.MaxUniformBlockSize = static_cast<Int>(properties.limits.maxUniformBufferRange);
|
||||||
caps.MaxImageUnits = static_cast<Int>(properties.limits.maxPerStageDescriptorStorageImages);
|
caps.MaxImageUnits = static_cast<Int>(properties.limits.maxPerStageDescriptorStorageImages);
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ namespace MobileGL {
|
|||||||
Int MaxComputeWorkGroupInvocations = 128;
|
Int MaxComputeWorkGroupInvocations = 128;
|
||||||
Int MaxShaderStorageBufferBindings = 8;
|
Int MaxShaderStorageBufferBindings = 8;
|
||||||
Int MaxTextureBufferSize = 65536;
|
Int MaxTextureBufferSize = 65536;
|
||||||
|
// GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT; 1 means the offset is unconstrained.
|
||||||
|
Int TextureBufferOffsetAlignment = 1;
|
||||||
Int MaxUniformBufferBindings = 24;
|
Int MaxUniformBufferBindings = 24;
|
||||||
Int MaxUniformBlockSize = 16384;
|
Int MaxUniformBlockSize = 16384;
|
||||||
Int MaxImageUnits = 8;
|
Int MaxImageUnits = 8;
|
||||||
|
|||||||
Reference in New Issue
Block a user