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

@ -151,7 +151,7 @@ int main()
textureBinding.setIndex = 0; textureBinding.setIndex = 0;
textureBinding.bindingIndex = 1; textureBinding.bindingIndex = 1;
textureBinding.shaderStageFlags = nzsl::ShaderStageType::Fragment; textureBinding.shaderStageFlags = nzsl::ShaderStageType::Fragment;
textureBinding.type = Nz::ShaderBindingType::Texture; textureBinding.type = Nz::ShaderBindingType::Sampler;
std::shared_ptr<Nz::RenderPipelineLayout> skyboxPipelineLayout = device->InstantiateRenderPipelineLayout(std::move(skyboxPipelineLayoutInfo)); std::shared_ptr<Nz::RenderPipelineLayout> skyboxPipelineLayout = device->InstantiateRenderPipelineLayout(std::move(skyboxPipelineLayoutInfo));
@ -275,7 +275,7 @@ int main()
0, 0,
i + 1, i + 1,
1, 1,
Nz::ShaderBindingType::Texture, Nz::ShaderBindingType::Sampler,
nzsl::ShaderStageType::Fragment, nzsl::ShaderStageType::Fragment,
}); });
} }
@ -367,7 +367,7 @@ int main()
fullscreenPipelineLayoutInfoViewer.bindings.push_back({ fullscreenPipelineLayoutInfoViewer.bindings.push_back({
0, 1, 1, 0, 1, 1,
Nz::ShaderBindingType::Texture, Nz::ShaderBindingType::Sampler,
nzsl::ShaderStageType::Fragment, nzsl::ShaderStageType::Fragment,
}); });
@ -452,7 +452,7 @@ int main()
bloomBlendPipelineLayoutInfo.bindings.push_back({ bloomBlendPipelineLayoutInfo.bindings.push_back({
0, 2, 1, 0, 2, 1,
Nz::ShaderBindingType::Texture, Nz::ShaderBindingType::Sampler,
nzsl::ShaderStageType::Fragment, nzsl::ShaderStageType::Fragment,
}); });
@ -476,7 +476,7 @@ int main()
fullscreenPipelineLayoutInfo.bindings.push_back({ fullscreenPipelineLayoutInfo.bindings.push_back({
0, 0, 1, 0, 0, 1,
Nz::ShaderBindingType::Texture, Nz::ShaderBindingType::Sampler,
nzsl::ShaderStageType::Fragment, nzsl::ShaderStageType::Fragment,
}); });
@ -504,7 +504,7 @@ int main()
}, },
{ {
0, 2, 1, 0, 2, 1,
Nz::ShaderBindingType::Texture, Nz::ShaderBindingType::Sampler,
nzsl::ShaderStageType::Fragment, nzsl::ShaderStageType::Fragment,
}, },
} }
@ -613,7 +613,7 @@ int main()
}, },
{ {
1, 1,
Nz::ShaderBinding::TextureBinding { Nz::ShaderBinding::SampledTextureBinding {
skyboxTexture.get(), skyboxTexture.get(),
textureSampler.get() textureSampler.get()
} }
@ -837,10 +837,10 @@ int main()
{ {
builder.BindShaderBinding(1, *lightingShaderBindings[i]); builder.BindShaderBinding(1, *lightingShaderBindings[i]);
builder.BindPipeline(*stencilPipeline); builder.BindRenderPipeline(*stencilPipeline);
builder.DrawIndexed(coneMeshGfx->GetIndexCount(0)); builder.DrawIndexed(coneMeshGfx->GetIndexCount(0));
builder.BindPipeline(*lightingPipeline); builder.BindRenderPipeline(*lightingPipeline);
builder.DrawIndexed(coneMeshGfx->GetIndexCount(0)); builder.DrawIndexed(coneMeshGfx->GetIndexCount(0));
} }
}); });
@ -862,7 +862,7 @@ int main()
builder.BindIndexBuffer(*cubeMeshGfx->GetIndexBuffer(0), Nz::IndexType::U16); builder.BindIndexBuffer(*cubeMeshGfx->GetIndexBuffer(0), Nz::IndexType::U16);
builder.BindVertexBuffer(0, *cubeMeshGfx->GetVertexBuffer(0)); builder.BindVertexBuffer(0, *cubeMeshGfx->GetVertexBuffer(0));
builder.BindPipeline(*skyboxPipeline); builder.BindRenderPipeline(*skyboxPipeline);
builder.DrawIndexed(Nz::SafeCast<Nz::UInt32>(cubeMeshGfx->GetIndexCount(0))); builder.DrawIndexed(Nz::SafeCast<Nz::UInt32>(cubeMeshGfx->GetIndexCount(0)));
@ -932,7 +932,7 @@ int main()
builder.BindShaderBinding(0, *godRaysShaderBinding); builder.BindShaderBinding(0, *godRaysShaderBinding);
builder.BindPipeline(*godraysPipeline); builder.BindRenderPipeline(*godraysPipeline);
builder.Draw(3); builder.Draw(3);
}); });
@ -948,7 +948,7 @@ int main()
builder.BindShaderBinding(0, *bloomBrightShaderBinding); builder.BindShaderBinding(0, *bloomBrightShaderBinding);
builder.BindPipeline(*bloomBrightPipeline); builder.BindRenderPipeline(*bloomBrightPipeline);
builder.Draw(3); builder.Draw(3);
}); });
@ -970,7 +970,7 @@ int main()
builder.SetViewport(env.renderRect); builder.SetViewport(env.renderRect);
builder.BindShaderBinding(0, *gaussianBlurShaderBinding[i * 2 + 0]); builder.BindShaderBinding(0, *gaussianBlurShaderBinding[i * 2 + 0]);
builder.BindPipeline(*gaussianBlurPipeline); builder.BindRenderPipeline(*gaussianBlurPipeline);
builder.Draw(3); builder.Draw(3);
}); });
@ -990,7 +990,7 @@ int main()
builder.SetViewport(env.renderRect); builder.SetViewport(env.renderRect);
builder.BindShaderBinding(0, *gaussianBlurShaderBinding[i * 2 + 1]); builder.BindShaderBinding(0, *gaussianBlurShaderBinding[i * 2 + 1]);
builder.BindPipeline(*gaussianBlurPipeline); builder.BindRenderPipeline(*gaussianBlurPipeline);
builder.Draw(3); builder.Draw(3);
}); });
@ -1011,7 +1011,7 @@ int main()
builder.SetViewport(env.renderRect); builder.SetViewport(env.renderRect);
// Blend bloom // Blend bloom
builder.BindPipeline(*bloomBlendPipeline); builder.BindRenderPipeline(*bloomBlendPipeline);
for (std::size_t i = 0; i < BloomSubdivisionCount; ++i) for (std::size_t i = 0; i < BloomSubdivisionCount; ++i)
{ {
builder.BindShaderBinding(0, *bloomBlendShaderBinding[i]); builder.BindShaderBinding(0, *bloomBlendShaderBinding[i]);
@ -1046,7 +1046,7 @@ int main()
builder.SetViewport(env.renderRect); builder.SetViewport(env.renderRect);
builder.BindShaderBinding(0, *toneMappingShaderBinding); builder.BindShaderBinding(0, *toneMappingShaderBinding);
builder.BindPipeline(*toneMappingPipeline); builder.BindRenderPipeline(*toneMappingPipeline);
builder.Draw(3); builder.Draw(3);
}); });
@ -1218,21 +1218,21 @@ int main()
}, },
{ {
1, 1,
Nz::ShaderBinding::TextureBinding { Nz::ShaderBinding::SampledTextureBinding {
bakedGraph.GetAttachmentTexture(colorTexture).get(), bakedGraph.GetAttachmentTexture(colorTexture).get(),
textureSampler.get() textureSampler.get()
} }
}, },
{ {
2, 2,
Nz::ShaderBinding::TextureBinding { Nz::ShaderBinding::SampledTextureBinding {
bakedGraph.GetAttachmentTexture(normalTexture).get(), bakedGraph.GetAttachmentTexture(normalTexture).get(),
textureSampler.get() textureSampler.get()
} }
}, },
{ {
3, 3,
Nz::ShaderBinding::TextureBinding { Nz::ShaderBinding::SampledTextureBinding {
bakedGraph.GetAttachmentTexture(positionTexture).get(), bakedGraph.GetAttachmentTexture(positionTexture).get(),
textureSampler.get() textureSampler.get()
} }
@ -1271,7 +1271,7 @@ int main()
}, },
{ {
1, 1,
Nz::ShaderBinding::TextureBinding { Nz::ShaderBinding::SampledTextureBinding {
bakedGraph.GetAttachmentTexture(lightOutput).get(), bakedGraph.GetAttachmentTexture(lightOutput).get(),
textureSampler.get() textureSampler.get()
} }
@ -1296,7 +1296,7 @@ int main()
}, },
{ {
1, 1,
Nz::ShaderBinding::TextureBinding { Nz::ShaderBinding::SampledTextureBinding {
bakedGraph.GetAttachmentTexture((i == 0 && j == 0) ? bloomBrightOutput : bloomTextures[bloomTextureIndex++]).get(), bakedGraph.GetAttachmentTexture((i == 0 && j == 0) ? bloomBrightOutput : bloomTextures[bloomTextureIndex++]).get(),
textureSampler.get() textureSampler.get()
} }
@ -1331,7 +1331,7 @@ int main()
},*/ },*/
{ {
2, 2,
Nz::ShaderBinding::TextureBinding { Nz::ShaderBinding::SampledTextureBinding {
bakedGraph.GetAttachmentTexture(bloomTextures[i * 2 + 1]).get(), bakedGraph.GetAttachmentTexture(bloomTextures[i * 2 + 1]).get(),
textureSampler.get() textureSampler.get()
} }
@ -1345,7 +1345,7 @@ int main()
bloomBlitBinding->Update({ bloomBlitBinding->Update({
{ {
0, 0,
Nz::ShaderBinding::TextureBinding { Nz::ShaderBinding::SampledTextureBinding {
bakedGraph.GetAttachmentTexture(lightOutput).get(), bakedGraph.GetAttachmentTexture(lightOutput).get(),
textureSampler.get() textureSampler.get()
} }
@ -1358,7 +1358,7 @@ int main()
bloomSkipBlit->Update({ bloomSkipBlit->Update({
{ {
0, 0,
Nz::ShaderBinding::TextureBinding { Nz::ShaderBinding::SampledTextureBinding {
bakedGraph.GetAttachmentTexture(lightOutput).get(), bakedGraph.GetAttachmentTexture(lightOutput).get(),
textureSampler.get() textureSampler.get()
} }
@ -1385,7 +1385,7 @@ int main()
}, },
{ {
2, 2,
Nz::ShaderBinding::TextureBinding { Nz::ShaderBinding::SampledTextureBinding {
bakedGraph.GetAttachmentTexture(occluderTexture).get(), bakedGraph.GetAttachmentTexture(occluderTexture).get(),
textureSampler.get() textureSampler.get()
} }
@ -1405,7 +1405,7 @@ int main()
}, },
{ {
1, 1,
Nz::ShaderBinding::TextureBinding { Nz::ShaderBinding::SampledTextureBinding {
bakedGraph.GetAttachmentTexture(bloomOutput).get(), bakedGraph.GetAttachmentTexture(bloomOutput).get(),
textureSampler.get() textureSampler.get()
} }
@ -1432,7 +1432,7 @@ int main()
},*/ },*/
{ {
2, 2,
Nz::ShaderBinding::TextureBinding { Nz::ShaderBinding::SampledTextureBinding {
bakedGraph.GetAttachmentTexture(godRaysTexture).get(), bakedGraph.GetAttachmentTexture(godRaysTexture).get(),
textureSampler.get() textureSampler.get()
} }
@ -1445,7 +1445,7 @@ int main()
finalBlitBinding->Update({ finalBlitBinding->Update({
{ {
0, 0,
Nz::ShaderBinding::TextureBinding { Nz::ShaderBinding::SampledTextureBinding {
bakedGraph.GetAttachmentTexture(toneMappingOutput).get(), bakedGraph.GetAttachmentTexture(toneMappingOutput).get(),
textureSampler.get() textureSampler.get()
} }
@ -1548,7 +1548,7 @@ int main()
builder.SetViewport(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) }); builder.SetViewport(Nz::Recti{ 0, 0, int(windowSize.x), int(windowSize.y) });
builder.BindShaderBinding(0, *finalBlitBinding); builder.BindShaderBinding(0, *finalBlitBinding);
builder.BindPipeline(*fullscreenPipeline); builder.BindRenderPipeline(*fullscreenPipeline);
builder.Draw(3); builder.Draw(3);
} }

View File

@ -200,7 +200,7 @@ int main()
pipelineTextureBinding.setIndex = 1; pipelineTextureBinding.setIndex = 1;
pipelineTextureBinding.bindingIndex = 0; pipelineTextureBinding.bindingIndex = 0;
pipelineTextureBinding.shaderStageFlags = nzsl::ShaderStageType::Fragment; pipelineTextureBinding.shaderStageFlags = nzsl::ShaderStageType::Fragment;
pipelineTextureBinding.type = Nz::ShaderBindingType::Texture; pipelineTextureBinding.type = Nz::ShaderBindingType::Sampler;
std::shared_ptr<Nz::RenderPipelineLayout> renderPipelineLayout = device->InstantiateRenderPipelineLayout(std::move(pipelineLayoutInfo)); std::shared_ptr<Nz::RenderPipelineLayout> renderPipelineLayout = device->InstantiateRenderPipelineLayout(std::move(pipelineLayoutInfo));
@ -218,14 +218,14 @@ int main()
} }
}); });
Nz::ShaderBinding::TextureBinding textureBinding { Nz::ShaderBinding::SampledTextureBinding textureBinding {
texture.get(), textureSampler.get() texture.get(), textureSampler.get()
}; };
textureShaderBinding->Update({ textureShaderBinding->Update({
{ {
0, 0,
Nz::ShaderBinding::TextureBindings { Nz::ShaderBinding::SampledTextureBindings {
1, &textureBinding 1, &textureBinding
} }
} }
@ -389,7 +389,7 @@ int main()
builder.BeginRenderPass(windowRT->GetFramebuffer(frame.GetFramebufferIndex()), windowRT->GetRenderPass(), renderRect, { clearValues[0], clearValues[1] }); builder.BeginRenderPass(windowRT->GetFramebuffer(frame.GetFramebufferIndex()), windowRT->GetRenderPass(), renderRect, { clearValues[0], clearValues[1] });
{ {
builder.BindIndexBuffer(*renderBufferIB, Nz::IndexType::U16); builder.BindIndexBuffer(*renderBufferIB, Nz::IndexType::U16);
builder.BindPipeline(*pipeline); builder.BindRenderPipeline(*pipeline);
builder.BindVertexBuffer(0, *renderBufferVB); builder.BindVertexBuffer(0, *renderBufferVB);
builder.BindShaderBinding(0, *viewerShaderBinding); builder.BindShaderBinding(0, *viewerShaderBinding);
builder.BindShaderBinding(1, *textureShaderBinding); builder.BindShaderBinding(1, *textureShaderBinding);

View File

@ -45,6 +45,13 @@ namespace Nz
UInt32 bindingIndex; UInt32 bindingIndex;
}; };
struct ExternalSampler : ExternalData
{
UInt32 arraySize;
nzsl::ImageType imageType;
nzsl::Ast::PrimitiveType sampledType;
};
struct ExternalStorageBlock : ExternalData struct ExternalStorageBlock : ExternalData
{ {
std::size_t structIndex; std::size_t structIndex;
@ -53,8 +60,10 @@ namespace Nz
struct ExternalTexture : ExternalData struct ExternalTexture : ExternalData
{ {
UInt32 arraySize; UInt32 arraySize;
nzsl::AccessPolicy accessPolicy;
nzsl::ImageFormat imageFormat;
nzsl::ImageType imageType; nzsl::ImageType imageType;
nzsl::Ast::PrimitiveType sampledType; nzsl::Ast::PrimitiveType baseType;
}; };
struct ExternalUniformBlock : ExternalData struct ExternalUniformBlock : ExternalData
@ -64,8 +73,9 @@ namespace Nz
struct ExternalBlockData struct ExternalBlockData
{ {
std::unordered_map<std::string /*tag*/, ExternalSampler> samplers;
std::unordered_map<std::string /*tag*/, ExternalStorageBlock> storageBlocks; std::unordered_map<std::string /*tag*/, ExternalStorageBlock> storageBlocks;
std::unordered_map<std::string /*tag*/, ExternalTexture> samplers; std::unordered_map<std::string /*tag*/, ExternalTexture> textures;
std::unordered_map<std::string /*tag*/, ExternalUniformBlock> uniformBlocks; std::unordered_map<std::string /*tag*/, ExternalUniformBlock> uniformBlocks;
}; };

View File

@ -33,7 +33,7 @@ namespace Nz
private: private:
std::vector<ShaderBinding::Binding> m_bindingCache; std::vector<ShaderBinding::Binding> m_bindingCache;
std::vector<ShaderBinding::TextureBinding> m_textureBindingCache; std::vector<ShaderBinding::SampledTextureBinding> m_textureBindingCache;
RenderElementPool<RenderSubmesh> m_submeshPool; RenderElementPool<RenderSubmesh> m_submeshPool;
}; };

View File

@ -11,8 +11,8 @@
#include <Nazara/Core/Color.hpp> #include <Nazara/Core/Color.hpp>
#include <Nazara/Graphics/Config.hpp> #include <Nazara/Graphics/Config.hpp>
#include <Nazara/Graphics/InstancedRenderable.hpp> #include <Nazara/Graphics/InstancedRenderable.hpp>
#include <Nazara/Utils/Bitset.hpp>
#include <Nazara/Utility/VertexStruct.hpp> #include <Nazara/Utility/VertexStruct.hpp>
#include <Nazara/Utils/Bitset.hpp>
#include <memory> #include <memory>
namespace Nz namespace Nz

View File

@ -23,6 +23,7 @@
namespace Nz namespace Nz
{ {
class OpenGLCommandPool; class OpenGLCommandPool;
class OpenGLComputePipeline;
class OpenGLFramebuffer; class OpenGLFramebuffer;
class OpenGLRenderPass; class OpenGLRenderPass;
class OpenGLTexture; class OpenGLTexture;
@ -38,8 +39,9 @@ namespace Nz
inline void BeginDebugRegion(const std::string_view& regionName, const Color& color); 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 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 BindShaderBinding(const OpenGLRenderPipelineLayout& pipelineLayout, UInt32 set, const OpenGLShaderBinding* binding);
inline void BindVertexBuffer(UInt32 binding, GLuint vertexBuffer, UInt64 offset = 0); 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); 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 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 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 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); inline void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstIndex = 0, UInt32 firstInstance = 0);
@ -89,6 +93,11 @@ namespace Nz
SamplerFilter filter; SamplerFilter filter;
}; };
struct ComputeStates
{
const OpenGLComputePipeline* pipeline = nullptr;
};
struct CopyBufferData struct CopyBufferData
{ {
GLuint source; GLuint source;
@ -114,6 +123,14 @@ namespace Nz
UInt64 targetOffset; UInt64 targetOffset;
}; };
struct DispatchData
{
ComputeStates states;
UInt32 numGroupsX;
UInt32 numGroupsY;
UInt32 numGroupsZ;
};
struct DrawStates struct DrawStates
{ {
struct VertexBuffer struct VertexBuffer
@ -168,13 +185,15 @@ namespace Nz
CopyBufferData, CopyBufferData,
CopyBufferFromMemoryData, CopyBufferFromMemoryData,
CopyTextureData, CopyTextureData,
DispatchData,
DrawData, DrawData,
DrawIndexedData, DrawIndexedData,
EndDebugRegionData, EndDebugRegionData,
SetFrameBufferData SetFrameBufferData
>; >;
DrawStates m_currentStates; ComputeStates m_currentComputeStates;
DrawStates m_currentDrawStates;
std::size_t m_bindingIndex; std::size_t m_bindingIndex;
std::size_t m_maxColorBufferCount; std::size_t m_maxColorBufferCount;
std::size_t m_poolIndex; std::size_t m_poolIndex;

View File

@ -33,32 +33,37 @@ namespace Nz
m_commands.emplace_back(std::move(beginDebugRegion)); 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_currentComputeStates.pipeline = pipeline;
m_currentStates.indexBufferOffset = offset;
m_currentStates.indexBufferType = indexType;
} }
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) inline void OpenGLCommandBuffer::BindShaderBinding(const OpenGLRenderPipelineLayout& pipelineLayout, UInt32 set, const OpenGLShaderBinding* binding)
{ {
if (set >= m_currentStates.shaderBindings.size()) if (set >= m_currentDrawStates.shaderBindings.size())
m_currentStates.shaderBindings.resize(set + 1); 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) inline void OpenGLCommandBuffer::BindVertexBuffer(UInt32 binding, GLuint vertexBuffer, UInt64 offset)
{ {
if (binding >= m_currentStates.vertexBuffers.size()) if (binding >= m_currentDrawStates.vertexBuffers.size())
m_currentStates.vertexBuffers.resize(binding + 1); m_currentDrawStates.vertexBuffers.resize(binding + 1);
auto& vertexBufferData = m_currentStates.vertexBuffers[binding]; auto& vertexBufferData = m_currentDrawStates.vertexBuffers[binding];
vertexBufferData.offset = offset; vertexBufferData.offset = offset;
vertexBufferData.vertexBuffer = vertexBuffer; vertexBufferData.vertexBuffer = vertexBuffer;
} }
@ -113,13 +118,27 @@ namespace Nz
m_commands.emplace_back(std::move(copyTexture)); 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) 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"); throw std::runtime_error("no pipeline bound");
DrawData draw; DrawData draw;
draw.states = m_currentStates; draw.states = m_currentDrawStates;
draw.firstInstance = firstInstance; draw.firstInstance = firstInstance;
draw.firstVertex = firstVertex; draw.firstVertex = firstVertex;
draw.instanceCount = instanceCount; draw.instanceCount = instanceCount;
@ -130,11 +149,11 @@ namespace Nz
inline void OpenGLCommandBuffer::DrawIndexed(UInt32 indexCount, UInt32 instanceCount, UInt32 firstIndex, UInt32 firstInstance) 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"); throw std::runtime_error("no pipeline bound");
DrawIndexedData draw; DrawIndexedData draw;
draw.states = m_currentStates; draw.states = m_currentDrawStates;
draw.firstIndex = firstIndex; draw.firstIndex = firstIndex;
draw.firstInstance = firstInstance; draw.firstInstance = firstInstance;
draw.indexCount = indexCount; draw.indexCount = indexCount;
@ -177,17 +196,17 @@ namespace Nz
m_commands.emplace_back(std::move(setFramebuffer)); 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) inline void OpenGLCommandBuffer::SetScissor(const Recti& scissorRegion)
{ {
m_currentStates.scissorRegion = scissorRegion; m_currentDrawStates.scissorRegion = scissorRegion;
} }
inline void OpenGLCommandBuffer::SetViewport(const Recti& viewportRegion) 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 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 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 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(UInt32 set, const ShaderBinding& binding) override;
void BindShaderBinding(const RenderPipelineLayout& pipelineLayout, 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; 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 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 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 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; 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<RenderBuffer> InstantiateBuffer(BufferType type, UInt64 size, BufferUsageFlags usageFlags, const void* initialData = nullptr) override;
std::shared_ptr<CommandPool> InstantiateCommandPool(QueueType queueType) 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<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<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; std::shared_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) override;

View File

@ -43,6 +43,7 @@ namespace Nz
private: private:
struct DescriptorPool; struct DescriptorPool;
struct SampledTextureDescriptor;
struct StorageBufferDescriptor; struct StorageBufferDescriptor;
struct TextureDescriptor; struct TextureDescriptor;
struct UniformBufferDescriptor; struct UniformBufferDescriptor;
@ -50,12 +51,20 @@ namespace Nz
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);
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); 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 SampledTextureDescriptor
{
GLuint texture;
GLuint sampler;
GL::TextureTarget textureTarget;
};
struct StorageBufferDescriptor struct StorageBufferDescriptor
{ {
GLuint buffer; GLuint buffer;
@ -65,9 +74,12 @@ namespace Nz
struct TextureDescriptor struct TextureDescriptor
{ {
GLboolean layered;
GLenum access;
GLenum format;
GLint layer;
GLint level;
GLuint texture; GLuint texture;
GLuint sampler;
GL::TextureTarget textureTarget;
}; };
struct UniformBufferDescriptor struct UniformBufferDescriptor
@ -77,7 +89,7 @@ namespace Nz
GLsizeiptr size; GLsizeiptr size;
}; };
using Descriptor = std::variant<std::monostate, StorageBufferDescriptor, TextureDescriptor, UniformBufferDescriptor>; using Descriptor = std::variant<std::monostate, SampledTextureDescriptor, StorageBufferDescriptor, TextureDescriptor, UniformBufferDescriptor>;
struct DescriptorPool struct DescriptorPool
{ {

View File

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

View File

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

View File

@ -229,6 +229,7 @@ namespace Nz
{ {
switch (stageType) switch (stageType)
{ {
case nzsl::ShaderStageType::Compute: return GL_COMPUTE_SHADER;
case nzsl::ShaderStageType::Fragment: return GL_FRAGMENT_SHADER; case nzsl::ShaderStageType::Fragment: return GL_FRAGMENT_SHADER;
case nzsl::ShaderStageType::Vertex: return GL_VERTEX_SHADER; case nzsl::ShaderStageType::Vertex: return GL_VERTEX_SHADER;
} }
@ -255,6 +256,19 @@ namespace Nz
return {}; 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) inline GLenum ToOpenGL(GL::BufferTarget bufferTarget)
{ {
switch (bufferTarget) switch (bufferTarget)

View File

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

View File

@ -15,6 +15,22 @@ namespace Nz::GL
return !m_hadAnyError; 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 inline const OpenGLDevice* Context::GetDevice() const
{ {
return m_device; return m_device;
@ -25,15 +41,56 @@ namespace Nz::GL
return m_extensionStatus[UnderlyingCast(extension)]; 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 inline GLFunction Context::GetFunctionByIndex(std::size_t funcIndex) const
{ {
assert(funcIndex < m_originalFunctionPointer.size()); assert(funcIndex < m_originalFunctionPointer.size());
return m_originalFunctionPointer[funcIndex]; 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 inline const ContextParams& Context::GetParams() const
@ -41,6 +98,11 @@ namespace Nz::GL
return m_params; return m_params;
} }
inline const OpenGLVaoCache& Context::GetVaoCache() const
{
return m_vaoCache;
}
inline bool Context::IsExtensionSupported(Extension extension) const inline bool Context::IsExtensionSupported(Extension extension) const
{ {
return GetExtensionStatus(extension) != ExtensionStatus::NotSupported; return GetExtensionStatus(extension) != ExtensionStatus::NotSupported;

View File

@ -91,7 +91,7 @@ namespace Nz::GL
EnsureContext(); EnsureContext();
if (m_context->glObjectLabel) 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(glGetActiveUniformBlockiv, PFNGLGETACTIVEUNIFORMBLOCKIVPROC) \
cb(glGetActiveUniformBlockName, PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) \ cb(glGetActiveUniformBlockName, PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) \
cb(glGetBooleanv, PFNGLGETBOOLEANVPROC) \ cb(glGetBooleanv, PFNGLGETBOOLEANVPROC) \
cb(glGetBooleani_v, PFNGLGETBOOLEANI_VPROC) \
cb(glGetBufferParameteriv, PFNGLGETBUFFERPARAMETERIVPROC) \ cb(glGetBufferParameteriv, PFNGLGETBUFFERPARAMETERIVPROC) \
cb(glGetError, PFNGLGETERRORPROC) \ cb(glGetError, PFNGLGETERRORPROC) \
cb(glGetFloatv, PFNGLGETFLOATVPROC) \ cb(glGetFloatv, PFNGLGETFLOATVPROC) \
cb(glGetInteger64i_v, PFNGLGETINTEGER64I_VPROC) \
cb(glGetInteger64v, PFNGLGETINTEGER64VPROC) \
cb(glGetIntegeri_v, PFNGLGETINTEGERI_VPROC) \
cb(glGetIntegerv, PFNGLGETINTEGERVPROC) \ cb(glGetIntegerv, PFNGLGETINTEGERVPROC) \
cb(glGetProgramBinary, PFNGLGETPROGRAMBINARYPROC) \ cb(glGetProgramBinary, PFNGLGETPROGRAMBINARYPROC) \
cb(glGetProgramInfoLog, PFNGLGETPROGRAMINFOLOGPROC) \ cb(glGetProgramInfoLog, PFNGLGETPROGRAMINFOLOGPROC) \
@ -195,8 +199,11 @@ typedef void (GL_APIENTRYP PFNGLSPECIALIZESHADERPROC) (GLuint shader, const GLch
extCb(glDrawBuffer, PFNGLDRAWBUFFERPROC) \ extCb(glDrawBuffer, PFNGLDRAWBUFFERPROC) \
extCb(glPolygonMode, PFNGLPOLYGONMODEPROC) \ extCb(glPolygonMode, PFNGLPOLYGONMODEPROC) \
/* OpenGL 4.2 - OpenGL ES 3.1 */\ /* OpenGL 4.2 - OpenGL ES 3.1 */\
extCb(glBindImageTexture, PFNGLBINDIMAGETEXTUREPROC) \
extCb(glMemoryBarrier, PFNGLMEMORYBARRIERPROC) \ extCb(glMemoryBarrier, PFNGLMEMORYBARRIERPROC) \
extCb(glMemoryBarrierByRegion, PFNGLMEMORYBARRIERBYREGIONPROC) \ extCb(glMemoryBarrierByRegion, PFNGLMEMORYBARRIERBYREGIONPROC) \
/* OpenGL 4.3 - OpenGL ES 3.1 */\
extCb(glDispatchCompute, PFNGLDISPATCHCOMPUTEPROC) \
/* OpenGL 4.3 - OpenGL ES 3.2 */\ /* OpenGL 4.3 - OpenGL ES 3.2 */\
extCb(glCopyImageSubData, PFNGLCOPYIMAGESUBDATAPROC) \ extCb(glCopyImageSubData, PFNGLCOPYIMAGESUBDATAPROC) \
extCb(glDebugMessageCallback, PFNGLDEBUGMESSAGECALLBACKPROC) \ extCb(glDebugMessageCallback, PFNGLDEBUGMESSAGECALLBACKPROC) \

View File

@ -20,6 +20,7 @@
namespace Nz namespace Nz
{ {
class ComputePipeline;
class Framebuffer; class Framebuffer;
class RenderPass; class RenderPass;
class RenderPipeline; class RenderPipeline;
@ -42,8 +43,9 @@ namespace Nz
inline void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, const Recti& renderRect); inline void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, const Recti& renderRect);
inline void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, const Recti& renderRect, std::initializer_list<ClearValues> clearValues); inline void BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, const Recti& renderRect, std::initializer_list<ClearValues> clearValues);
virtual void BindComputePipeline(const ComputePipeline& pipeline) = 0;
virtual void BindIndexBuffer(const RenderBuffer& indexBuffer, IndexType indexType, UInt64 offset = 0) = 0; virtual void BindIndexBuffer(const RenderBuffer& indexBuffer, IndexType indexType, UInt64 offset = 0) = 0;
virtual void BindPipeline(const RenderPipeline& pipeline) = 0; virtual void BindRenderPipeline(const RenderPipeline& pipeline) = 0;
virtual void BindShaderBinding(UInt32 set, const ShaderBinding& binding) = 0; virtual void BindShaderBinding(UInt32 set, const ShaderBinding& binding) = 0;
virtual void BindShaderBinding(const RenderPipelineLayout& pipelineLayout, UInt32 set, const ShaderBinding& binding) = 0; virtual void BindShaderBinding(const RenderPipelineLayout& pipelineLayout, UInt32 set, const ShaderBinding& binding) = 0;
virtual void BindVertexBuffer(UInt32 binding, const RenderBuffer& vertexBuffer, UInt64 offset = 0) = 0; virtual void BindVertexBuffer(UInt32 binding, const RenderBuffer& vertexBuffer, UInt64 offset = 0) = 0;
@ -59,6 +61,8 @@ namespace Nz
virtual void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0) = 0; virtual void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0) = 0;
virtual void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstIndex = 0, UInt32 firstInstance = 0) = 0; virtual void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstIndex = 0, UInt32 firstInstance = 0) = 0;
virtual void Dispatch(UInt32 workgroupX, UInt32 workgroupY, UInt32 workgroupZ) = 0;
virtual void EndDebugRegion() = 0; virtual void EndDebugRegion() = 0;
virtual void EndRenderPass() = 0; virtual void EndRenderPass() = 0;

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 - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_RENDERER_COMPUTEPIPELINE_HPP
#define NAZARA_RENDERER_COMPUTEPIPELINE_HPP
#include <Nazara/Renderer/RenderPipelineLayout.hpp>
#include <Nazara/Renderer/ShaderModule.hpp>
#include <Nazara/Utility/Enums.hpp>
namespace Nz
{
class RenderPipelineLayout;
class ShaderModule;
struct ComputePipelineInfo
{
std::shared_ptr<RenderPipelineLayout> pipelineLayout;
std::shared_ptr<ShaderModule> shaderModule;
};
class NAZARA_RENDERER_API ComputePipeline
{
public:
ComputePipeline() = default;
virtual ~ComputePipeline();
virtual const ComputePipelineInfo& GetPipelineInfo() const = 0;
virtual void UpdateDebugName(std::string_view name) = 0;
};
}
#include <Nazara/Renderer/ComputePipeline.inl>
#endif // NAZARA_RENDERER_COMPUTEPIPELINE_HPP

View File

@ -0,0 +1,13 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/ComputePipeline.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Renderer/Debug.hpp>
namespace Nz
{
}
#include <Nazara/Renderer/DebugOff.hpp>

View File

@ -165,6 +165,7 @@ namespace Nz
enum class ShaderBindingType enum class ShaderBindingType
{ {
Sampler,
StorageBuffer, StorageBuffer,
Texture, Texture,
UniformBuffer, UniformBuffer,
@ -182,6 +183,13 @@ namespace Nz
SpirV SpirV
}; };
enum class TextureAccess
{
ReadOnly,
ReadWrite,
WriteOnly
};
enum class TextureLayout enum class TextureLayout
{ {
ColorInput, ColorInput,
@ -199,6 +207,7 @@ namespace Nz
ColorAttachment, ColorAttachment,
DepthStencilAttachment, DepthStencilAttachment,
InputAttachment, InputAttachment,
ShaderReadWrite,
ShaderSampling, ShaderSampling,
TransferSource, TransferSource,
TransferDestination, TransferDestination,

View File

@ -8,6 +8,7 @@
#define NAZARA_RENDERER_RENDERDEVICE_HPP #define NAZARA_RENDERER_RENDERDEVICE_HPP
#include <Nazara/Prerequisites.hpp> #include <Nazara/Prerequisites.hpp>
#include <Nazara/Renderer/ComputePipeline.hpp>
#include <Nazara/Renderer/Config.hpp> #include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/Enums.hpp> #include <Nazara/Renderer/Enums.hpp>
#include <Nazara/Renderer/Framebuffer.hpp> #include <Nazara/Renderer/Framebuffer.hpp>
@ -40,6 +41,7 @@ namespace Nz
virtual std::shared_ptr<RenderBuffer> InstantiateBuffer(BufferType type, UInt64 size, BufferUsageFlags usageFlags, const void* initialData = nullptr) = 0; virtual std::shared_ptr<RenderBuffer> InstantiateBuffer(BufferType type, UInt64 size, BufferUsageFlags usageFlags, const void* initialData = nullptr) = 0;
virtual std::shared_ptr<CommandPool> InstantiateCommandPool(QueueType queueType) = 0; virtual std::shared_ptr<CommandPool> InstantiateCommandPool(QueueType queueType) = 0;
virtual std::shared_ptr<ComputePipeline> InstantiateComputePipeline(ComputePipelineInfo pipelineInfo) = 0;
virtual 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) = 0; virtual 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) = 0;
virtual std::shared_ptr<RenderPass> InstantiateRenderPass(std::vector<RenderPass::Attachment> attachments, std::vector<RenderPass::SubpassDescription> subpassDescriptions, std::vector<RenderPass::SubpassDependency> subpassDependencies) = 0; virtual std::shared_ptr<RenderPass> InstantiateRenderPass(std::vector<RenderPass::Attachment> attachments, std::vector<RenderPass::SubpassDescription> subpassDescriptions, std::vector<RenderPass::SubpassDependency> subpassDependencies) = 0;
virtual std::shared_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) = 0; virtual std::shared_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) = 0;

View File

@ -8,6 +8,7 @@
#define NAZARA_RENDERER_RENDERDEVICEINFO_HPP #define NAZARA_RENDERER_RENDERDEVICEINFO_HPP
#include <Nazara/Prerequisites.hpp> #include <Nazara/Prerequisites.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <Nazara/Renderer/Enums.hpp> #include <Nazara/Renderer/Enums.hpp>
#include <string> #include <string>
@ -16,18 +17,27 @@ namespace Nz
struct RenderDeviceFeatures struct RenderDeviceFeatures
{ {
bool anisotropicFiltering = false; bool anisotropicFiltering = false;
bool computeShaders = false;
bool depthClamping = false; bool depthClamping = false;
bool nonSolidFaceFilling = false; bool nonSolidFaceFilling = false;
bool storageBuffers = false; bool storageBuffers = false;
bool textureRead = false;
bool textureReadWithoutFormat = false;
bool textureWrite = false;
bool textureWriteWithoutFormat = false;
bool unrestrictedTextureViews = false; bool unrestrictedTextureViews = false;
}; };
struct RenderDeviceLimits struct RenderDeviceLimits
{ {
UInt64 minStorageBufferOffsetAlignment; UInt64 maxComputeSharedMemorySize;
UInt64 minUniformBufferOffsetAlignment; UInt32 maxComputeWorkGroupInvocations;
Vector3ui32 maxComputeWorkGroupCount;
Vector3ui32 maxComputeWorkGroupSize;
UInt64 maxStorageBufferSize; UInt64 maxStorageBufferSize;
UInt64 maxUniformBufferSize; UInt64 maxUniformBufferSize;
UInt64 minStorageBufferOffsetAlignment;
UInt64 minUniformBufferOffsetAlignment;
}; };
struct RenderDeviceInfo struct RenderDeviceInfo

View File

@ -9,6 +9,7 @@
#include <Nazara/Prerequisites.hpp> #include <Nazara/Prerequisites.hpp>
#include <Nazara/Renderer/Config.hpp> #include <Nazara/Renderer/Config.hpp>
#include <Nazara/Renderer/Enums.hpp>
#include <memory> #include <memory>
#include <string_view> #include <string_view>
#include <variant> #include <variant>
@ -43,6 +44,18 @@ namespace Nz
ShaderBinding& operator=(const ShaderBinding&) = delete; ShaderBinding& operator=(const ShaderBinding&) = delete;
ShaderBinding& operator=(ShaderBinding&&) = delete; ShaderBinding& operator=(ShaderBinding&&) = delete;
struct SampledTextureBinding
{
const Texture* texture;
const TextureSampler* sampler;
};
struct SampledTextureBindings
{
UInt32 arraySize;
const SampledTextureBinding* textureBindings;
};
struct StorageBufferBinding struct StorageBufferBinding
{ {
RenderBuffer* buffer; RenderBuffer* buffer;
@ -53,13 +66,7 @@ namespace Nz
struct TextureBinding struct TextureBinding
{ {
const Texture* texture; const Texture* texture;
const TextureSampler* sampler; TextureAccess access;
};
struct TextureBindings
{
UInt32 arraySize;
const TextureBinding* textureBindings;
}; };
struct UniformBufferBinding struct UniformBufferBinding
@ -72,7 +79,7 @@ namespace Nz
struct Binding struct Binding
{ {
UInt32 bindingIndex; UInt32 bindingIndex;
std::variant<StorageBufferBinding, TextureBinding, TextureBindings, UniformBufferBinding> content; std::variant<SampledTextureBinding, SampledTextureBindings, StorageBufferBinding, TextureBinding, UniformBufferBinding> content;
}; };
protected: protected:

View File

@ -23,7 +23,6 @@ namespace Nz
bool IsValid() const; bool IsValid() const;
}; };
class Mutex;
class ImageStream; class ImageStream;
using ImageStreamLoader = ResourceLoader<ImageStream, ImageStreamParams>; using ImageStreamLoader = ResourceLoader<ImageStream, ImageStreamParams>;

View File

@ -382,8 +382,9 @@ namespace Nz
{ {
switch (bindingType) switch (bindingType)
{ {
case ShaderBindingType::Sampler: return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
case ShaderBindingType::StorageBuffer: return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 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_STORAGE_IMAGE;
case ShaderBindingType::UniformBuffer: return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; case ShaderBindingType::UniformBuffer: return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
} }
@ -395,6 +396,7 @@ namespace Nz
{ {
switch (stageType) switch (stageType)
{ {
case nzsl::ShaderStageType::Compute: return VK_SHADER_STAGE_COMPUTE_BIT;
case nzsl::ShaderStageType::Fragment: return VK_SHADER_STAGE_FRAGMENT_BIT; case nzsl::ShaderStageType::Fragment: return VK_SHADER_STAGE_FRAGMENT_BIT;
case nzsl::ShaderStageType::Vertex: return VK_SHADER_STAGE_VERTEX_BIT; case nzsl::ShaderStageType::Vertex: return VK_SHADER_STAGE_VERTEX_BIT;
} }
@ -459,6 +461,7 @@ namespace Nz
case TextureUsage::ColorAttachment: return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; case TextureUsage::ColorAttachment: return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
case TextureUsage::DepthStencilAttachment: return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; case TextureUsage::DepthStencilAttachment: return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
case TextureUsage::InputAttachment: return VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; case TextureUsage::InputAttachment: return VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
case TextureUsage::ShaderReadWrite: return VK_IMAGE_USAGE_STORAGE_BIT;
case TextureUsage::ShaderSampling: return VK_IMAGE_USAGE_SAMPLED_BIT; case TextureUsage::ShaderSampling: return VK_IMAGE_USAGE_SAMPLED_BIT;
case TextureUsage::TransferSource: return VK_IMAGE_USAGE_TRANSFER_SRC_BIT; case TextureUsage::TransferSource: return VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
case TextureUsage::TransferDestination: return VK_IMAGE_USAGE_TRANSFER_DST_BIT; case TextureUsage::TransferDestination: return VK_IMAGE_USAGE_TRANSFER_DST_BIT;

View File

@ -27,8 +27,9 @@ namespace Nz
void BeginDebugRegion(const std::string_view& regionName, const Color& color) override; 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 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 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(UInt32 set, const ShaderBinding& binding) override;
void BindShaderBinding(const RenderPipelineLayout& pipelineLayout, 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; 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 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 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 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; void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstIndex = 0, UInt32 firstInstance = 0) override;

View File

@ -0,0 +1,45 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Vulkan renderer"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_VULKANRENDERER_VULKANCOMPUTEPIPELINE_HPP
#define NAZARA_VULKANRENDERER_VULKANCOMPUTEPIPELINE_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Renderer/ComputePipeline.hpp>
#include <Nazara/VulkanRenderer/Config.hpp>
#include <Nazara/VulkanRenderer/Wrapper/Device.hpp>
#include <Nazara/VulkanRenderer/Wrapper/Pipeline.hpp>
namespace Nz
{
class VulkanDevice;
class NAZARA_VULKANRENDERER_API VulkanComputePipeline : public ComputePipeline
{
public:
VulkanComputePipeline(VulkanDevice& device, ComputePipelineInfo pipelineInfo);
VulkanComputePipeline(const VulkanComputePipeline&) = delete;
VulkanComputePipeline(VulkanComputePipeline&&) = delete;
~VulkanComputePipeline() = default;
inline const Vk::Pipeline& GetPipeline() const;
inline const ComputePipelineInfo& GetPipelineInfo() const override;
void UpdateDebugName(std::string_view name) override;
VulkanComputePipeline& operator=(const VulkanComputePipeline&) = delete;
VulkanComputePipeline& operator=(VulkanComputePipeline&&) = delete;
private:
Vk::Pipeline m_pipeline;
ComputePipelineInfo m_pipelineInfo;
};
}
#include <Nazara/VulkanRenderer/VulkanComputePipeline.inl>
#endif // NAZARA_VULKANRENDERER_VULKANCOMPUTEPIPELINE_HPP

View File

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

View File

@ -28,6 +28,7 @@ namespace Nz
std::shared_ptr<RenderBuffer> InstantiateBuffer(BufferType type, UInt64 size, BufferUsageFlags usageFlags, const void* initialData = nullptr) override; 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<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<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<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; std::shared_ptr<RenderPipeline> InstantiateRenderPipeline(RenderPipelineInfo pipelineInfo) override;

View File

@ -67,6 +67,8 @@ namespace Nz
inline void CopyImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, const VkImageCopy& region); inline void CopyImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, const VkImageCopy& region);
inline void CopyImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, UInt32 regionCount, const VkImageCopy* regions); inline void CopyImage(VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, UInt32 regionCount, const VkImageCopy* regions);
inline void Dispatch(UInt32 groupCountX, UInt32 groupCountY, UInt32 groupCountZ);
inline void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0); inline void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0);
inline void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, Int32 vertexOffset = 0, UInt32 firstInstance = 0); inline void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, Int32 vertexOffset = 0, UInt32 firstInstance = 0);

View File

@ -302,6 +302,11 @@ namespace Nz
return m_pool->GetDevice()->vkCmdCopyImage(m_handle, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, regions); return m_pool->GetDevice()->vkCmdCopyImage(m_handle, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount, regions);
} }
inline void CommandBuffer::Dispatch(UInt32 groupCountX, UInt32 groupCountY, UInt32 groupCountZ)
{
return m_pool->GetDevice()->vkCmdDispatch(m_handle, groupCountX, groupCountY, groupCountZ);
}
inline void CommandBuffer::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance) inline void CommandBuffer::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance)
{ {
return m_pool->GetDevice()->vkCmdDraw(m_handle, vertexCount, instanceCount, firstVertex, firstInstance); return m_pool->GetDevice()->vkCmdDraw(m_handle, vertexCount, instanceCount, firstVertex, firstInstance);

View File

@ -402,7 +402,7 @@ namespace Nz
viewerData.blitShaderBinding->Update({ viewerData.blitShaderBinding->Update({
{ {
0, 0,
ShaderBinding::TextureBinding { ShaderBinding::SampledTextureBinding {
m_bakedFrameGraph.GetAttachmentTexture(viewerData.debugColorAttachment).get(), m_bakedFrameGraph.GetAttachmentTexture(viewerData.debugColorAttachment).get(),
sampler.get() sampler.get()
} }
@ -419,7 +419,7 @@ namespace Nz
renderTargetData.blitShaderBinding->Update({ renderTargetData.blitShaderBinding->Update({
{ {
0, 0,
ShaderBinding::TextureBinding { ShaderBinding::SampledTextureBinding {
m_bakedFrameGraph.GetAttachmentTexture(renderTargetData.finalAttachment).get(), m_bakedFrameGraph.GetAttachmentTexture(renderTargetData.finalAttachment).get(),
sampler.get() sampler.get()
} }
@ -456,7 +456,7 @@ namespace Nz
{ {
builder.SetScissor(renderRegion); builder.SetScissor(renderRegion);
builder.SetViewport(renderRegion); builder.SetViewport(renderRegion);
builder.BindPipeline(*graphics->GetBlitPipeline(false)); builder.BindRenderPipeline(*graphics->GetBlitPipeline(false));
builder.BindShaderBinding(0, *data.blitShaderBinding); builder.BindShaderBinding(0, *data.blitShaderBinding);
builder.Draw(3); builder.Draw(3);
@ -644,7 +644,7 @@ namespace Nz
builder.SetViewport(env.renderRect); builder.SetViewport(env.renderRect);
Graphics* graphics = Graphics::Instance(); Graphics* graphics = Graphics::Instance();
builder.BindPipeline(*graphics->GetBlitPipeline(false)); builder.BindRenderPipeline(*graphics->GetBlitPipeline(false));
bool first = true; bool first = true;
@ -657,7 +657,7 @@ namespace Nz
if (first) if (first)
{ {
builder.BindPipeline(*graphics->GetBlitPipeline(true)); builder.BindRenderPipeline(*graphics->GetBlitPipeline(true));
first = false; first = false;
} }
} }

View File

@ -108,9 +108,14 @@ namespace Nz
RenderDeviceFeatures enabledFeatures; RenderDeviceFeatures enabledFeatures;
enabledFeatures.anisotropicFiltering = !config.forceDisableFeatures.anisotropicFiltering && renderDeviceInfo[bestRenderDeviceIndex].features.anisotropicFiltering; enabledFeatures.anisotropicFiltering = !config.forceDisableFeatures.anisotropicFiltering && renderDeviceInfo[bestRenderDeviceIndex].features.anisotropicFiltering;
enabledFeatures.computeShaders = !config.forceDisableFeatures.computeShaders && renderDeviceInfo[bestRenderDeviceIndex].features.computeShaders;
enabledFeatures.depthClamping = !config.forceDisableFeatures.depthClamping && renderDeviceInfo[bestRenderDeviceIndex].features.depthClamping; enabledFeatures.depthClamping = !config.forceDisableFeatures.depthClamping && renderDeviceInfo[bestRenderDeviceIndex].features.depthClamping;
enabledFeatures.nonSolidFaceFilling = !config.forceDisableFeatures.nonSolidFaceFilling && renderDeviceInfo[bestRenderDeviceIndex].features.nonSolidFaceFilling; enabledFeatures.nonSolidFaceFilling = !config.forceDisableFeatures.nonSolidFaceFilling && renderDeviceInfo[bestRenderDeviceIndex].features.nonSolidFaceFilling;
enabledFeatures.storageBuffers = !config.forceDisableFeatures.storageBuffers && renderDeviceInfo[bestRenderDeviceIndex].features.storageBuffers; enabledFeatures.storageBuffers = !config.forceDisableFeatures.storageBuffers && renderDeviceInfo[bestRenderDeviceIndex].features.storageBuffers;
enabledFeatures.textureRead = !config.forceDisableFeatures.textureRead && renderDeviceInfo[bestRenderDeviceIndex].features.textureRead;
enabledFeatures.textureReadWithoutFormat = !config.forceDisableFeatures.textureReadWithoutFormat && renderDeviceInfo[bestRenderDeviceIndex].features.textureReadWithoutFormat;
enabledFeatures.textureWrite = !config.forceDisableFeatures.textureWrite && renderDeviceInfo[bestRenderDeviceIndex].features.textureWrite;
enabledFeatures.textureWriteWithoutFormat = !config.forceDisableFeatures.textureWriteWithoutFormat && renderDeviceInfo[bestRenderDeviceIndex].features.textureWriteWithoutFormat;
enabledFeatures.unrestrictedTextureViews = !config.forceDisableFeatures.unrestrictedTextureViews && renderDeviceInfo[bestRenderDeviceIndex].features.unrestrictedTextureViews; enabledFeatures.unrestrictedTextureViews = !config.forceDisableFeatures.unrestrictedTextureViews && renderDeviceInfo[bestRenderDeviceIndex].features.unrestrictedTextureViews;
m_renderDevice = renderer->InstanciateRenderDevice(bestRenderDeviceIndex, enabledFeatures); m_renderDevice = renderer->InstanciateRenderDevice(bestRenderDeviceIndex, enabledFeatures);
@ -176,7 +181,7 @@ namespace Nz
layoutInfo.bindings.assign({ layoutInfo.bindings.assign({
{ {
0, 0, 1, 0, 0, 1,
ShaderBindingType::Texture, ShaderBindingType::Sampler,
nzsl::ShaderStageType::Fragment nzsl::ShaderStageType::Fragment
} }
}); });

View File

@ -150,7 +150,7 @@ namespace Nz
bindings.push_back({ bindings.push_back({
textureSlot.bindingIndex, textureSlot.bindingIndex,
ShaderBinding::TextureBinding { ShaderBinding::SampledTextureBinding {
texture.get(), sampler.get() texture.get(), sampler.get()
} }
}); });

View File

@ -56,6 +56,8 @@ namespace Nz
if (IsStorageType(*varType)) if (IsStorageType(*varType))
bindingType = ShaderBindingType::StorageBuffer; bindingType = ShaderBindingType::StorageBuffer;
else if (IsSamplerType(*varType)) else if (IsSamplerType(*varType))
bindingType = ShaderBindingType::Sampler;
else if (IsTextureType(*varType))
bindingType = ShaderBindingType::Texture; bindingType = ShaderBindingType::Texture;
else if (IsUniformType(*varType)) else if (IsUniformType(*varType))
bindingType = ShaderBindingType::UniformBuffer; bindingType = ShaderBindingType::UniformBuffer;
@ -67,7 +69,7 @@ namespace Nz
throw std::runtime_error("unexpected type " + ToString(innerType) + " in array " + ToString(arrayType)); throw std::runtime_error("unexpected type " + ToString(innerType) + " in array " + ToString(arrayType));
arraySize = arrayType.length; arraySize = arrayType.length;
bindingType = ShaderBindingType::Texture; bindingType = ShaderBindingType::Sampler;
varType = &innerType; varType = &innerType;
} }
else else
@ -86,6 +88,21 @@ namespace Nz
{ {
switch (bindingType) switch (bindingType)
{ {
case ShaderBindingType::Sampler:
{
if (externalBlock->samplers.find(externalVar.tag) != externalBlock->samplers.end())
throw std::runtime_error("duplicate sampler tag " + externalVar.tag + " in external block " + node.tag);
const auto& samplerType = std::get<nzsl::Ast::SamplerType>(*varType);
ExternalSampler& texture = externalBlock->samplers[externalVar.tag];
texture.bindingIndex = bindingIndex;
texture.bindingSet = bindingSet;
texture.imageType = samplerType.dim;
texture.sampledType = samplerType.sampledType;
break;
}
case ShaderBindingType::StorageBuffer: case ShaderBindingType::StorageBuffer:
{ {
if (externalBlock->storageBlocks.find(externalVar.tag) != externalBlock->storageBlocks.end()) if (externalBlock->storageBlocks.find(externalVar.tag) != externalBlock->storageBlocks.end())
@ -100,16 +117,18 @@ namespace Nz
case ShaderBindingType::Texture: case ShaderBindingType::Texture:
{ {
if (externalBlock->samplers.find(externalVar.tag) != externalBlock->samplers.end()) if (externalBlock->textures.find(externalVar.tag) != externalBlock->textures.end())
throw std::runtime_error("duplicate textures tag " + externalVar.tag + " in external block " + node.tag); throw std::runtime_error("duplicate textures tag " + externalVar.tag + " in external block " + node.tag);
const auto& samplerType = std::get<nzsl::Ast::SamplerType>(*varType); const auto& textureType = std::get<nzsl::Ast::TextureType>(*varType);
ExternalTexture& texture = externalBlock->samplers[externalVar.tag]; ExternalTexture& texture = externalBlock->textures[externalVar.tag];
texture.bindingIndex = bindingIndex; texture.bindingIndex = bindingIndex;
texture.bindingSet = bindingSet; texture.bindingSet = bindingSet;
texture.imageType = samplerType.dim; texture.accessPolicy = textureType.accessPolicy;
texture.sampledType = samplerType.sampledType; texture.baseType = textureType.baseType;
texture.imageFormat = textureType.format;
texture.imageType = textureType.dim;
break; break;
} }

View File

@ -199,7 +199,7 @@ namespace Nz
{ {
auto& bindingEntry = m_bindingCache.emplace_back(); auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex; bindingEntry.bindingIndex = bindingIndex;
bindingEntry.content = ShaderBinding::TextureBinding{ bindingEntry.content = ShaderBinding::SampledTextureBinding{
m_pendingData.currentTextureOverlay, defaultSampler.get() m_pendingData.currentTextureOverlay, defaultSampler.get()
}; };
} }
@ -310,7 +310,7 @@ namespace Nz
if (currentPipeline != drawData.renderPipeline) if (currentPipeline != drawData.renderPipeline)
{ {
commandBuffer.BindPipeline(*drawData.renderPipeline); commandBuffer.BindRenderPipeline(*drawData.renderPipeline);
currentPipeline = drawData.renderPipeline; currentPipeline = drawData.renderPipeline;
} }

View File

@ -175,7 +175,7 @@ namespace Nz
auto& bindingEntry = m_bindingCache.emplace_back(); auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex; bindingEntry.bindingIndex = bindingIndex;
bindingEntry.content = ShaderBinding::TextureBindings { bindingEntry.content = ShaderBinding::SampledTextureBindings {
SafeCast<UInt32>(renderState.shadowMaps2D.size()), &m_textureBindingCache[textureBindingBaseIndex] SafeCast<UInt32>(renderState.shadowMaps2D.size()), &m_textureBindingCache[textureBindingBaseIndex]
}; };
} }
@ -197,7 +197,7 @@ namespace Nz
auto& bindingEntry = m_bindingCache.emplace_back(); auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex; bindingEntry.bindingIndex = bindingIndex;
bindingEntry.content = ShaderBinding::TextureBindings { bindingEntry.content = ShaderBinding::SampledTextureBindings {
SafeCast<UInt32>(renderState.shadowMapsCube.size()), &m_textureBindingCache[textureBindingBaseIndex] SafeCast<UInt32>(renderState.shadowMapsCube.size()), &m_textureBindingCache[textureBindingBaseIndex]
}; };
} }
@ -230,7 +230,7 @@ namespace Nz
{ {
auto& bindingEntry = m_bindingCache.emplace_back(); auto& bindingEntry = m_bindingCache.emplace_back();
bindingEntry.bindingIndex = bindingIndex; bindingEntry.bindingIndex = bindingIndex;
bindingEntry.content = ShaderBinding::TextureBinding{ bindingEntry.content = ShaderBinding::SampledTextureBinding{
whiteTexture2D.get(), defaultSampler.get() whiteTexture2D.get(), defaultSampler.get()
}; };
} }
@ -285,7 +285,7 @@ namespace Nz
if (currentPipeline != drawData.renderPipeline) if (currentPipeline != drawData.renderPipeline)
{ {
commandBuffer.BindPipeline(*drawData.renderPipeline); commandBuffer.BindRenderPipeline(*drawData.renderPipeline);
currentPipeline = drawData.renderPipeline; currentPipeline = drawData.renderPipeline;
} }

View File

@ -4,6 +4,7 @@
#include <Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp> #include <Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp>
#include <Nazara/OpenGLRenderer/OpenGLCommandPool.hpp> #include <Nazara/OpenGLRenderer/OpenGLCommandPool.hpp>
#include <Nazara/OpenGLRenderer/OpenGLComputePipeline.hpp>
#include <Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp> #include <Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp>
#include <Nazara/OpenGLRenderer/OpenGLRenderPass.hpp> #include <Nazara/OpenGLRenderer/OpenGLRenderPass.hpp>
#include <Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp> #include <Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp>
@ -93,6 +94,14 @@ namespace Nz
{ {
context->CopyTexture(*command.source, *command.target, command.sourceBox, command.targetPoint); context->CopyTexture(*command.source, *command.target, command.sourceBox, command.targetPoint);
} }
else if constexpr (std::is_same_v<T, DispatchData>)
{
if (!context->glDispatchCompute)
throw std::runtime_error("compute shaders are not supported on this device");
command.states.pipeline->Apply(*context);
context->glDispatchCompute(command.numGroupsX, command.numGroupsY, command.numGroupsZ);
}
else if constexpr (std::is_same_v<T, DrawData>) else if constexpr (std::is_same_v<T, DrawData>)
{ {
ApplyStates(*context, command.states); ApplyStates(*context, command.states);

View File

@ -4,6 +4,7 @@
#include <Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.hpp> #include <Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.hpp>
#include <Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp> #include <Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp>
#include <Nazara/OpenGLRenderer/OpenGLComputePipeline.hpp>
#include <Nazara/OpenGLRenderer/OpenGLRenderPass.hpp> #include <Nazara/OpenGLRenderer/OpenGLRenderPass.hpp>
#include <Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp> #include <Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp>
#include <Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp> #include <Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp>
@ -26,6 +27,13 @@ namespace Nz
m_commandBuffer.SetFramebuffer(static_cast<const OpenGLFramebuffer&>(framebuffer), static_cast<const OpenGLRenderPass&>(renderPass), clearValues, clearValueCount); m_commandBuffer.SetFramebuffer(static_cast<const OpenGLFramebuffer&>(framebuffer), static_cast<const OpenGLRenderPass&>(renderPass), clearValues, clearValueCount);
} }
void OpenGLCommandBufferBuilder::BindComputePipeline(const ComputePipeline& pipeline)
{
const OpenGLComputePipeline& glPipeline = static_cast<const OpenGLComputePipeline&>(pipeline);
m_commandBuffer.BindComputePipeline(&glPipeline);
}
void OpenGLCommandBufferBuilder::BindIndexBuffer(const RenderBuffer& indexBuffer, IndexType indexType, UInt64 offset) void OpenGLCommandBufferBuilder::BindIndexBuffer(const RenderBuffer& indexBuffer, IndexType indexType, UInt64 offset)
{ {
const OpenGLBuffer& glBuffer = static_cast<const OpenGLBuffer&>(indexBuffer); const OpenGLBuffer& glBuffer = static_cast<const OpenGLBuffer&>(indexBuffer);
@ -33,11 +41,11 @@ namespace Nz
m_commandBuffer.BindIndexBuffer(glBuffer.GetBuffer().GetObjectId(), indexType, offset); m_commandBuffer.BindIndexBuffer(glBuffer.GetBuffer().GetObjectId(), indexType, offset);
} }
void OpenGLCommandBufferBuilder::BindPipeline(const RenderPipeline& pipeline) void OpenGLCommandBufferBuilder::BindRenderPipeline(const RenderPipeline& pipeline)
{ {
const OpenGLRenderPipeline& glPipeline = static_cast<const OpenGLRenderPipeline&>(pipeline); const OpenGLRenderPipeline& glPipeline = static_cast<const OpenGLRenderPipeline&>(pipeline);
m_commandBuffer.BindPipeline(&glPipeline); m_commandBuffer.BindRenderPipeline(&glPipeline);
} }
void OpenGLCommandBufferBuilder::BindShaderBinding(UInt32 set, const ShaderBinding& binding) void OpenGLCommandBufferBuilder::BindShaderBinding(UInt32 set, const ShaderBinding& binding)
@ -93,6 +101,11 @@ namespace Nz
m_commandBuffer.CopyTexture(sourceTexture, fromBox, targetTexture, toPos); m_commandBuffer.CopyTexture(sourceTexture, fromBox, targetTexture, toPos);
} }
void OpenGLCommandBufferBuilder::Dispatch(UInt32 workgroupX, UInt32 workgroupY, UInt32 workgroupZ)
{
m_commandBuffer.Dispatch(workgroupX, workgroupY, workgroupZ);
}
void OpenGLCommandBufferBuilder::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance) void OpenGLCommandBufferBuilder::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance)
{ {
m_commandBuffer.Draw(vertexCount, instanceCount, firstVertex, firstInstance); m_commandBuffer.Draw(vertexCount, instanceCount, firstVertex, firstInstance);

View File

@ -0,0 +1,75 @@
// 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/Core/ErrorFlags.hpp>
#include <Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp>
#include <Nazara/OpenGLRenderer/OpenGLShaderModule.hpp>
#include <Nazara/OpenGLRenderer/Utils.hpp>
#include <NZSL/GlslWriter.hpp>
#include <NZSL/ShaderBuilder.hpp>
#include <NZSL/Ast/Module.hpp>
#include <cassert>
#include <stdexcept>
#include <Nazara/OpenGLRenderer/Debug.hpp>
namespace Nz
{
OpenGLComputePipeline::OpenGLComputePipeline(OpenGLDevice& device, ComputePipelineInfo pipelineInfo) :
m_pipelineInfo(std::move(pipelineInfo))
{
if (device.GetEnabledFeatures().computeShaders)
throw std::runtime_error("compute shaders are not enabled on the device");
OpenGLRenderPipelineLayout& pipelineLayout = static_cast<OpenGLRenderPipelineLayout&>(*m_pipelineInfo.pipelineLayout);
if (!m_program.Create(device))
throw std::runtime_error("failed to create program");
NazaraAssert(pipelineInfo.shaderModule, "invalid shader module");
OpenGLShaderModule& shaderModule = static_cast<OpenGLShaderModule&>(*pipelineInfo.shaderModule);
std::vector<OpenGLShaderModule::ExplicitBinding> explicitBindings;
nzsl::ShaderStageTypeFlags stageFlags = shaderModule.Attach(m_program, pipelineLayout.GetBindingMapping(), &explicitBindings);
if (!stageFlags.Test(nzsl::ShaderStageType::Compute))
throw std::runtime_error("shader module has no compute stage");
m_program.Link();
std::string errLog;
if (!m_program.GetLinkStatus(&errLog))
throw std::runtime_error("failed to link program: " + errLog);
for (const auto& explicitBinding : explicitBindings)
{
if (explicitBinding.isBlock)
{
GLuint blockIndex = m_program.GetUniformBlockIndex(explicitBinding.name);
if (blockIndex == GL_INVALID_INDEX)
continue;
m_program.UniformBlockBinding(blockIndex, explicitBinding.binding);
}
else
{
int location = m_program.GetUniformLocation(explicitBinding.name);
if (location == -1)
continue;
m_program.Uniform(location, SafeCast<int>(explicitBinding.binding));
}
}
}
void OpenGLComputePipeline::Apply(const GL::Context& context) const
{
context.BindProgram(m_program.GetObjectId());
}
void OpenGLComputePipeline::UpdateDebugName(std::string_view name)
{
m_program.SetDebugName(name);
}
}

View File

@ -5,6 +5,7 @@
#include <Nazara/OpenGLRenderer/OpenGLDevice.hpp> #include <Nazara/OpenGLRenderer/OpenGLDevice.hpp>
#include <Nazara/OpenGLRenderer/OpenGLBuffer.hpp> #include <Nazara/OpenGLRenderer/OpenGLBuffer.hpp>
#include <Nazara/OpenGLRenderer/OpenGLCommandPool.hpp> #include <Nazara/OpenGLRenderer/OpenGLCommandPool.hpp>
#include <Nazara/OpenGLRenderer/OpenGLComputePipeline.hpp>
#include <Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp> #include <Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp>
#include <Nazara/OpenGLRenderer/OpenGLRenderPass.hpp> #include <Nazara/OpenGLRenderer/OpenGLRenderPass.hpp>
#include <Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp> #include <Nazara/OpenGLRenderer/OpenGLRenderPipeline.hpp>
@ -62,47 +63,58 @@ namespace Nz
if (m_referenceContext->IsExtensionSupported(GL::Extension::TextureFilterAnisotropic)) if (m_referenceContext->IsExtensionSupported(GL::Extension::TextureFilterAnisotropic))
m_deviceInfo.features.anisotropicFiltering = true; m_deviceInfo.features.anisotropicFiltering = true;
if (m_referenceContext->IsExtensionSupported(GL::Extension::ComputeShader))
m_deviceInfo.features.computeShaders = true;
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->glPolygonMode) //< not supported in core OpenGL ES, but supported in OpenGL or with GL_NV_polygon_mode extension
m_deviceInfo.features.nonSolidFaceFilling = true;
if (m_referenceContext->IsExtensionSupported(GL::Extension::StorageBuffers)) if (m_referenceContext->IsExtensionSupported(GL::Extension::StorageBuffers))
m_deviceInfo.features.storageBuffers = true; 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->IsExtensionSupported(GL::Extension::ShaderImageLoadStore))
m_deviceInfo.features.nonSolidFaceFilling = true; {
m_deviceInfo.features.textureRead = true;
m_deviceInfo.features.textureWrite = true;
m_deviceInfo.features.textureWriteWithoutFormat = true;
}
if (m_referenceContext->IsExtensionSupported(GL::Extension::ShaderImageLoadFormatted))
m_deviceInfo.features.textureReadWithoutFormat = true;
if (m_referenceContext->IsExtensionSupported(GL::Extension::TextureView)) if (m_referenceContext->IsExtensionSupported(GL::Extension::TextureView))
m_deviceInfo.features.unrestrictedTextureViews = true; m_deviceInfo.features.unrestrictedTextureViews = true;
// Limits // Limits
GLint minUboOffsetAlignment; m_deviceInfo.limits.maxUniformBufferSize = m_referenceContext->GetInteger<UInt64>(GL_MAX_UNIFORM_BLOCK_SIZE);
m_referenceContext->glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &minUboOffsetAlignment); m_deviceInfo.limits.minUniformBufferOffsetAlignment = m_referenceContext->GetInteger<UInt64>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
assert(minUboOffsetAlignment >= 1);
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) if (m_deviceInfo.features.storageBuffers)
{ {
GLint minStorageOffsetAlignment; m_deviceInfo.limits.maxStorageBufferSize = m_referenceContext->GetInteger<UInt64>(GL_MAX_SHADER_STORAGE_BLOCK_SIZE);
m_referenceContext->glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &minStorageOffsetAlignment); m_deviceInfo.limits.minStorageBufferOffsetAlignment = m_referenceContext->GetInteger<UInt64>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT);
}
assert(minStorageOffsetAlignment >= 1);
m_deviceInfo.limits.minStorageBufferOffsetAlignment = static_cast<UInt64>(minStorageOffsetAlignment); if (m_deviceInfo.features.computeShaders)
{
GLint maxStorageBlockSize; m_deviceInfo.limits.maxComputeSharedMemorySize = m_referenceContext->GetInteger<UInt64>(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE);
m_referenceContext->glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &maxStorageBlockSize); m_deviceInfo.limits.maxComputeWorkGroupInvocations = m_referenceContext->GetInteger<UInt32>(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS);
assert(maxStorageBlockSize >= 1); m_deviceInfo.limits.maxComputeWorkGroupCount = {
m_deviceInfo.limits.maxStorageBufferSize = static_cast<UInt64>(maxStorageBlockSize); m_referenceContext->GetInteger<UInt32>(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0),
m_referenceContext->GetInteger<UInt32>(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1),
m_referenceContext->GetInteger<UInt32>(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2)
};
m_deviceInfo.limits.maxComputeWorkGroupSize = {
m_referenceContext->GetInteger<UInt32>(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0),
m_referenceContext->GetInteger<UInt32>(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1),
m_referenceContext->GetInteger<UInt32>(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2)
};
} }
else
m_deviceInfo.limits.maxStorageBufferSize = 0;
m_contexts.insert(m_referenceContext.get()); m_contexts.insert(m_referenceContext.get());
} }
@ -154,6 +166,11 @@ namespace Nz
return std::make_shared<OpenGLCommandPool>(); return std::make_shared<OpenGLCommandPool>();
} }
std::shared_ptr<ComputePipeline> OpenGLDevice::InstantiateComputePipeline(ComputePipelineInfo pipelineInfo)
{
return std::make_shared<OpenGLComputePipeline>(*this, std::move(pipelineInfo));
}
std::shared_ptr<Framebuffer> OpenGLDevice::InstantiateFramebuffer(unsigned int /*width*/, unsigned int /*height*/, const std::shared_ptr<RenderPass>& /*renderPass*/, const std::vector<std::shared_ptr<Texture>>& attachments) std::shared_ptr<Framebuffer> OpenGLDevice::InstantiateFramebuffer(unsigned int /*width*/, unsigned int /*height*/, const std::shared_ptr<RenderPass>& /*renderPass*/, const std::vector<std::shared_ptr<Texture>>& attachments)
{ {
return std::make_shared<OpenGLFboFramebuffer>(*this, attachments); return std::make_shared<OpenGLFboFramebuffer>(*this, attachments);
@ -246,7 +263,7 @@ namespace Nz
case PixelFormat::RGBA32F: case PixelFormat::RGBA32F:
case PixelFormat::RGBA32I: case PixelFormat::RGBA32I:
case PixelFormat::RGBA32UI: case PixelFormat::RGBA32UI:
return usage == TextureUsage::ColorAttachment || usage == TextureUsage::InputAttachment || usage == TextureUsage::ShaderSampling || usage == TextureUsage::TransferDestination || usage == TextureUsage::TransferSource; return usage == TextureUsage::ColorAttachment || usage == TextureUsage::InputAttachment || usage == TextureUsage::ShaderSampling || usage == TextureUsage::ShaderReadWrite || usage == TextureUsage::TransferDestination || usage == TextureUsage::TransferSource;
case PixelFormat::DXT1: case PixelFormat::DXT1:
case PixelFormat::DXT3: case PixelFormat::DXT3:

View File

@ -88,7 +88,7 @@ namespace Nz
if (location == -1) if (location == -1)
continue; continue;
m_program.Uniform(location, static_cast<int>(explicitBinding.binding)); //< FIXME: Use SafeCast m_program.Uniform(location, SafeCast<int>(explicitBinding.binding));
} }
} }
} }

View File

@ -96,6 +96,16 @@ namespace Nz
return ShaderBindingPtr(PlacementNew(freeBindingMemory, *this, poolIndex, freeBindingId)); return ShaderBindingPtr(PlacementNew(freeBindingMemory, *this, poolIndex, freeBindingId));
} }
auto OpenGLRenderPipelineLayout::GetSampledTextureDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t descriptorIndex) -> SampledTextureDescriptor&
{
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<SampledTextureDescriptor>();
}
auto OpenGLRenderPipelineLayout::GetStorageBufferDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t descriptorIndex) -> StorageBufferDescriptor& auto OpenGLRenderPipelineLayout::GetStorageBufferDescriptor(std::size_t poolIndex, std::size_t bindingIndex, std::size_t descriptorIndex) -> StorageBufferDescriptor&
{ {
assert(poolIndex < m_descriptorPools.size()); assert(poolIndex < m_descriptorPools.size());

View File

@ -45,7 +45,15 @@ namespace Nz
UInt32 bindingPoint = bindingMappingIt->second; UInt32 bindingPoint = bindingMappingIt->second;
if constexpr (std::is_same_v<DescriptorType, OpenGLRenderPipelineLayout::StorageBufferDescriptor>) if constexpr (std::is_same_v<DescriptorType, OpenGLRenderPipelineLayout::SampledTextureDescriptor>)
{
if (bindingInfo.type != ShaderBindingType::Sampler)
throw std::runtime_error("descriptor (set=" + std::to_string(setIndex) + ", binding=" + std::to_string(bindingIndex) + ") is not a sampler");
context.BindSampler(bindingPoint, descriptor.sampler);
context.BindTexture(bindingPoint, descriptor.textureTarget, descriptor.texture);
}
else if constexpr (std::is_same_v<DescriptorType, OpenGLRenderPipelineLayout::StorageBufferDescriptor>)
{ {
if (bindingInfo.type != ShaderBindingType::StorageBuffer) 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"); throw std::runtime_error("descriptor (set=" + std::to_string(setIndex) + ", binding=" + std::to_string(bindingIndex) + ") is not a storage buffer");
@ -57,8 +65,7 @@ namespace Nz
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");
context.BindSampler(bindingPoint, descriptor.sampler); context.BindImageTexture(bindingPoint, descriptor.texture, descriptor.level, descriptor.layered, descriptor.layer, descriptor.access, descriptor.format);
context.BindTexture(bindingPoint, descriptor.textureTarget, descriptor.texture);
} }
else if constexpr (std::is_same_v<DescriptorType, OpenGLRenderPipelineLayout::UniformBufferDescriptor>) else if constexpr (std::is_same_v<DescriptorType, OpenGLRenderPipelineLayout::UniformBufferDescriptor>)
{ {
@ -82,7 +89,14 @@ namespace Nz
{ {
using T = std::decay_t<decltype(arg)>; using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, StorageBufferBinding>) if constexpr (std::is_same_v<T, SampledTextureBinding>)
HandleTextureBinding(binding.bindingIndex, arg);
else if constexpr (std::is_same_v<T, SampledTextureBindings>)
{
for (UInt32 i = 0; i < arg.arraySize; ++i)
HandleTextureBinding(binding.bindingIndex + i, arg.textureBindings[i]);
}
else if constexpr (std::is_same_v<T, StorageBufferBinding>)
{ {
auto& storageDescriptor = m_owner.GetStorageBufferDescriptor(m_poolIndex, m_bindingIndex, binding.bindingIndex); auto& storageDescriptor = m_owner.GetStorageBufferDescriptor(m_poolIndex, m_bindingIndex, binding.bindingIndex);
storageDescriptor.offset = arg.offset; storageDescriptor.offset = arg.offset;
@ -99,11 +113,41 @@ namespace Nz
storageDescriptor.buffer = 0; storageDescriptor.buffer = 0;
} }
else if constexpr (std::is_same_v<T, TextureBinding>) else if constexpr (std::is_same_v<T, TextureBinding>)
HandleTextureBinding(binding.bindingIndex, arg);
else if constexpr (std::is_same_v<T, TextureBindings>)
{ {
for (UInt32 i = 0; i < arg.arraySize; ++i) auto& textureDescriptor = m_owner.GetTextureDescriptor(m_poolIndex, m_bindingIndex, binding.bindingIndex);
HandleTextureBinding(binding.bindingIndex + i, arg.textureBindings[i]); if (const OpenGLTexture* glTexture = static_cast<const OpenGLTexture*>(arg.texture))
{
const TextureViewInfo& viewInfo = glTexture->GetTextureViewInfo();
std::optional<GLTextureFormat> format = DescribeTextureFormat(viewInfo.reinterpretFormat);
if (!format)
throw std::runtime_error("unexpected texture format");
textureDescriptor.access = ToOpenGL(arg.access);
textureDescriptor.format = format->internalFormat;
if (viewInfo.layerCount > 1)
{
textureDescriptor.layered = true;
textureDescriptor.layer = 0;
}
else
{
textureDescriptor.layered = false;
textureDescriptor.layer = viewInfo.baseArrayLayer;
}
textureDescriptor.level = viewInfo.baseMipLevel;
textureDescriptor.texture = glTexture->GetTexture().GetObjectId();
}
else
{
textureDescriptor.access = GL_READ_ONLY;
textureDescriptor.format = GL_RGBA8;
textureDescriptor.layer = 0;
textureDescriptor.layered = GL_FALSE;
textureDescriptor.level = 0;
textureDescriptor.texture = 0;
}
} }
else if constexpr (std::is_same_v<T, UniformBufferBinding>) else if constexpr (std::is_same_v<T, UniformBufferBinding>)
{ {
@ -133,9 +177,9 @@ namespace Nz
// No OpenGL object to name // No OpenGL object to name
} }
void OpenGLShaderBinding::HandleTextureBinding(UInt32 bindingIndex, const TextureBinding& textureBinding) void OpenGLShaderBinding::HandleTextureBinding(UInt32 bindingIndex, const SampledTextureBinding& textureBinding)
{ {
auto& textureDescriptor = m_owner.GetTextureDescriptor(m_poolIndex, m_bindingIndex, bindingIndex); auto& textureDescriptor = m_owner.GetSampledTextureDescriptor(m_poolIndex, m_bindingIndex, bindingIndex);
if (const OpenGLTexture* glTexture = static_cast<const OpenGLTexture*>(textureBinding.texture)) if (const OpenGLTexture* glTexture = static_cast<const OpenGLTexture*>(textureBinding.texture))
{ {

View File

@ -172,6 +172,32 @@ namespace Nz::GL
} }
} }
void Context::BindImageTexture(GLuint imageUnit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) const
{
if (imageUnit >= m_state.imageUnits.size())
throw std::runtime_error("unsupported image unit #" + std::to_string(imageUnit));
layer = (layered == GL_TRUE) ? layer : 0;
auto& unit = m_state.imageUnits[imageUnit];
if (unit.texture != texture || unit.level != level || unit.layered != layered || unit.layer != layer || unit.access != access || unit.format != format)
{
if (!SetCurrentContext(this))
throw std::runtime_error("failed to activate context");
if (!glBindImageTexture)
throw std::runtime_error("image binding is not supported");
glBindImageTexture(imageUnit, texture, level, layered, layer, access, format);
unit.access = access;
unit.format = format;
unit.layer = layer;
unit.layered = layered;
unit.level = level;
unit.texture = texture;
}
}
void Context::BindProgram(GLuint program) const void Context::BindProgram(GLuint program) const
{ {
if (m_state.boundProgram != program) if (m_state.boundProgram != program)
@ -413,21 +439,13 @@ namespace Nz::GL
return false; return false;
} }
GLint majorVersion = 0; m_params.glMajorVersion = GetInteger<unsigned int>(GL_MAJOR_VERSION);
glGetIntegerv(GL_MAJOR_VERSION, &majorVersion); m_params.glMinorVersion = GetInteger<unsigned int>(GL_MINOR_VERSION);
GLint minorVersion = 0; unsigned int glVersion = m_params.glMajorVersion * 100 + m_params.glMinorVersion * 10;
glGetIntegerv(GL_MINOR_VERSION, &minorVersion);
m_params.glMajorVersion = majorVersion;
m_params.glMinorVersion = minorVersion;
unsigned int glVersion = majorVersion * 100 + minorVersion * 10;
// Load extensions // Load extensions
GLint extensionCount = 0; GLint extensionCount = GetInteger<GLint>(GL_NUM_EXTENSIONS);
glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount);
for (GLint i = 0; i < extensionCount; ++i) for (GLint i = 0; i < extensionCount; ++i)
m_supportedExtensions.emplace(reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i))); m_supportedExtensions.emplace(reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i)));
@ -441,6 +459,12 @@ namespace Nz::GL
else if (m_supportedExtensions.count("GL_EXT_clip_control")) else if (m_supportedExtensions.count("GL_EXT_clip_control"))
m_extensionStatus[UnderlyingCast(Extension::ClipControl)] = ExtensionStatus::EXT; m_extensionStatus[UnderlyingCast(Extension::ClipControl)] = ExtensionStatus::EXT;
// Compute shaders
if ((m_params.type == ContextType::OpenGL && glVersion >= 430) || (m_params.type == ContextType::OpenGL_ES && glVersion >= 310))
m_extensionStatus[UnderlyingCast(Extension::ComputeShader)] = ExtensionStatus::Core;
else if (m_supportedExtensions.count("GL_ARB_compute_shader"))
m_extensionStatus[UnderlyingCast(Extension::ComputeShader)] = ExtensionStatus::ARB;
// Debug output // Debug output
if ((m_params.type == ContextType::OpenGL && glVersion >= 430) || (m_params.type == ContextType::OpenGL_ES && glVersion >= 320)) if ((m_params.type == ContextType::OpenGL && glVersion >= 430) || (m_params.type == ContextType::OpenGL_ES && glVersion >= 320))
m_extensionStatus[UnderlyingCast(Extension::DebugOutput)] = ExtensionStatus::Core; m_extensionStatus[UnderlyingCast(Extension::DebugOutput)] = ExtensionStatus::Core;
@ -465,6 +489,18 @@ namespace Nz::GL
else if (m_supportedExtensions.count("GL_NV_polygon_mode")) else if (m_supportedExtensions.count("GL_NV_polygon_mode"))
m_extensionStatus[UnderlyingCast(Extension::DepthClamp)] = ExtensionStatus::Vendor; m_extensionStatus[UnderlyingCast(Extension::DepthClamp)] = ExtensionStatus::Vendor;
// Shader image load formatted
if (m_supportedExtensions.count("GL_EXT_shader_image_load_formatted"))
m_extensionStatus[UnderlyingCast(Extension::ShaderImageLoadFormatted)] = ExtensionStatus::EXT;
// Shader image load/store
if ((m_params.type == ContextType::OpenGL && glVersion >= 420) || (m_params.type == ContextType::OpenGL_ES && glVersion >= 310))
m_extensionStatus[UnderlyingCast(Extension::ShaderImageLoadStore)] = ExtensionStatus::Core;
else if (m_supportedExtensions.count("GL_ARB_shader_image_load_store"))
m_extensionStatus[UnderlyingCast(Extension::ShaderImageLoadStore)] = ExtensionStatus::ARB;
else if (m_supportedExtensions.count("GL_EXT_shader_image_load_store"))
m_extensionStatus[UnderlyingCast(Extension::ShaderImageLoadStore)] = ExtensionStatus::EXT;
// SPIR-V support // SPIR-V support
if (m_params.type == ContextType::OpenGL && glVersion >= 460) if (m_params.type == ContextType::OpenGL && glVersion >= 460)
m_extensionStatus[UnderlyingCast(Extension::SpirV)] = ExtensionStatus::Core; m_extensionStatus[UnderlyingCast(Extension::SpirV)] = ExtensionStatus::Core;
@ -583,16 +619,14 @@ namespace Nz::GL
else else
m_params.validationLevel = m_params.validationLevel; m_params.validationLevel = m_params.validationLevel;
GLint maxTextureUnits = -1; unsigned int maxTextureUnits = GetInteger<unsigned int>(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
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) + ", expected >= 32"); 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);
GLint maxUniformBufferUnits = -1; unsigned int maxUniformBufferUnits = GetInteger<unsigned int>(GL_MAX_UNIFORM_BUFFER_BINDINGS);
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) + ", expected >= 24"); NazaraWarning("GL_MAX_UNIFORM_BUFFER_BINDINGS is " + std::to_string(maxUniformBufferUnits) + ", expected >= 24");
@ -601,8 +635,7 @@ namespace Nz::GL
if (IsExtensionSupported(Extension::StorageBuffers)) if (IsExtensionSupported(Extension::StorageBuffers))
{ {
GLint maxStorageBufferUnits = -1; unsigned int maxStorageBufferUnits = GetInteger<unsigned int>(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxStorageBufferUnits);
if (maxStorageBufferUnits < 8) //< OpenGL ES 3.1 requires at least 8 storage buffers units if (maxStorageBufferUnits < 8) //< 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"); NazaraWarning("GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS is " + std::to_string(maxUniformBufferUnits) + ", expected >= 8");

View File

@ -0,0 +1,11 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Renderer module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/ComputePipeline.hpp>
#include <Nazara/Renderer/Debug.hpp>
namespace Nz
{
ComputePipeline::~ComputePipeline() = default;
}

View File

@ -83,7 +83,7 @@ namespace Nz
return; return;
builder.BindShaderBinding(0, *m_currentViewerData.binding); builder.BindShaderBinding(0, *m_currentViewerData.binding);
builder.BindPipeline(*m_renderPipeline); builder.BindRenderPipeline(*m_renderPipeline);
for (auto& drawCall : m_drawCalls) for (auto& drawCall : m_drawCalls)
{ {

View File

@ -42,9 +42,14 @@ namespace Nz
} }
NzValidateFeature(anisotropicFiltering, "anistropic filtering feature") NzValidateFeature(anisotropicFiltering, "anistropic filtering feature")
NzValidateFeature(computeShaders, "compute shaders feature")
NzValidateFeature(depthClamping, "depth clamping feature") NzValidateFeature(depthClamping, "depth clamping feature")
NzValidateFeature(nonSolidFaceFilling, "non-solid face filling feature") NzValidateFeature(nonSolidFaceFilling, "non-solid face filling feature")
NzValidateFeature(storageBuffers, "storage buffers support") NzValidateFeature(storageBuffers, "storage buffers support")
NzValidateFeature(textureRead, "texture read")
NzValidateFeature(textureReadWithoutFormat, "texture read without format")
NzValidateFeature(textureWrite, "texture write")
NzValidateFeature(textureWriteWithoutFormat, "texture write without format")
NzValidateFeature(unrestrictedTextureViews, "unrestricted texture view support") NzValidateFeature(unrestrictedTextureViews, "unrestricted texture view support")
#undef NzValidateFeature #undef NzValidateFeature

View File

@ -243,7 +243,7 @@ namespace Nz
void Seek(UInt64 frameIndex) override void Seek(UInt64 frameIndex) override
{ {
assert(frameIndex < m_frames.size()); assert(frameIndex <= m_frames.size());
if (m_requiresFrameHistory) if (m_requiresFrameHistory)
{ {

View File

@ -54,11 +54,20 @@ namespace Nz
deviceInfo.name = physDevice.properties.deviceName; deviceInfo.name = physDevice.properties.deviceName;
deviceInfo.features.anisotropicFiltering = physDevice.features.samplerAnisotropy; deviceInfo.features.anisotropicFiltering = physDevice.features.samplerAnisotropy;
deviceInfo.features.computeShaders = true;
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.features.storageBuffers = true;
deviceInfo.features.textureRead = true;
deviceInfo.features.textureReadWithoutFormat = physDevice.features.shaderStorageImageReadWithoutFormat;
deviceInfo.features.textureWrite = true;
deviceInfo.features.textureWriteWithoutFormat = physDevice.features.shaderStorageImageWriteWithoutFormat;
deviceInfo.features.unrestrictedTextureViews = true; deviceInfo.features.unrestrictedTextureViews = true;
deviceInfo.limits.maxComputeSharedMemorySize = physDevice.properties.limits.maxComputeSharedMemorySize;
deviceInfo.limits.maxComputeWorkGroupCount = { physDevice.properties.limits.maxComputeWorkGroupCount[0], physDevice.properties.limits.maxComputeWorkGroupCount[1], physDevice.properties.limits.maxComputeWorkGroupCount[2] };
deviceInfo.limits.maxComputeWorkGroupSize = { physDevice.properties.limits.maxComputeWorkGroupSize[0], physDevice.properties.limits.maxComputeWorkGroupSize[1], physDevice.properties.limits.maxComputeWorkGroupSize[2] };
deviceInfo.limits.maxComputeWorkGroupInvocations = physDevice.properties.limits.maxComputeWorkGroupInvocations;
deviceInfo.limits.maxStorageBufferSize = physDevice.properties.limits.maxStorageBufferRange; deviceInfo.limits.maxStorageBufferSize = physDevice.properties.limits.maxStorageBufferRange;
deviceInfo.limits.maxUniformBufferSize = physDevice.properties.limits.maxUniformBufferRange; deviceInfo.limits.maxUniformBufferSize = physDevice.properties.limits.maxUniformBufferRange;
deviceInfo.limits.minStorageBufferOffsetAlignment = physDevice.properties.limits.minStorageBufferOffsetAlignment; deviceInfo.limits.minStorageBufferOffsetAlignment = physDevice.properties.limits.minStorageBufferOffsetAlignment;

View File

@ -5,6 +5,7 @@
#include <Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp> #include <Nazara/VulkanRenderer/VulkanCommandBufferBuilder.hpp>
#include <Nazara/Utility/PixelFormat.hpp> #include <Nazara/Utility/PixelFormat.hpp>
#include <Nazara/VulkanRenderer/VulkanBuffer.hpp> #include <Nazara/VulkanRenderer/VulkanBuffer.hpp>
#include <Nazara/VulkanRenderer/VulkanComputePipeline.hpp>
#include <Nazara/VulkanRenderer/VulkanRenderPass.hpp> #include <Nazara/VulkanRenderer/VulkanRenderPass.hpp>
#include <Nazara/VulkanRenderer/VulkanRenderPipeline.hpp> #include <Nazara/VulkanRenderer/VulkanRenderPipeline.hpp>
#include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp> #include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp>
@ -72,6 +73,13 @@ namespace Nz
m_currentSubpassIndex = 0; m_currentSubpassIndex = 0;
} }
void VulkanCommandBufferBuilder::BindComputePipeline(const ComputePipeline& pipeline)
{
const VulkanComputePipeline& vkPipeline = static_cast<const VulkanComputePipeline&>(pipeline);
m_commandBuffer.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, vkPipeline.GetPipeline());
}
void VulkanCommandBufferBuilder::BindIndexBuffer(const RenderBuffer& indexBuffer, IndexType indexType, UInt64 offset) void VulkanCommandBufferBuilder::BindIndexBuffer(const RenderBuffer& indexBuffer, IndexType indexType, UInt64 offset)
{ {
const VulkanBuffer& vkBuffer = static_cast<const VulkanBuffer&>(indexBuffer); const VulkanBuffer& vkBuffer = static_cast<const VulkanBuffer&>(indexBuffer);
@ -79,14 +87,14 @@ namespace Nz
m_commandBuffer.BindIndexBuffer(vkBuffer.GetBuffer(), offset, ToVulkan(indexType)); m_commandBuffer.BindIndexBuffer(vkBuffer.GetBuffer(), offset, ToVulkan(indexType));
} }
void VulkanCommandBufferBuilder::BindPipeline(const RenderPipeline& pipeline) void VulkanCommandBufferBuilder::BindRenderPipeline(const RenderPipeline& pipeline)
{ {
if (!m_currentRenderPass) if (!m_currentRenderPass)
throw std::runtime_error("BindPipeline must be called in a RenderPass"); throw std::runtime_error("BindPipeline must be called in a RenderPass");
const VulkanRenderPipeline& vkBinding = static_cast<const VulkanRenderPipeline&>(pipeline); const VulkanRenderPipeline& vkPipeline = static_cast<const VulkanRenderPipeline&>(pipeline);
m_commandBuffer.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vkBinding.Get(*m_currentRenderPass, m_currentSubpassIndex)); m_commandBuffer.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vkPipeline.Get(*m_currentRenderPass, m_currentSubpassIndex));
} }
void VulkanCommandBufferBuilder::BindShaderBinding(UInt32 set, const ShaderBinding& binding) void VulkanCommandBufferBuilder::BindShaderBinding(UInt32 set, const ShaderBinding& binding)
@ -207,6 +215,11 @@ namespace Nz
m_commandBuffer.CopyImage(vkFromTexture.GetImage(), ToVulkan(fromLayout), vkToTexture.GetImage(), ToVulkan(toLayout), region); m_commandBuffer.CopyImage(vkFromTexture.GetImage(), ToVulkan(fromLayout), vkToTexture.GetImage(), ToVulkan(toLayout), region);
} }
void VulkanCommandBufferBuilder::Dispatch(UInt32 workgroupX, UInt32 workgroupY, UInt32 workgroupZ)
{
m_commandBuffer.Dispatch(workgroupX, workgroupY, workgroupZ);
}
void VulkanCommandBufferBuilder::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance) void VulkanCommandBufferBuilder::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance)
{ {
m_commandBuffer.Draw(vertexCount, instanceCount, firstVertex, firstInstance); m_commandBuffer.Draw(vertexCount, instanceCount, firstVertex, firstInstance);

View File

@ -0,0 +1,61 @@
// Copyright (C) 2022 Jérôme "Lynix" Leclercq (lynix680@gmail.com)
// This file is part of the "Nazara Engine - Vulkan renderer"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/VulkanRenderer/VulkanComputePipeline.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/VulkanRenderer/Utils.hpp>
#include <Nazara/VulkanRenderer/VulkanDevice.hpp>
#include <Nazara/VulkanRenderer/VulkanComputePipeline.hpp>
#include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp>
#include <Nazara/VulkanRenderer/VulkanShaderModule.hpp>
#include <cassert>
#include <Nazara/VulkanRenderer/Debug.hpp>
namespace Nz
{
VulkanComputePipeline::VulkanComputePipeline(VulkanDevice& device, ComputePipelineInfo pipelineInfo) :
m_pipelineInfo(std::move(pipelineInfo))
{
if (device.GetEnabledFeatures().computeShaders)
throw std::runtime_error("compute shaders are not enabled on the device");
VulkanShaderModule& vulkanModule = static_cast<VulkanShaderModule&>(*m_pipelineInfo.shaderModule);
const VulkanShaderModule::Stage* computeStage = nullptr;
for (const auto& stage : vulkanModule.GetStages())
{
if (stage.stage != nzsl::ShaderStageType::Compute)
continue;
if (computeStage)
throw std::runtime_error("multiple compute stages found in shader module");
computeStage = &stage;
}
if (!computeStage)
throw std::runtime_error("no compute stages found in shader module");
VkComputePipelineCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
createInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
createInfo.stage.module = vulkanModule.GetHandle();
createInfo.stage.pName = computeStage->name.data();
createInfo.stage.stage = ToVulkan(computeStage->stage);
VulkanRenderPipelineLayout& pipelineLayout = *static_cast<VulkanRenderPipelineLayout*>(m_pipelineInfo.pipelineLayout.get());
createInfo.layout = pipelineLayout.GetPipelineLayout();
if (!m_pipeline.CreateCompute(device, createInfo))
throw std::runtime_error("failed to create compute pipeline: " + TranslateVulkanError(m_pipeline.GetLastErrorCode()));
}
void VulkanComputePipeline::UpdateDebugName(std::string_view name)
{
m_pipeline.SetDebugName(name);
}
}
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Core/AntiWindows.hpp>
#endif

View File

@ -4,6 +4,7 @@
#include <Nazara/VulkanRenderer/VulkanDevice.hpp> #include <Nazara/VulkanRenderer/VulkanDevice.hpp>
#include <Nazara/VulkanRenderer/VulkanCommandPool.hpp> #include <Nazara/VulkanRenderer/VulkanCommandPool.hpp>
#include <Nazara/VulkanRenderer/VulkanComputePipeline.hpp>
#include <Nazara/VulkanRenderer/VulkanRenderPass.hpp> #include <Nazara/VulkanRenderer/VulkanRenderPass.hpp>
#include <Nazara/VulkanRenderer/VulkanRenderPipeline.hpp> #include <Nazara/VulkanRenderer/VulkanRenderPipeline.hpp>
#include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp> #include <Nazara/VulkanRenderer/VulkanRenderPipelineLayout.hpp>
@ -37,6 +38,11 @@ namespace Nz
return std::make_shared<VulkanCommandPool>(*this, queueType); return std::make_shared<VulkanCommandPool>(*this, queueType);
} }
std::shared_ptr<ComputePipeline> VulkanDevice::InstantiateComputePipeline(ComputePipelineInfo pipelineInfo)
{
return std::make_shared<VulkanComputePipeline>(*this, std::move(pipelineInfo));
}
std::shared_ptr<Framebuffer> VulkanDevice::InstantiateFramebuffer(unsigned int width, unsigned int height, const std::shared_ptr<RenderPass>& renderPass, const std::vector<std::shared_ptr<Texture>>& attachments) std::shared_ptr<Framebuffer> VulkanDevice::InstantiateFramebuffer(unsigned int width, unsigned int height, const std::shared_ptr<RenderPass>& renderPass, const std::vector<std::shared_ptr<Texture>>& attachments)
{ {
return std::make_shared<VulkanTextureFramebuffer>(*this, width, height, renderPass, attachments); return std::make_shared<VulkanTextureFramebuffer>(*this, width, height, renderPass, attachments);
@ -111,6 +117,10 @@ namespace Nz
flags = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; flags = VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
break; break;
case TextureUsage::ShaderReadWrite:
flags = VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
break;
case TextureUsage::TransferSource: case TextureUsage::TransferSource:
flags = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT; flags = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT;
break; break;

View File

@ -27,9 +27,9 @@ namespace Nz
if constexpr (std::is_same_v<T, StorageBufferBinding> || std::is_same_v<T, UniformBufferBinding>) if constexpr (std::is_same_v<T, StorageBufferBinding> || std::is_same_v<T, UniformBufferBinding>)
bufferBindingCount++; bufferBindingCount++;
else if constexpr (std::is_same_v<T, TextureBinding>) else if constexpr (std::is_same_v<T, SampledTextureBinding> || std::is_same_v<T, TextureBinding>)
imageBindingCount++; imageBindingCount++;
else if constexpr (std::is_same_v<T, TextureBindings>) else if constexpr (std::is_same_v<T, SampledTextureBindings>)
imageBindingCount += arg.arraySize; imageBindingCount += arg.arraySize;
else else
static_assert(AlwaysFalse<T>(), "non-exhaustive visitor"); static_assert(AlwaysFalse<T>(), "non-exhaustive visitor");
@ -58,20 +58,7 @@ namespace Nz
{ {
using T = std::decay_t<decltype(arg)>; using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, StorageBufferBinding>) if constexpr (std::is_same_v<T, SampledTextureBinding>)
{
VulkanBuffer* vkBuffer = SafeCast<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 = SafeCast<const VulkanTexture*>(arg.texture); const VulkanTexture* vkTexture = SafeCast<const VulkanTexture*>(arg.texture);
const VulkanTextureSampler* vkSampler = SafeCast<const VulkanTextureSampler*>(arg.sampler); const VulkanTextureSampler* vkSampler = SafeCast<const VulkanTextureSampler*>(arg.sampler);
@ -85,7 +72,7 @@ namespace Nz
writeOp.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; writeOp.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeOp.pImageInfo = &imageInfo; writeOp.pImageInfo = &imageInfo;
} }
else if constexpr (std::is_same_v<T, TextureBindings>) else if constexpr (std::is_same_v<T, SampledTextureBindings>)
{ {
for (UInt32 i = 0; i < arg.arraySize; ++i) for (UInt32 i = 0; i < arg.arraySize; ++i)
{ {
@ -102,6 +89,32 @@ namespace Nz
writeOp.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; writeOp.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeOp.pImageInfo = &imageBinding[imageBinding.size() - arg.arraySize]; writeOp.pImageInfo = &imageBinding[imageBinding.size() - arg.arraySize];
} }
else if constexpr (std::is_same_v<T, StorageBufferBinding>)
{
VulkanBuffer* vkBuffer = SafeCast<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 = SafeCast<const VulkanTexture*>(arg.texture);
VkDescriptorImageInfo& imageInfo = imageBinding.emplace_back();
imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
imageInfo.imageView = (vkTexture) ? vkTexture->GetImageView() : VK_NULL_HANDLE;
imageInfo.sampler = VK_NULL_HANDLE;
writeOp.descriptorCount = 1;
writeOp.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
writeOp.pImageInfo = &imageInfo;
}
else if constexpr (std::is_same_v<T, UniformBufferBinding>) else if constexpr (std::is_same_v<T, UniformBufferBinding>)
{ {
VulkanBuffer* vkBuffer = static_cast<VulkanBuffer*>(arg.buffer); VulkanBuffer* vkBuffer = static_cast<VulkanBuffer*>(arg.buffer);