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/OpenGLRenderer/OpenGLFramebuffer.hpp>
|
||||
#include <Nazara/OpenGLRenderer/Wrapper/Context.hpp>
|
||||
#include <Nazara/OpenGLRenderer/Wrapper/Framebuffer.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
|
|
@ -22,14 +24,14 @@ namespace Nz
|
|||
class NAZARA_OPENGLRENDERER_API OpenGLFboFramebuffer final : public OpenGLFramebuffer
|
||||
{
|
||||
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(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<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;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -11,29 +11,87 @@
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
OpenGLFboFramebuffer::OpenGLFboFramebuffer(OpenGLDevice& device, const std::vector<std::shared_ptr<Texture>>& attachments) :
|
||||
OpenGLFramebuffer(FramebufferType::Texture)
|
||||
OpenGLFboFramebuffer::OpenGLFboFramebuffer(OpenGLDevice& device, std::vector<std::shared_ptr<Texture>> 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<const OpenGLTexture&>(*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<const OpenGLTexture&>(*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<GLsizei>(m_colorAttachmentCount), fboDrawBuffers.data());
|
||||
framebuffer.DrawBuffers(SafeCast<GLsizei>(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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1023,6 +1023,8 @@ namespace Nz::GL
|
|||
|
||||
void Context::OnContextRelease()
|
||||
{
|
||||
OnContextDestruction(this);
|
||||
|
||||
m_blitFramebuffers.reset();
|
||||
m_vaoCache.Clear();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue