Renderer: Add support for storage buffers
This commit is contained in:
parent
0978feafbc
commit
093d9d344e
|
|
@ -41,17 +41,26 @@ namespace Nz
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct DescriptorPool;
|
struct DescriptorPool;
|
||||||
|
struct StorageBufferDescriptor;
|
||||||
struct TextureDescriptor;
|
struct TextureDescriptor;
|
||||||
struct UniformBufferDescriptor;
|
struct UniformBufferDescriptor;
|
||||||
|
|
||||||
DescriptorPool& AllocatePool();
|
DescriptorPool& AllocatePool();
|
||||||
ShaderBindingPtr AllocateFromPool(std::size_t poolIndex, UInt32 setIndex);
|
ShaderBindingPtr AllocateFromPool(std::size_t poolIndex, UInt32 setIndex);
|
||||||
template<typename F> void ForEachDescriptor(std::size_t poolIndex, std::size_t bindingIndex, F&& functor);
|
template<typename F> void ForEachDescriptor(std::size_t poolIndex, std::size_t bindingIndex, F&& functor);
|
||||||
|
StorageBufferDescriptor& GetStorageBufferDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t descriptorIndex);
|
||||||
TextureDescriptor& GetTextureDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t descriptorIndex);
|
TextureDescriptor& GetTextureDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t descriptorIndex);
|
||||||
UniformBufferDescriptor& GetUniformBufferDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t descriptorIndex);
|
UniformBufferDescriptor& GetUniformBufferDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t descriptorIndex);
|
||||||
void Release(ShaderBinding& binding);
|
void Release(ShaderBinding& binding);
|
||||||
inline void TryToShrink();
|
inline void TryToShrink();
|
||||||
|
|
||||||
|
struct StorageBufferDescriptor
|
||||||
|
{
|
||||||
|
GLuint buffer;
|
||||||
|
GLintptr offset;
|
||||||
|
GLsizeiptr size;
|
||||||
|
};
|
||||||
|
|
||||||
struct TextureDescriptor
|
struct TextureDescriptor
|
||||||
{
|
{
|
||||||
GLuint texture;
|
GLuint texture;
|
||||||
|
|
@ -66,7 +75,7 @@ namespace Nz
|
||||||
GLsizeiptr size;
|
GLsizeiptr size;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Descriptor = std::variant<std::monostate, TextureDescriptor, UniformBufferDescriptor>;
|
using Descriptor = std::variant<std::monostate, StorageBufferDescriptor, TextureDescriptor, UniformBufferDescriptor>;
|
||||||
|
|
||||||
struct DescriptorPool
|
struct DescriptorPool
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,7 @@ namespace Nz
|
||||||
case GL::BufferTarget::ElementArray: return GL_ELEMENT_ARRAY_BUFFER;
|
case GL::BufferTarget::ElementArray: return GL_ELEMENT_ARRAY_BUFFER;
|
||||||
case GL::BufferTarget::PixelPack: return GL_PIXEL_PACK_BUFFER;
|
case GL::BufferTarget::PixelPack: return GL_PIXEL_PACK_BUFFER;
|
||||||
case GL::BufferTarget::PixelUnpack: return GL_PIXEL_UNPACK_BUFFER;
|
case GL::BufferTarget::PixelUnpack: return GL_PIXEL_UNPACK_BUFFER;
|
||||||
|
case GL::BufferTarget::Storage: return GL_SHADER_STORAGE_BUFFER;
|
||||||
case GL::BufferTarget::TransformFeedback: return GL_TRANSFORM_FEEDBACK_BUFFER;
|
case GL::BufferTarget::TransformFeedback: return GL_TRANSFORM_FEEDBACK_BUFFER;
|
||||||
case GL::BufferTarget::Uniform: return GL_UNIFORM_BUFFER;
|
case GL::BufferTarget::Uniform: return GL_UNIFORM_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ namespace Nz::GL
|
||||||
ElementArray,
|
ElementArray,
|
||||||
PixelPack,
|
PixelPack,
|
||||||
PixelUnpack,
|
PixelUnpack,
|
||||||
|
Storage,
|
||||||
TransformFeedback,
|
TransformFeedback,
|
||||||
Uniform,
|
Uniform,
|
||||||
|
|
||||||
|
|
@ -52,6 +53,7 @@ namespace Nz::GL
|
||||||
{
|
{
|
||||||
DepthClamp,
|
DepthClamp,
|
||||||
SpirV,
|
SpirV,
|
||||||
|
StorageBuffers,
|
||||||
TextureCompressionS3tc,
|
TextureCompressionS3tc,
|
||||||
TextureFilterAnisotropic,
|
TextureFilterAnisotropic,
|
||||||
|
|
||||||
|
|
@ -120,6 +122,7 @@ namespace Nz::GL
|
||||||
void BindFramebuffer(FramebufferTarget target, GLuint fbo) const;
|
void BindFramebuffer(FramebufferTarget target, GLuint fbo) const;
|
||||||
void BindProgram(GLuint program) const;
|
void BindProgram(GLuint program) const;
|
||||||
void BindSampler(UInt32 textureUnit, GLuint sampler) const;
|
void BindSampler(UInt32 textureUnit, GLuint sampler) const;
|
||||||
|
void BindStorageBuffer(UInt32 storageUnit, GLuint buffer, GLintptr offset, GLsizeiptr size) const;
|
||||||
void BindTexture(TextureTarget target, GLuint texture) const;
|
void BindTexture(TextureTarget target, GLuint texture) const;
|
||||||
void BindTexture(UInt32 textureUnit, TextureTarget target, GLuint texture) const;
|
void BindTexture(UInt32 textureUnit, TextureTarget target, GLuint texture) const;
|
||||||
void BindUniformBuffer(UInt32 uboUnit, GLuint buffer, GLintptr offset, GLsizeiptr size) const;
|
void BindUniformBuffer(UInt32 uboUnit, GLuint buffer, GLintptr offset, GLsizeiptr size) const;
|
||||||
|
|
@ -212,22 +215,23 @@ namespace Nz::GL
|
||||||
GLsizei width, height;
|
GLsizei width, height;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TextureUnit
|
struct BufferBinding
|
||||||
{
|
|
||||||
GLuint sampler = 0;
|
|
||||||
std::array<GLuint, UnderlyingCast(TextureTarget::Max) + 1> textureTargets = { 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UniformBufferUnit
|
|
||||||
{
|
{
|
||||||
GLuint buffer = 0;
|
GLuint buffer = 0;
|
||||||
GLintptr offset = 0;
|
GLintptr offset = 0;
|
||||||
GLsizeiptr size = 0;
|
GLsizeiptr size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TextureUnit
|
||||||
|
{
|
||||||
|
GLuint sampler = 0;
|
||||||
|
std::array<GLuint, UnderlyingCast(TextureTarget::Max) + 1> textureTargets = { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
std::array<GLuint, UnderlyingCast(BufferTarget::Max) + 1> bufferTargets = { 0 };
|
std::array<GLuint, UnderlyingCast(BufferTarget::Max) + 1> bufferTargets = { 0 };
|
||||||
std::vector<TextureUnit> textureUnits;
|
std::vector<TextureUnit> textureUnits;
|
||||||
std::vector<UniformBufferUnit> uboUnits;
|
std::vector<BufferBinding> storageUnits;
|
||||||
|
std::vector<BufferBinding> uboUnits;
|
||||||
Box scissorBox;
|
Box scissorBox;
|
||||||
Box viewport;
|
Box viewport;
|
||||||
GLuint boundProgram = 0;
|
GLuint boundProgram = 0;
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,7 @@ namespace Nz
|
||||||
|
|
||||||
enum class ShaderBindingType
|
enum class ShaderBindingType
|
||||||
{
|
{
|
||||||
|
StorageBuffer,
|
||||||
Texture,
|
Texture,
|
||||||
UniformBuffer,
|
UniformBuffer,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,14 @@ namespace Nz
|
||||||
bool anisotropicFiltering = false;
|
bool anisotropicFiltering = false;
|
||||||
bool depthClamping = false;
|
bool depthClamping = false;
|
||||||
bool nonSolidFaceFilling = false;
|
bool nonSolidFaceFilling = false;
|
||||||
|
bool storageBuffers = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RenderDeviceLimits
|
struct RenderDeviceLimits
|
||||||
{
|
{
|
||||||
UInt64 minUniformBufferOffsetAlignment;
|
UInt64 minUniformBufferOffsetAlignment;
|
||||||
|
UInt64 maxStorageBufferSize;
|
||||||
|
UInt64 maxUniformBufferSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RenderDeviceInfo
|
struct RenderDeviceInfo
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,13 @@ namespace Nz
|
||||||
ShaderBinding& operator=(const ShaderBinding&) = delete;
|
ShaderBinding& operator=(const ShaderBinding&) = delete;
|
||||||
ShaderBinding& operator=(ShaderBinding&&) = delete;
|
ShaderBinding& operator=(ShaderBinding&&) = delete;
|
||||||
|
|
||||||
|
struct StorageBufferBinding
|
||||||
|
{
|
||||||
|
RenderBuffer* buffer;
|
||||||
|
UInt64 offset;
|
||||||
|
UInt64 range;
|
||||||
|
};
|
||||||
|
|
||||||
struct TextureBinding
|
struct TextureBinding
|
||||||
{
|
{
|
||||||
const Texture* texture;
|
const Texture* texture;
|
||||||
|
|
@ -56,7 +63,7 @@ namespace Nz
|
||||||
struct Binding
|
struct Binding
|
||||||
{
|
{
|
||||||
std::size_t bindingIndex;
|
std::size_t bindingIndex;
|
||||||
std::variant<TextureBinding, UniformBufferBinding> content;
|
std::variant<StorageBufferBinding, TextureBinding, UniformBufferBinding> content;
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
Index,
|
Index,
|
||||||
Vertex,
|
Vertex,
|
||||||
|
Storage,
|
||||||
Uniform,
|
Uniform,
|
||||||
|
|
||||||
Max = Uniform
|
Max = Uniform
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@ namespace Nz
|
||||||
switch (bufferType)
|
switch (bufferType)
|
||||||
{
|
{
|
||||||
case BufferType::Index: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
|
case BufferType::Index: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
|
||||||
|
case BufferType::Storage: return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
||||||
case BufferType::Vertex: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
case BufferType::Vertex: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
||||||
case BufferType::Uniform: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
case BufferType::Uniform: return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||||
}
|
}
|
||||||
|
|
@ -381,6 +382,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
switch (bindingType)
|
switch (bindingType)
|
||||||
{
|
{
|
||||||
|
case ShaderBindingType::StorageBuffer: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||||
case ShaderBindingType::Texture: return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
case ShaderBindingType::Texture: return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
case ShaderBindingType::UniformBuffer: return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
case ShaderBindingType::UniformBuffer: return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ namespace Nz
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case BufferType::Index: target = GL::BufferTarget::ElementArray; break;
|
case BufferType::Index: target = GL::BufferTarget::ElementArray; break;
|
||||||
|
case BufferType::Storage: target = GL::BufferTarget::Storage; break;
|
||||||
case BufferType::Uniform: target = GL::BufferTarget::Uniform; break;
|
case BufferType::Uniform: target = GL::BufferTarget::Uniform; break;
|
||||||
case BufferType::Vertex: target = GL::BufferTarget::Array; break;
|
case BufferType::Vertex: target = GL::BufferTarget::Array; break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,9 @@ namespace Nz
|
||||||
if (m_referenceContext->IsExtensionSupported(GL::Extension::DepthClamp))
|
if (m_referenceContext->IsExtensionSupported(GL::Extension::DepthClamp))
|
||||||
m_deviceInfo.features.depthClamping = true;
|
m_deviceInfo.features.depthClamping = true;
|
||||||
|
|
||||||
|
if (m_referenceContext->IsExtensionSupported(GL::Extension::StorageBuffers))
|
||||||
|
m_deviceInfo.features.storageBuffers = true;
|
||||||
|
|
||||||
if (m_referenceContext->glPolygonMode) //< not supported in core OpenGL ES, but supported in OpenGL or with GL_NV_polygon_mode extension
|
if (m_referenceContext->glPolygonMode) //< not supported in core OpenGL ES, but supported in OpenGL or with GL_NV_polygon_mode extension
|
||||||
m_deviceInfo.features.nonSolidFaceFilling = true;
|
m_deviceInfo.features.nonSolidFaceFilling = true;
|
||||||
|
|
||||||
|
|
@ -74,6 +77,23 @@ namespace Nz
|
||||||
assert(minUboOffsetAlignment >= 1);
|
assert(minUboOffsetAlignment >= 1);
|
||||||
m_deviceInfo.limits.minUniformBufferOffsetAlignment = static_cast<UInt64>(minUboOffsetAlignment);
|
m_deviceInfo.limits.minUniformBufferOffsetAlignment = static_cast<UInt64>(minUboOffsetAlignment);
|
||||||
|
|
||||||
|
GLint maxUboBlockSize;
|
||||||
|
m_referenceContext->glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUboBlockSize);
|
||||||
|
|
||||||
|
assert(maxUboBlockSize >= 1);
|
||||||
|
m_deviceInfo.limits.maxUniformBufferSize = static_cast<UInt64>(maxUboBlockSize);
|
||||||
|
|
||||||
|
if (m_deviceInfo.features.storageBuffers)
|
||||||
|
{
|
||||||
|
GLint maxStorageBlockSize;
|
||||||
|
m_referenceContext->glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &maxStorageBlockSize);
|
||||||
|
|
||||||
|
assert(maxStorageBlockSize >= 1);
|
||||||
|
m_deviceInfo.limits.maxStorageBufferSize = static_cast<UInt64>(maxStorageBlockSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_deviceInfo.limits.maxStorageBufferSize = 0;
|
||||||
|
|
||||||
m_contexts.insert(m_referenceContext.get());
|
m_contexts.insert(m_referenceContext.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,16 @@ namespace Nz
|
||||||
return ShaderBindingPtr(PlacementNew(freeBindingMemory, *this, poolIndex, freeBindingId));
|
return ShaderBindingPtr(PlacementNew(freeBindingMemory, *this, poolIndex, freeBindingId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto OpenGLRenderPipelineLayout::GetStorageBufferDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t descriptorIndex) -> StorageBufferDescriptor&
|
||||||
|
{
|
||||||
|
assert(poolIndex < m_descriptorPools.size());
|
||||||
|
auto& pool = m_descriptorPools[poolIndex];
|
||||||
|
assert(!pool.freeBindings.Test(bindingIndex));
|
||||||
|
assert(descriptorIndex < m_maxDescriptorCount);
|
||||||
|
|
||||||
|
return pool.descriptors[bindingIndex * m_maxDescriptorCount + descriptorIndex].emplace<StorageBufferDescriptor>();
|
||||||
|
}
|
||||||
|
|
||||||
auto OpenGLRenderPipelineLayout::GetTextureDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t descriptorIndex) -> TextureDescriptor&
|
auto OpenGLRenderPipelineLayout::GetTextureDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t descriptorIndex) -> TextureDescriptor&
|
||||||
{
|
{
|
||||||
assert(poolIndex < m_descriptorPools.size());
|
assert(poolIndex < m_descriptorPools.size());
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,14 @@ namespace Nz
|
||||||
|
|
||||||
UInt32 bindingPoint = bindingMappingIt->second;
|
UInt32 bindingPoint = bindingMappingIt->second;
|
||||||
|
|
||||||
if constexpr (std::is_same_v<DescriptorType, OpenGLRenderPipelineLayout::TextureDescriptor>)
|
if constexpr (std::is_same_v<DescriptorType, OpenGLRenderPipelineLayout::StorageBufferDescriptor>)
|
||||||
|
{
|
||||||
|
if (bindingInfo.type != ShaderBindingType::StorageBuffer)
|
||||||
|
throw std::runtime_error("descriptor (set=" + std::to_string(setIndex) + ", binding=" + std::to_string(bindingIndex) + ") is not a storage buffer");
|
||||||
|
|
||||||
|
context.BindStorageBuffer(bindingPoint, descriptor.buffer, descriptor.offset, descriptor.size);
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<DescriptorType, OpenGLRenderPipelineLayout::TextureDescriptor>)
|
||||||
{
|
{
|
||||||
if (bindingInfo.type != ShaderBindingType::Texture)
|
if (bindingInfo.type != ShaderBindingType::Texture)
|
||||||
throw std::runtime_error("descriptor (set=" + std::to_string(setIndex) + ", binding=" + std::to_string(bindingIndex) + ") is not a texture");
|
throw std::runtime_error("descriptor (set=" + std::to_string(setIndex) + ", binding=" + std::to_string(bindingIndex) + ") is not a texture");
|
||||||
|
|
@ -63,8 +70,24 @@ namespace Nz
|
||||||
std::visit([&](auto&& arg)
|
std::visit([&](auto&& arg)
|
||||||
{
|
{
|
||||||
using T = std::decay_t<decltype(arg)>;
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
|
||||||
|
if constexpr (std::is_same_v<T, StorageBufferBinding>)
|
||||||
|
{
|
||||||
|
auto& storageDescriptor = m_owner.GetStorageBufferDescriptor(m_poolIndex, m_bindingIndex, binding.bindingIndex);
|
||||||
|
storageDescriptor.offset = arg.offset;
|
||||||
|
storageDescriptor.size = arg.range;
|
||||||
|
|
||||||
if constexpr (std::is_same_v<T, TextureBinding>)
|
if (OpenGLBuffer* glBuffer = static_cast<OpenGLBuffer*>(arg.buffer))
|
||||||
|
{
|
||||||
|
if (glBuffer->GetType() != BufferType::Storage)
|
||||||
|
throw std::runtime_error("expected storage buffer");
|
||||||
|
|
||||||
|
storageDescriptor.buffer = glBuffer->GetBuffer().GetObjectId();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
storageDescriptor.buffer = 0;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, TextureBinding>)
|
||||||
{
|
{
|
||||||
auto& textureDescriptor = m_owner.GetTextureDescriptor(m_poolIndex, m_bindingIndex, binding.bindingIndex);
|
auto& textureDescriptor = m_owner.GetTextureDescriptor(m_poolIndex, m_bindingIndex, binding.bindingIndex);
|
||||||
|
|
||||||
|
|
@ -103,7 +126,7 @@ namespace Nz
|
||||||
uboDescriptor.buffer = 0;
|
uboDescriptor.buffer = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor");
|
static_assert(AlwaysFalse<T>(), "non-exhaustive visitor");
|
||||||
|
|
||||||
}, binding.content);
|
}, binding.content);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,28 @@ namespace Nz::GL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Context::BindStorageBuffer(UInt32 storageUnit, GLuint buffer, GLintptr offset, GLsizeiptr size) const
|
||||||
|
{
|
||||||
|
if (storageUnit >= m_state.storageUnits.size())
|
||||||
|
throw std::runtime_error("unsupported storage buffer unit #" + std::to_string(storageUnit));
|
||||||
|
|
||||||
|
auto& unit = m_state.storageUnits[storageUnit];
|
||||||
|
if (unit.buffer != buffer || unit.offset != offset || unit.size != size)
|
||||||
|
{
|
||||||
|
if (!SetCurrentContext(this))
|
||||||
|
throw std::runtime_error("failed to activate context");
|
||||||
|
|
||||||
|
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, storageUnit, buffer, offset, size);
|
||||||
|
|
||||||
|
unit.buffer = buffer;
|
||||||
|
unit.offset = offset;
|
||||||
|
unit.size = size;
|
||||||
|
|
||||||
|
// glBindBufferRange does replace the currently bound buffer
|
||||||
|
m_state.bufferTargets[UnderlyingCast(BufferTarget::Storage)] = buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Context::BindTexture(TextureTarget target, GLuint texture) const
|
void Context::BindTexture(TextureTarget target, GLuint texture) const
|
||||||
{
|
{
|
||||||
BindTexture(m_state.currentTextureUnit, target, texture);
|
BindTexture(m_state.currentTextureUnit, target, texture);
|
||||||
|
|
@ -375,6 +397,12 @@ namespace Nz::GL
|
||||||
else if (m_supportedExtensions.count("GL_ARB_gl_spirv"))
|
else if (m_supportedExtensions.count("GL_ARB_gl_spirv"))
|
||||||
m_extensionStatus[UnderlyingCast(Extension::SpirV)] = ExtensionStatus::ARB;
|
m_extensionStatus[UnderlyingCast(Extension::SpirV)] = ExtensionStatus::ARB;
|
||||||
|
|
||||||
|
// Storage buffers (SSBO)
|
||||||
|
if ((m_params.type == ContextType::OpenGL && glVersion >= 430) || (m_params.type == ContextType::OpenGL_ES && glVersion >= 310))
|
||||||
|
m_extensionStatus[UnderlyingCast(Extension::StorageBuffers)] = ExtensionStatus::Core;
|
||||||
|
else if (m_supportedExtensions.count("GL_ARB_shader_storage_buffer_object"))
|
||||||
|
m_extensionStatus[UnderlyingCast(Extension::StorageBuffers)] = ExtensionStatus::ARB;
|
||||||
|
|
||||||
// Texture compression (S3tc)
|
// Texture compression (S3tc)
|
||||||
if (m_supportedExtensions.count("GL_EXT_texture_compression_s3tc"))
|
if (m_supportedExtensions.count("GL_EXT_texture_compression_s3tc"))
|
||||||
m_extensionStatus[UnderlyingCast(Extension::TextureCompressionS3tc)] = ExtensionStatus::EXT;
|
m_extensionStatus[UnderlyingCast(Extension::TextureCompressionS3tc)] = ExtensionStatus::EXT;
|
||||||
|
|
@ -449,7 +477,7 @@ namespace Nz::GL
|
||||||
GLint maxTextureUnits = -1;
|
GLint maxTextureUnits = -1;
|
||||||
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
|
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
|
||||||
if (maxTextureUnits < 32) //< OpenGL ES 3.0 requires at least 32 textures units
|
if (maxTextureUnits < 32) //< OpenGL ES 3.0 requires at least 32 textures units
|
||||||
NazaraWarning("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS is " + std::to_string(maxTextureUnits) + ", >= 32 expected");
|
NazaraWarning("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS is " + std::to_string(maxTextureUnits) + ", expected >= 32");
|
||||||
|
|
||||||
assert(maxTextureUnits > 0);
|
assert(maxTextureUnits > 0);
|
||||||
m_state.textureUnits.resize(maxTextureUnits);
|
m_state.textureUnits.resize(maxTextureUnits);
|
||||||
|
|
@ -457,11 +485,22 @@ namespace Nz::GL
|
||||||
GLint maxUniformBufferUnits = -1;
|
GLint maxUniformBufferUnits = -1;
|
||||||
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferUnits);
|
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferUnits);
|
||||||
if (maxUniformBufferUnits < 24) //< OpenGL ES 3.0 requires at least 24 uniform buffers units
|
if (maxUniformBufferUnits < 24) //< OpenGL ES 3.0 requires at least 24 uniform buffers units
|
||||||
NazaraWarning("GL_MAX_UNIFORM_BUFFER_BINDINGS is " + std::to_string(maxUniformBufferUnits) + ", >= 24 expected");
|
NazaraWarning("GL_MAX_UNIFORM_BUFFER_BINDINGS is " + std::to_string(maxUniformBufferUnits) + ", expected >= 24");
|
||||||
|
|
||||||
assert(maxUniformBufferUnits > 0);
|
assert(maxUniformBufferUnits > 0);
|
||||||
m_state.uboUnits.resize(maxUniformBufferUnits);
|
m_state.uboUnits.resize(maxUniformBufferUnits);
|
||||||
|
|
||||||
|
if (IsExtensionSupported(Extension::StorageBuffers))
|
||||||
|
{
|
||||||
|
GLint maxStorageBufferUnits = -1;
|
||||||
|
glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxStorageBufferUnits);
|
||||||
|
if (maxStorageBufferUnits < 24) //< OpenGL ES 3.1 requires at least 8 storage buffers units
|
||||||
|
NazaraWarning("GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS is " + std::to_string(maxUniformBufferUnits) + ", expected >= 8");
|
||||||
|
|
||||||
|
assert(maxStorageBufferUnits > 0);
|
||||||
|
m_state.storageUnits.resize(maxStorageBufferUnits);
|
||||||
|
}
|
||||||
|
|
||||||
std::array<GLint, 4> res;
|
std::array<GLint, 4> res;
|
||||||
|
|
||||||
glGetIntegerv(GL_SCISSOR_BOX, res.data());
|
glGetIntegerv(GL_SCISSOR_BOX, res.data());
|
||||||
|
|
|
||||||
|
|
@ -51,5 +51,11 @@ namespace Nz
|
||||||
NazaraWarning("non-solid face filling was enabled but device doesn't support it, disabling...");
|
NazaraWarning("non-solid face filling was enabled but device doesn't support it, disabling...");
|
||||||
enabledFeatures.nonSolidFaceFilling = false;
|
enabledFeatures.nonSolidFaceFilling = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (enabledFeatures.storageBuffers && !supportedFeatures.storageBuffers)
|
||||||
|
{
|
||||||
|
NazaraWarning("storage buffers support was enabled but device doesn't support it, disabling...");
|
||||||
|
enabledFeatures.storageBuffers = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,10 @@ namespace Nz
|
||||||
deviceInfo.features.anisotropicFiltering = physDevice.features.samplerAnisotropy;
|
deviceInfo.features.anisotropicFiltering = physDevice.features.samplerAnisotropy;
|
||||||
deviceInfo.features.depthClamping = physDevice.features.depthClamp;
|
deviceInfo.features.depthClamping = physDevice.features.depthClamp;
|
||||||
deviceInfo.features.nonSolidFaceFilling = physDevice.features.fillModeNonSolid;
|
deviceInfo.features.nonSolidFaceFilling = physDevice.features.fillModeNonSolid;
|
||||||
|
deviceInfo.features.storageBuffers = true;
|
||||||
|
|
||||||
deviceInfo.limits.minUniformBufferOffsetAlignment = physDevice.properties.limits.minUniformBufferOffsetAlignment;
|
deviceInfo.limits.maxStorageBufferSize = physDevice.properties.limits.maxStorageBufferRange;
|
||||||
|
deviceInfo.limits.maxUniformBufferSize = physDevice.properties.limits.maxUniformBufferRange;
|
||||||
|
|
||||||
switch (physDevice.properties.deviceType)
|
switch (physDevice.properties.deviceType)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,20 @@ namespace Nz
|
||||||
{
|
{
|
||||||
using T = std::decay_t<decltype(arg)>;
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
|
||||||
if constexpr (std::is_same_v<T, TextureBinding>)
|
if constexpr (std::is_same_v<T, StorageBufferBinding>)
|
||||||
|
{
|
||||||
|
VulkanBuffer* vkBuffer = static_cast<VulkanBuffer*>(arg.buffer);
|
||||||
|
|
||||||
|
VkDescriptorBufferInfo& bufferInfo = bufferBinding.emplace_back();
|
||||||
|
bufferInfo.buffer = (vkBuffer) ? vkBuffer->GetBuffer() : VK_NULL_HANDLE;
|
||||||
|
bufferInfo.offset = arg.offset;
|
||||||
|
bufferInfo.range = arg.range;
|
||||||
|
|
||||||
|
writeOp.descriptorCount = 1;
|
||||||
|
writeOp.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
||||||
|
writeOp.pBufferInfo = &bufferInfo;
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, TextureBinding>)
|
||||||
{
|
{
|
||||||
const VulkanTexture* vkTexture = static_cast<const VulkanTexture*>(arg.texture);
|
const VulkanTexture* vkTexture = static_cast<const VulkanTexture*>(arg.texture);
|
||||||
const VulkanTextureSampler* vkSampler = static_cast<const VulkanTextureSampler*>(arg.sampler);
|
const VulkanTextureSampler* vkSampler = static_cast<const VulkanTextureSampler*>(arg.sampler);
|
||||||
|
|
@ -60,7 +73,7 @@ namespace Nz
|
||||||
writeOp.pBufferInfo = &bufferInfo;
|
writeOp.pBufferInfo = &bufferInfo;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
static_assert(AlwaysFalse<T>::value, "non-exhaustive visitor");
|
static_assert(AlwaysFalse<T>(), "non-exhaustive visitor");
|
||||||
|
|
||||||
}, binding.content);
|
}, binding.content);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue