diff --git a/include/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp b/include/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp index 99d3b1eac..60c0fcb08 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp +++ b/include/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.hpp @@ -9,9 +9,11 @@ #include #include +#include #include #include #include +#include namespace Nz { @@ -22,14 +24,14 @@ namespace Nz class NAZARA_OPENGLRENDERER_API OpenGLFboFramebuffer final : public OpenGLFramebuffer { public: - OpenGLFboFramebuffer(OpenGLDevice& device, const std::vector>& attachments); + OpenGLFboFramebuffer(OpenGLDevice& device, std::vector> attachments); OpenGLFboFramebuffer(const OpenGLFboFramebuffer&) = delete; - OpenGLFboFramebuffer(OpenGLFboFramebuffer&&) noexcept = default; + OpenGLFboFramebuffer(OpenGLFboFramebuffer&&) = delete; ~OpenGLFboFramebuffer() = default; void Activate() const override; - inline const Vector2ui& GetAttachmentSize(std::size_t i) const; + inline Vector2ui GetAttachmentSize(std::size_t i) const; std::size_t GetColorBufferCount() const override; @@ -41,9 +43,20 @@ namespace Nz OpenGLFboFramebuffer& operator=(OpenGLFboFramebuffer&&) = delete; private: - GL::Framebuffer m_framebuffer; + GL::Framebuffer& CreateFramebuffer(const GL::Context& context) const; + + struct ContextFramebuffer + { + GL::Framebuffer framebuffer; + + NazaraSlot(GL::Context, OnContextDestruction, onContextDestruction); + }; + std::size_t m_colorAttachmentCount; - std::vector m_attachmentSizes; + std::string m_debugName; + std::vector> m_attachments; + mutable std::unordered_map m_framebuffers; + OpenGLDevice& m_device; Vector2ui m_size; }; } diff --git a/include/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.inl b/include/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.inl index af2ae0712..9b82fcb30 100644 --- a/include/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.inl +++ b/include/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.inl @@ -7,9 +7,9 @@ namespace Nz { - inline const Vector2ui& OpenGLFboFramebuffer::GetAttachmentSize(std::size_t i) const + inline Vector2ui OpenGLFboFramebuffer::GetAttachmentSize(std::size_t i) const { - return m_attachmentSizes[i]; + return Vector2ui(m_attachments[i]->GetSize()); } } diff --git a/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp b/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp index d832a9519..55c1cce46 100644 --- a/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp +++ b/include/Nazara/OpenGLRenderer/Wrapper/Context.hpp @@ -199,6 +199,8 @@ namespace Nz::GL static const Context* GetCurrentContext(); static bool SetCurrentContext(const Context* context); + NazaraSignal(OnContextDestruction, Context* /*context*/); + protected: virtual bool Activate() const = 0; virtual void Desactivate() const = 0; diff --git a/src/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.cpp b/src/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.cpp index 90b5f4617..eba1c13b2 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLFboFramebuffer.cpp @@ -11,29 +11,87 @@ namespace Nz { - OpenGLFboFramebuffer::OpenGLFboFramebuffer(OpenGLDevice& device, const std::vector>& attachments) : - OpenGLFramebuffer(FramebufferType::Texture) + OpenGLFboFramebuffer::OpenGLFboFramebuffer(OpenGLDevice& device, std::vector> attachments) : + OpenGLFramebuffer(FramebufferType::Texture), + m_attachments(std::move(attachments)), + m_device(device) { - if (!m_framebuffer.Create(device.GetReferenceContext())) + m_colorAttachmentCount = 0; + for (std::size_t i = 0; i < m_attachments.size(); ++i) + { + assert(m_attachments[i]); + Vector2ui textureSize = Vector2ui(m_attachments[i]->GetSize()); + if (i == 0) + m_size = textureSize; + else + m_size.Minimize(textureSize); + + PixelFormat textureFormat = m_attachments[i]->GetFormat(); + if (PixelFormatInfo::GetContent(textureFormat) == PixelFormatContent::ColorRGBA) + m_colorAttachmentCount++; + } + + // Create a framebuffer with the current context to ensure its completeness + const GL::Context* currentContext = GL::Context::GetCurrentContext(); + if (!currentContext) + { + currentContext = &m_device.GetReferenceContext(); + GL::Context::SetCurrentContext(currentContext); + } + + CreateFramebuffer(*currentContext); + } + + void OpenGLFboFramebuffer::Activate() const + { + const GL::Context* currentContext = GL::Context::GetCurrentContext(); + if (!currentContext) + { + currentContext = &m_device.GetReferenceContext(); + GL::Context::SetCurrentContext(currentContext); + } + + GLuint fbo; + auto it = m_framebuffers.find(currentContext); + if (it == m_framebuffers.end()) + fbo = CreateFramebuffer(*currentContext).GetObjectId(); + else + fbo = it->second.framebuffer.GetObjectId(); + + currentContext->BindFramebuffer(GL::FramebufferTarget::Draw, fbo); + } + + std::size_t OpenGLFboFramebuffer::GetColorBufferCount() const + { + return m_colorAttachmentCount; + } + + const Vector2ui& OpenGLFboFramebuffer::GetSize() const + { + return m_size; + } + + void OpenGLFboFramebuffer::UpdateDebugName(std::string_view name) + { + m_debugName = name; + for (auto&& [context, framebufferEntry] : m_framebuffers) + framebufferEntry.framebuffer.SetDebugName(m_debugName); + } + + GL::Framebuffer& OpenGLFboFramebuffer::CreateFramebuffer(const GL::Context& context) const + { + GL::Framebuffer framebuffer; + if (!framebuffer.Create(context)) throw std::runtime_error("failed to create framebuffer object"); std::size_t colorAttachmentCount = 0; bool hasDepth = false; bool hasStencil = false; - m_attachmentSizes.resize(attachments.size()); - for (std::size_t i = 0; i < attachments.size(); ++i) + for (std::size_t i = 0; i < m_attachments.size(); ++i) { - assert(attachments[i]); - const OpenGLTexture& glTexture = static_cast(*attachments[i]); - - Vector2ui textureSize = Vector2ui(glTexture.GetSize()); - m_attachmentSizes[i] = textureSize; - - if (i == 0) - m_size = textureSize; - else - m_size.Minimize(textureSize); + assert(m_attachments[i]); + const OpenGLTexture& glTexture = static_cast(*m_attachments[i]); PixelFormat textureFormat = glTexture.GetFormat(); @@ -94,31 +152,34 @@ namespace Nz assert(texViewInfo.baseArrayLayer < faceTargets.size()); GLenum texTarget = faceTargets[texViewInfo.baseArrayLayer]; - m_framebuffer.Texture2D(GL_COLOR_ATTACHMENT0, texTarget, parentTexture.GetTexture().GetObjectId(), texViewInfo.baseMipLevel); + framebuffer.Texture2D(GL_COLOR_ATTACHMENT0, texTarget, parentTexture.GetTexture().GetObjectId(), texViewInfo.baseMipLevel); break; } case ImageType::E1D: case ImageType::E2D: - m_framebuffer.Texture2D(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, parentTexture.GetTexture().GetObjectId(), texViewInfo.baseMipLevel); + framebuffer.Texture2D(GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, parentTexture.GetTexture().GetObjectId(), texViewInfo.baseMipLevel); break; case ImageType::E1D_Array: case ImageType::E2D_Array: case ImageType::E3D: - m_framebuffer.TextureLayer(GL_COLOR_ATTACHMENT0, parentTexture.GetTexture().GetObjectId(), texViewInfo.baseArrayLayer, texViewInfo.baseMipLevel); + framebuffer.TextureLayer(GL_COLOR_ATTACHMENT0, parentTexture.GetTexture().GetObjectId(), texViewInfo.baseArrayLayer, texViewInfo.baseMipLevel); break; } } else - m_framebuffer.Texture2D(attachment, ToOpenGL(OpenGLTexture::ToTextureTarget(glTexture.GetType())), glTexture.GetTexture().GetObjectId()); + framebuffer.Texture2D(attachment, ToOpenGL(OpenGLTexture::ToTextureTarget(glTexture.GetType())), glTexture.GetTexture().GetObjectId()); } - GLenum status = m_framebuffer.Check(); + GLenum status = framebuffer.Check(); if (status != GL_FRAMEBUFFER_COMPLETE) throw std::runtime_error("invalid framebuffer: 0x" + NumberToString(status, 16)); - m_colorAttachmentCount = colorAttachmentCount; + if (!m_debugName.empty()) + framebuffer.SetDebugName(m_debugName); + + assert(m_colorAttachmentCount == colorAttachmentCount); if (m_colorAttachmentCount > 0) { @@ -126,34 +187,21 @@ namespace Nz for (std::size_t i = 0; i < m_colorAttachmentCount; ++i) fboDrawBuffers[i] = GLenum(GL_COLOR_ATTACHMENT0 + i); - m_framebuffer.DrawBuffers(SafeCast(m_colorAttachmentCount), fboDrawBuffers.data()); + framebuffer.DrawBuffers(SafeCast(m_colorAttachmentCount), fboDrawBuffers.data()); } else { GLenum buffer = GL_NONE; - m_framebuffer.DrawBuffers(1, &buffer); + framebuffer.DrawBuffers(1, &buffer); } - } - void OpenGLFboFramebuffer::Activate() const - { - const GL::Context& context = m_framebuffer.EnsureContext(); + auto& framebufferEntry = m_framebuffers[&context]; + framebufferEntry.framebuffer = std::move(framebuffer); + framebufferEntry.onContextDestruction.Connect(context.OnContextDestruction, [this](GL::Context* context) + { + m_framebuffers.erase(context); + }); - context.BindFramebuffer(GL::FramebufferTarget::Draw, m_framebuffer.GetObjectId()); - } - - std::size_t OpenGLFboFramebuffer::GetColorBufferCount() const - { - return m_colorAttachmentCount; - } - - const Vector2ui& OpenGLFboFramebuffer::GetSize() const - { - return m_size; - } - - void OpenGLFboFramebuffer::UpdateDebugName(std::string_view name) - { - m_framebuffer.SetDebugName(name); + return framebufferEntry.framebuffer; } } diff --git a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp index 5bd0f5728..d8de50797 100644 --- a/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp +++ b/src/Nazara/OpenGLRenderer/Wrapper/Context.cpp @@ -1023,6 +1023,8 @@ namespace Nz::GL void Context::OnContextRelease() { + OnContextDestruction(this); + m_blitFramebuffers.reset(); m_vaoCache.Clear(); }