Flutter Engine
The Flutter Engine
Classes | Macros | Typedefs | Functions
SkRuntimeEffectTest.cpp File Reference
#include "include/core/SkAlphaType.h"
#include "include/core/SkBlendMode.h"
#include "include/core/SkBlender.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkCapabilities.h"
#include "include/core/SkColor.h"
#include "include/core/SkColorFilter.h"
#include "include/core/SkColorType.h"
#include "include/core/SkData.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPixmap.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkShader.h"
#include "include/core/SkSize.h"
#include "include/core/SkSpan.h"
#include "include/core/SkStream.h"
#include "include/core/SkString.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTypes.h"
#include "include/effects/SkBlenders.h"
#include "include/effects/SkGradientShader.h"
#include "include/effects/SkRuntimeEffect.h"
#include "include/gpu/GpuTypes.h"
#include "include/gpu/GrDirectContext.h"
#include "include/gpu/ganesh/SkSurfaceGanesh.h"
#include "include/private/SkColorData.h"
#include "include/private/SkSLSampleUsage.h"
#include "include/private/base/SkTArray.h"
#include "include/sksl/SkSLDebugTrace.h"
#include "include/sksl/SkSLVersion.h"
#include "src/base/SkStringView.h"
#include "src/base/SkTLazy.h"
#include "src/core/SkColorSpacePriv.h"
#include "src/core/SkRuntimeEffectPriv.h"
#include "src/gpu/KeyBuilder.h"
#include "src/gpu/SkBackingFit.h"
#include "src/gpu/ganesh/GrCaps.h"
#include "src/gpu/ganesh/GrColor.h"
#include "src/gpu/ganesh/GrDirectContextPriv.h"
#include "src/gpu/ganesh/GrFragmentProcessor.h"
#include "src/gpu/ganesh/GrImageInfo.h"
#include "src/gpu/ganesh/GrPixmap.h"
#include "src/gpu/ganesh/SurfaceFillContext.h"
#include "src/gpu/ganesh/effects/GrSkSLFP.h"
#include "src/sksl/SkSLString.h"
#include "tests/CtsEnforcement.h"
#include "tests/Test.h"
#include <array>
#include <cstdint>
#include <functional>
#include <initializer_list>
#include <memory>
#include <string>
#include <thread>
#include <utility>

Go to the source code of this file.

Classes

struct  GraphiteInfo
 
class  TestEffect
 
class  TestBlend
 

Macros

#define EMPTY_MAIN   "half4 main(float2 p) { return half4(0); }"
 

Typedefs

using PreTestFn = std::function< void(SkCanvas *, SkPaint *)>
 

Functions

void test_invalid_effect (skiatest::Reporter *r, const char *src, const char *expected)
 
 DEF_TEST (SkRuntimeEffectInvalid_NoInVariables, r)
 
 DEF_TEST (SkRuntimeEffectInvalid_UndefinedFunction, r)
 
 DEF_TEST (SkRuntimeEffectInvalid_UndefinedMain, r)
 
 DEF_TEST (SkRuntimeEffectInvalid_SkCapsDisallowed, r)
 
 DEF_TEST (SkRuntimeEffect_DeadCodeEliminationStackOverflow, r)
 
 DEF_TEST (SkRuntimeEffectCanDisableES2Restrictions, r)
 
 DEF_TEST (SkRuntimeEffectCanEnableVersion300, r)
 
 DEF_TEST (SkRuntimeEffectUniformFlags, r)
 
 DEF_TEST (SkRuntimeEffectValidation, r)
 
 DEF_TEST (SkRuntimeEffectForColorFilter, r)
 
 DEF_TEST (SkRuntimeEffectForBlender, r)
 
 DEF_TEST (SkRuntimeEffectForShader, r)
 
void paint_canvas (SkCanvas *canvas, SkPaint *paint, const PreTestFn &preTestCallback)
 
static bool read_pixels (SkSurface *surface, GrColor *pixels)
 
static void verify_2x2_surface_results (skiatest::Reporter *r, const SkRuntimeEffect *effect, SkSurface *surface, std::array< GrColor, 4 > expected)
 
static sk_sp< SkSurfacemake_surface (GrRecordingContext *grContext, const GraphiteInfo *graphite, SkISize size)
 
static sk_sp< SkShadermake_RGBW_shader ()
 
static void test_RuntimeEffect_Shaders (skiatest::Reporter *r, GrRecordingContext *grContext, const GraphiteInfo *graphite)
 
 DEF_TEST (SkRuntimeEffectSimple, r)
 
 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS (SkRuntimeEffectSimple_GPU, r, ctxInfo, CtsEnforcement::kApiLevel_T)
 
static void verify_draw_obeys_capabilities (skiatest::Reporter *r, const SkRuntimeEffect *effect, SkSurface *surface, const SkPaint &paint)
 
static void test_RuntimeEffectObeysCapabilities (skiatest::Reporter *r, SkSurface *surface)
 
 DEF_TEST (SkRuntimeEffectObeysCapabilities_CPU, r)
 
 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS (SkRuntimeEffectObeysCapabilities_GPU, r, ctxInfo, CtsEnforcement::kApiLevel_U)
 
 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS (SkRuntimeColorFilterReturningInvalidAlpha_GPU, r, ctxInfo, CtsEnforcement::kNever)
 
 DEF_TEST (SkRuntimeColorFilterLimitedToES2, r)
 
 DEF_TEST (SkRuntimeEffectTraceShader, r)
 
 DEF_TEST (SkRuntimeEffectTracesAreUnoptimized, r)
 
 DEF_TEST (SkRuntimeEffectTraceCodeThatCannotBeUnoptimized, r)
 
static void test_RuntimeEffect_Blenders (skiatest::Reporter *r, GrRecordingContext *grContext, const GraphiteInfo *graphite)
 
 DEF_TEST (SkRuntimeEffect_Blender_CPU, r)
 
 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS (SkRuntimeEffect_Blender_GPU, r, ctxInfo, CtsEnforcement::kApiLevel_T)
 
 DEF_TEST (SkRuntimeShaderBuilderReuse, r)
 
 DEF_TEST (SkRuntimeBlendBuilderReuse, r)
 
 DEF_TEST (SkRuntimeShaderBuilderSetUniforms, r)
 
 DEF_TEST (SkRuntimeEffectThreaded, r)
 
 DEF_TEST (SkRuntimeEffectAllowsPrivateAccess, r)
 
 DEF_TEST (SkRuntimeColorFilterSingleColor, r)
 
static void test_RuntimeEffectStructNameReuse (skiatest::Reporter *r, GrRecordingContext *rContext)
 
 DEF_TEST (SkRuntimeStructNameReuse, r)
 
 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS (SkRuntimeStructNameReuse_GPU, r, ctxInfo, CtsEnforcement::kApiLevel_T)
 
 DEF_TEST (SkRuntimeColorFilterFlags, r)
 
 DEF_TEST (SkRuntimeShaderSampleCoords, r)
 
 DEF_TEST (SkRuntimeShaderIsOpaque, r)
 
 DEF_GANESH_TEST_FOR_ALL_CONTEXTS (GrSkSLFP_Specialized, r, ctxInfo, CtsEnforcement::kApiLevel_T)
 
 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS (GrSkSLFP_UniformArray, r, ctxInfo, CtsEnforcement::kApiLevel_T)
 

Macro Definition Documentation

◆ EMPTY_MAIN

#define EMPTY_MAIN   "half4 main(float2 p) { return half4(0); }"

Definition at line 99 of file SkRuntimeEffectTest.cpp.

Typedef Documentation

◆ PreTestFn

Definition at line 387 of file SkRuntimeEffectTest.cpp.

Function Documentation

◆ DEF_GANESH_TEST_FOR_ALL_CONTEXTS()

DEF_GANESH_TEST_FOR_ALL_CONTEXTS ( GrSkSLFP_Specialized  ,
,
ctxInfo  ,
CtsEnforcement::kApiLevel_T   
)

Definition at line 1539 of file SkRuntimeEffectTest.cpp.

1550 { return uZeros; } else { return cZeros.eval(xy).rgb1; }", false);
1551 test("if (xy.x < 100) { return uZeros.rgb1; } else { return cZeros.eval(xy); }", false);
1552
1553 // There should (must) not be any false-positive cases. There are false-negatives.
1554 // In these cases, our optimization would be valid, but does not happen:
1555
1556 // More complex expressions that can't be simplified
1557 test("return xy.x < 100 ? uZeros.rgb1 : cZeros.eval(xy).rgb1;", false);
1558
1559 // Finally, there are cases that are conditional on the uniforms and children. These *could*
1560 // determine dynamically if the uniform and/or child being referenced is opaque, and use that
1561 // information. Today, we don't do this, so we pessimistically assume they're transparent:
1562 test("return uOnes;", false);
1563 test("return cOnes.eval(xy);", false);
1564}
1565
1566DEF_GANESH_TEST_FOR_ALL_CONTEXTS(GrSkSLFP_Specialized, r, ctxInfo, CtsEnforcement::kApiLevel_T) {
1567 struct FpAndKey {
1568 std::unique_ptr<GrFragmentProcessor> fp;
1569 TArray<uint32_t, true> key;
1570 };
1571
1572 // Constant color, but with an 'specialize' option that decides if the color is inserted in the
1573 // SkSL as a literal, or left as a uniform

◆ DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS() [1/6]

DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS ( GrSkSLFP_UniformArray  ,
,
ctxInfo  ,
CtsEnforcement::kApiLevel_T   
)

Definition at line 1575 of file SkRuntimeEffectTest.cpp.

1577 { return color; }"
1578 );
1579 FpAndKey result;
1580 result.fp = GrSkSLFP::Make(effect, "color_fp", /*inputFP=*/nullptr,
1581 GrSkSLFP::OptFlags::kNone,
1582 "color", GrSkSLFP::SpecializeIf(specialize, color));
1583 skgpu::KeyBuilder builder(&result.key);
1584 result.fp->addToKey(*ctxInfo.directContext()->priv().caps()->shaderCaps(), &builder);
1585 builder.flush();
1586 return result;
1587 };
1588
1589 FpAndKey uRed = make_color_fp({1, 0, 0, 1}, false),
1590 uGreen = make_color_fp({0, 1, 0, 1}, false),
1591 sRed = make_color_fp({1, 0, 0, 1}, true),
1592 sGreen = make_color_fp({0, 1, 0, 1}, true);
1593
1594 // uRed and uGreen should have the same key - they just have different uniforms
1595 SkASSERT(uRed.key == uGreen.key);
1596 // sRed and sGreen should have keys that are different from the uniform case, and each other
1597 SkASSERT(sRed.key != uRed.key);
1598 SkASSERT(sGreen.key != uRed.key);
1599 SkASSERT(sRed.key != sGreen.key);
1600}
1601
1602DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(GrSkSLFP_UniformArray,
1603 r,
1604 ctxInfo,
1605 CtsEnforcement::kApiLevel_T) {
1606 // Make a fill-context to draw into.
1607 GrDirectContext* directContext = ctxInfo.directContext();
1608 SkImageInfo info = SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
1609 std::unique_ptr<skgpu::ganesh::SurfaceFillContext> testCtx =
1610 directContext->priv().makeSFC(info, /*label=*/{}, SkBackingFit::kExact);
1611
1612 // Make an effect that takes a uniform array as input.
1613 static constexpr std::array<float, 4> kRed {1.0f, 0.0f, 0.0f, 1.0f};
1614 static constexpr std::array<float, 4> kGreen{0.0f, 1.0f, 0.0f, 1.0f};
1615 static constexpr std::array<float, 4> kBlue {0.0f, 0.0f, 1.0f, 1.0f};
1616 static constexpr std::array<float, 4> kGray {0.499f, 0.499f, 0.499f, 1.0f};
1617
1618 for (const auto& colorArray : {kRed, kGreen, kBlue, kGray}) {
1619 // Compile our runtime effect.
1620 static const SkRuntimeEffect* effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader,
DlColor color

◆ DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS() [2/6]

DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS ( SkRuntimeColorFilterReturningInvalidAlpha_GPU  ,
,
ctxInfo  ,
CtsEnforcement::kNever   
)

Definition at line 852 of file SkRuntimeEffectTest.cpp.

855 {
858 SkSurfaces::RenderTarget(ctxInfo.directContext(), skgpu::Budgeted::kNo, info);
860
862 half4 main(half4 color) { return half4(2); }
863 )")).effect;
864 REPORTER_ASSERT(r, effect);
866 paint.setColorFilter(effect->makeColorFilter(/*uniforms=*/nullptr));
867 REPORTER_ASSERT(r, paint.getColorFilter());
868 surface->getCanvas()->drawPaint(paint);
869}
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
static Result MakeForColorFilter(SkString sksl, const Options &)
const Paint & paint
Definition: color_source.cc:38
VkSurfaceKHR surface
Definition: main.cc:49
SK_API sk_sp< SkSurface > RenderTarget(GrRecordingContext *context, skgpu::Budgeted budgeted, const SkImageInfo &imageInfo, int sampleCount, GrSurfaceOrigin surfaceOrigin, const SkSurfaceProps *surfaceProps, bool shouldCreateWithMips=false, bool isProtected=false)
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
sk_sp< SkRuntimeEffect > effect

◆ DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS() [3/6]

DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS ( SkRuntimeEffect_Blender_GPU  ,
,
ctxInfo  ,
CtsEnforcement::kApiLevel_T   
)

Definition at line 1147 of file SkRuntimeEffectTest.cpp.

1149 { return child.eval(half4(1)); }");
1150 effect.child("child") = SkColorFilters::Blend(0xFF012345, SkBlendMode::kSrc);
1151 effect.test(0xFF452301);
1152
Vec< 4, uint16_t > half4
Definition: SkVx.h:1176

◆ DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS() [4/6]

DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS ( SkRuntimeEffectObeysCapabilities_GPU  ,
,
ctxInfo  ,
CtsEnforcement::kApiLevel_U   
)

Definition at line 841 of file SkRuntimeEffectTest.cpp.

844 {
847 SkSurfaces::RenderTarget(ctxInfo.directContext(), skgpu::Budgeted::kNo, info);
850}
static void test_RuntimeEffectObeysCapabilities(skiatest::Reporter *r, SkSurface *surface)

◆ DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS() [5/6]

DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS ( SkRuntimeEffectSimple_GPU  ,
,
ctxInfo  ,
CtsEnforcement::kApiLevel_T   
)

Definition at line 728 of file SkRuntimeEffectTest.cpp.

731 {
732 test_RuntimeEffect_Shaders(r, ctxInfo.directContext(), /*graphite=*/nullptr);
733}
static void test_RuntimeEffect_Shaders(skiatest::Reporter *r, GrRecordingContext *grContext, const GraphiteInfo *graphite)

◆ DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS() [6/6]

DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS ( SkRuntimeStructNameReuse_GPU  ,
,
ctxInfo  ,
CtsEnforcement::kApiLevel_T   
)

Definition at line 1328 of file SkRuntimeEffectTest.cpp.

1329 { half4 rgba; };"
1330 "void process(inout S s) { s.rgba.rgb *= 0.5; }"
1331 "half4 main(float2 p) { S s; s.rgba = paint.eval(p); process(s); return s.rgba; }"
1332 ));
1333 REPORTER_ASSERT(r, childEffect, "%s\n", err.c_str());
static const uint32_t rgba[kNumPixels]
int main(int argc, char **argv)
Definition: benchmarking.cc:29
struct MyStruct s
static void process(const char *inPath, const char *lexer, const char *token, const char *hPath, const char *cppPath)
Definition: Main.cpp:114
Definition: SkVx.h:83

◆ DEF_TEST() [1/29]

DEF_TEST ( SkRuntimeBlendBuilderReuse  ,
 
)

Definition at line 1172 of file SkRuntimeEffectTest.cpp.

1177 {
1178 test_RuntimeEffect_Blenders(r, ctxInfo.directContext(), /*graphite=*/nullptr);
1179}
1180
1181DEF_TEST(SkRuntimeShaderBuilderReuse, r) {
1182 const char* kSource = R"(
1183 uniform half x;
1184 half4 main(float2 p) { return half4(x); }
1185 )";
1186
static void test_RuntimeEffect_Blenders(skiatest::Reporter *r, GrRecordingContext *grContext, const GraphiteInfo *graphite)
DEF_TEST(SkRuntimeEffectInvalid_NoInVariables, r)
static Result MakeForShader(SkString sksl, const Options &)

◆ DEF_TEST() [2/29]

DEF_TEST ( SkRuntimeColorFilterFlags  ,
 
)

Definition at line 1335 of file SkRuntimeEffectTest.cpp.

1343 { float2 coord; };"
1344 "void process(inout S s) { s.coord = s.coord.yx; }"
1345 "half4 main(float2 p) { S s; s.coord = p; process(s); return child.eval(s.coord); "
1346 "}");
1347 effect.child("child") = child;
1348 effect.test(kExpected, [](SkCanvas*, SkPaint* paint) {});
1349}
1350
1351DEF_TEST(SkRuntimeStructNameReuse, r) {
1352 test_RuntimeEffectStructNameReuse(r, nullptr);
1353}
1354
1355DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(SkRuntimeStructNameReuse_GPU,
1356 r,
1357 ctxInfo,
1358 CtsEnforcement::kApiLevel_T) {
1359 test_RuntimeEffectStructNameReuse(r, ctxInfo.directContext());
1360}
1361
1362DEF_TEST(SkRuntimeColorFilterFlags, r) {
1363 auto expectAlphaUnchanged = [&](const char* shader) {
1364 auto [effect, err] = SkRuntimeEffect::MakeForColorFilter(SkString{shader});
1365 REPORTER_ASSERT(r, effect && err.isEmpty(), "%s", shader);
1366 sk_sp<SkColorFilter> filter = effect->makeColorFilter(SkData::MakeEmpty());
1367 REPORTER_ASSERT(r, filter && filter->isAlphaUnchanged(), "%s", shader);
1368 };
1369
1370 auto expectAlphaChanged = [&](const char* shader) {
1371 auto [effect, err] = SkRuntimeEffect::MakeForColorFilter(SkString{shader});
1372 REPORTER_ASSERT(r, effect && err.isEmpty(), "%s", shader);
1373 sk_sp<SkColorFilter> filter = effect->makeColorFilter(SkData::MakeEmpty());
1374 REPORTER_ASSERT(r, filter && !filter->isAlphaUnchanged(), "%s", shader);
1375 };
1376
1377 // We expect these patterns to be detected as alpha-unchanged.
1378 expectAlphaUnchanged("half4 main(half4 color) { return color; }");
1379 expectAlphaUnchanged("half4 main(half4 color) { return color.aaaa; }");
1380 expectAlphaUnchanged("half4 main(half4 color) { return color.bgra; }");
1381 expectAlphaUnchanged("half4 main(half4 color) { return color.rraa; }");
1382 expectAlphaUnchanged("half4 main(half4 color) { return color.010a; }");
1383 expectAlphaUnchanged("half4 main(half4 color) { return half4(0, 0, 0, color.a); }");
1384 expectAlphaUnchanged("half4 main(half4 color) { return half4(half2(1), color.ba); }");
1385 expectAlphaUnchanged("half4 main(half4 color) { return half4(half2(1), half2(color.a)); }");
1386 expectAlphaUnchanged("half4 main(half4 color) { return half4(color.a); }");
1387 expectAlphaUnchanged("half4 main(half4 color) { return half4(float4(color.baba)); }");
1388 expectAlphaUnchanged("half4 main(half4 color) { return color.r != color.g ? color :"
1389 " color.000a; }");
1390 expectAlphaUnchanged("half4 main(half4 color) { return color.a == color.r ? color.rrra : "
1391 "color.g == color.b ? color.ggga : "
1392 " color.bbba; }");
1393 // Modifying the input color invalidates the check.
1394 expectAlphaChanged("half4 main(half4 color) { color.a = 0; return color; }");
1395
1396 // These swizzles don't end in alpha.
1397 expectAlphaChanged("half4 main(half4 color) { return color.argb; }");
1398 expectAlphaChanged("half4 main(half4 color) { return color.rrrr; }");
skvx::float4 float4
Definition: GrQuadUtils.cpp:23
struct MyStruct a[10]
Vec< 2, uint16_t > half2
Definition: SkVx.h:1175

◆ DEF_TEST() [3/29]

DEF_TEST ( SkRuntimeColorFilterLimitedToES2  ,
 
)

Definition at line 871 of file SkRuntimeEffectTest.cpp.

871 {
872 // Verify that SkSL requesting #version 300 can't be used to create a color-filter effect.
873 // This restriction could be removed if we can find a way to implement filterColor4f for these
874 // color filters.
875 {
877 #version 300
878 half4 main(half4 inColor) { return half4(1, 0, 0, 1); }
879 )")).effect;
880 REPORTER_ASSERT(r, !effect);
881 }
882
883 {
885 #version 300
886 uniform int loops;
887 half4 main(half4 inColor) {
888 half4 result = half4(1, 0, 0, 1);
889 for (int i = 0; i < loops; i++) {
890 result = result.argb;
891 }
892 return result;
893 }
894 )")).effect;
895 REPORTER_ASSERT(r, !effect);
896 }
897}

◆ DEF_TEST() [4/29]

DEF_TEST ( SkRuntimeColorFilterSingleColor  ,
 
)

Definition at line 1280 of file SkRuntimeEffectTest.cpp.

1283 {
1284 static constexpr char kColorFilter[] =
1285 "half4 main(half4 c) { return $hsl_to_rgb(c.rgb, c.a); }";
1287 SkRuntimeEffect::MakeForColorFilter(SkString(kColorFilter), defaultOptions);
1288 REPORTER_ASSERT(r, !normal.effect);
1289 SkRuntimeEffect::Result privileged =
1290 SkRuntimeEffect::MakeForColorFilter(SkString(kColorFilter), optionsWithAccess);
1291 REPORTER_ASSERT(r, privileged.effect, "%s", privileged.errorText.c_str());
1292 }
1293
1294 // Confirm that blenders can only access $private_functions when private access is allowed.
1295 {
1296 static constexpr char kBlender[] =
const char * c_str() const
Definition: SkString.h:133

◆ DEF_TEST() [5/29]

DEF_TEST ( SkRuntimeEffect_Blender_CPU  ,
 
)

Definition at line 1143 of file SkRuntimeEffectTest.cpp.

1144 {1.5, 1.5};
1145 effect.test(0xFFFFFFFF);

◆ DEF_TEST() [6/29]

DEF_TEST ( SkRuntimeEffect_DeadCodeEliminationStackOverflow  ,
 
)

Definition at line 127 of file SkRuntimeEffectTest.cpp.

127 {
128 // Verify that a deeply-nested loop does not cause stack overflow during dead-code elimination.
129 auto [effect, errorText] = SkRuntimeEffect::MakeForColorFilter(SkString(R"(
130 half4 main(half4 color) {
131 half value = color.r;
132
133 for (int a=0; a<10; ++a) { // 10
134 for (int b=0; b<10; ++b) { // 100
135 for (int c=0; c<10; ++c) { // 1000
136 for (int d=0; d<10; ++d) { // 10000
137 ++value;
138 }}}}
139
140 return value.xxxx;
141 }
142 )"));
143 REPORTER_ASSERT(r, effect, "%s", errorText.c_str());
144}

◆ DEF_TEST() [7/29]

DEF_TEST ( SkRuntimeEffectAllowsPrivateAccess  ,
 
)

Definition at line 1238 of file SkRuntimeEffectTest.cpp.

1244 {
1245 // This tests that we can safely use SkRuntimeEffect::MakeForShader from more than one thread,
1246 // and also that programs don't refer to shared structures owned by the compiler.
1247 // skbug.com/10589
1248 static constexpr char kSource[] = "half4 main(float2 p) { return sk_FragCoord.xyxy; }";
1249
1250 std::thread threads[16];
1251 for (auto& thread : threads) {
1252 thread = std::thread([r]() {
1255 auto [effect, error] = SkRuntimeEffect::MakeForShader(SkString(kSource), options);
1256 REPORTER_ASSERT(r, effect);
1257 });
1258 }
1259
1260 for (auto& thread : threads) {
1261 thread.join();
1262 }
1263}
1264
1265DEF_TEST(SkRuntimeEffectAllowsPrivateAccess, r) {
1266 SkRuntimeEffect::Options defaultOptions;
1267 SkRuntimeEffect::Options optionsWithAccess;
1268 SkRuntimeEffectPriv::AllowPrivateAccess(&optionsWithAccess);
1269
1270 // Confirm that shaders can only access $private_functions when private access is allowed.
1271 {
1272 static constexpr char kShader[] =
1273 "half4 main(float2 p) { return $hsl_to_rgb(p.xxx, p.y); }";
1275 SkRuntimeEffect::MakeForShader(SkString(kShader), defaultOptions);
1276 REPORTER_ASSERT(r, !normal.effect);
1277 SkRuntimeEffect::Result privileged =
1278 SkRuntimeEffect::MakeForShader(SkString(kShader), optionsWithAccess);
const char * options
static void AllowPrivateAccess(SkRuntimeEffect::Options *options)
const uint8_t uint32_t uint32_t GError ** error

◆ DEF_TEST() [8/29]

DEF_TEST ( SkRuntimeEffectCanDisableES2Restrictions  ,
 
)

Definition at line 146 of file SkRuntimeEffectTest.cpp.

146 {
147 auto test_valid_es3 = [](skiatest::Reporter* r, const char* sksl) {
149 auto [effect, errorText] = SkRuntimeEffect::MakeForShader(SkString(sksl), opt);
150 REPORTER_ASSERT(r, effect, "%s", errorText.c_str());
151 };
152
153 test_invalid_effect(r, "float f[2] = float[2](0, 1);" EMPTY_MAIN, "construction of array type");
154 test_valid_es3 (r, "float f[2] = float[2](0, 1);" EMPTY_MAIN);
155}
void test_invalid_effect(skiatest::Reporter *r, const char *src, const char *expected)
#define EMPTY_MAIN
static SkRuntimeEffect::Options ES3Options()

◆ DEF_TEST() [9/29]

DEF_TEST ( SkRuntimeEffectCanEnableVersion300  ,
 
)

Definition at line 157 of file SkRuntimeEffectTest.cpp.

157 {
158 auto test_valid = [](skiatest::Reporter* r, const char* sksl) {
159 auto [effect, errorText] = SkRuntimeEffect::MakeForShader(SkString(sksl));
160 REPORTER_ASSERT(r, effect, "%s", errorText.c_str());
161 };
162
163 test_invalid_effect(r, "#version 100\nfloat f[2] = float[2](0, 1);" EMPTY_MAIN,
164 "construction of array type");
165 test_valid (r, "#version 300\nfloat f[2] = float[2](0, 1);" EMPTY_MAIN);
166}

◆ DEF_TEST() [10/29]

DEF_TEST ( SkRuntimeEffectForBlender  ,
 
)

Definition at line 255 of file SkRuntimeEffectTest.cpp.

255 {
256 // Tests that the blender factory rejects or accepts certain SkSL constructs
257 auto test_valid = [r](const char* sksl) {
258 auto [effect, errorText] = SkRuntimeEffect::MakeForBlender(SkString(sksl));
259 REPORTER_ASSERT(r, effect, "%s", errorText.c_str());
260 };
261
262 auto test_invalid = [r](const char* sksl, const char* expected) {
263 auto [effect, errorText] = SkRuntimeEffect::MakeForBlender(SkString(sksl));
264 REPORTER_ASSERT(r, !effect);
266 errorText.contains(expected),
267 "Expected error message to contain \"%s\". Actual message: \"%s\"",
268 expected,
269 errorText.c_str());
270 };
271
272 // Blenders must use the 'half4 main(half4, half4)' signature. Any mixture of float4/vec4/half4
273 // is allowed.
274 test_valid("half4 main(half4 s, half4 d) { return s; }");
275 test_valid("float4 main(float4 s, float4 d) { return d; }");
276 test_valid("float4 main(half4 s, float4 d) { return s; }");
277 test_valid("half4 main(float4 s, half4 d) { return d; }");
278 test_valid("vec4 main(half4 s, half4 d) { return s; }");
279 test_valid("half4 main(vec4 s, vec4 d) { return d; }");
280 test_valid("vec4 main(vec4 s, vec4 d) { return s; }");
281
282 // Invalid return types
283 test_invalid("void main(half4 s, half4 d) {}", "'main' must return");
284 test_invalid("half3 main(half4 s, half4 d) { return s.rgb; }", "'main' must return");
285
286 // Invalid argument types (some are valid as shaders/color filters)
287 test_invalid("half4 main() { return half4(1); }", "'main' parameter");
288 test_invalid("half4 main(half4 c) { return c; }", "'main' parameter");
289 test_invalid("half4 main(float2 p) { return half4(1); }", "'main' parameter");
290 test_invalid("half4 main(float2 p, half4 c) { return c; }", "'main' parameter");
291 test_invalid("half4 main(float2 p, half4 a, half4 b) { return a; }", "'main' parameter");
292 test_invalid("half4 main(half4 a, half4 b, half4 c) { return a; }", "'main' parameter");
293
294 // sk_FragCoord should not be available
295 test_invalid("half4 main(half4 s, half4 d) { return sk_FragCoord.xy01; }",
296 "unknown identifier");
297
298 // Sampling a child shader requires that we pass explicit coords
299 test_valid("uniform shader child;"
300 "half4 main(half4 s, half4 d) { return child.eval(s.rg); }");
301
302 // Sampling a colorFilter requires a color
303 test_valid("uniform colorFilter child;"
304 "half4 main(half4 s, half4 d) { return child.eval(d); }");
305
306 // Sampling a blender requires two colors
307 test_valid("uniform blender child;"
308 "half4 main(half4 s, half4 d) { return child.eval(s, d); }");
309}
static void test_invalid(skiatest::Reporter *r, const char path[])
Definition: CodecTest.cpp:704
static Result MakeForBlender(SkString sksl, const Options &)

◆ DEF_TEST() [11/29]

DEF_TEST ( SkRuntimeEffectForColorFilter  ,
 
)

Definition at line 204 of file SkRuntimeEffectTest.cpp.

204 {
205 // Tests that the color filter factory rejects or accepts certain SkSL constructs
206 auto test_valid = [r](const char* sksl) {
207 auto [effect, errorText] = SkRuntimeEffect::MakeForColorFilter(SkString(sksl));
208 REPORTER_ASSERT(r, effect, "%s", errorText.c_str());
209 };
210
211 auto test_invalid = [r](const char* sksl, const char* expected) {
212 auto [effect, errorText] = SkRuntimeEffect::MakeForColorFilter(SkString(sksl));
213 REPORTER_ASSERT(r, !effect);
215 errorText.contains(expected),
216 "Expected error message to contain \"%s\". Actual message: \"%s\"",
217 expected,
218 errorText.c_str());
219 };
220
221 // Color filters must use the 'half4 main(half4)' signature. Either color can be float4/vec4
222 test_valid("half4 main(half4 c) { return c; }");
223 test_valid("float4 main(half4 c) { return c; }");
224 test_valid("half4 main(float4 c) { return c; }");
225 test_valid("float4 main(float4 c) { return c; }");
226 test_valid("vec4 main(half4 c) { return c; }");
227 test_valid("half4 main(vec4 c) { return c; }");
228 test_valid("vec4 main(vec4 c) { return c; }");
229
230 // Invalid return types
231 test_invalid("void main(half4 c) {}", "'main' must return");
232 test_invalid("half3 main(half4 c) { return c.rgb; }", "'main' must return");
233
234 // Invalid argument types (some are valid as shaders, but not color filters)
235 test_invalid("half4 main() { return half4(1); }", "'main' parameter");
236 test_invalid("half4 main(float2 p) { return half4(1); }", "'main' parameter");
237 test_invalid("half4 main(float2 p, half4 c) { return c; }", "'main' parameter");
238
239 // sk_FragCoord should not be available
240 test_invalid("half4 main(half4 c) { return sk_FragCoord.xy01; }", "unknown identifier");
241
242 // Sampling a child shader requires that we pass explicit coords
243 test_valid("uniform shader child;"
244 "half4 main(half4 c) { return child.eval(c.rg); }");
245
246 // Sampling a colorFilter requires a color
247 test_valid("uniform colorFilter child;"
248 "half4 main(half4 c) { return child.eval(c); }");
249
250 // Sampling a blender requires two colors
251 test_valid("uniform blender child;"
252 "half4 main(half4 c) { return child.eval(c, c); }");
253}

◆ DEF_TEST() [12/29]

DEF_TEST ( SkRuntimeEffectForShader  ,
 
)

Definition at line 311 of file SkRuntimeEffectTest.cpp.

311 {
312 // Tests that the shader factory rejects or accepts certain SkSL constructs
313 auto test_valid = [r](const char* sksl, SkRuntimeEffect::Options options = {}) {
314 auto [effect, errorText] = SkRuntimeEffect::MakeForShader(SkString(sksl), options);
315 REPORTER_ASSERT(r, effect, "%s", errorText.c_str());
316 };
317
318 auto test_invalid = [r](const char* sksl,
319 const char* expected,
321 auto [effect, errorText] = SkRuntimeEffect::MakeForShader(SkString(sksl));
322 REPORTER_ASSERT(r, !effect);
324 errorText.contains(expected),
325 "Expected error message to contain \"%s\". Actual message: \"%s\"",
326 expected,
327 errorText.c_str());
328 };
329
330 // Shaders must use the 'half4 main(float2)' signature
331 // Either color can be half4/float4/vec4, but the coords must be float2/vec2
332 test_valid("half4 main(float2 p) { return p.xyxy; }");
333 test_valid("float4 main(float2 p) { return p.xyxy; }");
334 test_valid("vec4 main(float2 p) { return p.xyxy; }");
335 test_valid("half4 main(vec2 p) { return p.xyxy; }");
336 test_valid("vec4 main(vec2 p) { return p.xyxy; }");
337
338 // The 'half4 main(float2, half4|float4)' signature is disallowed on both public and private
339 // runtime effects.
342 test_invalid("half4 main(float2 p, half4 c) { return c; }", "'main' parameter");
343 test_invalid("half4 main(float2 p, half4 c) { return c; }", "'main' parameter", options);
344
345 test_invalid("half4 main(float2 p, float4 c) { return c; }", "'main' parameter");
346 test_invalid("half4 main(float2 p, float4 c) { return c; }", "'main' parameter", options);
347
348 test_invalid("half4 main(float2 p, vec4 c) { return c; }", "'main' parameter");
349 test_invalid("half4 main(float2 p, vec4 c) { return c; }", "'main' parameter", options);
350
351 test_invalid("float4 main(float2 p, half4 c) { return c; }", "'main' parameter");
352 test_invalid("float4 main(float2 p, half4 c) { return c; }", "'main' parameter", options);
353
354 test_invalid("vec4 main(float2 p, half4 c) { return c; }", "'main' parameter");
355 test_invalid("vec4 main(float2 p, half4 c) { return c; }", "'main' parameter", options);
356
357 test_invalid("vec4 main(vec2 p, vec4 c) { return c; }", "'main' parameter");
358 test_invalid("vec4 main(vec2 p, vec4 c) { return c; }", "'main' parameter", options);
359
360 // Invalid return types
361 test_invalid("void main(float2 p) {}", "'main' must return");
362 test_invalid("half3 main(float2 p) { return p.xy1; }", "'main' must return");
363
364 // Invalid argument types (some are valid as color filters, but not shaders)
365 test_invalid("half4 main() { return half4(1); }", "'main' parameter");
366 test_invalid("half4 main(half4 c) { return c; }", "'main' parameter");
367
368 // sk_FragCoord should be available, but only if we've enabled it via Options
369 test_invalid("half4 main(float2 p) { return sk_FragCoord.xy01; }",
370 "unknown identifier 'sk_FragCoord'");
371
372 test_valid("half4 main(float2 p) { return sk_FragCoord.xy01; }", options);
373
374 // Sampling a child shader requires that we pass explicit coords
375 test_valid("uniform shader child;"
376 "half4 main(float2 p) { return child.eval(p); }");
377
378 // Sampling a colorFilter requires a color
379 test_valid("uniform colorFilter child;"
380 "half4 main(float2 p) { return child.eval(half4(1)); }");
381
382 // Sampling a blender requires two colors
383 test_valid("uniform blender child;"
384 "half4 main(float2 p) { return child.eval(half4(0.5), half4(0.6)); }");
385}

◆ DEF_TEST() [13/29]

DEF_TEST ( SkRuntimeEffectInvalid_NoInVariables  ,
 
)

Definition at line 101 of file SkRuntimeEffectTest.cpp.

101 {
102 // 'in' variables aren't allowed at all:
103 test_invalid_effect(r, "in bool b;" EMPTY_MAIN, "'in'");
104 test_invalid_effect(r, "in float f;" EMPTY_MAIN, "'in'");
105 test_invalid_effect(r, "in float2 v;" EMPTY_MAIN, "'in'");
106 test_invalid_effect(r, "in half3x3 m;" EMPTY_MAIN, "'in'");
107}

◆ DEF_TEST() [14/29]

DEF_TEST ( SkRuntimeEffectInvalid_SkCapsDisallowed  ,
 
)

Definition at line 119 of file SkRuntimeEffectTest.cpp.

119 {
120 // sk_Caps is an internal system. It should not be visible to runtime effects
122 r,
123 "half4 main(float2 p) { return sk_Caps.floatIs32Bits ? half4(1) : half4(0); }",
124 "name 'sk_Caps' is reserved");
125}

◆ DEF_TEST() [15/29]

DEF_TEST ( SkRuntimeEffectInvalid_UndefinedFunction  ,
 
)

Definition at line 109 of file SkRuntimeEffectTest.cpp.

109 {
110 test_invalid_effect(r, "half4 missing(); half4 main(float2 p) { return missing(); }",
111 "function 'half4 missing()' is not defined");
112}

◆ DEF_TEST() [16/29]

DEF_TEST ( SkRuntimeEffectInvalid_UndefinedMain  ,
 
)

Definition at line 114 of file SkRuntimeEffectTest.cpp.

114 {
115 // Shouldn't be possible to create an SkRuntimeEffect without "main"
116 test_invalid_effect(r, "", "main");
117}

◆ DEF_TEST() [17/29]

DEF_TEST ( SkRuntimeEffectObeysCapabilities_CPU  ,
 
)

Definition at line 834 of file SkRuntimeEffectTest.cpp.

834 {
839}
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)

◆ DEF_TEST() [18/29]

DEF_TEST ( SkRuntimeEffectSimple  ,
 
)

Definition at line 715 of file SkRuntimeEffectTest.cpp.

715 {
716 test_RuntimeEffect_Shaders(r, /*grContext=*/nullptr, /*graphite=*/nullptr);
717}

◆ DEF_TEST() [19/29]

DEF_TEST ( SkRuntimeEffectThreaded  ,
 
)

Definition at line 1217 of file SkRuntimeEffectTest.cpp.

1220 { return half4(x); }
1221 )";
1222
1223 sk_sp<SkRuntimeEffect> effect = SkRuntimeEffect::MakeForShader(SkString(kSource)).effect;
1224 REPORTER_ASSERT(r, effect);
1225
1226 SkRuntimeShaderBuilder b(std::move(effect));
1227
1228 // Test passes if this sequence doesn't assert.
1229 float x = 1.0f;
1230 REPORTER_ASSERT(r, b.uniform("x").set(&x, 1));
1231
1232 // add extra value to ensure that set doesn't try to use sizeof(array)
1233 float origin[] = { 2.0f, 3.0f, 4.0f };
1234 REPORTER_ASSERT(r, b.uniform("offset").set<float>(origin, 2));
1235
1236#ifndef SK_DEBUG
double x
SeparatedVector2 offset

◆ DEF_TEST() [20/29]

DEF_TEST ( SkRuntimeEffectTraceCodeThatCannotBeUnoptimized  ,
 
)

Definition at line 986 of file SkRuntimeEffectTest.cpp.

1003 :\n%.*s\n", (int)dump.size(), dump.data());
1004}
1005
1006DEF_TEST(SkRuntimeEffectTraceCodeThatCannotBeUnoptimized, r) {
1007 TestEffect effect(r, /*grContext=*/nullptr, /*graphite=*/nullptr);
1008
1009 effect.build(R"(
1010 half4 main(float2 p) {
1011 int variableThatGetsOptimizedAway = 7;
1012 if (true) {
1013 return half4(1);
1014 }
1015 // This (unreachable) path doesn't return a value.
1016 // Without optimization, SkSL thinks this code doesn't return a value on every path.
1017 }
1018 )");
1019 std::string dump = effect.trace({1, 1});
1020 static constexpr char kSkRPSlotDump[] =
1021R"($0 = p (float2 : slot 1/2, L0)

◆ DEF_TEST() [21/29]

DEF_TEST ( SkRuntimeEffectTracesAreUnoptimized  ,
 
)

Definition at line 937 of file SkRuntimeEffectTest.cpp.

941 :\n%.*s\n",
942 imageSize, imageSize, (int)dump.size(), dump.data());
943 }
944}
945
946DEF_TEST(SkRuntimeEffectTracesAreUnoptimized, r) {
947 TestEffect effect(r, /*grContext=*/nullptr, /*graphite=*/nullptr);
948
949 effect.build(R"(
950 int globalUnreferencedVar = 7;
951 half inlinableFunction() {
952 return 1;
953 }
954 half4 main(float2 p) {
955 if (true) {
956 int localUnreferencedVar = 7;
957 }
958 return inlinableFunction().xxxx;
959 }
960 )");
961 std::string dump = effect.trace({1, 1});
962 static constexpr char kSkRPSlotDump[] =
963R"($0 = p (float2 : slot 1/2, L0)
964$1 = p (float2 : slot 2/2, L0)
965$2 = globalUnreferencedVar (int, L0)
966$3 = [main].result (float4 : slot 1/4, L0)
967$4 = [main].result (float4 : slot 2/4, L0)
968$5 = [main].result (float4 : slot 3/4, L0)
969$6 = [main].result (float4 : slot 4/4, L0)
970$7 = localUnreferencedVar (int, L0)
971$8 = [inlinableFunction].result (float, L0)
973F1 = half inlinableFunction()
974)";
975 static constexpr char kExpectedTrace[] = R"(
976globalUnreferencedVar = 7
977enter half4 main(float2 p)
978 p.x = 1.5
979 p.y = 1.5
980 scope +1
981 line 7
982 scope +1
983 line 8
984 localUnreferencedVar = 7
static constexpr F F1
Definition: Transform_inl.h:28
static constexpr F F0
Definition: Transform_inl.h:27

◆ DEF_TEST() [22/29]

DEF_TEST ( SkRuntimeEffectTraceShader  ,
 
)

Definition at line 899 of file SkRuntimeEffectTest.cpp.

899 {
900 for (int imageSize : {2, 80}) {
901 TestEffect effect(r, /*grContext=*/nullptr, /*graphite=*/nullptr,
902 SkISize{imageSize, imageSize});
903 effect.build(R"(
904 half4 main(float2 p) {
905 float2 val = p - 0.5;
906 return val.0y01;
907 }
908 )");
909 int center = imageSize / 2;
910 std::string dump = effect.trace({center, 1});
911 static constexpr char kSkRPSlotDump[] =
912R"($0 = p (float2 : slot 1/2, L0)
913$1 = p (float2 : slot 2/2, L0)
914$2 = [main].result (float4 : slot 1/4, L0)
915$3 = [main].result (float4 : slot 2/4, L0)
916$4 = [main].result (float4 : slot 3/4, L0)
917$5 = [main].result (float4 : slot 4/4, L0)
918$6 = val (float2 : slot 1/2, L0)
919$7 = val (float2 : slot 2/2, L0)
920F0 = half4 main(float2 p)
921)";
922 auto expectedTrace = SkSL::String::printf(R"(
923enter half4 main(float2 p)
924 p.x = %d.5
925 p.y = 1.5
926 scope +1
927 line 3
928 val.x = %d
929 val.y = 1
930 line 4
931 [main].result.x = 0
932 [main].result.y = 1
933 [main].result.z = 0
934 [main].result.w = 1
935 scope -1
static void dump(const float m[20], SkYUVColorSpace cs, bool rgb2yuv)
Definition: SkYUVMath.cpp:629
static SkScalar center(float pos0, float pos1)
void build(const char *src)
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: SkSLString.cpp:83
Definition: SkSize.h:16

◆ DEF_TEST() [23/29]

DEF_TEST ( SkRuntimeEffectUniformFlags  ,
 
)

Definition at line 168 of file SkRuntimeEffectTest.cpp.

168 {
169 auto [effect, errorText] = SkRuntimeEffect::MakeForShader(SkString(R"(
170 uniform int simple; // should have no flags
171 uniform float arrayOfOne[1]; // should have kArray_Flag
172 uniform float arrayOfMultiple[2]; // should have kArray_Flag
173 layout(color) uniform float4 color; // should have kColor_Flag
174 uniform half3 halfPrecisionFloat; // should have kHalfPrecision_Flag
175 layout(color) uniform half4 allFlags[2]; // should have Array | Color | HalfPrecision
176 )" EMPTY_MAIN));
177 REPORTER_ASSERT(r, effect, "%s", errorText.c_str());
178
179 SkSpan<const SkRuntimeEffect::Uniform> uniforms = effect->uniforms();
180 REPORTER_ASSERT(r, uniforms.size() == 6);
181
182 REPORTER_ASSERT(r, uniforms[0].flags == 0);
190}
constexpr size_t size() const
Definition: SkSpan_impl.h:95
FlutterSemanticsFlag flags

◆ DEF_TEST() [24/29]

DEF_TEST ( SkRuntimeEffectValidation  ,
 
)

Definition at line 192 of file SkRuntimeEffectTest.cpp.

192 {
193 auto es2Effect = SkRuntimeEffect::MakeForShader(SkString("#version 100\n" EMPTY_MAIN)).effect;
194 auto es3Effect = SkRuntimeEffect::MakeForShader(SkString("#version 300\n" EMPTY_MAIN)).effect;
195 REPORTER_ASSERT(r, es2Effect && es3Effect);
196
197 auto es2Caps = SkCapabilities::RasterBackend();
198 REPORTER_ASSERT(r, es2Caps->skslVersion() == SkSL::Version::k100);
199
200 REPORTER_ASSERT(r, SkRuntimeEffectPriv::CanDraw(es2Caps.get(), es2Effect.get()));
201 REPORTER_ASSERT(r, !SkRuntimeEffectPriv::CanDraw(es2Caps.get(), es3Effect.get()));
202}
static sk_sp< const SkCapabilities > RasterBackend()
static bool CanDraw(const SkCapabilities *, const SkSL::Program *)

◆ DEF_TEST() [25/29]

DEF_TEST ( SkRuntimeShaderBuilderReuse  ,
 
)

Definition at line 1154 of file SkRuntimeEffectTest.cpp.

1156 { return child.eval(s, d); }");
1157 effect.child("child") = SkBlender::Mode(SkBlendMode::kPlus);
1158 effect.test({0xFF4523FF, 0xFF45FF01, 0xFFFF2301, 0xFFFFFFFF},
1159 [](SkCanvas*, SkPaint* paint) { paint->setColor(0xFF012345); });
1160
1161 // Sampling a runtime-effect blender
1162 effect.surface()->getCanvas()->drawPaint(rgbwPaint);
1163 effect.build("uniform blender child;"
1164 "half4 main(half4 s, half4 d) { return child.eval(s, d); }");
1165 effect.child("child") = SkBlenders::Arithmetic(0, 1, 1, 0, /*enforcePremul=*/false);
1166 effect.test({0xFF4523FF, 0xFF45FF01, 0xFFFF2301, 0xFFFFFFFF},
1167 [](SkCanvas*, SkPaint* paint) { paint->setColor(0xFF012345); });
1168}
1169
1170DEF_TEST(SkRuntimeEffect_Blender_CPU, r) {
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19

◆ DEF_TEST() [26/29]

DEF_TEST ( SkRuntimeShaderBuilderSetUniforms  ,
 
)

Definition at line 1189 of file SkRuntimeEffectTest.cpp.

1199 {
1200 const char* kSource = R"(
1201 uniform half x;
1202 half4 main(half4 s, half4 d) { return half4(x); }
1203 )";
1204
1206 REPORTER_ASSERT(r, effect);
1207
1208 // We should be able to construct multiple SkBlenders in a row without asserting.
1209 SkRuntimeBlendBuilder b(std::move(effect));
1210 for (float x = 0.0f; x <= 2.0f; x += 2.0f) {
1211 b.uniform("x") = x;
1212 sk_sp<SkBlender> blender = b.makeBlender();
1213 }
1214}
1215
static bool b

◆ DEF_TEST() [27/29]

DEF_TEST ( SkRuntimeShaderIsOpaque  ,
 
)

Definition at line 1454 of file SkRuntimeEffectTest.cpp.

1455 { return child.eval(xy) + sin(xy.x); }", false, true);
1456
1457 // Cases where our optimization is not valid, and does not happen:
1458
1459 // Sampling with values completely unrelated to passed-in coords
1460 test("half4 main(float2 xy) { return child.eval(float2(0, 0)); }", true, false);
1461 // Use of expression involving passed in coords
1462 test("half4 main(float2 xy) { return child.eval(xy * 0.5); }", true, true);
1463 // Use of coords after modification
1464 test("half4 main(float2 xy) { xy *= 2; return child.eval(xy); }", true, true);
1465 // Use of coords after modification via out-param call
1466 test("void adjust(inout float2 xy) { xy *= 2; }"
1467 "half4 main(float2 xy) { adjust(xy); return child.eval(xy); }", true, true);
1468
1469 // There should (must) not be any false-positive cases. There are false-negatives.
1470 // In all of these cases, our optimization would be valid, but does not happen:
1471
1472 // Direct use of passed-in coords, modified after use
1473 test("half4 main(float2 xy) { half4 c = child.eval(xy); xy *= 2; return c; }", true, true);
1474 // Passed-in coords copied to a temp variable
1475 test("half4 main(float2 xy) { float2 p = xy; return child.eval(p); }", true, true);
1476 // Use of coords passed to helper function
1477 test("half4 helper(float2 xy) { return child.eval(xy); }"
1478 "half4 main(float2 xy) { return helper(xy); }", true, true);
1479}
1480
1481DEF_TEST(SkRuntimeShaderIsOpaque, r) {
1482 // This test verifies that we detect certain simple patterns in runtime shaders, and can deduce
1483 // (via code in SkSL::Analysis::ReturnsOpaqueColor) that the resulting shader is always opaque.
1484 // That logic is conservative, and the tests below reflect this.
1485
1486 auto test = [&](const char* body, bool expectOpaque) {
1487 auto [effect, err] = SkRuntimeEffect::MakeForShader(SkStringPrintf(R"(
1488 uniform shader cOnes;
1489 uniform shader cZeros;
1490 uniform float4 uOnes;
1491 uniform float4 uZeros;
1492 half4 main(float2 xy) {
1493 %s
1494 })", body));
1495 REPORTER_ASSERT(r, effect);
1496
1497 auto cOnes = SkShaders::Color(SK_ColorWHITE);
1498 auto cZeros = SkShaders::Color(SK_ColorTRANSPARENT);
1499 SkASSERT(cOnes->isOpaque());
1500 SkASSERT(!cZeros->isOpaque());
1501
1502 SkRuntimeShaderBuilder builder(effect);
1503 builder.child("cOnes") = std::move(cOnes);
1504 builder.child("cZeros") = std::move(cZeros);
1505 builder.uniform("uOnes") = SkColors::kWhite;
1506 builder.uniform("uZeros") = SkColors::kTransparent;
1507
1508 auto shader = builder.makeShader();
1509 REPORTER_ASSERT(r, shader->isOpaque() == expectOpaque);
1510 };
1511
1512 // Cases where our optimization is valid, and works:
1513
1514 // Returning opaque literals
1515 test("return half4(1);", true);
1516 test("return half4(0, 1, 0, 1);", true);
1517 test("return half4(0, 0, 0, 1);", true);
1518
1519 // Simple expressions involving uniforms
1520 test("return uZeros.rgb1;", true);
1521 test("return uZeros.bgra.rgb1;", true);
1522 test("return half4(uZeros.rgb, 1);", true);
1523
1524 // Simple expressions involving child.eval
1525 test("return cZeros.eval(xy).rgb1;", true);
1526 test("return cZeros.eval(xy).bgra.rgb1;", true);
1527 test("return half4(cZeros.eval(xy).rgb, 1);", true);
1528
1529 // Multiple returns
1530 test("if (xy.x < 100) { return uZeros.rgb1; } else { return cZeros.eval(xy).rgb1; }", true);
1531
1532 // More expression cases:
1533 test("return (cZeros.eval(xy) * uZeros).rgb1;", true);
1534 test("return half4(1, 1, 1, 0.5 + 0.5);", true);
1535
1536 // Constant variable propagation
1537 test("const half4 kWhite = half4(1); return kWhite;", true);
skvx::float2 float2
constexpr SkColor4f kWhite
Definition: SkColor.h:439

◆ DEF_TEST() [28/29]

DEF_TEST ( SkRuntimeShaderSampleCoords  ,
 
)

Definition at line 1400 of file SkRuntimeEffectTest.cpp.

1401 { return half4(1, 1, 1, color.r); }");
1402
1403 // This splat constructor doesn't use alpha.
1404 expectAlphaChanged("half4 main(half4 color) { return half4(color.r); }");
1405
1406 // These ternaries don't return alpha on both sides
1407 expectAlphaChanged("half4 main(half4 color) { return color.a > 0 ? half4(0) : color; }");
1408 expectAlphaChanged("half4 main(half4 color) { return color.g < 1 ? color.bgra : color.abgr; }");
1409 expectAlphaChanged("half4 main(half4 color) { return color.b > 0.5 ? half4(0) : half4(1); }");
1410
1411 // Performing arithmetic on the input causes it to report as "alpha changed" even if the
1412 // arithmetic is a no-op; we aren't smart enough to see through it.
1413 expectAlphaChanged("half4 main(half4 color) { return color + half4(1,1,1,0); }");
1414 expectAlphaChanged("half4 main(half4 color) { return color + half4(0,0,0,4); }");
1415
1416 // All exit paths are checked.
1417 expectAlphaChanged("half4 main(half4 color) { "
1418 " if (color.r > 0.5) { return color; }"
1419 " return half4(0);"
1420 "}");
1421 expectAlphaChanged("half4 main(half4 color) { "
1422 " if (color.r > 0.5) { return half4(0); }"
1423 " return color;"
1424 "}");
1425}
1426
1427DEF_TEST(SkRuntimeShaderSampleCoords, r) {
1428 // This test verifies that we detect calls to sample where the coords are the same as those
1429 // passed to main. In those cases, it's safe to turn the "explicit" sampling into "passthrough"
1430 // sampling. This optimization is implemented very conservatively.
1431 //
1432 // It also checks that we correctly set the "referencesSampleCoords" bit on the runtime effect
1433 // FP, depending on how the coords parameter to main is used.
1434
1435 auto test = [&](const char* src, bool expectExplicit, bool expectReferencesSampleCoords) {
1436 auto [effect, err] =
1437 SkRuntimeEffect::MakeForShader(SkStringPrintf("uniform shader child; %s", src));
1438 REPORTER_ASSERT(r, effect);
1439
1440 auto child = GrFragmentProcessor::MakeColor({ 1, 1, 1, 1 });
1441 auto fp = GrSkSLFP::Make(effect.get(), "test_fp", /*inputFP=*/nullptr,
1442 GrSkSLFP::OptFlags::kNone, "child", std::move(child));
1443 REPORTER_ASSERT(r, fp);
1444
1445 REPORTER_ASSERT(r, fp->childProcessor(0)->sampleUsage().isExplicit() == expectExplicit);
1446 REPORTER_ASSERT(r, fp->usesSampleCoords() == expectReferencesSampleCoords);
1447 };
1448
1449 // Cases where our optimization is valid, and works:
1450
1451 // Direct use of passed-in coords. Here, the only use of sample coords is for a sample call
1452 // converted to passthrough, so referenceSampleCoords is *false*, despite appearing in main.

◆ DEF_TEST() [29/29]

DEF_TEST ( SkRuntimeStructNameReuse  ,
 
)

Definition at line 1324 of file SkRuntimeEffectTest.cpp.

1325 {
1326 // Test that two different runtime effects can reuse struct names in a single paint operation

◆ make_RGBW_shader()

static sk_sp< SkShader > make_RGBW_shader ( )
static

Definition at line 595 of file SkRuntimeEffectTest.cpp.

595 {
596 static constexpr SkColor colors[] = {SK_ColorWHITE, SK_ColorWHITE,
600 static constexpr SkScalar pos[] = { 0, .25f, .25f, .50f, .50f, .75, .75, 1 };
601 static_assert(std::size(colors) == std::size(pos), "size mismatch");
603}
SkPoint pos
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorBLUE
Definition: SkColor.h:135
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
constexpr SkColor SK_ColorGREEN
Definition: SkColor.h:131
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
static sk_sp< SkShader > MakeSweep(SkScalar cx, SkScalar cy, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, SkScalar startAngle, SkScalar endAngle, uint32_t flags, const SkMatrix *localMatrix)
float SkScalar
Definition: extension.cpp:12
PODArray< SkColor > colors
Definition: SkRecords.h:276
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

◆ make_surface()

static sk_sp< SkSurface > make_surface ( GrRecordingContext grContext,
const GraphiteInfo graphite,
SkISize  size 
)
static

Definition at line 428 of file SkRuntimeEffectTest.cpp.

430 {
433 if (graphite) {
434#if defined(SK_GRAPHITE)
436#endif
437 } else if (grContext) {
439 } else {
441 }
443 return surface;
444}
#define SkASSERT(cond)
Definition: SkAssert.h:116

◆ paint_canvas()

void paint_canvas ( SkCanvas canvas,
SkPaint paint,
const PreTestFn preTestCallback 
)

Definition at line 389 of file SkRuntimeEffectTest.cpp.

389 {
390 canvas->save();
391 if (preTestCallback) {
392 preTestCallback(canvas, paint);
393 }
394 canvas->drawPaint(*paint);
395 canvas->restore();
396}
void restore()
Definition: SkCanvas.cpp:461
void drawPaint(const SkPaint &paint)
Definition: SkCanvas.cpp:1668
int save()
Definition: SkCanvas.cpp:447

◆ read_pixels()

static bool read_pixels ( SkSurface surface,
GrColor pixels 
)
static

Definition at line 398 of file SkRuntimeEffectTest.cpp.

399 {
400 SkImageInfo info = surface->imageInfo();
401 SkPixmap dest{info, pixels, info.minRowBytes()};
402 return surface->readPixels(dest, /*srcX=*/0, /*srcY=*/0);
403}
dest
Definition: zip.py:79

◆ test_invalid_effect()

void test_invalid_effect ( skiatest::Reporter r,
const char *  src,
const char *  expected 
)

Definition at line 91 of file SkRuntimeEffectTest.cpp.

91 {
92 auto [effect, errorText] = SkRuntimeEffect::MakeForShader(SkString(src));
93 REPORTER_ASSERT(r, !effect);
94 REPORTER_ASSERT(r, errorText.contains(expected),
95 "Expected error message to contain \"%s\". Actual message: \"%s\"",
96 expected, errorText.c_str());
97}

◆ test_RuntimeEffect_Blenders()

static void test_RuntimeEffect_Blenders ( skiatest::Reporter r,
GrRecordingContext grContext,
const GraphiteInfo graphite 
)
static

Definition at line 1023 of file SkRuntimeEffectTest.cpp.

1023 : slot 1/4, L0)
1024$3 = [main].result (float4 : slot 2/4, L0)
1025$4 = [main].result (float4 : slot 3/4, L0)
1026$5 = [main].result (float4 : slot 4/4, L0)
1027F0 = half4 main(float2 p)
1028)";
1029 static constexpr char kExpectedTrace[] = R"(
1030enter half4 main(float2 p)
1031 p.x = 1.5
1032 p.y = 1.5
1033 scope +1
1034 scope +1
1035 line 5
1036 [main].result.x = 1
1037 [main].result.y = 1
1038 [main].result.z = 1
1039 [main].result.w = 1
1040 scope -1
1041 scope -1
1043)";
1044 REPORTER_ASSERT(
1045 r,
1046 skstd::starts_with(dump, kSkRPSlotDump) && skstd::ends_with(dump, kExpectedTrace),
1047 "Trace output does not match expectation:\n%.*s\n", (int)dump.size(), dump.data());
1048}
1049
1050static void test_RuntimeEffect_Blenders(skiatest::Reporter* r,
1051 GrRecordingContext* grContext,
1052 const GraphiteInfo* graphite) {
1053 TestBlend effect(r, grContext, graphite);
1054
1055 using float2 = std::array<float, 2>;
1056 using float4 = std::array<float, 4>;
1057 using int4 = std::array<int, 4>;
1058
1059 // Use of a simple uniform. (Draw twice with two values to ensure it's updated).
1060 effect.build("uniform float4 gColor; half4 main(half4 s, half4 d) { return half4(gColor); }");
1061 effect.uniform("gColor") = float4{ 0.0f, 0.25f, 0.75f, 1.0f };
1062 effect.test(0xFFBF4000);
1063 effect.uniform("gColor") = float4{ 1.0f, 0.0f, 0.0f, 0.498f };
1064 effect.test(0x7F0000FF); // We don't clamp here either
1065
1066 // Same, with integer uniforms
1067 effect.build("uniform int4 gColor;"
1068 "half4 main(half4 s, half4 d) { return half4(gColor) / 255.0; }");
1069 effect.uniform("gColor") = int4{ 0x00, 0x40, 0xBF, 0xFF };
1070 effect.test(0xFFBF4000);
1071 effect.uniform("gColor") = int4{ 0xFF, 0x00, 0x00, 0x7F };
1072 effect.test(0x7F0000FF); // We don't clamp here either
1073
1074 // Verify that mutating the source and destination colors is allowed
1075 effect.build("half4 main(half4 s, half4 d) { s += d; d += s; return half4(1); }");
1076 effect.test(0xFFFFFFFF);
1077
1078 // Verify that we can write out the source color (ignoring the dest color)
1079 // This is equivalent to the kSrc blend mode.
1080 effect.build("half4 main(half4 s, half4 d) { return s; }");
1081 effect.test(0xFF888888);
1082
1083 // Fill the destination with a variety of colors (using the RGBW shader)
1084 SkPaint rgbwPaint;
1085 rgbwPaint.setShader(make_RGBW_shader());
1086 rgbwPaint.setBlendMode(SkBlendMode::kSrc);
1087 effect.surface()->getCanvas()->drawPaint(rgbwPaint);
1088
1089 // Verify that we can read back the dest color exactly as-is (ignoring the source color)
1090 // This is equivalent to the kDst blend mode.
1091 effect.build("half4 main(half4 s, half4 d) { return d; }");
1092 effect.test({0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 0xFFFFFFFF});
1093
1094 // Verify that we can invert the destination color (including the alpha channel).
1095 // The expected outputs are the exact inverse of the previous test.
1096 effect.build("half4 main(half4 s, half4 d) { return half4(1) - d; }");
1097 effect.test({0x00FFFF00, 0x00FF00FF, 0x0000FFFF, 0x00000000});
1098
1099 // Verify that color values are clamped to 0 and 1.
1100 effect.build("half4 main(half4 s, half4 d) { return half4(-1); }");
1101 effect.test(0x00000000);
1102 effect.build("half4 main(half4 s, half4 d) { return half4(2); }");
1103 effect.test(0xFFFFFFFF);
1104
1105 //
1106 // Sampling children
1107 //
1108
1109 // Sampling a null shader should return transparent black.
1110 effect.build("uniform shader child;"
1111 "half4 main(half4 s, half4 d) { return child.eval(s.rg); }");
1112 effect.child("child") = nullptr;
1113 effect.test(0x00000000,
1114 [](SkCanvas*, SkPaint* paint) { paint->setColor4f({1.0f, 1.0f, 0.0f, 1.0f}); });
1115
1116 effect.build("uniform colorFilter child;"
1117 "half4 main(half4 s, half4 d) { return child.eval(s); }");
1118 effect.child("child") = nullptr;
1119 effect.test(0xFF00FFFF,
1120 [](SkCanvas*, SkPaint* paint) { paint->setColor4f({1.0f, 1.0f, 0.0f, 1.0f}); });
1121
1122 // Sampling a null blender should do a src-over blend. Draw 50% black over RGBW to verify this.
1123 effect.surface()->getCanvas()->drawPaint(rgbwPaint);
1124 effect.build("uniform blender child;"
1125 "half4 main(half4 s, half4 d) { return child.eval(s, d); }");
1126 effect.child("child") = nullptr;
1127 effect.test({0xFF000080, 0xFF008000, 0xFF800000, 0xFF808080},
1128 [](SkCanvas*, SkPaint* paint) { paint->setColor4f({0.0f, 0.0f, 0.0f, 0.497f}); });
1129
1130 // Sampling a shader at various coordinates
1131 effect.build("uniform shader child;"
1132 "uniform half2 pos;"
1133 "half4 main(half4 s, half4 d) { return child.eval(pos); }");
1134 effect.child("child") = make_RGBW_shader();
1135 effect.uniform("pos") = float2{0.5, 0.5};
1136 effect.test(0xFF0000FF);
1137
1138 effect.uniform("pos") = float2{1.5, 0.5};
1139 effect.test(0xFF00FF00);
1140
1141 effect.uniform("pos") = float2{0.5, 1.5};
GAsyncResult * result
def match(bench, filt)
Definition: benchmark.py:23
exit(kErrorExitCode)
Definition: main.py:1
Vec< 4, int32_t > int4
Definition: SkVx.h:1159

◆ test_RuntimeEffect_Shaders()

static void test_RuntimeEffect_Shaders ( skiatest::Reporter r,
GrRecordingContext grContext,
const GraphiteInfo graphite 
)
static

Definition at line 605 of file SkRuntimeEffectTest.cpp.

607 {
608 TestEffect effect(r, grContext, graphite);
609 using float4 = std::array<float, 4>;
610 using int4 = std::array<int, 4>;
611
612 // Local coords
613 effect.build("half4 main(float2 p) { return half4(half2(p - 0.5), 0, 1); }");
614 effect.test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF});
615
616 // Use of a simple uniform. (Draw twice with two values to ensure it's updated).
617 effect.build("uniform float4 gColor; half4 main(float2 p) { return half4(gColor); }");
618 effect.uniform("gColor") = float4{ 0.0f, 0.25f, 0.75f, 1.0f };
619 effect.test(0xFFBF4000);
620 effect.uniform("gColor") = float4{ 1.0f, 0.0f, 0.0f, 0.498f };
621 effect.test(0x7F0000FF); // Tests that we don't clamp to valid premul
622
623 // Same, with integer uniforms
624 effect.build("uniform int4 gColor; half4 main(float2 p) { return half4(gColor) / 255.0; }");
625 effect.uniform("gColor") = int4{ 0x00, 0x40, 0xBF, 0xFF };
626 effect.test(0xFFBF4000);
627 effect.uniform("gColor") = int4{ 0xFF, 0x00, 0x00, 0x7F };
628 effect.test(0x7F0000FF); // Tests that we don't clamp to valid premul
629
630 // Test sk_FragCoord (device coords). Rotate the canvas to be sure we're seeing device coords.
631 // Since the surface is 2x2, we should see (0,0), (1,0), (0,1), (1,1). Multiply by 0.498 to
632 // make sure we're not saturating unexpectedly.
633 effect.build(
634 "half4 main(float2 p) { return half4(0.498 * (half2(sk_FragCoord.xy) - 0.5), 0, 1); }");
635 effect.test({0xFF000000, 0xFF00007F, 0xFF007F00, 0xFF007F7F},
636 [](SkCanvas* canvas, SkPaint*) { canvas->rotate(45.0f); });
637
638 // Runtime effects should use relaxed precision rules by default
639 effect.build("half4 main(float2 p) { return float4(p - 0.5, 0, 1); }");
640 effect.test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF});
641
642 // ... and support *returning* float4 (aka vec4), not just half4
643 effect.build("float4 main(float2 p) { return float4(p - 0.5, 0, 1); }");
644 effect.test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF});
645 effect.build("vec4 main(float2 p) { return float4(p - 0.5, 0, 1); }");
646 effect.test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF});
647
648 // Mutating coords should work. (skbug.com/10918)
649 effect.build("vec4 main(vec2 p) { p -= 0.5; return vec4(p, 0, 1); }");
650 effect.test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF});
651 effect.build("void moveCoords(inout vec2 p) { p -= 0.5; }"
652 "vec4 main(vec2 p) { moveCoords(p); return vec4(p, 0, 1); }");
653 effect.test({0xFF000000, 0xFF0000FF, 0xFF00FF00, 0xFF00FFFF});
654
655 //
656 // Sampling children
657 //
658
659 // Sampling a null shader should return transparent black
660 if (!graphite) {
661 // TODO: Graphite does not yet pass this test.
662 effect.build("uniform shader child;"
663 "half4 main(float2 p) { return child.eval(p); }");
664 effect.child("child") = nullptr;
665 effect.test(0x00000000,
666 [](SkCanvas*, SkPaint* paint) { paint->setColor4f({1.0f, 1.0f, 0.0f, 1.0f}); });
667 }
668
669 // Sampling a null color-filter should return the passed-in color
670 effect.build("uniform colorFilter child;"
671 "half4 main(float2 p) { return child.eval(half4(1, 1, 0, 1)); }");
672 effect.child("child") = nullptr;
673 effect.test(0xFF00FFFF);
674
675 // Sampling a null blender should return blend_src_over(src, dest).
676 effect.build("uniform blender child;"
677 "half4 main(float2 p) {"
678 " float4 src = float4(p - 0.5, 0, 1) * 0.498;"
679 " return child.eval(src, half4(0, 0, 0, 1));"
680 "}");
681 effect.child("child") = nullptr;
682 effect.test({0xFF000000, 0xFF00007F, 0xFF007F00, 0xFF007F7F});
683
684 // Sampling a simple child at our coordinates
685 sk_sp<SkShader> rgbwShader = make_RGBW_shader();
686
687 effect.build("uniform shader child;"
688 "half4 main(float2 p) { return child.eval(p); }");
689 effect.child("child") = rgbwShader;
690 effect.test({0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 0xFFFFFFFF});
691
692 // Sampling with explicit coordinates (reflecting about the diagonal)
693 effect.build("uniform shader child;"
694 "half4 main(float2 p) { return child.eval(p.yx); }");
695 effect.child("child") = rgbwShader;
696 effect.test({0xFF0000FF, 0xFFFF0000, 0xFF00FF00, 0xFFFFFFFF});
697
698 // Bind an image shader, but don't use it - ensure that we don't assert or generate bad shaders.
699 // (skbug.com/12429)
700 effect.build("uniform shader child;"
701 "half4 main(float2 p) { return half4(0, 1, 0, 1); }");
702 effect.child("child") = rgbwShader;
703 effect.test(0xFF00FF00);
704
705 //
706 // Helper functions
707 //
708
709 // Test case for inlining in the pipeline-stage and fragment-shader passes (skbug.com/10526):
710 effect.build("float2 helper(float2 x) { return x + 1; }"
711 "half4 main(float2 p) { float2 v = helper(p); return half4(half2(v), 0, 1); }");
712 effect.test(0xFF00FFFF);
713}
static sk_sp< SkShader > make_RGBW_shader()
void rotate(SkScalar degrees)
Definition: SkCanvas.cpp:1300

◆ test_RuntimeEffectObeysCapabilities()

static void test_RuntimeEffectObeysCapabilities ( skiatest::Reporter r,
SkSurface surface 
)
static

Definition at line 751 of file SkRuntimeEffectTest.cpp.

751 {
752 // This test creates shaders and blenders that target `#version 300`. If a user validates an
753 // effect like this against a particular device, and later draws that effect to a device with
754 // insufficient capabilities -- we want to fail gracefully (drop the draw entirely).
755 // If the capabilities indicate that the effect is supported, we expect it to work.
756 //
757 // We test two different scenarios here:
758 // 1) An effect flagged as #version 300, but actually compatible with #version 100.
759 // 2) An effect flagged as #version 300, and using features not available in ES2.
760 //
761 // We expect both cases to fail cleanly on ES2-only devices -- nothing should be drawn, and
762 // there should be no asserts or driver shader-compilation errors.
763 //
764 // In all tests, we first clear the canvas to RED, then draw an effect that (if it renders)
765 // will fill the canvas with GREEN. We check that the final colors match our expectations,
766 // based on the device capabilities.
767
768 // Effect that would actually work on CPU/ES2, but should still fail on those devices:
769 {
771 #version 300
772 half4 main(float2 xy) { return half4(0, 1, 0, 1); }
773 )")).effect;
774 REPORTER_ASSERT(r, effect);
776 paint.setShader(effect->makeShader(/*uniforms=*/nullptr, /*children=*/{}));
777 REPORTER_ASSERT(r, paint.getShader());
779 }
780
781 // Effect that won't work on CPU/ES2 at all, and should fail gracefully on those devices.
782 // We choose to use bit-pun intrinsics because SkSL doesn't automatically inject an extension
783 // to enable them (like it does for derivatives). We pass a non-literal value so that SkSL's
784 // constant folding doesn't elide them entirely before the driver sees the shader.
785 {
787 #version 300
788 half4 main(float2 xy) {
789 half4 result = half4(0, 1, 0, 1);
790 result.g = intBitsToFloat(floatBitsToInt(result.g));
791 return result;
792 }
793 )")).effect;
794 REPORTER_ASSERT(r, effect);
796 paint.setShader(effect->makeShader(/*uniforms=*/nullptr, /*children=*/{}));
797 REPORTER_ASSERT(r, paint.getShader());
799 }
800
801 //
802 // As above, but with a blender
803 //
804
805 {
807 #version 300
808 half4 main(half4 src, half4 dst) { return half4(0, 1, 0, 1); }
809 )")).effect;
810 REPORTER_ASSERT(r, effect);
812 paint.setBlender(effect->makeBlender(/*uniforms=*/nullptr, /*children=*/{}));
813 REPORTER_ASSERT(r, paint.getBlender());
815 }
816
817 {
819 #version 300
820 half4 main(half4 src, half4 dst) {
821 half4 result = half4(0, 1, 0, 1);
822 result.g = intBitsToFloat(floatBitsToInt(result.g));
823 return result;
824 }
825 )")).effect;
826 REPORTER_ASSERT(r, effect);
828 paint.setBlender(effect->makeBlender(/*uniforms=*/nullptr, /*children=*/{}));
829 REPORTER_ASSERT(r, paint.getBlender());
831 }
832}
static void verify_draw_obeys_capabilities(skiatest::Reporter *r, const SkRuntimeEffect *effect, SkSurface *surface, const SkPaint &paint)

◆ test_RuntimeEffectStructNameReuse()

static void test_RuntimeEffectStructNameReuse ( skiatest::Reporter r,
GrRecordingContext rContext 
)
static

Definition at line 1298 of file SkRuntimeEffectTest.cpp.

1307 {
1308 // Test runtime colorfilters support filterColor4f().
1309 auto [effect, err] =
1310 SkRuntimeEffect::MakeForColorFilter(SkString{"half4 main(half4 c) { return c*c; }"});
1311 REPORTER_ASSERT(r, effect);
1312 REPORTER_ASSERT(r, err.isEmpty());
1313
1314 sk_sp<SkColorFilter> cf = effect->makeColorFilter(SkData::MakeEmpty());
1315 REPORTER_ASSERT(r, cf);
1316
1317 SkColor4f c = cf->filterColor4f({0.25, 0.5, 0.75, 1.0},
1319 REPORTER_ASSERT(r, c.fR == 0.0625f);
1320 REPORTER_ASSERT(r, c.fG == 0.25f);
1321 REPORTER_ASSERT(r, c.fB == 0.5625f);
1322 REPORTER_ASSERT(r, c.fA == 1.0f);
SkColorSpace * sk_srgb_singleton()
SkColor4f filterColor4f(const SkColor4f &srcColor, SkColorSpace *srcCS, SkColorSpace *dstCS) const
static sk_sp< SkData > MakeEmpty()
Definition: SkData.cpp:94

◆ verify_2x2_surface_results()

static void verify_2x2_surface_results ( skiatest::Reporter r,
const SkRuntimeEffect effect,
SkSurface surface,
std::array< GrColor, 4 >  expected 
)
static

Definition at line 405 of file SkRuntimeEffectTest.cpp.

408 {
409 std::array<GrColor, 4> actual;
410 SkImageInfo info = surface->imageInfo();
411 if (!read_pixels(surface, actual.data())) {
412 REPORT_FAILURE(r, "readPixels", SkString("readPixels failed"));
413 return;
414 }
415
416 if (actual != expected) {
417 REPORT_FAILURE(r, "Runtime effect didn't match expectations",
418 SkStringPrintf("\n"
419 "Expected: [ %08x %08x %08x %08x ]\n"
420 "Got : [ %08x %08x %08x %08x ]\n"
421 "SkSL:\n%s\n",
422 expected[0], expected[1], expected[2], expected[3],
423 actual[0], actual[1], actual[2], actual[3],
424 effect->source().c_str()));
425 }
426}
static bool read_pixels(SkSurface *surface, GrColor *pixels)
SK_API SkString SkStringPrintf(const char *format,...) SK_PRINTF_LIKE(1
Creates a new string and writes into it using a printf()-style format.
#define REPORT_FAILURE(reporter, cond, message)
Definition: Test.h:90
const std::string & source() const

◆ verify_draw_obeys_capabilities()

static void verify_draw_obeys_capabilities ( skiatest::Reporter r,
const SkRuntimeEffect effect,
SkSurface surface,
const SkPaint paint 
)
static

Definition at line 735 of file SkRuntimeEffectTest.cpp.

738 {
739 // We expect the draw to do something if-and-only-if expectSuccess is true:
740 const bool expectSuccess = surface->capabilities()->skslVersion() >= SkSL::Version::k300;
741
742 constexpr GrColor kGreen = 0xFF00FF00;
743 constexpr GrColor kRed = 0xFF0000FF;
744 const GrColor kExpected = expectSuccess ? kGreen : kRed;
745
746 surface->getCanvas()->clear(SK_ColorRED);
747 surface->getCanvas()->drawPaint(paint);
748 verify_2x2_surface_results(r, effect, surface, {kExpected, kExpected, kExpected, kExpected});
749}
uint32_t GrColor
Definition: GrColor.h:25
static const uint64_t kGreen
static const uint64_t kRed
static void verify_2x2_surface_results(skiatest::Reporter *r, const SkRuntimeEffect *effect, SkSurface *surface, std::array< GrColor, 4 > expected)