| /* | |
| * 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_RGB10_A2(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_UNPACK(v_windingWeight, half); | |
| half fragCoverage = v_windingWeight; | |
| #else | |
| VARYING_UNPACK(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 |