blob: 73148877eb60c2cd6cf275ca884e1dc2c163b811 [file]
/*
* Copyright 2023 Rive
*/
#include "rive/pls/gl/pls_render_context_gl.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 PLSRenderContextGL::PLSImplFramebufferFetch : public PLSRenderContextGL::PLSImpl
{
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(PLSRenderContextGL* context,
const PLSRenderTargetGL* renderTarget,
LoadAction loadAction,
bool needsClipBuffer) override
{
assert(context->m_extensions.EXT_shader_framebuffer_fetch);
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,
loadAction == LoadAction::clear ? 4 : 3,
loadAction == LoadAction::clear ? kPLSDrawBuffers
: kPLSDrawBuffers + 1);
// Clear the PLS planes.
constexpr static uint32_t kZero[4]{};
if (loadAction == LoadAction::clear)
{
float clearColor4f[4];
UnpackColorToRGBA32F(context->frameDescriptor().clearColor, clearColor4f);
glClearBufferfv(GL_COLOR, kFramebufferPlaneIdx, clearColor4f);
}
glClearBufferuiv(GL_COLOR, kCoveragePlaneIdx, kZero);
if (needsClipBuffer)
{
glClearBufferuiv(GL_COLOR, kClipPlaneIdx, kZero);
}
}
void deactivatePixelLocalStorage() 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; }
};
std::unique_ptr<PLSRenderContextGL::PLSImpl> PLSRenderContextGL::MakePLSImplFramebufferFetch()
{
return std::make_unique<PLSImplFramebufferFetch>();
}
} // namespace rive::pls