| /* |
| * Copyright 2022 Rive |
| */ |
| |
| #include "testing_gl_renderer.hpp" |
| |
| #ifndef RIVE_TOOLS_NO_GL |
| |
| #include "rive/renderer/render_context.hpp" |
| #include "rive/renderer/rive_renderer.hpp" |
| #include "rive/renderer/gl/render_context_gl_impl.hpp" |
| #include "rive/renderer/gl/render_target_gl.hpp" |
| |
| TestingGLRenderer::~TestingGLRenderer() {} |
| |
| std::unique_ptr<TestingGLRenderer> TestingGLRenderer::Make( |
| TestingWindow::RendererFlags rendererFlags) |
| { |
| return TestingGLRenderer::MakePLS(rendererFlags); |
| } |
| |
| std::unique_ptr<TestingGLRenderer> TestingGLRenderer::MakePLS( |
| TestingWindow::RendererFlags rendererFlags) |
| { |
| class RiveRenderer : public TestingGLRenderer |
| { |
| public: |
| RiveRenderer(TestingWindow::RendererFlags rendererFlags) : |
| m_rendererFlags(rendererFlags) |
| { |
| if (m_rendererFlags & TestingWindow::RendererFlags::useMSAA) |
| { |
| m_contextOptions.disablePixelLocalStorage = true; |
| } |
| if (m_rendererFlags & |
| TestingWindow::RendererFlags::disableRasterOrdering) |
| { |
| m_contextOptions.disableFragmentShaderInterlock = true; |
| } |
| } |
| |
| void init(void* getGLProcAddress) override |
| { |
| m_renderContext = |
| rive::gpu::RenderContextGLImpl::MakeContext(m_contextOptions); |
| } |
| |
| rive::Factory* factory() override { return m_renderContext.get(); } |
| |
| std::unique_ptr<rive::Renderer> reset(int width, |
| int height, |
| uint32_t targetTextureID) override |
| { |
| if (targetTextureID == 0) |
| { |
| // Render directly to the default framebuffer. |
| GLint sampleCount; |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| glGetIntegerv(GL_SAMPLES, &sampleCount); |
| m_renderTarget = |
| rive::make_rcp<rive::gpu::FramebufferRenderTargetGL>( |
| width, |
| height, |
| 0, |
| sampleCount); |
| } |
| else |
| { |
| // Render to targetTextureID. |
| auto renderTarget = |
| rive::make_rcp<rive::gpu::TextureRenderTargetGL>(width, |
| height); |
| renderTarget->setTargetTexture(targetTextureID); |
| m_renderTarget = std::move(renderTarget); |
| } |
| return std::make_unique<rive::RiveRenderer>(m_renderContext.get()); |
| } |
| |
| void beginFrame(const TestingWindow::FrameOptions& options) override |
| { |
| // For testing, reset GPU resources to their initial sizes every |
| // frame. This will stress intermediate flushes more, as well as |
| // creating more consistency when rendering in multiple threads and |
| // a nondeterministic order. |
| m_renderContext->releaseResources(); |
| |
| rive::gpu::RenderContext::FrameDescriptor frameDescriptor = { |
| .renderTargetWidth = m_renderTarget->width(), |
| .renderTargetHeight = m_renderTarget->height(), |
| .loadAction = options.doClear |
| ? rive::gpu::LoadAction::clear |
| : rive::gpu::LoadAction::preserveRenderTarget, |
| .clearColor = options.clearColor, |
| .msaaSampleCount = |
| (m_rendererFlags & TestingWindow::RendererFlags::useMSAA) |
| ? 4 |
| : 0, |
| .disableRasterOrdering = |
| (m_rendererFlags & |
| TestingWindow::RendererFlags::disableRasterOrdering), |
| .wireframe = options.wireframe, |
| .clockwiseFillOverride = |
| (m_rendererFlags & |
| TestingWindow::RendererFlags::clockwiseFillOverride) || |
| options.clockwiseFillOverride}; |
| m_renderContext->beginFrame(frameDescriptor); |
| } |
| |
| void flush(int dpiScale) override { flushPLSContext(); } |
| |
| rive::gpu::RenderContext* renderContext() const override |
| { |
| return m_renderContext.get(); |
| } |
| rive::gpu::RenderTarget* renderTarget() const override |
| { |
| return m_renderTarget.get(); |
| } |
| |
| void flushPLSContext() override |
| { |
| m_renderContext->flush({.renderTarget = m_renderTarget.get()}); |
| } |
| |
| private: |
| const TestingWindow::RendererFlags m_rendererFlags; |
| rive::gpu::RenderContextGLImpl::ContextOptions m_contextOptions; |
| std::unique_ptr<rive::gpu::RenderContext> m_renderContext; |
| rive::rcp<rive::gpu::RenderTargetGL> m_renderTarget; |
| }; |
| return std::make_unique<RiveRenderer>(rendererFlags); |
| } |
| |
| #endif |