/* * Copyright 2023 Rive */ #include "gm.hpp" #include "gr_inner_fan_triangulator.hpp" #include "common/testing_window.hpp" #include "rive/renderer.hpp" #include "rive/renderer/draw.hpp" #include "rive/renderer/render_context.hpp" #include "../src/rive_render_paint.hpp" #include "../src/rive_render_path.hpp" #include "../src/shaders/constants.glsl" using namespace rivegm; using namespace rive; using namespace rive::gpu; constexpr static std::array kTris[] = { {Vec2D{10, 10}, Vec2D{50, 10}, Vec2D{10, 120}}, {Vec2D{10, 290}, Vec2D{290, 10}, Vec2D{270, 280}}, {Vec2D{60, 60}, Vec2D{30, 190}, Vec2D{250, 20}}, }; constexpr static size_t kNumTriangles = sizeof(kTris) / sizeof(kTris[0]); rcp make_nonempty_placeholder_path() { auto path = make_rcp(); path->moveTo(0, 0); return path; } class PushRetrofittedTrianglesGMDraw : public PathDraw { public: PushRetrofittedTrianglesGMDraw(RenderContext* context, const RiveRenderPaint* paint) : PathDraw(FULLSCREEN_PIXEL_BOUNDS, Mat2D(), make_nonempty_placeholder_path(), context->frameDescriptor().clockwiseFillOverride ? FillRule::clockwise : FillRule::nonZero, paint, 1.0f, // modulatedOpacity SelectCoverageType(paint, 1, context->platformFeatures(), context->frameInterlockMode()), context->frameDescriptor()) { m_resourceCounts.pathCount = 1; m_resourceCounts.contourCount = 1; m_resourceCounts.maxTessellatedSegmentCount = kNumTriangles; m_resourceCounts.outerCubicTessVertexCount = context->frameInterlockMode() != gpu::InterlockMode::msaa ? gpu::kOuterCurvePatchSegmentSpan * kNumTriangles * 2 : gpu::kOuterCurvePatchSegmentSpan * kNumTriangles; m_triangulator = context->make( RawPath(), Mat2D(), GrTriangulator::Comparator::Direction::kHorizontal, FillRule::nonZero, &context->perFrameAllocator()); } void countSubpasses() override { assert(m_prepassCount == 0); assert(m_subpassCount == 1); } bool allocateResources(RenderContext::LogicalFlush* flush) override { if (!PathDraw::allocateResources(flush)) { return false; } return true; } void pushToRenderContext(RenderContext::LogicalFlush* flush, int subpassIndex) override { // Make sure the rawPath in our path reference hasn't changed since we // began holding! assert(m_rawPathMutationID == m_pathRef->getRawPathMutationID()); assert(!m_pathRef->getRawPath().empty()); assert(subpassIndex == 0); uint32_t tessVertexCount = math::lossless_numeric_cast( m_resourceCounts.outerCubicTessVertexCount); if (tessVertexCount > 0) { m_pathID = flush->pushPath(this); uint32_t tessLocation = flush->allocateOuterCubicTessVertices(tessVertexCount); uint32_t forwardTessVertexCount, forwardTessLocation, mirroredTessVertexCount, mirroredTessLocation; if (m_contourDirections == gpu::ContourDirections::reverseThenForward) { forwardTessVertexCount = mirroredTessVertexCount = tessVertexCount / 2; forwardTessLocation = mirroredTessLocation = tessLocation + tessVertexCount / 2; } else { assert(m_contourDirections == gpu::ContourDirections::forward); forwardTessVertexCount = tessVertexCount; forwardTessLocation = tessLocation; mirroredTessVertexCount = mirroredTessLocation = 0; } RenderContext::TessellationWriter tessWriter( flush, m_pathID, m_contourDirections, forwardTessVertexCount, forwardTessLocation, mirroredTessVertexCount, mirroredTessLocation); uint32_t contourID = tessWriter.pushContour( {0, 0}, /*isStroke=*/false, /*closed=*/true, 0 /* gpu::kOuterCurvePatchSegmentSpan - 2 */); for (const auto& pts : kTris) { Vec2D tri[4] = {pts[0], pts[1], {0, 0}, pts[2]}; tessWriter.pushCubic(tri, m_contourDirections, {0, 0}, gpu::kOuterCurvePatchSegmentSpan - 1, 1, 1, contourID | RETROFITTED_TRIANGLE_CONTOUR_FLAG); } if (flush->frameDescriptor().clockwiseFillOverride) { m_drawContents |= gpu::DrawContents::clockwiseFill; } flush->pushOuterCubicsDraw(this, m_coverageType == CoverageType::msaa ? gpu::DrawType::msaaOuterCubics : gpu::DrawType::outerCurvePatches, tessVertexCount, tessLocation, gpu::ShaderMiscFlags::none); } } }; // Checks that RenderContext properly draws single triangles when using the // "kRetrofittedTriangle" flag. class RetrofittedCubicTrianglesGM : public GM { public: RetrofittedCubicTrianglesGM() : GM(300, 300) {} protected: void onDraw(Renderer* renderer) override { TestingWindow::Get()->endFrame(nullptr); gpu::RenderContext* renderContext = TestingWindow::Get()->renderContext(); if (!renderContext) { TestingWindow::Get()->beginFrame({.clearColor = 0xffff0000}); } else { TestingWindow::Get()->beginFrame({.clearColor = 0xff000000}); RiveRenderPaint paint; paint.color(0xffffffff); DrawUniquePtr draw( renderContext->make( renderContext, &paint)); bool success RIVE_MAYBE_UNUSED = renderContext->pushDraws(&draw, 1); assert(success); } } }; GMREGISTER(retrofittedcubictriangles, return new RetrofittedCubicTrianglesGM;)