| /* |
| * 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( |
| const TestingWindow::BackendParams& backendParams) |
| { |
| class RiveRenderer : public TestingGLRenderer |
| { |
| public: |
| RiveRenderer(const TestingWindow::BackendParams& backendParams) : |
| m_backendParams(backendParams) |
| { |
| m_contextOptions.shaderCompilationMode = |
| rive::gpu::ShaderCompilationMode::alwaysSynchronous; |
| if (m_backendParams.msaa) |
| { |
| m_contextOptions.disablePixelLocalStorage = true; |
| } |
| if (m_backendParams.atomic) |
| { |
| 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_backendParams.msaa || options.forceMSAA) ? 4u : 0u, |
| .disableRasterOrdering = |
| m_backendParams.atomic || options.disableRasterOrdering, |
| .wireframe = options.wireframe, |
| .clockwiseFillOverride = |
| m_backendParams.clockwise || options.clockwiseFillOverride, |
| .synthesizedFailureType = options.synthesizedFailureType, |
| }; |
| m_renderContext->beginFrame(frameDescriptor); |
| } |
| |
| void flush(int dpiScale) override { flushPLSContext(nullptr); } |
| |
| rive::gpu::RenderContext* renderContext() const override |
| { |
| return m_renderContext.get(); |
| } |
| rive::gpu::RenderTarget* renderTarget() const override |
| { |
| return m_renderTarget.get(); |
| } |
| |
| void flushPLSContext( |
| rive::gpu::RenderTarget* offscreenRenderTarget) override |
| { |
| m_renderContext->flush({ |
| .renderTarget = offscreenRenderTarget != nullptr |
| ? offscreenRenderTarget |
| : m_renderTarget.get(), |
| }); |
| } |
| |
| private: |
| const TestingWindow::BackendParams m_backendParams; |
| 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>(backendParams); |
| } |
| |
| #endif |