Add initial support for compute pipelines

This commit is contained in:
SirLynix
2022-12-24 11:54:55 +01:00
committed by Jérôme Leclercq
parent e4064997d8
commit 9578ba3ef5
57 changed files with 915 additions and 182 deletions

View File

@@ -23,6 +23,7 @@
namespace Nz
{
class OpenGLCommandPool;
class OpenGLComputePipeline;
class OpenGLFramebuffer;
class OpenGLRenderPass;
class OpenGLTexture;
@@ -38,8 +39,9 @@ namespace Nz
inline void BeginDebugRegion(const std::string_view& regionName, const Color& color);
inline void BindComputePipeline(const OpenGLComputePipeline* pipeline);
inline void BindIndexBuffer(GLuint indexBuffer, IndexType indexType, UInt64 offset = 0);
inline void BindPipeline(const OpenGLRenderPipeline* pipeline);
inline void BindRenderPipeline(const OpenGLRenderPipeline* pipeline);
inline void BindShaderBinding(const OpenGLRenderPipelineLayout& pipelineLayout, UInt32 set, const OpenGLShaderBinding* binding);
inline void BindVertexBuffer(UInt32 binding, GLuint vertexBuffer, UInt64 offset = 0);
inline void BlitTexture(const OpenGLTexture& source, const Boxui& sourceBox, const OpenGLTexture& target, const Boxui& targetBox, SamplerFilter filter = SamplerFilter::Nearest);
@@ -48,6 +50,8 @@ namespace Nz
inline void CopyBuffer(const UploadPool::Allocation& allocation, GLuint target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0);
inline void CopyTexture(const OpenGLTexture& source, const Boxui& sourceBox, const OpenGLTexture& target, const Vector3ui& targetPoint);
inline void Dispatch(UInt32 numGroupsX, UInt32 numGroupsY, UInt32 numGroupsZ);
inline void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0);
inline void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstIndex = 0, UInt32 firstInstance = 0);
@@ -89,6 +93,11 @@ namespace Nz
SamplerFilter filter;
};
struct ComputeStates
{
const OpenGLComputePipeline* pipeline = nullptr;
};
struct CopyBufferData
{
GLuint source;
@@ -114,6 +123,14 @@ namespace Nz
UInt64 targetOffset;
};
struct DispatchData
{
ComputeStates states;
UInt32 numGroupsX;
UInt32 numGroupsY;
UInt32 numGroupsZ;
};
struct DrawStates
{
struct VertexBuffer
@@ -168,13 +185,15 @@ namespace Nz
CopyBufferData,
CopyBufferFromMemoryData,
CopyTextureData,
DispatchData,
DrawData,
DrawIndexedData,
EndDebugRegionData,
SetFrameBufferData
>;
DrawStates m_currentStates;
ComputeStates m_currentComputeStates;
DrawStates m_currentDrawStates;
std::size_t m_bindingIndex;
std::size_t m_maxColorBufferCount;
std::size_t m_poolIndex;

View File

@@ -33,32 +33,37 @@ namespace Nz
m_commands.emplace_back(std::move(beginDebugRegion));
}
inline void OpenGLCommandBuffer::BindIndexBuffer(GLuint indexBuffer, IndexType indexType, UInt64 offset)
inline void OpenGLCommandBuffer::BindComputePipeline(const OpenGLComputePipeline* pipeline)
{
m_currentStates.indexBuffer = indexBuffer;
m_currentStates.indexBufferOffset = offset;
m_currentStates.indexBufferType = indexType;
m_currentComputeStates.pipeline = pipeline;
}
inline void OpenGLCommandBuffer::BindPipeline(const OpenGLRenderPipeline* pipeline)
inline void OpenGLCommandBuffer::BindIndexBuffer(GLuint indexBuffer, IndexType indexType, UInt64 offset)
{
m_currentStates.pipeline = pipeline;
m_currentDrawStates.indexBuffer = indexBuffer;
m_currentDrawStates.indexBufferOffset = offset;
m_currentDrawStates.indexBufferType = indexType;
}
inline void OpenGLCommandBuffer::BindRenderPipeline(const OpenGLRenderPipeline* pipeline)
{
m_currentDrawStates.pipeline = pipeline;
}
inline void OpenGLCommandBuffer::BindShaderBinding(const OpenGLRenderPipelineLayout& pipelineLayout, UInt32 set, const OpenGLShaderBinding* binding)
{
if (set >= m_currentStates.shaderBindings.size())
m_currentStates.shaderBindings.resize(set + 1);
if (set >= m_currentDrawStates.shaderBindings.size())
m_currentDrawStates.shaderBindings.resize(set + 1);
m_currentStates.shaderBindings[set] = std::make_pair(&pipelineLayout, binding);
m_currentDrawStates.shaderBindings[set] = std::make_pair(&pipelineLayout, binding);
}
inline void OpenGLCommandBuffer::BindVertexBuffer(UInt32 binding, GLuint vertexBuffer, UInt64 offset)
{
if (binding >= m_currentStates.vertexBuffers.size())
m_currentStates.vertexBuffers.resize(binding + 1);
if (binding >= m_currentDrawStates.vertexBuffers.size())
m_currentDrawStates.vertexBuffers.resize(binding + 1);
auto& vertexBufferData = m_currentStates.vertexBuffers[binding];
auto& vertexBufferData = m_currentDrawStates.vertexBuffers[binding];
vertexBufferData.offset = offset;
vertexBufferData.vertexBuffer = vertexBuffer;
}
@@ -113,13 +118,27 @@ namespace Nz
m_commands.emplace_back(std::move(copyTexture));
}
inline void OpenGLCommandBuffer::Dispatch(UInt32 numGroupsX, UInt32 numGroupsY, UInt32 numGroupsZ)
{
if (!m_currentComputeStates.pipeline)
throw std::runtime_error("no pipeline bound");
DispatchData dispatch;
dispatch.states = m_currentComputeStates;
dispatch.numGroupsX = numGroupsX;
dispatch.numGroupsY = numGroupsY;
dispatch.numGroupsZ = numGroupsZ;
m_commands.emplace_back(std::move(dispatch));
}
inline void OpenGLCommandBuffer::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance)
{
if (!m_currentStates.pipeline)
if (!m_currentDrawStates.pipeline)
throw std::runtime_error("no pipeline bound");
DrawData draw;
draw.states = m_currentStates;
draw.states = m_currentDrawStates;
draw.firstInstance = firstInstance;
draw.firstVertex = firstVertex;
draw.instanceCount = instanceCount;
@@ -130,11 +149,11 @@ namespace Nz
inline void OpenGLCommandBuffer::DrawIndexed(UInt32 indexCount, UInt32 instanceCount, UInt32 firstIndex, UInt32 firstInstance)
{
if (!m_currentStates.pipeline)
if (!m_currentDrawStates.pipeline)
throw std::runtime_error("no pipeline bound");
DrawIndexedData draw;
draw.states = m_currentStates;
draw.states = m_currentDrawStates;
draw.firstIndex = firstIndex;
draw.firstInstance = firstInstance;
draw.indexCount = indexCount;
@@ -177,17 +196,17 @@ namespace Nz
m_commands.emplace_back(std::move(setFramebuffer));
m_currentStates.shouldFlipY = (framebuffer.GetType() == FramebufferType::Window);
m_currentDrawStates.shouldFlipY = (framebuffer.GetType() == FramebufferType::Window);
}
inline void OpenGLCommandBuffer::SetScissor(const Recti& scissorRegion)
{
m_currentStates.scissorRegion = scissorRegion;
m_currentDrawStates.scissorRegion = scissorRegion;
}
inline void OpenGLCommandBuffer::SetViewport(const Recti& viewportRegion)
{
m_currentStates.viewportRegion = viewportRegion;
m_currentDrawStates.viewportRegion = viewportRegion;
}
}

View File

@@ -27,8 +27,9 @@ namespace Nz
void BeginDebugRegion(const std::string_view& regionName, const Color& color) override;
void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, const Recti& renderRect, const ClearValues* clearValues, std::size_t clearValueCount) override;
void BindComputePipeline(const ComputePipeline& pipeline) override;
void BindIndexBuffer(const RenderBuffer& indexBuffer, IndexType indexType, UInt64 offset = 0) override;
void BindPipeline(const RenderPipeline& pipeline) override;
void BindRenderPipeline(const RenderPipeline& pipeline) override;
void BindShaderBinding(UInt32 set, const ShaderBinding& binding) override;
void BindShaderBinding(const RenderPipelineLayout& pipelineLayout, UInt32 set, const ShaderBinding& binding) override;
void BindVertexBuffer(UInt32 binding, const RenderBuffer& vertexBuffer, UInt64 offset = 0) override;
@@ -39,6 +40,8 @@ namespace Nz
void CopyBuffer(const UploadPool::Allocation& allocation, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset = 0, UInt64 targetOffset = 0) override;
void CopyTexture(const Texture& fromTexture, const Boxui& fromBox, TextureLayout fromLayout, const Texture& toTexture, const Vector3ui& toPos, TextureLayout toLayout) override;
void Dispatch(UInt32 workgroupX, UInt32 workgroupY, UInt32 workgroupZ) override;
void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0) override;
void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstIndex = 0, UInt32 firstInstance = 0) override;

View File

@@ -0,0 +1,39 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - OpenGL renderer"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_OPENGLRENDERER_OPENGLCOMPUTEPIPELINE_HPP
#define NAZARA_OPENGLRENDERER_OPENGLCOMPUTEPIPELINE_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/OpenGLRenderer/Config.hpp>
#include <Nazara/OpenGLRenderer/Wrapper/Program.hpp>
#include <Nazara/Renderer/ComputePipeline.hpp>
#include <Nazara/Utils/MovablePtr.hpp>
#include <vector>
namespace Nz
{
class NAZARA_OPENGLRENDERER_API OpenGLComputePipeline : public ComputePipeline
{
public:
OpenGLComputePipeline(OpenGLDevice& device, ComputePipelineInfo pipelineInfo);
~OpenGLComputePipeline() = default;
void Apply(const GL::Context& context) const;
inline const ComputePipelineInfo& GetPipelineInfo() const override;
void UpdateDebugName(std::string_view name) override;
private:
ComputePipelineInfo m_pipelineInfo;
GL::Program m_program;
};
}
#include <Nazara/OpenGLRenderer/OpenGLComputePipeline.inl>
#endif // NAZARA_OPENGLRENDERER_OPENGLCOMPUTEPIPELINE_HPP

View File

@@ -0,0 +1,16 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - OpenGL renderer"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/OpenGLRenderer/OpenGLComputePipeline.hpp>
#include <Nazara/OpenGLRenderer/Debug.hpp>
namespace Nz
{
inline const ComputePipelineInfo& OpenGLComputePipeline::GetPipelineInfo() const
{
return m_pipelineInfo;
}
}
#include <Nazara/OpenGLRenderer/DebugOff.hpp>

View File

@@ -38,6 +38,7 @@ namespace Nz
std::shared_ptr<RenderBuffer> InstantiateBuffer(BufferType type, UInt64 size, BufferUsageFlags usageFlags, const void* initialData = nullptr) override;
std::shared_ptr<CommandPool> InstantiateCommandPool(QueueType queueType) override;
std::shared_ptr<ComputePipeline> InstantiateComputePipeline(ComputePipelineInfo pipelineInfo) override;
std::shared_ptr<Framebuffer> InstantiateFramebuffer(unsigned int width, unsigned int height, const std::shared_ptr<RenderPass>& renderPass, const std::vector<std::shared_ptr<Texture>>& attachments) override;
std::shared_ptr<RenderPass> InstantiateRenderPass(std::vector<RenderPass::Attachment> attachments, std::vector<RenderPass::SubpassDescription> subpassDescriptions, std::vector<RenderPass::SubpassDependency> subpassDependencies) override;
std::shared_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) override;

View File

@@ -43,6 +43,7 @@ namespace Nz
private:
struct DescriptorPool;
struct SampledTextureDescriptor;
struct StorageBufferDescriptor;
struct TextureDescriptor;
struct UniformBufferDescriptor;
@@ -50,12 +51,20 @@ namespace Nz
DescriptorPool& AllocatePool();
ShaderBindingPtr AllocateFromPool(std::size_t poolIndex, UInt32 setIndex);
template<typename F> void ForEachDescriptor(std::size_t poolIndex, std::size_t bindingIndex, F&& functor);
SampledTextureDescriptor& GetSampledTextureDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t descriptorIndex);
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);
UniformBufferDescriptor& GetUniformBufferDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t descriptorIndex);
void Release(ShaderBinding& binding);
inline void TryToShrink();
struct SampledTextureDescriptor
{
GLuint texture;
GLuint sampler;
GL::TextureTarget textureTarget;
};
struct StorageBufferDescriptor
{
GLuint buffer;
@@ -65,9 +74,12 @@ namespace Nz
struct TextureDescriptor
{
GLboolean layered;
GLenum access;
GLenum format;
GLint layer;
GLint level;
GLuint texture;
GLuint sampler;
GL::TextureTarget textureTarget;
};
struct UniformBufferDescriptor
@@ -77,7 +89,7 @@ namespace Nz
GLsizeiptr size;
};
using Descriptor = std::variant<std::monostate, StorageBufferDescriptor, TextureDescriptor, UniformBufferDescriptor>;
using Descriptor = std::variant<std::monostate, SampledTextureDescriptor, StorageBufferDescriptor, TextureDescriptor, UniformBufferDescriptor>;
struct DescriptorPool
{

View File

@@ -38,7 +38,7 @@ namespace Nz
OpenGLShaderBinding& operator=(OpenGLShaderBinding&&) = delete;
private:
void HandleTextureBinding(UInt32 bindingIndex, const TextureBinding& textureBinding);
void HandleTextureBinding(UInt32 bindingIndex, const SampledTextureBinding& textureBinding);
void Release() override;
OpenGLRenderPipelineLayout& m_owner;

View File

@@ -42,6 +42,7 @@ namespace Nz
inline GLenum ToOpenGL(SamplerWrap wrapMode);
inline GLenum ToOpenGL(nzsl::ShaderStageType stageType);
inline GLenum ToOpenGL(StencilOperation stencilOp);
inline GLenum ToOpenGL(TextureAccess textureAccess);
inline GLenum ToOpenGL(GL::BufferTarget bufferTarget);
inline GLenum ToOpenGL(GL::TextureTarget bufferTarget);

View File

@@ -229,6 +229,7 @@ namespace Nz
{
switch (stageType)
{
case nzsl::ShaderStageType::Compute: return GL_COMPUTE_SHADER;
case nzsl::ShaderStageType::Fragment: return GL_FRAGMENT_SHADER;
case nzsl::ShaderStageType::Vertex: return GL_VERTEX_SHADER;
}
@@ -255,6 +256,19 @@ namespace Nz
return {};
}
inline GLenum ToOpenGL(TextureAccess textureAccess)
{
switch (textureAccess)
{
case TextureAccess::ReadOnly: return GL_READ_ONLY;
case TextureAccess::ReadWrite: return GL_READ_WRITE;
case TextureAccess::WriteOnly: return GL_WRITE_ONLY;
}
NazaraError("Unhandled TextureAccess 0x" + NumberToString(UnderlyingCast(textureAccess), 16));
return {};
}
inline GLenum ToOpenGL(GL::BufferTarget bufferTarget)
{
switch (bufferTarget)

View File

@@ -54,9 +54,12 @@ namespace Nz::GL
enum class Extension
{
ClipControl,
ComputeShader,
DebugOutput,
DepthClamp,
PolygonMode,
ShaderImageLoadFormatted,
ShaderImageLoadStore,
SpirV,
StorageBuffers,
TextureCompressionS3tc,
@@ -127,6 +130,7 @@ namespace Nz::GL
void BindBuffer(BufferTarget target, GLuint buffer, bool force = false) const;
[[nodiscard]] GLenum BindFramebuffer(GLuint fbo) const;
void BindFramebuffer(FramebufferTarget target, GLuint fbo) const;
void BindImageTexture(GLuint imageUnit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) const;
void BindProgram(GLuint program) const;
void BindSampler(UInt32 textureUnit, GLuint sampler) const;
void BindStorageBuffer(UInt32 storageUnit, GLuint buffer, GLintptr offset, GLsizeiptr size) const;
@@ -145,11 +149,16 @@ namespace Nz::GL
virtual void EnableVerticalSync(bool enabled) = 0;
inline bool GetBoolean(GLenum name) const;
inline bool GetBoolean(GLenum name, GLuint index) const;
inline const OpenGLDevice* GetDevice() const;
inline ExtensionStatus GetExtensionStatus(Extension extension) const;
inline float GetFloat(GLenum name) const;
inline GLFunction GetFunctionByIndex(std::size_t funcIndex) const;
inline const OpenGLVaoCache& GetVaoCache() const;
template<typename T> T GetInteger(GLenum name) const;
template<typename T> T GetInteger(GLenum name, GLuint index) const;
inline const ContextParams& GetParams() const;
inline const OpenGLVaoCache& GetVaoCache() const;
inline bool IsExtensionSupported(Extension extension) const;
inline bool IsExtensionSupported(const std::string& extension) const;
@@ -232,6 +241,16 @@ namespace Nz::GL
GLsizeiptr size = 0;
};
struct ImageUnits
{
GLboolean layered = GL_FALSE;
GLenum access = GL_READ_ONLY;
GLenum format = GL_RGBA8;
GLint layer = 0;
GLint level = 0;
GLuint texture = 0;
};
struct TextureUnit
{
GLuint sampler = 0;
@@ -239,9 +258,10 @@ namespace Nz::GL
};
std::array<GLuint, UnderlyingCast(BufferTarget::Max) + 1> bufferTargets = { 0 };
std::vector<TextureUnit> textureUnits;
std::vector<BufferBinding> storageUnits;
std::vector<BufferBinding> uboUnits;
std::vector<ImageUnits> imageUnits;
std::vector<TextureUnit> textureUnits;
Box scissorBox;
Box viewport;
GLuint boundProgram = 0;

View File

@@ -15,6 +15,22 @@ namespace Nz::GL
return !m_hadAnyError;
}
inline bool Context::GetBoolean(GLenum name) const
{
GLboolean value;
glGetBooleanv(name, &value);
return value != GL_FALSE;
}
inline bool Context::GetBoolean(GLenum name, GLuint index) const
{
GLboolean value;
glGetBooleani_v(name, index, &value);
return value != GL_FALSE;
}
inline const OpenGLDevice* Context::GetDevice() const
{
return m_device;
@@ -25,15 +41,56 @@ namespace Nz::GL
return m_extensionStatus[UnderlyingCast(extension)];
}
inline float Context::GetFloat(GLenum name) const
{
GLfloat value;
glGetFloatv(name, &value);
return value;
}
inline GLFunction Context::GetFunctionByIndex(std::size_t funcIndex) const
{
assert(funcIndex < m_originalFunctionPointer.size());
return m_originalFunctionPointer[funcIndex];
}
inline const OpenGLVaoCache& Context::GetVaoCache() const
template<typename T>
T Context::GetInteger(GLenum name) const
{
return m_vaoCache;
if constexpr (std::is_same_v<T, Int64> || std::is_same_v<T, UInt64>)
{
GLint64 value;
glGetInteger64v(name, &value);
return SafeCast<T>(value);
}
else
{
GLint value;
glGetIntegerv(name, &value);
return SafeCast<T>(value);
}
}
template<typename T>
T Context::GetInteger(GLenum name, GLuint index) const
{
if constexpr (std::is_same_v<T, Int64> || std::is_same_v<T, UInt64>)
{
GLint64 value;
glGetInteger64i_v(name, index, &value);
return SafeCast<T>(value);
}
else
{
GLint value;
glGetIntegeri_v(name, index, &value);
return SafeCast<T>(value);
}
}
inline const ContextParams& Context::GetParams() const
@@ -41,6 +98,11 @@ namespace Nz::GL
return m_params;
}
inline const OpenGLVaoCache& Context::GetVaoCache() const
{
return m_vaoCache;
}
inline bool Context::IsExtensionSupported(Extension extension) const
{
return GetExtensionStatus(extension) != ExtensionStatus::NotSupported;

View File

@@ -91,7 +91,7 @@ namespace Nz::GL
EnsureContext();
if (m_context->glObjectLabel)
m_context->glObjectLabel(ObjectType, m_objectId, name.size(), name.data());
m_context->glObjectLabel(ObjectType, m_objectId, SafeCast<GLsizei>(name.size()), name.data());
}
}

View File

@@ -118,9 +118,13 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERPROC) (GLuint shader, const GLch
cb(glGetActiveUniformBlockiv, PFNGLGETACTIVEUNIFORMBLOCKIVPROC) \
cb(glGetActiveUniformBlockName, PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) \
cb(glGetBooleanv, PFNGLGETBOOLEANVPROC) \
cb(glGetBooleani_v, PFNGLGETBOOLEANI_VPROC) \
cb(glGetBufferParameteriv, PFNGLGETBUFFERPARAMETERIVPROC) \
cb(glGetError, PFNGLGETERRORPROC) \
cb(glGetFloatv, PFNGLGETFLOATVPROC) \
cb(glGetInteger64i_v, PFNGLGETINTEGER64I_VPROC) \
cb(glGetInteger64v, PFNGLGETINTEGER64VPROC) \
cb(glGetIntegeri_v, PFNGLGETINTEGERI_VPROC) \
cb(glGetIntegerv, PFNGLGETINTEGERVPROC) \
cb(glGetProgramBinary, PFNGLGETPROGRAMBINARYPROC) \
cb(glGetProgramInfoLog, PFNGLGETPROGRAMINFOLOGPROC) \
@@ -195,8 +199,11 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERPROC) (GLuint shader, const GLch
extCb(glDrawBuffer, PFNGLDRAWBUFFERPROC) \
extCb(glPolygonMode, PFNGLPOLYGONMODEPROC) \
/* OpenGL 4.2 - OpenGL ES 3.1 */\
extCb(glBindImageTexture, PFNGLBINDIMAGETEXTUREPROC) \
extCb(glMemoryBarrier, PFNGLMEMORYBARRIERPROC) \
extCb(glMemoryBarrierByRegion, PFNGLMEMORYBARRIERBYREGIONPROC) \
/* OpenGL 4.3 - OpenGL ES 3.1 */\
extCb(glDispatchCompute, PFNGLDISPATCHCOMPUTEPROC) \
/* OpenGL 4.3 - OpenGL ES 3.2 */\
extCb(glCopyImageSubData, PFNGLCOPYIMAGESUBDATAPROC) \
extCb(glDebugMessageCallback, PFNGLDEBUGMESSAGECALLBACKPROC) \