blob: 79a65f04352becdfb606e9e45e632c9cdadd9a76 [file] [log] [blame]
/*
* Copyright 2023 Rive
*/
#include "rive/pls/gl/pls_render_context_gl_impl.hpp"
#include "rive/pls/gl/pls_render_target_gl.hpp"
#include "../out/obj/generated/glsl.exports.h"
namespace rive::pls
{
constexpr static GLenum kPLSDrawBuffers[4] = {GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3};
class PLSRenderContextGLImpl::PLSImplFramebufferFetch : public PLSRenderContextGLImpl::PLSImpl
{
public:
PLSImplFramebufferFetch(const GLExtensions& extensions) : m_extensions(extensions) {}
rcp<PLSRenderTargetGL> wrapGLRenderTarget(GLuint framebufferID,
size_t width,
size_t height,
const PlatformFeatures& platformFeatures) override
{
if (framebufferID == 0)
{
return nullptr; // FBO 0 doesn't support additional color attachments.
}
auto renderTarget =
rcp(new PLSRenderTargetGL(framebufferID, width, height, platformFeatures));
renderTarget->allocateCoverageBackingTextures();
renderTarget->attachTexturesToCurrentFramebuffer();
return renderTarget;
}
rcp<PLSRenderTargetGL> makeOffscreenRenderTarget(
size_t width,
size_t height,
const PlatformFeatures& platformFeatures) override
{
auto renderTarget = rcp(new PLSRenderTargetGL(width, height, platformFeatures));
renderTarget->allocateCoverageBackingTextures();
renderTarget->attachTexturesToCurrentFramebuffer();
return renderTarget;
}
void activatePixelLocalStorage(PLSRenderContextGLImpl* context,
const PLSRenderContext::FlushDescriptor& desc) override
{
assert(context->m_extensions.EXT_shader_framebuffer_fetch);
auto renderTarget = static_cast<const PLSRenderTargetGL*>(desc.renderTarget);
glBindFramebuffer(GL_FRAMEBUFFER, renderTarget->drawFramebufferID());
// Enable multiple render targets, with a draw buffer for each PLS plane.
glDrawBuffers(4, kPLSDrawBuffers);
// Instruct the driver not to load existing PLS plane contents into tiled memory, with the
// exception of the color buffer after an intermediate flush.
static_assert(kFramebufferPlaneIdx == 0);
glInvalidateFramebuffer(GL_FRAMEBUFFER,
desc.loadAction == LoadAction::clear ? 4 : 3,
desc.loadAction == LoadAction::clear ? kPLSDrawBuffers
: kPLSDrawBuffers + 1);
// Clear the PLS planes.
constexpr static uint32_t kZero[4]{};
if (desc.loadAction == LoadAction::clear)
{
float clearColor4f[4];
UnpackColorToRGBA32F(desc.clearColor, clearColor4f);
glClearBufferfv(GL_COLOR, kFramebufferPlaneIdx, clearColor4f);
}
glClearBufferuiv(GL_COLOR, kCoveragePlaneIdx, kZero);
if (desc.needsClipBuffer)
{
glClearBufferuiv(GL_COLOR, kClipPlaneIdx, kZero);
}
}
void deactivatePixelLocalStorage(PLSRenderContextGLImpl*) override
{
// Instruct the driver not to flush PLS contents from tiled memory, with the exception of
// the color buffer.
static_assert(kFramebufferPlaneIdx == 0);
glInvalidateFramebuffer(GL_FRAMEBUFFER, 3, kPLSDrawBuffers + 1);
// Don't restore glDrawBuffers. The client can assume we've changed it, if we have a wrapped
// render target.
}
const char* shaderDefineName() const override { return GLSL_PLS_IMPL_FRAMEBUFFER_FETCH; }
void onEnableRasterOrdering(bool rasterOrderingEnabled) override
{
if (!m_extensions.QCOM_shader_framebuffer_fetch_noncoherent)
{
return;
}
if (rasterOrderingEnabled)
{
glDisable(GL_FRAMEBUFFER_FETCH_NONCOHERENT_QCOM);
}
else
{
glEnable(GL_FRAMEBUFFER_FETCH_NONCOHERENT_QCOM);
}
}
void onBarrier() override
{
if (!m_extensions.QCOM_shader_framebuffer_fetch_noncoherent)
{
return;
}
glFramebufferFetchBarrierQCOM();
}
private:
const GLExtensions m_extensions;
};
std::unique_ptr<PLSRenderContextGLImpl::PLSImpl> PLSRenderContextGLImpl::
MakePLSImplFramebufferFetch(const GLExtensions& extensions)
{
return std::make_unique<PLSImplFramebufferFetch>(extensions);
}
} // namespace rive::pls