From e4eae425b29397a0d5cc07138b502acf98c78278 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 6 Jun 2018 20:18:42 +0200 Subject: [PATCH] Add support for Uniform Buffer to Utility/Renderer --- include/Nazara/Renderer/OpenGL.hpp | 2 +- include/Nazara/Renderer/Renderer.hpp | 3 + include/Nazara/Utility/Enums.hpp | 3 +- include/Nazara/Utility/IndexBuffer.hpp | 1 - include/Nazara/Utility/IndexBuffer.inl | 5 - include/Nazara/Utility/UniformBuffer.hpp | 69 +++++++++++++ include/Nazara/Utility/UniformBuffer.inl | 41 ++++++++ src/Nazara/Renderer/OpenGL.cpp | 17 ++-- src/Nazara/Renderer/Renderer.cpp | 17 ++++ src/Nazara/Utility/IndexBuffer.cpp | 1 + src/Nazara/Utility/UniformBuffer.cpp | 118 +++++++++++++++++++++++ src/Nazara/Utility/VertexBuffer.cpp | 1 + 12 files changed, 259 insertions(+), 19 deletions(-) create mode 100644 include/Nazara/Utility/UniformBuffer.hpp create mode 100644 include/Nazara/Utility/UniformBuffer.inl create mode 100644 src/Nazara/Utility/UniformBuffer.cpp diff --git a/include/Nazara/Renderer/OpenGL.hpp b/include/Nazara/Renderer/OpenGL.hpp index c87426f12..ef791f96e 100644 --- a/include/Nazara/Renderer/OpenGL.hpp +++ b/include/Nazara/Renderer/OpenGL.hpp @@ -132,7 +132,6 @@ namespace Nz static GLenum BufferLock[BufferAccess_Max+1]; static GLenum BufferLockRange[BufferAccess_Max+1]; static GLenum BufferTarget[BufferType_Max+1]; - static GLenum BufferTargetBinding[BufferType_Max+1]; static GLenum ComponentType[ComponentType_Max+1]; static GLenum CubemapFace[6]; // Un cube possède six faces et ça n'est pas près de changer static GLenum FaceFilling[FaceFilling_Max+1]; @@ -161,6 +160,7 @@ NAZARA_RENDERER_API extern PFNGLBEGINCONDITIONALRENDERPROC glBeginConditionalR NAZARA_RENDERER_API extern PFNGLBEGINQUERYPROC glBeginQuery; NAZARA_RENDERER_API extern PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation; NAZARA_RENDERER_API extern PFNGLBINDBUFFERPROC glBindBuffer; +NAZARA_RENDERER_API extern PFNGLBINDBUFFERRANGEPROC glBindBufferRange; NAZARA_RENDERER_API extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; NAZARA_RENDERER_API extern PFNGLBINDFRAGDATALOCATIONPROC glBindFragDataLocation; NAZARA_RENDERER_API extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; diff --git a/include/Nazara/Renderer/Renderer.hpp b/include/Nazara/Renderer/Renderer.hpp index f0154934b..c23001ef0 100644 --- a/include/Nazara/Renderer/Renderer.hpp +++ b/include/Nazara/Renderer/Renderer.hpp @@ -25,6 +25,7 @@ namespace Nz class Shader; class Texture; class TextureSampler; + class UniformBuffer; class VertexBuffer; class VertexDeclaration; @@ -41,6 +42,8 @@ namespace Nz static void BeginCondition(const GpuQuery& query, GpuQueryCondition condition); + static void BindUniformBuffer(unsigned int bindingPoint, const UniformBuffer* uniformBuffer); + static void Clear(UInt32 flags = RendererBuffer_Color | RendererBuffer_Depth); static void DrawFullscreenQuad(); diff --git a/include/Nazara/Utility/Enums.hpp b/include/Nazara/Utility/Enums.hpp index d6fee2127..edc8708b4 100644 --- a/include/Nazara/Utility/Enums.hpp +++ b/include/Nazara/Utility/Enums.hpp @@ -49,8 +49,9 @@ namespace Nz { BufferType_Index, BufferType_Vertex, + BufferType_Uniform, - BufferType_Max = BufferType_Vertex + BufferType_Max = BufferType_Uniform }; enum BufferUsage diff --git a/include/Nazara/Utility/IndexBuffer.hpp b/include/Nazara/Utility/IndexBuffer.hpp index 7feee06e8..dd30a4e49 100644 --- a/include/Nazara/Utility/IndexBuffer.hpp +++ b/include/Nazara/Utility/IndexBuffer.hpp @@ -38,7 +38,6 @@ namespace Nz inline const BufferRef& GetBuffer() const; inline UInt32 GetEndOffset() const; inline UInt32 GetIndexCount() const; - inline DataStorage GetStorage() const; inline UInt32 GetStride() const; inline UInt32 GetStartOffset() const; diff --git a/include/Nazara/Utility/IndexBuffer.inl b/include/Nazara/Utility/IndexBuffer.inl index 1bcf60b26..52103b46d 100644 --- a/include/Nazara/Utility/IndexBuffer.inl +++ b/include/Nazara/Utility/IndexBuffer.inl @@ -22,11 +22,6 @@ namespace Nz return m_indexCount; } - inline DataStorage IndexBuffer::GetStorage() const - { - return DataStorage(); - } - inline UInt32 IndexBuffer::GetStride() const { return static_cast((m_largeIndices) ? sizeof(UInt32) : sizeof(UInt16)); diff --git a/include/Nazara/Utility/UniformBuffer.hpp b/include/Nazara/Utility/UniformBuffer.hpp new file mode 100644 index 000000000..aa77c3069 --- /dev/null +++ b/include/Nazara/Utility/UniformBuffer.hpp @@ -0,0 +1,69 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_UNIFORMBUFFER_HPP +#define NAZARA_UNIFORMBUFFER_HPP + +#include +#include +#include +#include + +namespace Nz +{ + class UniformBuffer; + + using UniformBufferConstRef = ObjectRef; + using UniformBufferRef = ObjectRef; + + class NAZARA_UTILITY_API UniformBuffer : public RefCounted + { + public: + UniformBuffer() = default; + UniformBuffer(BufferRef buffer); + UniformBuffer(BufferRef buffer, UInt32 offset, UInt32 size); + UniformBuffer(UInt32 length, DataStorage storage, BufferUsageFlags usage); + UniformBuffer(const UniformBuffer& uniformBuffer); + UniformBuffer(UniformBuffer&&) = delete; + ~UniformBuffer(); + + bool Fill(const void* data, UInt32 offset, UInt32 size); + + inline const BufferRef& GetBuffer() const; + inline UInt32 GetEndOffset() const; + inline UInt32 GetStartOffset() const; + + inline bool IsValid() const; + + void* Map(BufferAccess access, UInt32 offset = 0, UInt32 size = 0); + void* Map(BufferAccess access, UInt32 offset = 0, UInt32 size = 0) const; + + void Reset(); + void Reset(BufferRef buffer); + void Reset(BufferRef buffer, UInt32 offset, UInt32 size); + void Reset(UInt32 size, DataStorage storage, BufferUsageFlags usage); + void Reset(const UniformBuffer& uniformBuffer); + + void Unmap() const; + + UniformBuffer& operator=(const UniformBuffer& uniformBuffer); + UniformBuffer& operator=(UniformBuffer&&) = delete; + + template static UniformBufferRef New(Args&&... args); + + // Signals: + NazaraSignal(OnUniformBufferRelease, const UniformBuffer* /*UniformBuffer*/); + + private: + BufferRef m_buffer; + UInt32 m_endOffset; + UInt32 m_startOffset; + }; +} + +#include + +#endif // NAZARA_UNIFORMBUFFER_HPP diff --git a/include/Nazara/Utility/UniformBuffer.inl b/include/Nazara/Utility/UniformBuffer.inl new file mode 100644 index 000000000..50b2199eb --- /dev/null +++ b/include/Nazara/Utility/UniformBuffer.inl @@ -0,0 +1,41 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline const BufferRef& UniformBuffer::GetBuffer() const + { + return m_buffer; + } + + inline UInt32 UniformBuffer::GetEndOffset() const + { + return m_endOffset; + } + + inline UInt32 UniformBuffer::GetStartOffset() const + { + return m_startOffset; + } + + inline bool UniformBuffer::IsValid() const + { + return m_buffer.IsValid(); + } + + template + UniformBufferRef UniformBuffer::New(Args&&... args) + { + std::unique_ptr object(new UniformBuffer(std::forward(args)...)); + object->SetPersistent(false); + + return object.release(); + } +} + +#include diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index 0d6f07d2e..080c1e73c 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -885,6 +885,7 @@ namespace Nz glBeginQuery = reinterpret_cast(LoadEntry("glBeginQuery")); glBindAttribLocation = reinterpret_cast(LoadEntry("glBindAttribLocation")); glBindBuffer = reinterpret_cast(LoadEntry("glBindBuffer")); + glBindBufferRange = reinterpret_cast(LoadEntry("glBindBufferRange")); glBindFragDataLocation = reinterpret_cast(LoadEntry("glBindFragDataLocation")); glBindFramebuffer = reinterpret_cast(LoadEntry("glBindFramebuffer")); glBindRenderbuffer = reinterpret_cast(LoadEntry("glBindRenderbuffer")); @@ -1896,19 +1897,12 @@ namespace Nz GLenum OpenGL::BufferTarget[] = { - GL_ELEMENT_ARRAY_BUFFER, // BufferType_Index, - GL_ARRAY_BUFFER, // BufferType_Vertex + GL_ELEMENT_ARRAY_BUFFER, // BufferType_Index + GL_ARRAY_BUFFER, // BufferType_Vertex + GL_UNIFORM_BUFFER // BufferType_Uniform }; - static_assert(BufferType_Max + 1 == 2, "Buffer target array is incomplete"); - - GLenum OpenGL::BufferTargetBinding[] = - { - GL_ELEMENT_ARRAY_BUFFER_BINDING, // BufferType_Index, - GL_ARRAY_BUFFER_BINDING, // BufferType_Vertex - }; - - static_assert(BufferType_Max + 1 == 2, "Buffer target binding array is incomplete"); + static_assert(BufferType_Max + 1 == 3, "Buffer target array is incomplete"); GLenum OpenGL::ComponentType[] = { @@ -2117,6 +2111,7 @@ PFNGLBEGINCONDITIONALRENDERPROC glBeginConditionalRender = nullptr; PFNGLBEGINQUERYPROC glBeginQuery = nullptr; PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation = nullptr; PFNGLBINDBUFFERPROC glBindBuffer = nullptr; +PFNGLBINDBUFFERRANGEPROC glBindBufferRange = nullptr; PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = nullptr; PFNGLBINDFRAGDATALOCATIONPROC glBindFragDataLocation = nullptr; PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = nullptr; diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index d2a3ed7e1..b70e64423 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -134,6 +135,22 @@ namespace Nz glBeginConditionalRender(query.GetOpenGLID(), OpenGL::QueryCondition[condition]); } + void Renderer::BindUniformBuffer(unsigned int bindingPoint, const UniformBuffer* uniformBuffer) + { + NazaraAssert(uniformBuffer && uniformBuffer->IsValid(), "Buffer must be valid"); + + const Nz::BufferRef& buffer = uniformBuffer->GetBuffer(); + if (buffer->GetStorage() != DataStorage_Hardware) + { + NazaraError("Uniform buffer storage is not hardware"); + return; + } + + HardwareBuffer* hwBuffer = static_cast(buffer->GetImpl()); + + glBindBufferRange(GL_UNIFORM_BUFFER, bindingPoint, hwBuffer->GetOpenGLID(), uniformBuffer->GetStartOffset(), uniformBuffer->GetEndOffset() - uniformBuffer->GetStartOffset()); + } + void Renderer::Clear(UInt32 flags) { #ifdef NAZARA_DEBUG diff --git a/src/Nazara/Utility/IndexBuffer.cpp b/src/Nazara/Utility/IndexBuffer.cpp index 4455a2f0c..e1e5cb126 100644 --- a/src/Nazara/Utility/IndexBuffer.cpp +++ b/src/Nazara/Utility/IndexBuffer.cpp @@ -106,6 +106,7 @@ namespace Nz void IndexBuffer::Reset(bool largeIndices, BufferRef buffer, UInt32 offset, UInt32 size) { NazaraAssert(buffer && buffer->IsValid(), "Invalid buffer"); + NazaraAssert(buffer->GetType() == BufferType_Index, "Buffer must be an index buffer"); NazaraAssert(size > 0, "Invalid size"); NazaraAssert(offset + size > buffer->GetSize(), "Virtual buffer exceed buffer bounds"); diff --git a/src/Nazara/Utility/UniformBuffer.cpp b/src/Nazara/Utility/UniformBuffer.cpp new file mode 100644 index 000000000..0ae065e3f --- /dev/null +++ b/src/Nazara/Utility/UniformBuffer.cpp @@ -0,0 +1,118 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +namespace Nz +{ + UniformBuffer::UniformBuffer(BufferRef buffer) + { + ErrorFlags(ErrorFlag_ThrowException, true); + Reset(std::move(buffer)); + } + + UniformBuffer::UniformBuffer(BufferRef buffer, UInt32 offset, UInt32 size) + { + ErrorFlags(ErrorFlag_ThrowException, true); + Reset(std::move(buffer), offset, size); + } + + UniformBuffer::UniformBuffer(UInt32 length, DataStorage storage, BufferUsageFlags usage) + { + ErrorFlags(ErrorFlag_ThrowException, true); + Reset(length, storage, usage); + } + + UniformBuffer::UniformBuffer(const UniformBuffer& uniformBuffer) : + RefCounted(), + m_buffer(uniformBuffer.m_buffer), + m_endOffset(uniformBuffer.m_endOffset), + m_startOffset(uniformBuffer.m_startOffset) + { + } + + UniformBuffer::~UniformBuffer() + { + OnUniformBufferRelease(this); + } + + bool UniformBuffer::Fill(const void* data, UInt32 offset, UInt32 size) + { + NazaraAssert(m_buffer && m_buffer->IsValid(), "Invalid buffer"); + NazaraAssert(m_startOffset + offset + size <= m_endOffset, "Exceeding virtual buffer size"); + + return m_buffer->Fill(data, m_startOffset + offset, size); + } + + void* UniformBuffer::Map(BufferAccess access, UInt32 offset, UInt32 size) + { + NazaraAssert(m_buffer && m_buffer->IsValid(), "Invalid buffer"); + NazaraAssert(m_startOffset + offset + size <= m_endOffset, "Exceeding virtual buffer size"); + + return m_buffer->Map(access, offset, size); + } + + void* UniformBuffer::Map(BufferAccess access, UInt32 offset, UInt32 size) const + { + NazaraAssert(m_buffer && m_buffer->IsValid(), "Invalid buffer"); + NazaraAssert(m_startOffset + offset + size <= m_endOffset, "Exceeding virtual buffer size"); + + return m_buffer->Map(access, offset, size); + } + + void UniformBuffer::Reset() + { + m_buffer.Reset(); + } + + void UniformBuffer::Reset(BufferRef buffer) + { + NazaraAssert(buffer && buffer->IsValid(), "Invalid buffer"); + + Reset(buffer, 0, buffer->GetSize()); + } + + void UniformBuffer::Reset(BufferRef buffer, UInt32 offset, UInt32 size) + { + NazaraAssert(buffer && buffer->IsValid(), "Invalid buffer"); + NazaraAssert(buffer->GetType() == BufferType_Uniform, "Buffer must be an uniform buffer"); + NazaraAssert(size > 0, "Invalid size"); + NazaraAssert(offset + size > buffer->GetSize(), "Virtual buffer exceed buffer bounds"); + + m_buffer = buffer; + m_endOffset = offset + size; + m_startOffset = offset; + } + + void UniformBuffer::Reset(UInt32 size, DataStorage storage, BufferUsageFlags usage) + { + m_endOffset = size; + m_startOffset = 0; + + m_buffer = Buffer::New(BufferType_Uniform, m_endOffset, storage, usage); + } + + void UniformBuffer::Reset(const UniformBuffer& UniformBuffer) + { + m_buffer = UniformBuffer.m_buffer; + m_endOffset = UniformBuffer.m_endOffset; + m_startOffset = UniformBuffer.m_startOffset; + } + + void UniformBuffer::Unmap() const + { + m_buffer->Unmap(); + } + + UniformBuffer& UniformBuffer::operator=(const UniformBuffer& uniformBuffer) + { + Reset(uniformBuffer); + + return *this; + } +} diff --git a/src/Nazara/Utility/VertexBuffer.cpp b/src/Nazara/Utility/VertexBuffer.cpp index e072c4aa1..d84dd8b39 100644 --- a/src/Nazara/Utility/VertexBuffer.cpp +++ b/src/Nazara/Utility/VertexBuffer.cpp @@ -98,6 +98,7 @@ namespace Nz void VertexBuffer::Reset(VertexDeclarationConstRef vertexDeclaration, BufferRef buffer) { NazaraAssert(buffer && buffer->IsValid(), "Invalid buffer"); + NazaraAssert(buffer->GetType() == BufferType_Vertex, "Buffer must be a vertex buffer"); UInt32 size = buffer->GetSize(); Reset(std::move(vertexDeclaration), std::move(buffer), 0, size);