Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Public Member Functions | Private Member Functions | List of all members
CircularRRectEffect::Impl Class Reference
Inheritance diagram for CircularRRectEffect::Impl:
GrFragmentProcessor::ProgramImpl

Public Member Functions

void emitCode (EmitArgs &) override
 
- Public Member Functions inherited from GrFragmentProcessor::ProgramImpl
 ProgramImpl ()=default
 
virtual ~ProgramImpl ()=default
 
void setData (const GrGLSLProgramDataManager &pdman, const GrFragmentProcessor &processor)
 
int numChildProcessors () const
 
ProgramImplchildProcessor (int index) const
 
void setFunctionName (SkString name)
 
const char * functionName () const
 
SkString invokeChild (int childIndex, EmitArgs &parentArgs, std::string_view skslCoords={})
 
SkString invokeChildWithMatrix (int childIndex, EmitArgs &parentArgs)
 
SkString invokeChild (int childIndex, const char *inputColor, EmitArgs &parentArgs, std::string_view skslCoords={})
 
SkString invokeChildWithMatrix (int childIndex, const char *inputColor, EmitArgs &parentArgs)
 
SkString invokeChild (int childIndex, const char *inputColor, const char *destColor, EmitArgs &parentArgs, std::string_view skslCoords={})
 
SkString invokeChildWithMatrix (int childIndex, const char *inputColor, const char *destColor, EmitArgs &parentArgs)
 

Private Member Functions

void onSetData (const GrGLSLProgramDataManager &, const GrFragmentProcessor &) override
 

Additional Inherited Members

- Public Types inherited from GrFragmentProcessor::ProgramImpl
using UniformHandle = GrGLSLUniformHandler::UniformHandle
 
using SamplerHandle = GrGLSLUniformHandler::SamplerHandle
 

Detailed Description

Definition at line 159 of file GrRRectEffect.cpp.

Member Function Documentation

◆ emitCode()

void CircularRRectEffect::Impl::emitCode ( EmitArgs args)
overridevirtual

Implements GrFragmentProcessor::ProgramImpl.

Definition at line 171 of file GrRRectEffect.cpp.

171 {
172 const CircularRRectEffect& crre = args.fFp.cast<CircularRRectEffect>();
173 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
174 const char *rectName;
175 const char *radiusPlusHalfName;
176 // The inner rect is the rrect bounds inset by the radius. Its left, top, right, and bottom
177 // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has
178 // only rectangular corners, that side's value corresponds to the rect edge's value outset by
179 // half a pixel.
180 fInnerRectUniform = uniformHandler->addUniform(&crre, kFragment_GrShaderFlag, SkSLType::kFloat4,
181 "innerRect", &rectName);
182 // x is (r + .5) and y is 1/(r + .5)
183 fRadiusPlusHalfUniform = uniformHandler->addUniform(&crre, kFragment_GrShaderFlag,
184 SkSLType::kHalf2, "radiusPlusHalf",
185 &radiusPlusHalfName);
186
187 // If we're on a device where float != fp32 then the length calculation could overflow.
188 SkString clampedCircleDistance;
189 if (!args.fShaderCaps->fFloatIs32Bits) {
190 clampedCircleDistance.printf("saturate(%s.x * (1.0 - length(dxy * %s.y)))",
191 radiusPlusHalfName, radiusPlusHalfName);
192 } else {
193 clampedCircleDistance.printf("saturate(%s.x - length(dxy))", radiusPlusHalfName);
194 }
195
196 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
197 // At each quarter-circle corner we compute a vector that is the offset of the fragment position
198 // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant
199 // to that corner. This means that points near the interior near the rrect top edge will have
200 // a vector that points straight up for both the TL left and TR corners. Computing an
201 // alpha from this vector at either the TR or TL corner will give the correct result. Similarly,
202 // fragments near the other three edges will get the correct AA. Fragments in the interior of
203 // the rrect will have a (0,0) vector at all four corners. So long as the radius > 0.5 they will
204 // correctly produce an alpha value of 1 at all four corners. We take the min of all the alphas.
205 // The code below is a simplified version of the above that performs maxs on the vector
206 // components before computing distances and alpha values so that only one distance computation
207 // need be computed to determine the min alpha.
208 //
209 // For the cases where one half of the rrect is rectangular we drop one of the x or y
210 // computations, compute a separate rect edge alpha for the rect side, and mul the two computed
211 // alphas together.
212 switch (crre.fCircularCornerFlags) {
213 case CircularRRectEffect::kAll_CornerFlags:
214 fragBuilder->codeAppendf("float2 dxy0 = %s.LT - sk_FragCoord.xy;", rectName);
215 fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.RB;", rectName);
216 fragBuilder->codeAppend("float2 dxy = max(max(dxy0, dxy1), 0.0);");
217 fragBuilder->codeAppendf("half alpha = half(%s);", clampedCircleDistance.c_str());
218 break;
219 case CircularRRectEffect::kTopLeft_CornerFlag:
220 fragBuilder->codeAppendf("float2 dxy = max(%s.LT - sk_FragCoord.xy, 0.0);",
221 rectName);
222 fragBuilder->codeAppendf("half rightAlpha = half(saturate(%s.R - sk_FragCoord.x));",
223 rectName);
224 fragBuilder->codeAppendf("half bottomAlpha = half(saturate(%s.B - sk_FragCoord.y));",
225 rectName);
226 fragBuilder->codeAppendf("half alpha = bottomAlpha * rightAlpha * half(%s);",
227 clampedCircleDistance.c_str());
228 break;
229 case CircularRRectEffect::kTopRight_CornerFlag:
230 fragBuilder->codeAppendf("float2 dxy = max(float2(sk_FragCoord.x - %s.R, "
231 "%s.T - sk_FragCoord.y), 0.0);",
232 rectName, rectName);
233 fragBuilder->codeAppendf("half leftAlpha = half(saturate(sk_FragCoord.x - %s.L));",
234 rectName);
235 fragBuilder->codeAppendf("half bottomAlpha = half(saturate(%s.B - sk_FragCoord.y));",
236 rectName);
237 fragBuilder->codeAppendf("half alpha = bottomAlpha * leftAlpha * half(%s);",
238 clampedCircleDistance.c_str());
239 break;
240 case CircularRRectEffect::kBottomRight_CornerFlag:
241 fragBuilder->codeAppendf("float2 dxy = max(sk_FragCoord.xy - %s.RB, 0.0);",
242 rectName);
243 fragBuilder->codeAppendf("half leftAlpha = half(saturate(sk_FragCoord.x - %s.L));",
244 rectName);
245 fragBuilder->codeAppendf("half topAlpha = half(saturate(sk_FragCoord.y - %s.T));",
246 rectName);
247 fragBuilder->codeAppendf("half alpha = topAlpha * leftAlpha * half(%s);",
248 clampedCircleDistance.c_str());
249 break;
250 case CircularRRectEffect::kBottomLeft_CornerFlag:
251 fragBuilder->codeAppendf("float2 dxy = max(float2(%s.L - sk_FragCoord.x, "
252 "sk_FragCoord.y - %s.B), 0.0);",
253 rectName, rectName);
254 fragBuilder->codeAppendf("half rightAlpha = half(saturate(%s.R - sk_FragCoord.x));",
255 rectName);
256 fragBuilder->codeAppendf("half topAlpha = half(saturate(sk_FragCoord.y - %s.T));",
257 rectName);
258 fragBuilder->codeAppendf("half alpha = topAlpha * rightAlpha * half(%s);",
259 clampedCircleDistance.c_str());
260 break;
261 case CircularRRectEffect::kLeft_CornerFlags:
262 fragBuilder->codeAppendf("float2 dxy0 = %s.LT - sk_FragCoord.xy;", rectName);
263 fragBuilder->codeAppendf("float dy1 = sk_FragCoord.y - %s.B;", rectName);
264 fragBuilder->codeAppend("float2 dxy = max(float2(dxy0.x, max(dxy0.y, dy1)), 0.0);");
265 fragBuilder->codeAppendf("half rightAlpha = half(saturate(%s.R - sk_FragCoord.x));",
266 rectName);
267 fragBuilder->codeAppendf("half alpha = rightAlpha * half(%s);",
268 clampedCircleDistance.c_str());
269 break;
270 case CircularRRectEffect::kTop_CornerFlags:
271 fragBuilder->codeAppendf("float2 dxy0 = %s.LT - sk_FragCoord.xy;", rectName);
272 fragBuilder->codeAppendf("float dx1 = sk_FragCoord.x - %s.R;", rectName);
273 fragBuilder->codeAppend("float2 dxy = max(float2(max(dxy0.x, dx1), dxy0.y), 0.0);");
274 fragBuilder->codeAppendf("half bottomAlpha = half(saturate(%s.B - sk_FragCoord.y));",
275 rectName);
276 fragBuilder->codeAppendf("half alpha = bottomAlpha * half(%s);",
277 clampedCircleDistance.c_str());
278 break;
279 case CircularRRectEffect::kRight_CornerFlags:
280 fragBuilder->codeAppendf("float dy0 = %s.T - sk_FragCoord.y;", rectName);
281 fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.RB;", rectName);
282 fragBuilder->codeAppend("float2 dxy = max(float2(dxy1.x, max(dy0, dxy1.y)), 0.0);");
283 fragBuilder->codeAppendf("half leftAlpha = half(saturate(sk_FragCoord.x - %s.L));",
284 rectName);
285 fragBuilder->codeAppendf("half alpha = leftAlpha * half(%s);",
286 clampedCircleDistance.c_str());
287 break;
288 case CircularRRectEffect::kBottom_CornerFlags:
289 fragBuilder->codeAppendf("float dx0 = %s.L - sk_FragCoord.x;", rectName);
290 fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.RB;", rectName);
291 fragBuilder->codeAppend("float2 dxy = max(float2(max(dx0, dxy1.x), dxy1.y), 0.0);");
292 fragBuilder->codeAppendf("half topAlpha = half(saturate(sk_FragCoord.y - %s.T));",
293 rectName);
294 fragBuilder->codeAppendf("half alpha = topAlpha * half(%s);",
295 clampedCircleDistance.c_str());
296 break;
297 }
298
299 if (GrClipEdgeType::kInverseFillAA == crre.fEdgeType) {
300 fragBuilder->codeAppend("alpha = 1.0 - alpha;");
301 }
302
303 SkString inputSample = this->invokeChild(/*childIndex=*/0, args);
304
305 fragBuilder->codeAppendf("return %s * alpha;", inputSample.c_str());
306}
@ kFragment_GrShaderFlag
SkString invokeChild(int childIndex, EmitArgs &parentArgs, std::string_view skslCoords={})
void codeAppend(const char *str)
void codeAppendf(const char format[],...) SK_PRINTF_LIKE(2
void printf(const char format[],...) SK_PRINTF_LIKE(2
Definition SkString.cpp:534
const char * c_str() const
Definition SkString.h:133
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args

◆ onSetData()

void CircularRRectEffect::Impl::onSetData ( const GrGLSLProgramDataManager ,
const GrFragmentProcessor  
)
overrideprivatevirtual

A ProgramImpl instance can be reused with any GrFragmentProcessor that produces the same the same key; this function reads data from a GrFragmentProcessor and uploads any uniform variables required by the shaders created in emitCode(). The GrFragmentProcessor parameter is guaranteed to be of the same type that created this ProgramImpl and to have an identical key as the one that created this ProgramImpl.

Reimplemented from GrFragmentProcessor::ProgramImpl.

Definition at line 308 of file GrRRectEffect.cpp.

309 {
310 const CircularRRectEffect& crre = processor.cast<CircularRRectEffect>();
311 const SkRRect& rrect = crre.fRRect;
312 if (rrect != fPrevRRect) {
314 SkScalar radius = 0;
315 switch (crre.fCircularCornerFlags) {
316 case CircularRRectEffect::kAll_CornerFlags:
318 radius = SkRRectPriv::GetSimpleRadii(rrect).fX;
319 SkASSERT(radius >= kRadiusMin);
320 rect.inset(radius, radius);
321 break;
322 case CircularRRectEffect::kTopLeft_CornerFlag:
324 rect.fLeft += radius;
325 rect.fTop += radius;
326 rect.fRight += 0.5f;
327 rect.fBottom += 0.5f;
328 break;
329 case CircularRRectEffect::kTopRight_CornerFlag:
331 rect.fLeft -= 0.5f;
332 rect.fTop += radius;
333 rect.fRight -= radius;
334 rect.fBottom += 0.5f;
335 break;
336 case CircularRRectEffect::kBottomRight_CornerFlag:
338 rect.fLeft -= 0.5f;
339 rect.fTop -= 0.5f;
340 rect.fRight -= radius;
341 rect.fBottom -= radius;
342 break;
343 case CircularRRectEffect::kBottomLeft_CornerFlag:
345 rect.fLeft += radius;
346 rect.fTop -= 0.5f;
347 rect.fRight += 0.5f;
348 rect.fBottom -= radius;
349 break;
350 case CircularRRectEffect::kLeft_CornerFlags:
352 rect.fLeft += radius;
353 rect.fTop += radius;
354 rect.fRight += 0.5f;
355 rect.fBottom -= radius;
356 break;
357 case CircularRRectEffect::kTop_CornerFlags:
359 rect.fLeft += radius;
360 rect.fTop += radius;
361 rect.fRight -= radius;
362 rect.fBottom += 0.5f;
363 break;
364 case CircularRRectEffect::kRight_CornerFlags:
366 rect.fLeft -= 0.5f;
367 rect.fTop += radius;
368 rect.fRight -= radius;
369 rect.fBottom -= radius;
370 break;
371 case CircularRRectEffect::kBottom_CornerFlags:
373 rect.fLeft += radius;
374 rect.fTop -= 0.5f;
375 rect.fRight -= radius;
376 rect.fBottom -= radius;
377 break;
378 default:
379 SK_ABORT("Should have been one of the above cases.");
380 }
381 pdman.set4f(fInnerRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
382 radius += 0.5f;
383 pdman.set2f(fRadiusPlusHalfUniform, radius, 1.f / radius);
384 fPrevRRect = rrect;
385 }
386}
static const SkScalar kRadiusMin
#define SK_ABORT(message,...)
Definition SkAssert.h:70
#define SkASSERT(cond)
Definition SkAssert.h:116
static bool IsSimpleCircular(const SkRRect &rr)
Definition SkRRectPriv.h:27
static SkVector GetSimpleRadii(const SkRRect &rr)
Definition SkRRectPriv.h:22
SkVector radii(Corner corner) const
Definition SkRRect.h:271
@ kUpperLeft_Corner
index of top-left corner radii
Definition SkRRect.h:252
@ kLowerRight_Corner
index of bottom-right corner radii
Definition SkRRect.h:254
@ kUpperRight_Corner
index of top-right corner radii
Definition SkRRect.h:253
@ kLowerLeft_Corner
index of bottom-left corner radii
Definition SkRRect.h:255
const SkRect & getBounds() const
Definition SkRRect.h:279
float SkScalar
Definition extension.cpp:12
SkRRect rrect
Definition SkRecords.h:232
sk_sp< SkBlender > blender SkRect rect
Definition SkRecords.h:350
float fX
x-axis value

The documentation for this class was generated from the following file: