mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 20:28: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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1669,7 +1669,7 @@ namespace MobileGL::MG_Impl::GLImpl {
|
||||
*params = static_cast<GLint>(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;
|
||||
|
||||
@@ -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<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) {
|
||||
// ======================= 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<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) {
|
||||
return IsTexture_State(texture);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -21,10 +21,31 @@ namespace MobileGL {
|
||||
BindingSlot<BufferObject>& 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<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:
|
||||
Uint GetIndexOfTextureUploadTarget(TextureUploadTarget target) const override;
|
||||
|
||||
BindingSlot<BufferObject> m_bufferBindingSlot = BindingSlot<BufferObject>(BufferTarget::Texture);
|
||||
SizeT m_bufferRangeOffset = 0;
|
||||
SizeT m_bufferRangeSize = kWholeBuffer;
|
||||
const Vector<TextureUploadTarget> m_uploadTargets{TextureUploadTarget::TextureBuffer};
|
||||
};
|
||||
} // namespace GLState
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -177,6 +177,8 @@ namespace MobileGL::MG_Util::BackendLoader {
|
||||
caps.MaxComputeWorkGroupInvocations = static_cast<Int>(p.limits.maxComputeWorkGroupInvocations);
|
||||
caps.MaxShaderStorageBufferBindings = static_cast<Int>(p.limits.maxDescriptorSetStorageBuffers);
|
||||
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.MaxUniformBlockSize = static_cast<Int>(p.limits.maxUniformBufferRange);
|
||||
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.MaxShaderStorageBufferBindings = static_cast<Int>(properties.limits.maxDescriptorSetStorageBuffers);
|
||||
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.MaxUniformBlockSize = static_cast<Int>(properties.limits.maxUniformBufferRange);
|
||||
caps.MaxImageUnits = static_cast<Int>(properties.limits.maxPerStageDescriptorStorageImages);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user