Skip to content

Commit

Permalink
Initial refactor to simplfigy class structure
Browse files Browse the repository at this point in the history
Diffs=
edc91a599 Initial refactor to simplfigy class structure (#8122)

Co-authored-by: rivessamr <[email protected]>
  • Loading branch information
rivessamr and rivessamr committed Sep 13, 2024
1 parent 8f44db1 commit ed33f09
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 141 deletions.
2 changes: 1 addition & 1 deletion .rive_head
Original file line number Diff line number Diff line change
@@ -1 +1 @@
e9918f2496734dac2a3e16b6566dc2fb10ef0434
edc91a599a7f182007e488b232d64e0166f43139
63 changes: 12 additions & 51 deletions renderer/include/rive/renderer/draw.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,20 +137,20 @@ class RiveRenderPathDraw : public Draw
float strokeRadius() const { return m_strokeRadius; }
gpu::ContourDirections contourDirections() const { return m_contourDirections; }

void pushToRenderContext(RenderContext::LogicalFlush*) final;
void pushToRenderContext(RenderContext::LogicalFlush*) override;

void releaseRefs() override;

public:
RiveRenderPathDraw(IAABB pathBounds,
RiveRenderPathDraw(IAABB,
const Mat2D&,
rcp<const RiveRenderPath>,
FillRule,
const RiveRenderPaint*,
Type,
gpu::InterlockMode);

virtual void onPushToRenderContext(RenderContext::LogicalFlush*) = 0;
void onPushToRenderContext(RenderContext::LogicalFlush*);

const RiveRenderPath* const m_pathRef;
const FillRule
Expand All @@ -161,22 +161,13 @@ class RiveRenderPathDraw : public Draw

// Used to guarantee m_pathRef doesn't change for the entire time we hold it.
RIVE_DEBUG_CODE(uint64_t m_rawPathMutationID;)
};

// Draws a path by fanning tessellation patches around the midpoint of each contour.
class MidpointFanPathDraw : public RiveRenderPathDraw
{
public:
MidpointFanPathDraw(RenderContext*,
IAABB pixelBounds,
const Mat2D&,
rcp<const RiveRenderPath>,
FillRule,
const RiveRenderPaint*);

protected:
void onPushToRenderContext(RenderContext::LogicalFlush*) override;
// Midpoint path draw
void initForMidpointFan(RenderContext*, const RiveRenderPaint*);

private:
// Draws a path by fanning tessellation patches around the midpoint of each contour.
// Emulates a stroke cap before the given cubic by pushing a copy of the cubic, reversed, with 0
// tessellation segments leading up to the join section, and a 180-degree join that looks like
// the desired stroke cap.
Expand Down Expand Up @@ -220,52 +211,22 @@ class MidpointFanPathDraw : public RiveRenderPathDraw
RIVE_DEBUG_CODE(size_t m_pendingStrokeCapCount;)
// Counts how many additional curves were pushed by pushEmulatedStrokeCapAsJoinBeforeCubic().
RIVE_DEBUG_CODE(size_t m_pendingEmptyStrokeCountForCaps;)
};

// Draws a path by triangulating the interior into non-overlapping triangles and tessellating the
// outer curves.
class InteriorTriangulationDraw : public RiveRenderPathDraw
{
public:
// Draws a path by triangulating the interior into non-overlapping triangles and tessellating
// the outer curves.
enum class TriangulatorAxis
{
horizontal,
vertical,
dontCare,
};

InteriorTriangulationDraw(RenderContext*,
IAABB pixelBounds,
const Mat2D&,
rcp<const RiveRenderPath>,
FillRule,
const RiveRenderPaint*,
RawPath* scratchPath,
TriangulatorAxis);

// Interior Triangulation path draw
void initForInteriorTriangulation(RenderContext*, RawPath*, TriangulatorAxis);
GrInnerFanTriangulator* triangulator() const { return m_triangulator; }

protected:
void onPushToRenderContext(RenderContext::LogicalFlush*) override;

// The final segment in an outerCurve patch is a bowtie join.
constexpr static size_t kJoinSegmentCount = 1;
constexpr static size_t kPatchSegmentCountExcludingJoin =
kOuterCurvePatchSegmentSpan - kJoinSegmentCount;

// Maximum # of outerCurve patches a curve on the path can be subdivided into.
constexpr static size_t kMaxCurveSubdivisions =
(kMaxParametricSegments + kPatchSegmentCountExcludingJoin - 1) /
kPatchSegmentCountExcludingJoin;

static uint32_t FindSubdivisionCount(const Vec2D pts[],
const wangs_formula::VectorXform& vectorXform)
{
float numSubdivisions = ceilf(wangs_formula::cubic(pts, kParametricPrecision, vectorXform) *
(1.f / kPatchSegmentCountExcludingJoin));
return static_cast<uint32_t>(math::clamp(numSubdivisions, 1, kMaxCurveSubdivisions));
}

private:
enum class PathOp : bool
{
countDataAndTriangulate,
Expand Down
6 changes: 1 addition & 5 deletions renderer/include/rive/renderer/render_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ class GradientLibrary;
class IntersectionBoard;
class ImageMeshDraw;
class ImageRectDraw;
class InteriorTriangulationDraw;
class MidpointFanPathDraw;
class StencilClipReset;
class Draw;
class Gradient;
Expand Down Expand Up @@ -256,8 +254,6 @@ class RenderContext : public RiveRenderFactory
private:
friend class Draw;
friend class RiveRenderPathDraw;
friend class MidpointFanPathDraw;
friend class InteriorTriangulationDraw;
friend class ImageRectDraw;
friend class ImageMeshDraw;
friend class StencilClipReset;
Expand Down Expand Up @@ -527,7 +523,7 @@ class RenderContext : public RiveRenderFactory

// Pushes triangles to be drawn using the data records from the most recent calls to
// pushPath() and pushPaint().
void pushInteriorTriangulation(InteriorTriangulationDraw*);
void pushInteriorTriangulation(RiveRenderPathDraw*);

// Pushes an imageRect to the draw list.
// This should only be used when we don't have bindless textures in atomic mode. Otherwise,
Expand Down
143 changes: 76 additions & 67 deletions renderer/src/draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,25 @@ namespace rive::gpu
{
namespace
{

// The final segment in an outerCurve patch is a bowtie join.
constexpr static size_t kJoinSegmentCount = 1;
constexpr static size_t kPatchSegmentCountExcludingJoin =
kOuterCurvePatchSegmentSpan - kJoinSegmentCount;

// Maximum # of outerCurve patches a curve on the path can be subdivided into.
constexpr static size_t kMaxCurveSubdivisions =
(kMaxParametricSegments + kPatchSegmentCountExcludingJoin - 1) /
kPatchSegmentCountExcludingJoin;

static uint32_t FindSubdivisionCount(const Vec2D pts[],
const wangs_formula::VectorXform& vectorXform)
{
float numSubdivisions = ceilf(wangs_formula::cubic(pts, kParametricPrecision, vectorXform) *
(1.f / kPatchSegmentCountExcludingJoin));
return static_cast<uint32_t>(math::clamp(numSubdivisions, 1, kMaxCurveSubdivisions));
}

constexpr static int kNumSegmentsInMiterOrBevelJoin = 5;
constexpr static int kStrokeStyleFlag = 8;
constexpr static int kRoundJoinStyleFlag = kStrokeStyleFlag << 1;
Expand Down Expand Up @@ -363,6 +382,8 @@ DrawUniquePtr RiveRenderPathDraw::Make(RenderContext* context,
mappedBounds = mappedBounds.inset(-strokePixelOutset.width(), -strokePixelOutset.height());
}
IAABB pixelBounds = mappedBounds.roundOut();
bool doTriangulation = false;
const AABB& localBounds = path->getBounds();
if (context->isOutsideCurrentFrame(pixelBounds))
{
return DrawUniquePtr();
Expand All @@ -371,31 +392,38 @@ DrawUniquePtr RiveRenderPathDraw::Make(RenderContext* context,
{
// Use interior triangulation to draw filled paths if they're large enough to benefit from
// it.
const AABB& localBounds = path->getBounds();
// FIXME! Implement interior triangulation in depthStencil mode.

if (context->frameInterlockMode() != gpu::InterlockMode::depthStencil &&
path->getRawPath().verbs().count() < 1000 &&
gpu::FindTransformedArea(localBounds, matrix) > 512 * 512)
{
return DrawUniquePtr(context->make<InteriorTriangulationDraw>(
context,
pixelBounds,
matrix,
std::move(path),
fillRule,
paint,
scratchPath,
localBounds.width() > localBounds.height()
? InteriorTriangulationDraw::TriangulatorAxis::horizontal
: InteriorTriangulationDraw::TriangulatorAxis::vertical));
doTriangulation = true;
}
}
return DrawUniquePtr(context->make<MidpointFanPathDraw>(context,
pixelBounds,
matrix,
std::move(path),
fillRule,
paint));

auto draw = context->make<RiveRenderPathDraw>(pixelBounds,
matrix,
std::move(path),
fillRule,
paint,
doTriangulation ? Type::interiorTriangulationPath
: Type::midpointFanPath,
context->frameInterlockMode());
if (doTriangulation)
{
draw->initForInteriorTriangulation(context,
scratchPath,
localBounds.width() > localBounds.height()
? RiveRenderPathDraw::TriangulatorAxis::horizontal
: RiveRenderPathDraw::TriangulatorAxis::vertical);
}
else
{
draw->initForMidpointFan(context, paint);
}

return DrawUniquePtr(draw);
}

RiveRenderPathDraw::RiveRenderPathDraw(IAABB pixelBounds,
Expand Down Expand Up @@ -500,19 +528,7 @@ void RiveRenderPathDraw::releaseRefs()
m_pathRef->unref();
}

MidpointFanPathDraw::MidpointFanPathDraw(RenderContext* context,
IAABB pixelBounds,
const Mat2D& matrix,
rcp<const RiveRenderPath> path,
FillRule fillRule,
const RiveRenderPaint* paint) :
RiveRenderPathDraw(pixelBounds,
matrix,
std::move(path),
fillRule,
paint,
Type::midpointFanPath,
context->frameInterlockMode())
void RiveRenderPathDraw::initForMidpointFan(RenderContext* context, const RiveRenderPaint* paint)
{
if (isStroked())
{
Expand Down Expand Up @@ -1012,8 +1028,24 @@ MidpointFanPathDraw::MidpointFanPathDraw(RenderContext* context,
}
}

void MidpointFanPathDraw::onPushToRenderContext(RenderContext::LogicalFlush* flush)
void RiveRenderPathDraw::onPushToRenderContext(RenderContext::LogicalFlush* flush)
{
if (type() == Type::interiorTriangulationPath)
{
// Interior Triangulation Case
processPath(PathOp::submitOuterCubics, nullptr, nullptr, TriangulatorAxis::dontCare, flush);
if (flush->desc().interlockMode == gpu::InterlockMode::atomics)
{
// We need a barrier between the outer cubics and interior triangles in atomic mode.
flush->pushBarrier();
}
flush->pushInteriorTriangulation(this);
return;
}

assert(type() == Type::midpointFanPath);

// Midpoint Fan Case
const RawPath& rawPath = m_pathRef->getRawPath();
RawPath::Iter startOfContour = rawPath.begin();
for (size_t i = 0; i < m_resourceCounts.contourCount; ++i)
Expand Down Expand Up @@ -1323,10 +1355,10 @@ void MidpointFanPathDraw::onPushToRenderContext(RenderContext::LogicalFlush* flu
assert(m_pendingEmptyStrokeCountForCaps == 0);
}

void MidpointFanPathDraw::pushEmulatedStrokeCapAsJoinBeforeCubic(RenderContext::LogicalFlush* flush,
const Vec2D cubic[],
uint32_t emulatedCapAsJoinFlags,
uint32_t strokeCapSegmentCount)
void RiveRenderPathDraw::pushEmulatedStrokeCapAsJoinBeforeCubic(RenderContext::LogicalFlush* flush,
const Vec2D cubic[],
uint32_t emulatedCapAsJoinFlags,
uint32_t strokeCapSegmentCount)
{
// Reverse the cubic and push it with zero parametric and polar segments, and a 180-degree join
// tangent. This results in a solitary join, positioned immediately before the provided cubic,
Expand All @@ -1342,21 +1374,9 @@ void MidpointFanPathDraw::pushEmulatedStrokeCapAsJoinBeforeCubic(RenderContext::
RIVE_DEBUG_CODE(--m_pendingEmptyStrokeCountForCaps;)
}

InteriorTriangulationDraw::InteriorTriangulationDraw(RenderContext* context,
IAABB pixelBounds,
const Mat2D& matrix,
rcp<const RiveRenderPath> path,
FillRule fillRule,
const RiveRenderPaint* paint,
RawPath* scratchPath,
TriangulatorAxis triangulatorAxis) :
RiveRenderPathDraw(pixelBounds,
matrix,
std::move(path),
fillRule,
paint,
Type::interiorTriangulationPath,
context->frameInterlockMode())
void RiveRenderPathDraw::initForInteriorTriangulation(RenderContext* context,
RawPath* scratchPath,
TriangulatorAxis triangulatorAxis)
{
assert(!isStroked());
assert(m_strokeRadius == 0);
Expand All @@ -1367,22 +1387,11 @@ InteriorTriangulationDraw::InteriorTriangulationDraw(RenderContext* context,
nullptr);
}

void InteriorTriangulationDraw::onPushToRenderContext(RenderContext::LogicalFlush* flush)
{
processPath(PathOp::submitOuterCubics, nullptr, nullptr, TriangulatorAxis::dontCare, flush);
if (flush->desc().interlockMode == gpu::InterlockMode::atomics)
{
// We need a barrier between the outer cubics and interior triangles in atomic mode.
flush->pushBarrier();
}
flush->pushInteriorTriangulation(this);
}

void InteriorTriangulationDraw::processPath(PathOp op,
TrivialBlockAllocator* allocator,
RawPath* scratchPath,
TriangulatorAxis triangulatorAxis,
RenderContext::LogicalFlush* flush)
void RiveRenderPathDraw::processPath(PathOp op,
TrivialBlockAllocator* allocator,
RawPath* scratchPath,
TriangulatorAxis triangulatorAxis,
RenderContext::LogicalFlush* flush)
{
Vec2D chops[kMaxCurveSubdivisions * 3 + 1];
const RawPath& rawPath = m_pathRef->getRawPath();
Expand Down
2 changes: 1 addition & 1 deletion renderer/src/render_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1710,7 +1710,7 @@ RIVE_ALWAYS_INLINE void RenderContext::LogicalFlush::pushMirroredAndForwardTesse
assert(m_pathMirroredTessLocation >= m_expectedPathMirroredTessLocationAtEndOfPath);
}

void RenderContext::LogicalFlush::pushInteriorTriangulation(InteriorTriangulationDraw* draw)
void RenderContext::LogicalFlush::pushInteriorTriangulation(RiveRenderPathDraw* draw)
{
assert(m_hasDoneLayout);

Expand Down
Loading

0 comments on commit ed33f09

Please sign in to comment.