diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp index a597a2958..fc80a9ada 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.hpp @@ -8,22 +8,138 @@ #define NAZARA_OPENGLRENDERER_OPENGLCOMMANDBUFFER_HPP #include +#include +#include #include +#include #include +#include +#include +#include +#include +#include #include namespace Nz { + class OpenGLFramebuffer; + class NAZARA_OPENGLRENDERER_API OpenGLCommandBuffer final : public CommandBuffer { public: - inline OpenGLCommandBuffer(); + OpenGLCommandBuffer() = default; OpenGLCommandBuffer(const OpenGLCommandBuffer&) = delete; OpenGLCommandBuffer(OpenGLCommandBuffer&&) noexcept = default; ~OpenGLCommandBuffer() = default; + inline void BeginDebugRegion(const std::string_view& regionName, const Nz::Color& color); + + inline void BindIndexBuffer(GLuint indexBuffer, UInt64 offset = 0); + inline void BindPipeline(const OpenGLRenderPipeline* pipeline); + inline void BindShaderBinding(const OpenGLShaderBinding* binding); + inline void BindVertexBuffer(UInt32 binding, GLuint vertexBuffer, UInt64 offset = 0); + + inline void CopyBuffer(GLuint source, 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 Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0); + inline void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0); + + inline void EndDebugRegion(); + + void Execute(); + + inline void SetFramebuffer(const OpenGLFramebuffer& framebuffer, const RenderPass& renderPass, std::initializer_list clearValues); + inline void SetScissor(Nz::Recti scissorRegion); + inline void SetViewport(Nz::Recti viewportRegion); + OpenGLCommandBuffer& operator=(const OpenGLCommandBuffer&) = delete; OpenGLCommandBuffer& operator=(OpenGLCommandBuffer&&) = delete; + + private: + struct DrawStates; + + void ApplyStates(const GL::Context& context, const DrawStates& states); + + struct BeginDebugRegionData + { + std::string regionName; + Nz::Color color; + }; + + struct CopyBufferData + { + GLuint source; + GLuint target; + UInt64 size; + UInt64 sourceOffset; + UInt64 targetOffset; + }; + + struct CopyBufferFromMemoryData + { + const void* memory; + GLuint target; + UInt64 size; + UInt64 targetOffset; + }; + + struct DrawStates + { + struct VertexBuffer + { + GLuint vertexBuffer = 0; + UInt64 offset; + }; + + GLuint indexBuffer = 0; + const OpenGLRenderPipeline* pipeline = nullptr; + const OpenGLShaderBinding* shaderBindings = nullptr; + UInt64 indexBufferOffset; + std::optional scissorRegion; + std::optional viewportRegion; + std::vector vertexBuffers; + }; + + struct DrawData + { + DrawStates states; + UInt32 firstInstance; + UInt32 firstVertex; + UInt32 instanceCount; + UInt32 vertexCount; + }; + + struct DrawIndexedData + { + DrawStates states; + UInt32 firstInstance; + UInt32 firstVertex; + UInt32 indexCount; + UInt32 instanceCount; + }; + + struct EndDebugRegionData + { + }; + + struct SetFrameBufferData + { + const OpenGLFramebuffer* framebuffer; + }; + + using CommandData = std::variant< + BeginDebugRegionData, + CopyBufferData, + CopyBufferFromMemoryData, + DrawData, + DrawIndexedData, + EndDebugRegionData, + SetFrameBufferData + >; + + DrawStates m_currentStates; + std::vector m_commands; }; } diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl index 7ccd4573a..892550d8e 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandBuffer.inl @@ -3,10 +3,124 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include #include namespace Nz { + inline void OpenGLCommandBuffer::BeginDebugRegion(const std::string_view& regionName, const Nz::Color& color) + { + BeginDebugRegionData beginDebugRegion; + beginDebugRegion.color = color; + beginDebugRegion.regionName = regionName; + + m_commands.emplace_back(std::move(beginDebugRegion)); + } + + inline void OpenGLCommandBuffer::BindIndexBuffer(GLuint indexBuffer, UInt64 offset) + { + m_currentStates.indexBuffer = indexBuffer; + m_currentStates.indexBufferOffset = offset; + } + + inline void OpenGLCommandBuffer::BindPipeline(const OpenGLRenderPipeline* pipeline) + { + m_currentStates.pipeline = pipeline; + } + + inline void OpenGLCommandBuffer::BindShaderBinding(const OpenGLShaderBinding* binding) + { + m_currentStates.shaderBindings = binding; + } + + inline void OpenGLCommandBuffer::BindVertexBuffer(UInt32 binding, GLuint vertexBuffer, UInt64 offset) + { + if (binding >= m_currentStates.vertexBuffers.size()) + m_currentStates.vertexBuffers.resize(binding + 1); + + auto& vertexBufferData = m_currentStates.vertexBuffers[binding]; + vertexBufferData.offset = offset; + vertexBufferData.vertexBuffer = vertexBuffer; + } + + inline void OpenGLCommandBuffer::CopyBuffer(GLuint source, GLuint target, UInt64 size, UInt64 sourceOffset, UInt64 targetOffset) + { + CopyBufferData copyBuffer = { + source, + target, + size, + sourceOffset, + targetOffset + }; + + m_commands.emplace_back(std::move(copyBuffer)); + } + + inline void OpenGLCommandBuffer::CopyBuffer(const UploadPool::Allocation& allocation, GLuint target, UInt64 size, UInt64 sourceOffset, UInt64 targetOffset) + { + CopyBufferFromMemoryData copyBuffer = { + static_cast(allocation.mappedPtr) + sourceOffset, + target, + size, + targetOffset + }; + + m_commands.emplace_back(std::move(copyBuffer)); + } + + inline void OpenGLCommandBuffer::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance) + { + if (!m_currentStates.pipeline) + throw std::runtime_error("no pipeline bound"); + + DrawData draw; + draw.states = m_currentStates; + draw.firstInstance = firstInstance; + draw.firstVertex = firstVertex; + draw.instanceCount = instanceCount; + draw.vertexCount = vertexCount; + + m_commands.emplace_back(std::move(draw)); + } + + inline void OpenGLCommandBuffer::DrawIndexed(UInt32 indexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance) + { + if (!m_currentStates.pipeline) + throw std::runtime_error("no pipeline bound"); + + DrawIndexedData draw; + draw.states = m_currentStates; + draw.firstInstance = firstInstance; + draw.firstVertex = firstVertex; + draw.indexCount = indexCount; + draw.instanceCount = instanceCount; + + m_commands.emplace_back(std::move(draw)); + } + + inline void OpenGLCommandBuffer::EndDebugRegion() + { + m_commands.emplace_back(EndDebugRegionData{}); + } + + inline void OpenGLCommandBuffer::SetFramebuffer(const OpenGLFramebuffer& framebuffer, const RenderPass& /*renderPass*/, std::initializer_list clearValues) + { + SetFrameBufferData setFramebuffer; + setFramebuffer.framebuffer = &framebuffer; + + m_commands.emplace_back(std::move(setFramebuffer)); + } + + inline void OpenGLCommandBuffer::SetScissor(Nz::Recti scissorRegion) + { + m_currentStates.scissorRegion = scissorRegion; + } + + inline void OpenGLCommandBuffer::SetViewport(Nz::Recti viewportRegion) + { + m_currentStates.viewportRegion = viewportRegion; + } } #include diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.hpp b/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.hpp index dc50b94d6..14199c665 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.hpp @@ -13,12 +13,12 @@ namespace Nz { - class OpenGLRenderPass; + class OpenGLCommandBuffer; class NAZARA_OPENGLRENDERER_API OpenGLCommandBufferBuilder final : public CommandBufferBuilder { public: - OpenGLCommandBufferBuilder() = default; + inline OpenGLCommandBufferBuilder(OpenGLCommandBuffer& commandBuffer); OpenGLCommandBufferBuilder(const OpenGLCommandBufferBuilder&) = delete; OpenGLCommandBufferBuilder(OpenGLCommandBufferBuilder&&) noexcept = default; ~OpenGLCommandBufferBuilder() = default; @@ -48,9 +48,12 @@ namespace Nz OpenGLCommandBufferBuilder& operator=(const OpenGLCommandBufferBuilder&) = delete; OpenGLCommandBufferBuilder& operator=(OpenGLCommandBufferBuilder&&) = delete; + + private: + OpenGLCommandBuffer& m_commandBuffer; }; } #include -#endif // NAZARA_OPENGLRENDERER_OPENGLCOMMANDBUFFERBUILDER_HPP +#endif diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.inl b/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.inl index 8649e54e2..54d7f17c4 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.inl @@ -7,6 +7,10 @@ namespace Nz { + inline OpenGLCommandBufferBuilder::OpenGLCommandBufferBuilder(OpenGLCommandBuffer& commandBuffer) : + m_commandBuffer(commandBuffer) + { + } } #include diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandPool.hpp b/include/Nazara/OpenGLRenderer/OpenGLCommandPool.hpp index fa68f0ac4..bc79593b9 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandPool.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandPool.hpp @@ -10,15 +10,13 @@ #include #include #include -#include namespace Nz { class NAZARA_OPENGLRENDERER_API OpenGLCommandPool final : public CommandPool { public: - inline OpenGLCommandPool(Vk::Device& device, QueueType queueType); - inline OpenGLCommandPool(Vk::Device& device, UInt32 queueFamilyIndex); + OpenGLCommandPool() = default; OpenGLCommandPool(const OpenGLCommandPool&) = delete; OpenGLCommandPool(OpenGLCommandPool&&) noexcept = default; ~OpenGLCommandPool() = default; @@ -27,9 +25,6 @@ namespace Nz OpenGLCommandPool& operator=(const OpenGLCommandPool&) = delete; OpenGLCommandPool& operator=(OpenGLCommandPool&&) = delete; - - private: - Vk::CommandPool m_commandPool; }; } diff --git a/include/Nazara/OpenGLRenderer/OpenGLCommandPool.inl b/include/Nazara/OpenGLRenderer/OpenGLCommandPool.inl index a8db6b7f3..3da51fb3b 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLCommandPool.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLCommandPool.inl @@ -8,21 +8,6 @@ namespace Nz { - inline OpenGLCommandPool::OpenGLCommandPool(Vk::Device& device, QueueType queueType) - { - UInt32 queueFamilyIndex = device.GetDefaultFamilyIndex(queueType); - if (queueFamilyIndex == Vk::Device::InvalidQueue) - throw std::runtime_error("QueueType " + std::to_string(UnderlyingCast(queueType)) + " is not supported"); - - if (!m_commandPool.Create(device, queueFamilyIndex)) - throw std::runtime_error("Failed to create command pool: " + TranslateOpenGLError(m_commandPool.GetLastErrorCode())); - } - - inline OpenGLCommandPool::OpenGLCommandPool(Vk::Device& device, UInt32 queueFamilyIndex) - { - if (!m_commandPool.Create(device, queueFamilyIndex)) - throw std::runtime_error("Failed to create command pool: " + TranslateOpenGLError(m_commandPool.GetLastErrorCode())); - } } #include diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderImage.hpp b/include/Nazara/OpenGLRenderer/OpenGLRenderImage.hpp index def3104e2..2c8507e7f 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderImage.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderImage.hpp @@ -14,6 +14,7 @@ namespace Nz { + class OpenGLCommandBuffer; class OpenGLRenderWindow; class NAZARA_OPENGLRENDERER_API OpenGLRenderImage : public RenderImage diff --git a/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp b/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp index 2107d9379..30ceb101c 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLRenderPipelineLayout.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -53,12 +54,15 @@ namespace Nz struct TextureDescriptor { + UInt32 bindingIndex; GLuint texture; GLuint sampler; + GL::TextureTarget textureTarget; }; struct UniformBufferDescriptor { + UInt32 bindingIndex; GLuint buffer; GLintptr offset; GLsizeiptr size; diff --git a/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.hpp b/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.hpp index d920c2929..f74cc904d 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLShaderBinding.hpp @@ -9,6 +9,7 @@ #include #include +#include #include namespace Nz @@ -23,6 +24,8 @@ namespace Nz OpenGLShaderBinding(OpenGLShaderBinding&&) noexcept = default; ~OpenGLShaderBinding() = default; + void Apply(const GL::Context& context) const; + inline std::size_t GetBindingIndex() const; inline std::size_t GetPoolIndex() const; inline const OpenGLRenderPipelineLayout& GetOwner() const; diff --git a/include/Nazara/OpenGLRenderer/OpenGLShaderStage.hpp b/include/Nazara/OpenGLRenderer/OpenGLShaderStage.hpp index 579704ffe..f72f282ad 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLShaderStage.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLShaderStage.hpp @@ -24,6 +24,8 @@ namespace Nz OpenGLShaderStage(OpenGLShaderStage&&) noexcept = default; ~OpenGLShaderStage() = default; + inline const GL::Shader& GetShader() const; + OpenGLShaderStage& operator=(const OpenGLShaderStage&) = delete; OpenGLShaderStage& operator=(OpenGLShaderStage&&) noexcept = default; diff --git a/include/Nazara/OpenGLRenderer/OpenGLShaderStage.inl b/include/Nazara/OpenGLRenderer/OpenGLShaderStage.inl index 305f1968a..6d1ccb62f 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLShaderStage.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLShaderStage.inl @@ -7,6 +7,10 @@ namespace Nz { + inline const GL::Shader& OpenGLShaderStage::GetShader() const + { + return m_shader; + } } #include diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp index ae0fd627f..1c648054e 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp @@ -9,7 +9,9 @@ #include #include +#include #include +#include #include #include #include @@ -94,17 +96,21 @@ namespace Nz::GL inline Context(const OpenGLDevice* device); virtual ~Context(); - void BindBuffer(BufferTarget target, GLuint buffer) const; + void BindBuffer(BufferTarget target, GLuint buffer, bool force = false) const; void BindFramebuffer(GLuint fbo) const; void BindFramebuffer(FramebufferTarget target, GLuint fbo) const; + void BindProgram(GLuint program) const; void BindSampler(UInt32 textureUnit, GLuint sampler) const; void BindTexture(TextureTarget target, GLuint texture) const; void BindTexture(UInt32 textureUnit, TextureTarget target, GLuint texture) const; + void BindUniformBuffer(UInt32 uboUnit, GLuint buffer, GLintptr offset, GLsizeiptr size) const; + void BindVertexArray(GLuint vertexArray, bool force = false) const; virtual void EnableVerticalSync(bool enabled) = 0; inline const OpenGLDevice* GetDevice() const; inline ExtensionStatus GetExtensionStatus(Extension extension) const; + inline const OpenGLVaoCache& GetVaoCache() const; inline const ContextParams& GetParams() const; inline bool IsExtensionSupported(Extension extension) const; @@ -116,8 +122,11 @@ namespace Nz::GL inline void NotifyProgramDestruction(GLuint program) const; inline void NotifySamplerDestruction(GLuint sampler) const; inline void NotifyTextureDestruction(GLuint texture) const; + inline void NotifyVertexArrayDestruction(GLuint vao) const; - inline void SetCurrentTextureUnit(UInt32 textureUnit) const; + void SetCurrentTextureUnit(UInt32 textureUnit) const; + void SetScissorBox(GLint x, GLint y, GLsizei width, GLsizei height) const; + void SetViewport(GLint x, GLint y, GLsizei width, GLsizei height) const; virtual void SwapBuffers() = 0; @@ -134,6 +143,7 @@ namespace Nz::GL virtual bool Activate() const = 0; virtual void Desactivate() const = 0; virtual const Loader& GetLoader() = 0; + void OnContextRelease(); virtual bool ImplementFallback(const std::string_view& function); @@ -146,23 +156,41 @@ namespace Nz::GL struct State { + struct Box + { + GLint x, y; + GLsizei width, height; + }; + struct TextureUnit { GLuint sampler = 0; std::array textureTargets = { 0 }; }; + struct UniformBufferUnit + { + GLuint buffer = 0; + GLintptr offset = 0; + GLsizeiptr size = 0; + }; + std::array bufferTargets = { 0 }; std::vector textureUnits; + std::vector uboUnits; + Box scissorBox; + Box viewport; GLuint boundProgram = 0; GLuint boundDrawFBO = 0; GLuint boundReadFBO = 0; + GLuint boundVertexArray = 0; UInt32 currentTextureUnit = 0; RenderStates renderStates; }; std::array m_extensionStatus; std::unordered_set m_supportedExtensions; + OpenGLVaoCache m_vaoCache; const OpenGLDevice* m_device; mutable State m_state; }; diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Context.inl b/include/Nazara/OpenGLRenderer/Wrapper/Context.inl index bf2dbe86b..59c44805b 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Context.inl +++ b/include/Nazara/OpenGLRenderer/Wrapper/Context.inl @@ -8,6 +8,7 @@ namespace Nz::GL { inline Context::Context(const OpenGLDevice* device) : + m_vaoCache(*this), m_device(device) { } @@ -22,6 +23,11 @@ namespace Nz::GL return m_extensionStatus[UnderlyingCast(extension)]; } + inline const OpenGLVaoCache& Context::GetVaoCache() const + { + return m_vaoCache; + } + inline const ContextParams& Context::GetParams() const { return m_params; @@ -73,13 +79,10 @@ namespace Nz::GL } } - inline void Context::SetCurrentTextureUnit(UInt32 textureUnit) const + inline void Context::NotifyVertexArrayDestruction(GLuint vao) const { - if (m_state.currentTextureUnit != textureUnit) - { - glActiveTexture(GL_TEXTURE0 + textureUnit); - m_state.currentTextureUnit = textureUnit; - } + if (m_state.boundVertexArray == vao) + m_state.boundVertexArray = 0; } } diff --git a/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp b/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp index 41bf3f3b1..eac73f9ca 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLCommandBuffer.cpp @@ -2,13 +2,141 @@ // This file is part of the "Nazara Engine - OpenGL Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp -#if 0 - #include +#include +#include +#include #include namespace Nz { -} + namespace + { + void BuildAttrib(GL::OpenGLVaoSetup::Attribs& attrib, ComponentType component) + { + switch (component) + { + case ComponentType_Color: + attrib.normalized = GL_TRUE; + attrib.size = 4; + attrib.type = GL_UNSIGNED_BYTE; + return; -#endif + case ComponentType_Float1: + case ComponentType_Float2: + case ComponentType_Float3: + case ComponentType_Float4: + attrib.normalized = GL_FALSE; + attrib.size = (component - ComponentType_Float1 + 1); + attrib.type = GL_FLOAT; + return; + + case ComponentType_Int1: + case ComponentType_Int2: + case ComponentType_Int3: + case ComponentType_Int4: + attrib.normalized = GL_FALSE; + attrib.size = (component - ComponentType_Int1 + 1); + attrib.type = GL_INT; + return; + + case ComponentType_Double1: + case ComponentType_Double2: + case ComponentType_Double3: + case ComponentType_Double4: + case ComponentType_Quaternion: + break; + } + + throw std::runtime_error(("component type 0x" + String::Number(component, 16) + " is not handled").ToStdString()); + } + } + + void OpenGLCommandBuffer::Execute() + { + const GL::Context* context = GL::Context::GetCurrentContext(); + + for (const auto& command : m_commands) + { + std::visit([&](auto&& command) + { + using T = std::decay_t; + + if constexpr (std::is_same_v || std::is_same_v) + { + // TODO + } + else if constexpr (std::is_same_v) + { + context->BindBuffer(GL::BufferTarget::CopyRead, command.source); + context->BindBuffer(GL::BufferTarget::CopyWrite, command.target); + context->glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, command.sourceOffset, command.targetOffset, command.size); + } + else if constexpr (std::is_same_v) + { + context->BindBuffer(GL::BufferTarget::CopyWrite, command.target); + context->glBufferSubData(GL_COPY_WRITE_BUFFER, command.targetOffset, command.size, command.memory); + } + else if constexpr (std::is_same_v) + { + ApplyStates(*context, m_currentStates); + context->glDrawArraysInstanced(GL_TRIANGLES, command.firstVertex, command.vertexCount, command.instanceCount); + } + else if constexpr (std::is_same_v) + { + ApplyStates(*context, m_currentStates); + context->glDrawElementsInstanced(GL_TRIANGLES, command.indexCount, GL_UNSIGNED_SHORT, nullptr, command.instanceCount); + } + else if constexpr (std::is_same_v) + { + command.framebuffer->Activate(); + + context = GL::Context::GetCurrentContext(); + context->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + else + static_assert(AlwaysFalse::value, "non-exhaustive visitor"); + + }, command); + } + } + + void OpenGLCommandBuffer::ApplyStates(const GL::Context& context, const DrawStates& states) + { + states.shaderBindings->Apply(context); + states.pipeline->Apply(context); + + if (states.scissorRegion) + context.SetScissorBox(states.scissorRegion->x, states.scissorRegion->y, states.scissorRegion->width, states.scissorRegion->height); + + if (states.viewportRegion) + context.SetViewport(states.viewportRegion->x, states.viewportRegion->y, states.viewportRegion->width, states.viewportRegion->height); + + GL::OpenGLVaoSetup vaoSetup; + vaoSetup.indexBuffer = states.indexBuffer; + + std::uint32_t locationIndex = 0; + const std::uint8_t* originPtr = 0; + + for (const auto& bufferData : states.pipeline->GetPipelineInfo().vertexBuffers) + { + assert(bufferData.binding < states.vertexBuffers.size()); + const auto& vertexBufferInfo = states.vertexBuffers[bufferData.binding]; + + GLsizei stride = GLsizei(bufferData.declaration->GetStride()); + + for (const auto& componentInfo : *bufferData.declaration) + { + auto& bufferAttribute = vaoSetup.vertexAttribs[locationIndex++].emplace(); + BuildAttrib(bufferAttribute, componentInfo.type); + + bufferAttribute.pointer = originPtr + vertexBufferInfo.offset + componentInfo.offset; + bufferAttribute.stride = stride; + bufferAttribute.vertexBuffer = vertexBufferInfo.vertexBuffer; + } + } + + const GL::VertexArray& vao = context.GetVaoCache().Get(vaoSetup); + context.BindVertexArray(vao.GetObjectId(), true); + } +} diff --git a/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp b/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp index 4e17054be..e10d0de22 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLCommandBufferBuilder.cpp @@ -2,16 +2,12 @@ // This file is part of the "Nazara Engine - OpenGL Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp -#if 0 - #include #include -#include -#include +#include #include #include #include -#include #include #include #include @@ -20,112 +16,40 @@ namespace Nz { void OpenGLCommandBufferBuilder::BeginDebugRegion(const std::string_view& regionName, const Nz::Color& color) { - // Ensure \0 at the end of string - StackArray regionNameEOS = NazaraStackArrayNoInit(char, regionName.size() + 1); - std::memcpy(regionNameEOS.data(), regionName.data(), regionName.size()); - regionNameEOS[regionName.size()] = '\0'; - - m_commandBuffer.BeginDebugRegion(regionNameEOS.data(), color); + m_commandBuffer.BeginDebugRegion(regionName, color); } void OpenGLCommandBufferBuilder::BeginRenderPass(const Framebuffer& framebuffer, const RenderPass& renderPass, Nz::Recti renderRect, std::initializer_list clearValues) { - const OpenGLRenderPass& vkRenderPass = static_cast(renderPass); - - const Vk::Framebuffer& vkFramebuffer = [&] () -> const Vk::Framebuffer& - { - const OpenGLFramebuffer& vkFramebuffer = static_cast(framebuffer); - switch (vkFramebuffer.GetType()) - { - case OpenGLFramebuffer::Type::Multiple: - { - const OpenGLMultipleFramebuffer& vkMultipleFramebuffer = static_cast(vkFramebuffer); - m_framebufferCount = std::max(m_framebufferCount, vkMultipleFramebuffer.GetFramebufferCount()); - return vkMultipleFramebuffer.GetFramebuffer(m_imageIndex); - } - - case OpenGLFramebuffer::Type::Single: - return static_cast(vkFramebuffer).GetFramebuffer(); - } - - throw std::runtime_error("Unhandled framebuffer type " + std::to_string(UnderlyingCast(vkFramebuffer.GetType()))); - }(); - - VkRect2D renderArea; - renderArea.offset.x = renderRect.x; - renderArea.offset.y = renderRect.y; - renderArea.extent.width = renderRect.width; - renderArea.extent.height = renderRect.height; - - StackArray vkClearValues = NazaraStackArray(VkClearValue, clearValues.size()); - - std::size_t index = 0; - for (const ClearValues& values : clearValues) - { - auto& vkValues = vkClearValues[index]; - - if (PixelFormatInfo::GetContent(vkRenderPass.GetAttachmentFormat(index)) == PixelFormatContent_ColorRGBA) - { - vkValues.color.float32[0] = values.color.r / 255.f; - vkValues.color.float32[1] = values.color.g / 255.f; - vkValues.color.float32[2] = values.color.b / 255.f; - vkValues.color.float32[3] = values.color.a / 255.f; - } - else - { - vkValues.depthStencil.depth = values.depth; - vkValues.depthStencil.stencil = values.stencil; - } - - index++; - } - - VkRenderPassBeginInfo beginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO }; - beginInfo.renderPass = vkRenderPass.GetRenderPass(); - beginInfo.framebuffer = vkFramebuffer; - beginInfo.renderArea.offset.x = renderRect.x; - beginInfo.renderArea.offset.y = renderRect.y; - beginInfo.renderArea.extent.width = renderRect.width; - beginInfo.renderArea.extent.height = renderRect.height; - beginInfo.clearValueCount = vkClearValues.size(); - beginInfo.pClearValues = vkClearValues.data(); - - m_commandBuffer.BeginRenderPass(beginInfo); - - m_currentRenderPass = &vkRenderPass; + m_commandBuffer.SetFramebuffer(static_cast(framebuffer), renderPass, clearValues); } void OpenGLCommandBufferBuilder::BindIndexBuffer(Nz::AbstractBuffer* indexBuffer, UInt64 offset) { - OpenGLBuffer& vkBuffer = *static_cast(indexBuffer); + OpenGLBuffer* glBuffer = static_cast(indexBuffer); - m_commandBuffer.BindIndexBuffer(vkBuffer.GetBuffer(), offset, VK_INDEX_TYPE_UINT16); //< Fuck me right? + m_commandBuffer.BindIndexBuffer(glBuffer->GetBuffer().GetObjectId()); } void OpenGLCommandBufferBuilder::BindPipeline(const RenderPipeline& pipeline) { - if (!m_currentRenderPass) - throw std::runtime_error("BindPipeline must be called in a RenderPass"); + const OpenGLRenderPipeline& glPipeline = static_cast(pipeline); - const OpenGLRenderPipeline& vkBinding = static_cast(pipeline); - - m_commandBuffer.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vkBinding.Get(m_currentRenderPass->GetRenderPass())); + m_commandBuffer.BindPipeline(&glPipeline); } void OpenGLCommandBufferBuilder::BindShaderBinding(const ShaderBinding& binding) { - const OpenGLShaderBinding& vkBinding = static_cast(binding); + const OpenGLShaderBinding& glBinding = static_cast(binding); - const OpenGLRenderPipelineLayout& pipelineLayout = vkBinding.GetOwner(); - - m_commandBuffer.BindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.GetPipelineLayout(), 0U, vkBinding.GetDescriptorSet()); + m_commandBuffer.BindShaderBinding(&glBinding); } void OpenGLCommandBufferBuilder::BindVertexBuffer(UInt32 binding, Nz::AbstractBuffer* vertexBuffer, UInt64 offset) { - OpenGLBuffer& vkBuffer = *static_cast(vertexBuffer); + OpenGLBuffer* glBuffer = static_cast(vertexBuffer); - m_commandBuffer.BindVertexBuffer(binding, vkBuffer.GetBuffer(), offset); + m_commandBuffer.BindVertexBuffer(binding, glBuffer->GetBuffer().GetObjectId(), offset); } void OpenGLCommandBufferBuilder::CopyBuffer(const RenderBufferView& source, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset, UInt64 targetOffset) @@ -133,15 +57,14 @@ namespace Nz OpenGLBuffer& sourceBuffer = *static_cast(source.GetBuffer()); OpenGLBuffer& targetBuffer = *static_cast(target.GetBuffer()); - m_commandBuffer.CopyBuffer(sourceBuffer.GetBuffer(), targetBuffer.GetBuffer(), size, sourceOffset + source.GetOffset(), targetOffset + target.GetOffset()); + m_commandBuffer.CopyBuffer(sourceBuffer.GetBuffer().GetObjectId(), targetBuffer.GetBuffer().GetObjectId(), size, sourceOffset + source.GetOffset(), targetOffset + target.GetOffset()); } void OpenGLCommandBufferBuilder::CopyBuffer(const UploadPool::Allocation& allocation, const RenderBufferView& target, UInt64 size, UInt64 sourceOffset, UInt64 targetOffset) { - const auto& vkAllocation = static_cast(allocation); OpenGLBuffer& targetBuffer = *static_cast(target.GetBuffer()); - m_commandBuffer.CopyBuffer(vkAllocation.buffer, targetBuffer.GetBuffer(), size, vkAllocation.offset + sourceOffset, target.GetOffset() + targetOffset); + m_commandBuffer.CopyBuffer(allocation, targetBuffer.GetBuffer().GetObjectId(), size, sourceOffset, target.GetOffset() + targetOffset); } void OpenGLCommandBufferBuilder::Draw(UInt32 vertexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance) @@ -151,7 +74,7 @@ namespace Nz void OpenGLCommandBufferBuilder::DrawIndexed(UInt32 indexCount, UInt32 instanceCount, UInt32 firstVertex, UInt32 firstInstance) { - m_commandBuffer.DrawIndexed(indexCount, instanceCount, firstVertex, 0, firstInstance); + m_commandBuffer.DrawIndexed(indexCount, instanceCount, firstVertex, firstInstance); } void OpenGLCommandBufferBuilder::EndDebugRegion() @@ -161,18 +84,14 @@ namespace Nz void OpenGLCommandBufferBuilder::EndRenderPass() { - m_commandBuffer.EndRenderPass(); - m_currentRenderPass = nullptr; } void OpenGLCommandBufferBuilder::PreTransferBarrier() { - m_commandBuffer.MemoryBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0U, VK_ACCESS_TRANSFER_READ_BIT); } void OpenGLCommandBufferBuilder::PostTransferBarrier() { - m_commandBuffer.MemoryBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT); } void OpenGLCommandBufferBuilder::SetScissor(Nz::Recti scissorRegion) @@ -182,8 +101,6 @@ namespace Nz void OpenGLCommandBufferBuilder::SetViewport(Nz::Recti viewportRegion) { - m_commandBuffer.SetViewport(Nz::Rectf(viewportRegion), 0.f, 1.f); + m_commandBuffer.SetViewport(viewportRegion); } } - -#endif diff --git a/src/Nazara/OpenGLRenderer/OpenGLCommandPool.cpp b/src/Nazara/OpenGLRenderer/OpenGLCommandPool.cpp index 9e13ed935..90bfd3593 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLCommandPool.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLCommandPool.cpp @@ -2,41 +2,20 @@ // This file is part of the "Nazara Engine - OpenGL Renderer" // For conditions of distribution and use, see copyright notice in Config.hpp -#if 0 - #include #include #include -#include #include namespace Nz { std::unique_ptr OpenGLCommandPool::BuildCommandBuffer(const std::function& callback) { - std::vector commandBuffers; - auto BuildCommandBuffer = [&](std::size_t imageIndex) - { - Vk::AutoCommandBuffer& commandBuffer = commandBuffers.emplace_back(m_commandPool.AllocateCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY)); + std::unique_ptr commandBuffer = std::make_unique(); - if (!commandBuffer->Begin(VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT)) - throw std::runtime_error("failed to begin command buffer: " + TranslateOpenGLError(commandBuffer->GetLastErrorCode())); + OpenGLCommandBufferBuilder builder(*commandBuffer); + callback(builder); - OpenGLCommandBufferBuilder builder(commandBuffer.Get(), imageIndex); - callback(builder); - - if (!commandBuffer->End()) - throw std::runtime_error("failed to build command buffer: " + TranslateOpenGLError(commandBuffer->GetLastErrorCode())); - - return builder.GetMaxFramebufferCount(); - }; - - std::size_t maxFramebufferCount = BuildCommandBuffer(0); - for (std::size_t i = 1; i < maxFramebufferCount; ++i) - BuildCommandBuffer(i); - - return std::make_unique(std::move(commandBuffers)); + return commandBuffer; } } - -#endif diff --git a/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp b/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp index ee6d1500a..34946874b 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLRenderImage.cpp @@ -3,6 +3,8 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include +#include #include #include #include @@ -17,6 +19,11 @@ namespace Nz void OpenGLRenderImage::Execute(const std::function& callback, QueueTypeFlags queueTypeFlags) { + OpenGLCommandBuffer commandBuffer; + OpenGLCommandBufferBuilder builder(commandBuffer); + callback(builder); + + commandBuffer.Execute(); } OpenGLUploadPool& OpenGLRenderImage::GetUploadPool() @@ -26,6 +33,8 @@ namespace Nz void OpenGLRenderImage::SubmitCommandBuffer(CommandBuffer* commandBuffer, QueueTypeFlags queueTypeFlags) { + OpenGLCommandBuffer* oglCommandBuffer = static_cast(commandBuffer); + oglCommandBuffer->Execute(); } void OpenGLRenderImage::Present() diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp index 371aa6248..b73dd76d2 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderBinding.cpp @@ -13,6 +13,29 @@ namespace Nz { + void OpenGLShaderBinding::Apply(const GL::Context& context) const + { + std::size_t textureDescriptorCount = m_owner.GetTextureDescriptorCount(); + std::size_t uniformBufferDescriptorCount = m_owner.GetUniformBufferDescriptorCount(); + + for (std::size_t i = 0; i < textureDescriptorCount; ++i) + { + const auto& textureDescriptor = m_owner.GetTextureDescriptor(m_poolIndex, m_bindingIndex, i); + + UInt32 textureIndex = textureDescriptor.bindingIndex; + + context.BindSampler(textureIndex, textureDescriptor.sampler); + context.BindTexture(textureIndex, textureDescriptor.textureTarget, textureDescriptor.texture); + } + + for (std::size_t i = 0; i < textureDescriptorCount; ++i) + { + const auto& uboDescriptor = m_owner.GetUniformBufferDescriptor(m_poolIndex, m_bindingIndex, i); + + context.BindUniformBuffer(uboDescriptor.bindingIndex, uboDescriptor.buffer, uboDescriptor.offset, uboDescriptor.size); + } + } + void OpenGLShaderBinding::Update(std::initializer_list bindings) { const auto& layoutInfo = m_owner.GetLayoutInfo(); @@ -43,8 +66,34 @@ namespace Nz OpenGLTextureSampler& glSampler = *static_cast(texBinding.sampler); auto& textureDescriptor = m_owner.GetTextureDescriptor(m_poolIndex, m_bindingIndex, resourceIndex); + textureDescriptor.bindingIndex = binding.bindingIndex; + textureDescriptor.texture = glTexture.GetTexture().GetObjectId(); textureDescriptor.sampler = glSampler.GetSampler(glTexture.GetLevelCount() > 1).GetObjectId(); + + switch (glTexture.GetType()) + { + case ImageType_2D: + textureDescriptor.textureTarget = GL::TextureTarget::Target2D; + break; + + case ImageType_2D_Array: + textureDescriptor.textureTarget = GL::TextureTarget::Target2D_Array; + break; + + case ImageType_3D: + textureDescriptor.textureTarget = GL::TextureTarget::Target3D; + break; + + case ImageType_Cubemap: + textureDescriptor.textureTarget = GL::TextureTarget::Cubemap; + break; + + case ImageType_1D: + case ImageType_1D_Array: + default: + throw std::runtime_error("unsupported texture type"); + } break; } @@ -60,6 +109,7 @@ namespace Nz throw std::runtime_error("expected uniform buffer"); auto& uboDescriptor = m_owner.GetUniformBufferDescriptor(m_poolIndex, m_bindingIndex, resourceIndex); + uboDescriptor.bindingIndex = binding.bindingIndex; uboDescriptor.buffer = glBuffer.GetBuffer().GetObjectId(); uboDescriptor.offset = uboBinding.offset; uboDescriptor.size = uboBinding.range; diff --git a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp index 9b9adff90..5d2c9f366 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp @@ -23,9 +23,9 @@ namespace Nz::GL m_device->NotifyContextDestruction(*this); } - void Context::BindBuffer(BufferTarget target, GLuint buffer) const + void Context::BindBuffer(BufferTarget target, GLuint buffer, bool force) const { - if (m_state.bufferTargets[UnderlyingCast(target)] != buffer) + if (m_state.bufferTargets[UnderlyingCast(target)] != buffer || force) { if (!SetCurrentContext(this)) throw std::runtime_error("failed to activate context"); @@ -62,6 +62,18 @@ namespace Nz::GL } } + void Context::BindProgram(GLuint program) const + { + if (m_state.boundProgram != program) + { + if (!SetCurrentContext(this)) + throw std::runtime_error("failed to activate context"); + + glUseProgram(program); + m_state.boundProgram = program; + } + } + void Context::BindSampler(UInt32 textureUnit, GLuint sampler) const { if (textureUnit >= m_state.textureUnits.size()) @@ -102,6 +114,37 @@ namespace Nz::GL } } + void Context::BindUniformBuffer(UInt32 uboUnit, GLuint buffer, GLintptr offset, GLsizeiptr size) const + { + if (uboUnit >= m_state.uboUnits.size()) + throw std::runtime_error("unsupported uniform buffer unit #" + std::to_string(uboUnit)); + + auto& unit = m_state.uboUnits[uboUnit]; + if (unit.buffer != buffer || unit.offset != offset || unit.size != size) + { + if (!SetCurrentContext(this)) + throw std::runtime_error("failed to activate context"); + + glBindBufferRange(GL_UNIFORM_BUFFER, uboUnit, buffer, offset, size); + + unit.buffer = buffer; + unit.offset = offset; + unit.size = size; + } + } + + void Context::BindVertexArray(GLuint vertexArray, bool force) const + { + if (m_state.boundVertexArray != vertexArray || force) + { + if (!SetCurrentContext(this)) + throw std::runtime_error("failed to activate context"); + + glBindVertexArray(vertexArray); + m_state.boundVertexArray = vertexArray; + } + } + bool Context::Initialize(const ContextParams& params) { if (!Activate()) @@ -220,9 +263,75 @@ namespace Nz::GL assert(maxTextureUnits > 0); m_state.textureUnits.resize(maxTextureUnits); + GLint maxUniformBufferUnits = -1; + glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferUnits); + if (maxUniformBufferUnits < 24) //< OpenGL ES 3.0 requires at least 24 uniform buffers units + NazaraWarning("GL_MAX_UNIFORM_BUFFER_BINDINGS is " + std::to_string(maxUniformBufferUnits) + ", >= 24 expected"); + + assert(maxUniformBufferUnits > 0); + m_state.uboUnits.resize(maxUniformBufferUnits); + + std::array res; + + glGetIntegerv(GL_SCISSOR_BOX, res.data()); + m_state.scissorBox = { res[0], res[1], res[2], res[3] }; + + glGetIntegerv(GL_VIEWPORT, res.data()); + m_state.viewport = { res[0], res[1], res[2], res[3] }; + return true; } + void Context::SetCurrentTextureUnit(UInt32 textureUnit) const + { + if (m_state.currentTextureUnit != textureUnit) + { + if (!SetCurrentContext(this)) + throw std::runtime_error("failed to activate context"); + + glActiveTexture(GL_TEXTURE0 + textureUnit); + m_state.currentTextureUnit = textureUnit; + } + } + + void Context::SetScissorBox(GLint x, GLint y, GLsizei width, GLsizei height) const + { + if (m_state.scissorBox.x != x || + m_state.scissorBox.y != y || + m_state.scissorBox.width != width || + m_state.scissorBox.height != height) + { + if (!SetCurrentContext(this)) + throw std::runtime_error("failed to activate context"); + + glScissor(x, y, width, height); + + m_state.scissorBox.x = x; + m_state.scissorBox.y = y; + m_state.scissorBox.width = width; + m_state.scissorBox.height = height; + } + } + + void Context::SetViewport(GLint x, GLint y, GLsizei width, GLsizei height) const + { + if (m_state.viewport.x != x || + m_state.viewport.y != y || + m_state.viewport.width != width || + m_state.viewport.height != height) + { + if (!SetCurrentContext(this)) + throw std::runtime_error("failed to activate context"); + + glViewport(x, y, width, height); + + m_state.viewport.x = x; + m_state.viewport.y = y; + m_state.viewport.width = width; + m_state.viewport.height = height; + } + } + void Context::UpdateStates(const RenderStates& renderStates) const { if (!SetCurrentContext(this)) @@ -402,6 +511,11 @@ namespace Nz::GL return true; } + void Context::OnContextRelease() + { + m_vaoCache.Clear(); + } + bool Context::ImplementFallback(const std::string_view& function) { const Loader& loader = GetLoader();