OpenGLRenderer: Fix FboFramebuffer making context switches
When a window was created and rendered onto, FBO rendering was made on the device reference context which required a context switch. This has been fixed with OpenGLFboFramebuffer managing a per-context framebuffer and creating one when needed
This commit is contained in:
parent
2e8ea0e887
commit
421e684344
|
|
@ -9,9 +9,11 @@
|
||||||
|
|
||||||
#include <Nazara/Prerequisites.hpp>
|
#include <Nazara/Prerequisites.hpp>
|
||||||
#include <Nazara/OpenGLRenderer/OpenGLFramebuffer.hpp>
|
#include <Nazara/OpenGLRenderer/OpenGLFramebuffer.hpp>
|
||||||
|
#include <Nazara/OpenGLRenderer/Wrapper/Context.hpp>
|
||||||
#include <Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp>
|
#include <Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
|
|
@ -22,14 +24,14 @@ namespace Nz
|
||||||
class NAZARA_OPENGLRENDERER_API OpenGLFboFramebuffer final : public OpenGLFramebuffer
|
class NAZARA_OPENGLRENDERER_API OpenGLFboFramebuffer final : public OpenGLFramebuffer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OpenGLFboFramebuffer(OpenGLDevice& device, const std::vector<std::shared_ptr<Texture>>& attachments);
|
OpenGLFboFramebuffer(OpenGLDevice& device, std::vector<std::shared_ptr<Texture>> attachments);
|
||||||
OpenGLFboFramebuffer(const OpenGLFboFramebuffer&) = delete;
|
OpenGLFboFramebuffer(const OpenGLFboFramebuffer&) = delete;
|
||||||
OpenGLFboFramebuffer(OpenGLFboFramebuffer&&) noexcept = default;
|
OpenGLFboFramebuffer(OpenGLFboFramebuffer&&) = delete;
|
||||||
~OpenGLFboFramebuffer() = default;
|
~OpenGLFboFramebuffer() = default;
|
||||||
|
|
||||||
void Activate() const override;
|
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;
|
std::size_t GetColorBufferCount() const override;
|
||||||
|
|
||||||
|
|
@ -41,9 +43,20 @@ namespace Nz
|
||||||
OpenGLFboFramebuffer& operator=(OpenGLFboFramebuffer&&) = delete;
|
OpenGLFboFramebuffer& operator=(OpenGLFboFramebuffer&&) = delete;
|
||||||
|
|
||||||
private:
|
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::size_t m_colorAttachmentCount;
|
||||||
std::vector<Vector2ui> m_attachmentSizes;
|
std::string m_debugName;
|
||||||
|
std::vector<std::shared_ptr<Texture>> m_attachments;
|
||||||
|
mutable std::unordered_map<const GL::Context*, ContextFramebuffer> m_framebuffers;
|
||||||
|
OpenGLDevice& m_device;
|
||||||
Vector2ui m_size;
|
Vector2ui m_size;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@
|
||||||
|
|
||||||
namespace Nz
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -199,6 +199,8 @@ namespace Nz::GL
|
||||||
static const Context* GetCurrentContext();
|
static const Context* GetCurrentContext();
|
||||||
static bool SetCurrentContext(const Context* context);
|
static bool SetCurrentContext(const Context* context);
|
||||||
|
|
||||||
|
NazaraSignal(OnContextDestruction, Context* /*context*/);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool Activate() const = 0;
|
virtual bool Activate() const = 0;
|
||||||
virtual void Desactivate() const = 0;
|
virtual void Desactivate() const = 0;
|
||||||
|
|
|
||||||
|
|
@ -11,29 +11,87 @@
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
OpenGLFboFramebuffer::OpenGLFboFramebuffer(OpenGLDevice& device, const std::vector<std::shared_ptr<Texture>>& attachments) :
|
OpenGLFboFramebuffer::OpenGLFboFramebuffer(OpenGLDevice& device, std::vector<std::shared_ptr<Texture>> attachments) :
|
||||||
OpenGLFramebuffer(FramebufferType::Texture)
|
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");
|
throw std::runtime_error("failed to create framebuffer object");
|
||||||
|
|
||||||
std::size_t colorAttachmentCount = 0;
|
std::size_t colorAttachmentCount = 0;
|
||||||
bool hasDepth = false;
|
bool hasDepth = false;
|
||||||
bool hasStencil = false;
|
bool hasStencil = false;
|
||||||
|
|
||||||
m_attachmentSizes.resize(attachments.size());
|
for (std::size_t i = 0; i < m_attachments.size(); ++i)
|
||||||
for (std::size_t i = 0; i < attachments.size(); ++i)
|
|
||||||
{
|
{
|
||||||
assert(attachments[i]);
|
assert(m_attachments[i]);
|
||||||
const OpenGLTexture& glTexture = static_cast<const OpenGLTexture&>(*attachments[i]);
|
const OpenGLTexture& glTexture = static_cast<const OpenGLTexture&>(*m_attachments[i]);
|
||||||
|
|
||||||
Vector2ui textureSize = Vector2ui(glTexture.GetSize());
|
|
||||||
m_attachmentSizes[i] = textureSize;
|
|
||||||
|
|
||||||
if (i == 0)
|
|
||||||
m_size = textureSize;
|
|
||||||
else
|
|
||||||
m_size.Minimize(textureSize);
|
|
||||||
|
|
||||||
PixelFormat textureFormat = glTexture.GetFormat();
|
PixelFormat textureFormat = glTexture.GetFormat();
|
||||||
|
|
||||||
|
|
@ -94,31 +152,34 @@ namespace Nz
|
||||||
assert(texViewInfo.baseArrayLayer < faceTargets.size());
|
assert(texViewInfo.baseArrayLayer < faceTargets.size());
|
||||||
|
|
||||||
GLenum texTarget = faceTargets[texViewInfo.baseArrayLayer];
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ImageType::E1D:
|
case ImageType::E1D:
|
||||||
case ImageType::E2D:
|
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;
|
break;
|
||||||
|
|
||||||
case ImageType::E1D_Array:
|
case ImageType::E1D_Array:
|
||||||
case ImageType::E2D_Array:
|
case ImageType::E2D_Array:
|
||||||
case ImageType::E3D:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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)
|
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||||
throw std::runtime_error("invalid framebuffer: 0x" + NumberToString(status, 16));
|
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)
|
if (m_colorAttachmentCount > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -126,34 +187,21 @@ namespace Nz
|
||||||
for (std::size_t i = 0; i < m_colorAttachmentCount; ++i)
|
for (std::size_t i = 0; i < m_colorAttachmentCount; ++i)
|
||||||
fboDrawBuffers[i] = GLenum(GL_COLOR_ATTACHMENT0 + i);
|
fboDrawBuffers[i] = GLenum(GL_COLOR_ATTACHMENT0 + i);
|
||||||
|
|
||||||
m_framebuffer.DrawBuffers(SafeCast<GLsizei>(m_colorAttachmentCount), fboDrawBuffers.data());
|
framebuffer.DrawBuffers(SafeCast<GLsizei>(m_colorAttachmentCount), fboDrawBuffers.data());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GLenum buffer = GL_NONE;
|
GLenum buffer = GL_NONE;
|
||||||
m_framebuffer.DrawBuffers(1, &buffer);
|
framebuffer.DrawBuffers(1, &buffer);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLFboFramebuffer::Activate() const
|
auto& framebufferEntry = m_framebuffers[&context];
|
||||||
|
framebufferEntry.framebuffer = std::move(framebuffer);
|
||||||
|
framebufferEntry.onContextDestruction.Connect(context.OnContextDestruction, [this](GL::Context* context)
|
||||||
{
|
{
|
||||||
const GL::Context& context = m_framebuffer.EnsureContext();
|
m_framebuffers.erase(context);
|
||||||
|
});
|
||||||
|
|
||||||
context.BindFramebuffer(GL::FramebufferTarget::Draw, m_framebuffer.GetObjectId());
|
return framebufferEntry.framebuffer;
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1023,6 +1023,8 @@ namespace Nz::GL
|
||||||
|
|
||||||
void Context::OnContextRelease()
|
void Context::OnContextRelease()
|
||||||
{
|
{
|
||||||
|
OnContextDestruction(this);
|
||||||
|
|
||||||
m_blitFramebuffers.reset();
|
m_blitFramebuffers.reset();
|
||||||
m_vaoCache.Clear();
|
m_vaoCache.Clear();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue