Flutter Engine
The Flutter Engine
Public Types | Public Member Functions | Static Public Member Functions | Static Public Attributes | List of all members
SkSL::Swizzle Class Referencefinal

#include <SkSLSwizzle.h>

Inheritance diagram for SkSL::Swizzle:
SkSL::Expression SkSL::IRNode SkSL::Poolable

Public Types

using Component = SwizzleComponent::Type
 
- Public Types inherited from SkSL::Expression
enum class  ComparisonResult { kUnknown = -1 , kNotEqual , kEqual }
 
using Kind = ExpressionKind
 

Public Member Functions

 Swizzle (const Context &context, Position pos, std::unique_ptr< Expression > base, const ComponentArray &components)
 
std::unique_ptr< Expression > & base ()
 
const std::unique_ptr< Expression > & base () const
 
const ComponentArraycomponents () const
 
std::unique_ptr< Expressionclone (Position pos) const override
 
std::string description (OperatorPrecedence) const override
 
- Public Member Functions inherited from SkSL::Expression
 Expression (Position pos, Kind kind, const Type *type)
 
Kind kind () const
 
const Typetype () const
 
bool isAnyConstructor () const
 
bool isIntLiteral () const
 
bool isFloatLiteral () const
 
bool isBoolLiteral () const
 
AnyConstructorasAnyConstructor ()
 
const AnyConstructorasAnyConstructor () const
 
bool isIncomplete (const Context &context) const
 
virtual ComparisonResult compareConstant (const Expression &other) const
 
CoercionCost coercionCost (const Type &target) const
 
virtual bool supportsConstantValues () const
 
virtual std::optional< double > getConstantValue (int n) const
 
virtual std::unique_ptr< Expressionclone (Position pos) const =0
 
std::unique_ptr< Expressionclone () const
 
std::string description () const final
 
virtual std::string description (OperatorPrecedence parentPrecedence) const =0
 
- Public Member Functions inherited from SkSL::IRNode
virtual ~IRNode ()
 
virtual std::string description () const =0
 
 IRNode (const IRNode &)=delete
 
IRNodeoperator= (const IRNode &)=delete
 
Position position () const
 
void setPosition (Position p)
 
template<typename T >
bool is () const
 
template<typename T >
const Tas () const
 
template<typename T >
Tas ()
 

Static Public Member Functions

static std::unique_ptr< ExpressionConvert (const Context &context, Position pos, Position maskPos, std::unique_ptr< Expression > base, std::string_view componentString)
 
static std::unique_ptr< ExpressionMake (const Context &context, Position pos, std::unique_ptr< Expression > expr, ComponentArray inComponents)
 
static std::string MaskString (const ComponentArray &inComponents)
 
static bool IsIdentity (const ComponentArray &components)
 
- Static Public Member Functions inherited from SkSL::Poolable
static void * operator new (const size_t size)
 
static void operator delete (void *ptr)
 

Static Public Attributes

static constexpr Kind kIRNodeKind = Kind::kSwizzle
 

Additional Inherited Members

- Public Attributes inherited from SkSL::IRNode
Position fPosition
 
- Protected Member Functions inherited from SkSL::IRNode
 IRNode (Position position, int kind)
 
- Protected Attributes inherited from SkSL::IRNode
int fKind
 

Detailed Description

Represents a vector swizzle operation such as 'float3(1, 2, 3).zyx'.

Definition at line 51 of file SkSLSwizzle.h.

Member Typedef Documentation

◆ Component

Definition at line 55 of file SkSLSwizzle.h.

Constructor & Destructor Documentation

◆ Swizzle()

SkSL::Swizzle::Swizzle ( const Context context,
Position  pos,
std::unique_ptr< Expression base,
const ComponentArray components 
)
inline

Definition at line 57 of file SkSLSwizzle.h.

59 : INHERITED(pos, kIRNodeKind,
60 &base->type().componentType().toCompound(context, components.size(), 1))
61 , fBase(std::move(base))
62 , fComponents(components) {
63 SkASSERT(this->components().size() >= 1 && this->components().size() <= 4);
64 }
SkPoint pos
#define SkASSERT(cond)
Definition: SkAssert.h:116
static constexpr Kind kIRNodeKind
Definition: SkSLSwizzle.h:53
const ComponentArray & components() const
Definition: SkSLSwizzle.h:90
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259

Member Function Documentation

◆ base() [1/2]

std::unique_ptr< Expression > & SkSL::Swizzle::base ( )
inline

Definition at line 82 of file SkSLSwizzle.h.

82 {
83 return fBase;
84 }

◆ base() [2/2]

const std::unique_ptr< Expression > & SkSL::Swizzle::base ( ) const
inline

Definition at line 86 of file SkSLSwizzle.h.

86 {
87 return fBase;
88 }

◆ clone()

std::unique_ptr< Expression > SkSL::Swizzle::clone ( Position  pos) const
inlineoverridevirtual

Implements SkSL::Expression.

Definition at line 94 of file SkSLSwizzle.h.

94 {
95 return std::unique_ptr<Expression>(new Swizzle(pos, &this->type(), this->base()->clone(),
96 this->components()));
97 }
std::unique_ptr< Expression > clone() const
const Type & type() const
Swizzle(const Context &context, Position pos, std::unique_ptr< Expression > base, const ComponentArray &components)
Definition: SkSLSwizzle.h:57
std::unique_ptr< Expression > & base()
Definition: SkSLSwizzle.h:82

◆ components()

const ComponentArray & SkSL::Swizzle::components ( ) const
inline

Definition at line 90 of file SkSLSwizzle.h.

90 {
91 return fComponents;
92 }

◆ Convert()

std::unique_ptr< Expression > SkSL::Swizzle::Convert ( const Context context,
Position  pos,
Position  maskPos,
std::unique_ptr< Expression base,
std::string_view  componentString 
)
static

Definition at line 246 of file SkSLSwizzle.cpp.

250 {
251 if (componentString.size() > 4) {
252 context.fErrors->error(Position::Range(maskPos.startOffset() + 4,
253 maskPos.endOffset()),
254 "too many components in swizzle mask");
255 return nullptr;
256 }
257
258 // Convert the component string into an equivalent array.
260 for (size_t i = 0; i < componentString.length(); ++i) {
261 char field = componentString[i];
262 switch (field) {
265 case 'x': components.push_back(SwizzleComponent::X); break;
266 case 'r': components.push_back(SwizzleComponent::R); break;
267 case 's': components.push_back(SwizzleComponent::S); break;
268 case 'L': components.push_back(SwizzleComponent::UL); break;
269 case 'y': components.push_back(SwizzleComponent::Y); break;
270 case 'g': components.push_back(SwizzleComponent::G); break;
271 case 't': components.push_back(SwizzleComponent::T); break;
272 case 'T': components.push_back(SwizzleComponent::UT); break;
273 case 'z': components.push_back(SwizzleComponent::Z); break;
274 case 'b': components.push_back(SwizzleComponent::B); break;
275 case 'p': components.push_back(SwizzleComponent::P); break;
276 case 'R': components.push_back(SwizzleComponent::UR); break;
277 case 'w': components.push_back(SwizzleComponent::W); break;
278 case 'a': components.push_back(SwizzleComponent::A); break;
279 case 'q': components.push_back(SwizzleComponent::Q); break;
280 case 'B': components.push_back(SwizzleComponent::UB); break;
281 default:
282 context.fErrors->error(Position::Range(maskPos.startOffset() + i,
283 maskPos.startOffset() + i + 1),
284 String::printf("invalid swizzle component '%c'", field));
285 return nullptr;
286 }
287 }
288
290 context.fErrors->error(maskPos, "invalid swizzle mask '" + MaskString(components) + "'");
291 return nullptr;
292 }
293
294 const Type& baseType = base->type().scalarTypeForLiteral();
295
296 if (!baseType.isVector() && !baseType.isScalar()) {
297 context.fErrors->error(pos, "cannot swizzle value of type '" +
298 baseType.displayName() + "'");
299 return nullptr;
300 }
301
302 ComponentArray maskComponents;
303 bool foundXYZW = false;
304 for (int i = 0; i < components.size(); ++i) {
305 switch (components[i]) {
308 // Skip over constant fields for now.
309 break;
314 foundXYZW = true;
315 maskComponents.push_back(SwizzleComponent::X);
316 break;
321 foundXYZW = true;
322 if (baseType.columns() >= 2) {
323 maskComponents.push_back(SwizzleComponent::Y);
324 break;
325 }
326 [[fallthrough]];
331 foundXYZW = true;
332 if (baseType.columns() >= 3) {
333 maskComponents.push_back(SwizzleComponent::Z);
334 break;
335 }
336 [[fallthrough]];
341 foundXYZW = true;
342 if (baseType.columns() >= 4) {
343 maskComponents.push_back(SwizzleComponent::W);
344 break;
345 }
346 [[fallthrough]];
347 default:
348 // The swizzle component references a field that doesn't exist in the base type.
349 context.fErrors->error(Position::Range(maskPos.startOffset() + i,
350 maskPos.startOffset() + i + 1),
351 String::printf("invalid swizzle component '%c'",
353 return nullptr;
354 }
355 }
356
357 if (!foundXYZW) {
358 context.fErrors->error(maskPos, "swizzle must refer to base expression");
359 return nullptr;
360 }
361
362 // Coerce literals in expressions such as `(12345).xxx` to their actual type.
363 base = baseType.coerceExpression(std::move(base), context);
364 if (!base) {
365 return nullptr;
366 }
367
368 // Swizzles are complicated due to constant components. The most difficult case is a mask like
369 // '.x1w0'. A naive approach might turn that into 'float4(base.x, 1, base.w, 0)', but that
370 // evaluates 'base' twice. We instead group the swizzle mask ('xw') and constants ('1, 0')
371 // together and use a secondary swizzle to put them back into the right order, so in this case
372 // we end up with 'float4(base.xw, 1, 0).xzyw'.
373 //
374 // First, we need a vector expression that is the non-constant portion of the swizzle, packed:
375 // scalar.xxx -> type3(scalar)
376 // scalar.x0x0 -> type2(scalar)
377 // vector.zyx -> vector.zyx
378 // vector.x0y0 -> vector.xy
379 std::unique_ptr<Expression> expr = Swizzle::Make(context, pos, std::move(base), maskComponents);
380
381 // If we have processed the entire swizzle, we're done.
382 if (maskComponents.size() == components.size()) {
383 return expr;
384 }
385
386 // Now we create a constructor that has the correct number of elements for the final swizzle,
387 // with all fields at the start. It's not finished yet; constants we need will be added below.
388 // scalar.x0x0 -> type4(type2(x), ...)
389 // vector.y111 -> type4(vector.y, ...)
390 // vector.z10x -> type4(vector.zx, ...)
391 //
392 // The constructor will have at most three arguments: { base expr, constant 0, constant 1 }
393 ExpressionArray constructorArgs;
394 constructorArgs.reserve_exact(3);
395 constructorArgs.push_back(std::move(expr));
396
397 // Apply another swizzle to shuffle the constants into the correct place. Any constant values we
398 // need are also tacked on to the end of the constructor.
399 // scalar.x0x0 -> type4(type2(x), 0).xyxy
400 // vector.y111 -> type2(vector.y, 1).xyyy
401 // vector.z10x -> type4(vector.zx, 1, 0).xzwy
402 const Type* scalarType = &baseType.componentType();
403 ComponentArray swizzleComponents;
404 int maskFieldIdx = 0;
405 int constantFieldIdx = maskComponents.size();
406 int constantZeroIdx = -1, constantOneIdx = -1;
407
408 for (int i = 0; i < components.size(); i++) {
409 switch (components[i]) {
411 if (constantZeroIdx == -1) {
412 // Synthesize a '0' argument at the end of the constructor.
413 constructorArgs.push_back(Literal::Make(pos, /*value=*/0, scalarType));
414 constantZeroIdx = constantFieldIdx++;
415 }
416 swizzleComponents.push_back(constantZeroIdx);
417 break;
419 if (constantOneIdx == -1) {
420 // Synthesize a '1' argument at the end of the constructor.
421 constructorArgs.push_back(Literal::Make(pos, /*value=*/1, scalarType));
422 constantOneIdx = constantFieldIdx++;
423 }
424 swizzleComponents.push_back(constantOneIdx);
425 break;
426 default:
427 // The non-constant fields are already in the expected order.
428 swizzleComponents.push_back(maskFieldIdx++);
429 break;
430 }
431 }
432
433 expr = ConstructorCompound::Make(context, pos,
434 scalarType->toCompound(context, constantFieldIdx, /*rows=*/1),
435 std::move(constructorArgs));
436
437 // Create (and potentially optimize-away) the resulting swizzle-expression.
438 return Swizzle::Make(context, pos, std::move(expr), swizzleComponents);
439}
static std::unique_ptr< Expression > Make(const Context &context, Position pos, const Type &type, ExpressionArray args)
static std::unique_ptr< Literal > Make(Position pos, double value, const Type *type)
Definition: SkSLLiteral.h:81
static Position Range(int startOffset, int endOffset)
Definition: SkSLPosition.h:24
static std::unique_ptr< Expression > Make(const Context &context, Position pos, std::unique_ptr< Expression > expr, ComponentArray inComponents)
static std::string MaskString(const ComponentArray &inComponents)
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: SkSLString.cpp:83
static bool validate_swizzle_domain(const ComponentArray &fields)
Definition: SkSLSwizzle.cpp:34
static char mask_char(int8_t component)
Definition: SkSLSwizzle.cpp:88
skia_private::FixedArray< 4, int8_t > ComponentArray
Definition: SkSLSwizzle.h:46

◆ description()

std::string SkSL::Swizzle::description ( OperatorPrecedence  ) const
overridevirtual

Implements SkSL::Expression.

Definition at line 533 of file SkSLSwizzle.cpp.

533 {
534 return this->base()->description(OperatorPrecedence::kPostfix) + "." +
535 MaskString(this->components());
536}

◆ IsIdentity()

bool SkSL::Swizzle::IsIdentity ( const ComponentArray components)
static

Definition at line 441 of file SkSLSwizzle.cpp.

441 {
442 for (int index = 0; index < components.size(); ++index) {
443 if (components[index] != index) {
444 return false;
445 }
446 }
447 return true;
448}

◆ Make()

std::unique_ptr< Expression > SkSL::Swizzle::Make ( const Context context,
Position  pos,
std::unique_ptr< Expression expr,
ComponentArray  inComponents 
)
static

Definition at line 450 of file SkSLSwizzle.cpp.

453 {
454 const Type& exprType = expr->type();
455 SkASSERTF(exprType.isVector() || exprType.isScalar(),
456 "cannot swizzle type '%s'", exprType.description().c_str());
457 SkASSERT(components.size() >= 1 && components.size() <= 4);
458
459 // Confirm that the component array only contains X/Y/Z/W. (Call MakeWith01 if you want support
460 // for ZERO and ONE. Once initial IR generation is complete, no swizzles should have zeros or
461 // ones in them.)
462 SkASSERT(std::all_of(components.begin(), components.end(), [](int8_t component) {
463 return component >= SwizzleComponent::X &&
464 component <= SwizzleComponent::W;
465 }));
466
467 // SkSL supports splatting a scalar via `scalar.xxxx`, but not all versions of GLSL allow this.
468 // Replace swizzles with equivalent splat constructors (`scalar.xxx` --> `half3(value)`).
469 if (exprType.isScalar()) {
470 return ConstructorSplat::Make(context, pos,
471 exprType.toCompound(context, components.size(), /*rows=*/1),
472 std::move(expr));
473 }
474
475 // Detect identity swizzles like `color.rgba` and optimize them away.
476 if (components.size() == exprType.columns() && IsIdentity(components)) {
477 expr->fPosition = pos;
478 return expr;
479 }
480
481 // Optimize swizzles of swizzles, e.g. replace `foo.argb.rggg` with `foo.arrr`.
482 if (expr->is<Swizzle>()) {
483 Swizzle& base = expr->as<Swizzle>();
484 ComponentArray combined;
485 for (int8_t c : components) {
486 combined.push_back(base.components()[c]);
487 }
488
489 // It may actually be possible to further simplify this swizzle. Go again.
490 // (e.g. `color.abgr.abgr` --> `color.rgba` --> `color`.)
491 return Swizzle::Make(context, pos, std::move(base.base()), combined);
492 }
493
494 // If we are swizzling a constant expression, we can use its value instead here (so that
495 // swizzles like `colorWhite.x` can be simplified to `1`).
497
498 // `half4(scalar).zyy` can be optimized to `half3(scalar)`, and `half3(scalar).y` can be
499 // optimized to just `scalar`. The swizzle components don't actually matter, as every field
500 // in a splat constructor holds the same value.
501 if (value->is<ConstructorSplat>()) {
502 const ConstructorSplat& splat = value->as<ConstructorSplat>();
504 context, pos,
505 splat.type().componentType().toCompound(context, components.size(), /*rows=*/1),
506 splat.argument()->clone());
507 }
508
509 // Swizzles on casts, like `half4(myFloat4).zyy`, can optimize to `half3(myFloat4.zyy)`.
510 if (value->is<ConstructorCompoundCast>()) {
511 const ConstructorCompoundCast& cast = value->as<ConstructorCompoundCast>();
512 const Type& castType = cast.type().componentType().toCompound(context, components.size(),
513 /*rows=*/1);
514 std::unique_ptr<Expression> swizzled = Swizzle::Make(context, pos, cast.argument()->clone(),
515 std::move(components));
516 return (castType.columns() > 1)
517 ? ConstructorCompoundCast::Make(context, pos, castType, std::move(swizzled))
518 : ConstructorScalarCast::Make(context, pos, castType, std::move(swizzled));
519 }
520
521 // Swizzles on compound constructors, like `half4(1, 2, 3, 4).yw`, can become `half2(2, 4)`.
522 if (value->is<ConstructorCompound>()) {
523 const ConstructorCompound& ctor = value->as<ConstructorCompound>();
524 if (auto replacement = optimize_constructor_swizzle(context, pos, ctor, components)) {
525 return replacement;
526 }
527 }
528
529 // The swizzle could not be simplified, so apply the requested swizzle to the base expression.
530 return std::make_unique<Swizzle>(context, pos, std::move(expr), components);
531}
#define SkASSERTF(cond, fmt,...)
Definition: SkAssert.h:117
SI D cast(const S &v)
static const Expression * GetConstantValueForVariable(const Expression &value)
static std::unique_ptr< Expression > Make(const Context &context, Position pos, const Type &type, std::unique_ptr< Expression > arg)
static std::unique_ptr< Expression > Make(const Context &context, Position pos, const Type &type, std::unique_ptr< Expression > arg)
Expression(Position pos, Kind kind, const Type *type)
static bool IsIdentity(const ComponentArray &components)
uint8_t value
static std::unique_ptr< Expression > optimize_constructor_swizzle(const Context &context, Position pos, const ConstructorCompound &base, ComponentArray components)
Definition: ref_ptr.h:256

◆ MaskString()

std::string SkSL::Swizzle::MaskString ( const ComponentArray inComponents)
static

Definition at line 112 of file SkSLSwizzle.cpp.

112 {
113 std::string result;
114 for (int8_t component : components) {
115 result += mask_char(component);
116 }
117 return result;
118}
GAsyncResult * result

Member Data Documentation

◆ kIRNodeKind

constexpr Kind SkSL::Swizzle::kIRNodeKind = Kind::kSwizzle
inlinestaticconstexpr

Definition at line 53 of file SkSLSwizzle.h.


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