blob: 5ba2ed119f2e7272f6eb33b6623fd58f6d9f63e0 [file] [log] [blame]
/*
* Copyright 2025 Rive
*/
#ifdef @FRAGMENT
PLS_BLOCK_BEGIN
#ifndef @FIXED_FUNCTION_COLOR_OUTPUT
PLS_DECL4F(COLOR_PLANE_IDX, colorBuffer);
#endif
PLS_DECLUI(CLIP_PLANE_IDX, clipBuffer);
#ifndef @FIXED_FUNCTION_COLOR_OUTPUT
PLS_DECL4F(SCRATCH_COLOR_PLANE_IDX, scratchColorBuffer);
#endif
PLS_DECLUI(COVERAGE_PLANE_IDX, coverageBuffer);
PLS_BLOCK_END
PLS_MAIN(@drawFragmentMain)
{
VARYING_UNPACK(v_clipIDs, half2);
half clipID = -v_clipIDs.x;
#ifdef @DRAW_INTERIOR_TRIANGLES
VARYING_INIT(v_windingWeight, half);
half fragCoverage = v_windingWeight;
#else
VARYING_INIT(v_coverages, COVERAGE_TYPE);
half fragCoverage = v_coverages.x;
#endif //@DRAW_INTERIOR_TRIANGLES
PLS_INTERLOCK_BEGIN;
half2 clipData;
half clipBufferID, clipCoverage;
#if defined(@DRAW_INTERIOR_TRIANGLES) && defined(@BORROWED_COVERAGE_PASS)
if (@BORROWED_COVERAGE_PASS)
{
// Interior triangles with borrowed coverage are always the first
// fragment of the path at their pixel, so we don't need to check the
// current coverage value.
clipCoverage = fragCoverage;
}
else
#endif
{
clipData = unpackHalf2x16(PLS_LOADUI(clipBuffer));
clipBufferID = clipData.g;
half initialCoverage =
clipBufferID == clipID ? clipData.r : make_half(.0);
clipCoverage = initialCoverage + fragCoverage;
}
#ifdef @ENABLE_NESTED_CLIPPING
half outerClipID = v_clipIDs.y;
if (@ENABLE_NESTED_CLIPPING && outerClipID != .0)
{
half outerClipCoverage = .0;
#if defined(@DRAW_INTERIOR_TRIANGLES) && defined(@BORROWED_COVERAGE_PASS)
if (@BORROWED_COVERAGE_PASS)
{
// Interior triangles with borrowed coverage did not load the clip
// buffer already, so do that now.
clipData = unpackHalf2x16(PLS_LOADUI(clipBuffer));
clipBufferID = clipData.g;
}
#endif
if (clipBufferID != clipID)
{
outerClipCoverage = clipBufferID == outerClipID ? clipData.r : .0;
// The coverage buffer is a free resource when rendering clip
// because we don't use it to track coverage. Use it instead to
// temporarily save the outer clip for nested clips. But make sure
// to write an invalid pathID so we don't corrupt any future paths
// that will be drawn.
PLS_STOREUI(
coverageBuffer,
packHalf2x16(make_half2(outerClipCoverage, INVALID_PATH_ID)));
}
else
{
outerClipCoverage = unpackHalf2x16(PLS_LOADUI(coverageBuffer)).r;
PLS_PRESERVE_UI(coverageBuffer);
}
clipCoverage = min(clipCoverage, outerClipCoverage);
}
else
#endif
{
PLS_PRESERVE_UI(coverageBuffer);
}
PLS_STOREUI(clipBuffer, packHalf2x16(make_half2(clipCoverage, clipID)));
#ifndef @FIXED_FUNCTION_COLOR_OUTPUT
PLS_PRESERVE_4F(colorBuffer);
#endif
PLS_INTERLOCK_END;
EMIT_PLS;
}
#endif // FRAGMENT