// Copyright (C) 2023 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_OPENGLCOMMANDBUFFER_HPP #define NAZARA_OPENGLRENDERER_OPENGLCOMMANDBUFFER_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Nz { class OpenGLCommandPool; class OpenGLComputePipeline; class OpenGLFramebuffer; class OpenGLRenderPass; class OpenGLTexture; class NAZARA_OPENGLRENDERER_API OpenGLCommandBuffer final : public CommandBuffer { public: inline OpenGLCommandBuffer(); inline OpenGLCommandBuffer(OpenGLCommandPool& owner, std::size_t poolIndex, std::size_t bindingIndex); OpenGLCommandBuffer(const OpenGLCommandBuffer&) = delete; OpenGLCommandBuffer(OpenGLCommandBuffer&&) = delete; ~OpenGLCommandBuffer() = default; inline void BeginDebugRegion(const std::string_view& regionName, const Color& color); inline void BindComputePipeline(const OpenGLComputePipeline* pipeline); inline void BindComputeShaderBinding(const OpenGLRenderPipelineLayout& pipelineLayout, UInt32 set, const OpenGLShaderBinding* binding); inline void BindIndexBuffer(GLuint indexBuffer, IndexType indexType, UInt64 offset = 0); inline void BindRenderPipeline(const OpenGLRenderPipeline* pipeline); inline void BindRenderShaderBinding(const OpenGLRenderPipelineLayout& pipelineLayout, UInt32 set, const OpenGLShaderBinding* binding); inline void BindVertexBuffer(UInt32 binding, GLuint vertexBuffer, UInt64 offset = 0); inline void BlitTexture(const OpenGLTexture& source, const Boxui& sourceBox, const OpenGLTexture& target, const Boxui& targetBox, SamplerFilter filter = SamplerFilter::Nearest); inline void BuildMipmaps(OpenGLTexture& texture, UInt8 baseLevel, UInt8 levelCount); 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 CopyTexture(const OpenGLTexture& source, const Boxui& sourceBox, const OpenGLTexture& target, const Vector3ui& targetPoint); inline void Dispatch(UInt32 numGroupsX, UInt32 numGroupsY, UInt32 numGroupsZ); inline void Draw(UInt32 vertexCount, UInt32 instanceCount = 1, UInt32 firstVertex = 0, UInt32 firstInstance = 0); inline void DrawIndexed(UInt32 indexCount, UInt32 instanceCount = 1, UInt32 firstIndex = 0, UInt32 firstInstance = 0); inline void EndDebugRegion(); void Execute(); inline std::size_t GetBindingIndex() const; inline std::size_t GetPoolIndex() const; inline const OpenGLCommandPool& GetOwner() const; inline void InsertMemoryBarrier(GLbitfield barriers); inline void SetFramebuffer(const OpenGLFramebuffer& framebuffer, const OpenGLRenderPass& renderPass, const CommandBufferBuilder::ClearValues* clearValues, std::size_t clearValueCount); inline void SetScissor(const Recti& scissorRegion); inline void SetViewport(const Recti& viewportRegion); void UpdateDebugName(std::string_view name) override; OpenGLCommandBuffer& operator=(const OpenGLCommandBuffer&) = delete; OpenGLCommandBuffer& operator=(OpenGLCommandBuffer&&) = delete; private: struct DrawStates; struct ShaderBindings; #define NAZARA_OPENGL_FOREACH_COMMANDS(cb, lastCb) \ cb(BeginDebugRegionCommand) \ cb(BlitTextureCommand) \ cb(BuildTextureMipmapsCommand) \ cb(CopyBufferCommand) \ cb(CopyBufferFromMemoryCommand) \ cb(CopyTextureCommand) \ cb(DispatchCommand) \ cb(DrawCommand) \ cb(DrawIndexedCommand) \ cb(EndDebugRegionCommand) \ cb(MemoryBarrier) \ lastCb(SetFrameBufferCommand) \ #define NAZARA_OPENGL_COMMAND_CALLBACK(Command) struct Command; NAZARA_OPENGL_FOREACH_COMMANDS(NAZARA_OPENGL_COMMAND_CALLBACK, NAZARA_OPENGL_COMMAND_CALLBACK) #undef NAZARA_OPENGL_COMMAND_CALLBACK using CommandList = TypeList< #define NAZARA_OPENGL_COMMAND_CALLBACK(Command) Command, #define NAZARA_OPENGL_COMMAND_CALLBACK_LAST(Command) Command NAZARA_OPENGL_FOREACH_COMMANDS(NAZARA_OPENGL_COMMAND_CALLBACK, NAZARA_OPENGL_COMMAND_CALLBACK_LAST) #undef NAZARA_OPENGL_COMMAND_CALLBACK_LAST #undef NAZARA_OPENGL_COMMAND_CALLBACK >; void ApplyBindings(const GL::Context& context, const ShaderBindings& bindings); void ApplyStates(const GL::Context& context, const DrawStates& states); inline void Execute(const GL::Context* context, const BeginDebugRegionCommand& command); inline void Execute(const GL::Context* context, const BlitTextureCommand& command); inline void Execute(const GL::Context* context, const BuildTextureMipmapsCommand& command); inline void Execute(const GL::Context* context, const CopyBufferCommand& command); inline void Execute(const GL::Context* context, const CopyBufferFromMemoryCommand& command); inline void Execute(const GL::Context* context, const CopyTextureCommand& command); inline void Execute(const GL::Context* context, const DispatchCommand& command); inline void Execute(const GL::Context* context, const DrawCommand& command); inline void Execute(const GL::Context* context, const DrawIndexedCommand& command); inline void Execute(const GL::Context* context, const EndDebugRegionCommand& command); inline void Execute(const GL::Context* context, const MemoryBarrier& command); inline void Execute(const GL::Context*& context, const SetFrameBufferCommand& command); void Release() override; struct BeginDebugRegionCommand { std::string regionName; Color color; }; struct BlitTextureCommand { const OpenGLTexture* source; const OpenGLTexture* target; Boxui sourceBox; Boxui targetBox; SamplerFilter filter; }; struct BuildTextureMipmapsCommand { OpenGLTexture* texture; UInt8 baseLevel; UInt8 levelCount; }; struct ComputeStates { const OpenGLComputePipeline* pipeline = nullptr; }; struct CopyBufferCommand { GLuint source; GLuint target; UInt64 size; UInt64 sourceOffset; UInt64 targetOffset; }; struct CopyTextureCommand { const OpenGLTexture* source; const OpenGLTexture* target; Boxui sourceBox; Vector3ui targetPoint; }; struct CopyBufferFromMemoryCommand { const void* memory; GLuint target; UInt64 size; UInt64 targetOffset; }; struct ShaderBindings { std::vector> shaderBindings; }; struct DispatchCommand { ComputeStates states; ShaderBindings bindings; UInt32 numGroupsX; UInt32 numGroupsY; UInt32 numGroupsZ; }; struct DrawStates { struct VertexBuffer { GLuint vertexBuffer = 0; UInt64 offset; }; GLuint indexBuffer = 0; const OpenGLRenderPipeline* pipeline = nullptr; UInt64 indexBufferOffset; IndexType indexBufferType; std::optional scissorRegion; std::optional viewportRegion; std::vector vertexBuffers; bool shouldFlipY = false; }; struct DrawCommand { DrawStates states; ShaderBindings bindings; UInt32 firstInstance; UInt32 firstVertex; UInt32 instanceCount; UInt32 vertexCount; }; struct DrawIndexedCommand { DrawStates states; ShaderBindings bindings; UInt32 firstIndex; UInt32 firstInstance; UInt32 indexCount; UInt32 instanceCount; }; struct EndDebugRegionCommand { }; struct MemoryBarrier { GLbitfield barriers; }; struct SetFrameBufferCommand { std::array clearValues; //< TODO: Remove hard limit? const OpenGLFramebuffer* framebuffer; const OpenGLRenderPass* renderpass; }; using CommandData = TypeListInstantiate; ComputeStates m_currentComputeStates; DrawStates m_currentDrawStates; ShaderBindings m_currentComputeShaderBindings; ShaderBindings m_currentGraphicsShaderBindings; std::optional m_pendingBarrier; std::size_t m_bindingIndex; std::size_t m_maxColorBufferCount; std::size_t m_poolIndex; std::vector m_commands; OpenGLCommandPool* m_owner; }; } #include #endif // NAZARA_OPENGLRENDERER_OPENGLCOMMANDBUFFER_HPP