Flutter Engine
The Flutter Engine
ProgramsTest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8// This is a GPU-backend specific test.
9
13#include "include/core/SkSize.h"
21#include "include/gpu/GrTypes.h"
25#include "src/base/SkRandom.h"
26#include "src/gpu/KeyBuilder.h"
28#include "src/gpu/Swizzle.h"
44#include "tests/Test.h"
45
46#include <algorithm>
47#include <array>
48#include <cstdint>
49#include <memory>
50#include <tuple>
51#include <utility>
52
54struct GrShaderCaps;
55
56#ifdef SK_GL
58#endif
59
60/*
61 * A simple processor which just tries to insert a massive key and verify that it can retrieve the
62 * whole thing correctly
63 */
64static const uint32_t kMaxKeySize = 1024;
65
66namespace {
67class BigKeyProcessor : public GrFragmentProcessor {
68public:
69 static std::unique_ptr<GrFragmentProcessor> Make() {
70 return std::unique_ptr<GrFragmentProcessor>(new BigKeyProcessor);
71 }
72
73 const char* name() const override { return "Big_Ole_Key"; }
74
75 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
76 class Impl : public ProgramImpl {
77 public:
78 void emitCode(EmitArgs& args) override {
79 args.fFragBuilder->codeAppendf("return half4(1);\n");
80 }
81 };
82
83 return std::make_unique<Impl>();
84 }
85
86 std::unique_ptr<GrFragmentProcessor> clone() const override { return Make(); }
87
88private:
89 BigKeyProcessor() : INHERITED(kBigKeyProcessor_ClassID, kNone_OptimizationFlags) {}
90 void onAddToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const override {
91 for (uint32_t i = 0; i < kMaxKeySize; i++) {
92 b->add32(i);
93 }
94 }
95 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
96
98
100};
101} // anonymous namespace
102
104
105#if defined(GR_TEST_UTILS)
106std::unique_ptr<GrFragmentProcessor> BigKeyProcessor::TestCreate(GrProcessorTestData*) {
107 return BigKeyProcessor::Make();
108}
109#endif
110
111//////////////////////////////////////////////////////////////////////////////
112
114public:
115 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) {
116 return std::unique_ptr<GrFragmentProcessor>(new BlockInputFragmentProcessor(std::move(fp)));
117 }
118
119 const char* name() const override { return "Block_Input"; }
120
121 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
122 return std::make_unique<GLFP>();
123 }
124
125 std::unique_ptr<GrFragmentProcessor> clone() const override {
126 return Make(this->childProcessor(0)->clone());
127 }
128
129private:
130 class GLFP : public ProgramImpl {
131 public:
132 void emitCode(EmitArgs& args) override {
133 SkString temp = this->invokeChild(0, args);
134 args.fFragBuilder->codeAppendf("return %s;", temp.c_str());
135 }
136
137 private:
138 using INHERITED = ProgramImpl;
139 };
140
141 BlockInputFragmentProcessor(std::unique_ptr<GrFragmentProcessor> child)
143 this->registerChild(std::move(child));
144 }
145
146 void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override {}
147
148 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
149
150 using INHERITED = GrFragmentProcessor;
151};
152
153//////////////////////////////////////////////////////////////////////////////
154
155/*
156 * Begin test code
157 */
158static const int kRenderTargetHeight = 1;
159static const int kRenderTargetWidth = 1;
160
161static std::unique_ptr<skgpu::ganesh::SurfaceDrawContext> random_surface_draw_context(
162 GrRecordingContext* rContext, SkRandom* random, const GrCaps* caps) {
165
168
169 int sampleCnt = random->nextBool() ? caps->getRenderTargetSampleCount(2, format) : 1;
170 // Above could be 0 if msaa isn't supported.
171 sampleCnt = std::max(1, sampleCnt);
172
175 nullptr,
179 /*label=*/{},
180 sampleCnt,
183 origin);
184}
185
186#if defined(GR_TEST_UTILS)
187static void set_random_xpf(GrPaint* paint, GrProcessorTestData* d) {
188 paint->setXPFactory(GrXPFactoryTestFactory::Get(d));
189}
190
191static std::unique_ptr<GrFragmentProcessor> create_random_proc_tree(GrProcessorTestData* d,
192 int minLevels, int maxLevels) {
193 SkASSERT(1 <= minLevels);
194 SkASSERT(minLevels <= maxLevels);
195
196 // Return a leaf node if maxLevels is 1 or if we randomly chose to terminate.
197 // If returning a leaf node, make sure that it doesn't have children (e.g. another
198 // GrComposeEffect)
199 const float terminateProbability = 0.3f;
200 if (1 == minLevels) {
201 bool terminate = (1 == maxLevels) || (d->fRandom->nextF() < terminateProbability);
202 if (terminate) {
203 std::unique_ptr<GrFragmentProcessor> fp;
204 while (true) {
206 if (!fp) {
207 return nullptr;
208 }
209 if (0 == fp->numNonNullChildProcessors()) {
210 break;
211 }
212 }
213 return fp;
214 }
215 }
216 // If we didn't terminate, choose either the left or right subtree to fulfill
217 // the minLevels requirement of this tree; the other child can have as few levels as it wants.
218 // Also choose a random xfer mode.
219 if (minLevels > 1) {
220 --minLevels;
221 }
222 auto minLevelsChild = create_random_proc_tree(d, minLevels, maxLevels - 1);
223 std::unique_ptr<GrFragmentProcessor> otherChild(create_random_proc_tree(d, 1, maxLevels - 1));
224 if (!minLevelsChild || !otherChild) {
225 return nullptr;
226 }
227 SkBlendMode mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0,
229 std::unique_ptr<GrFragmentProcessor> fp;
230 if (d->fRandom->nextF() < 0.5f) {
231 fp = GrBlendFragmentProcessor::Make(std::move(minLevelsChild), std::move(otherChild), mode);
232 SkASSERT(fp);
233 } else {
234 fp = GrBlendFragmentProcessor::Make(std::move(otherChild), std::move(minLevelsChild), mode);
235 SkASSERT(fp);
236 }
237 return fp;
238}
239
240static void set_random_color_coverage_stages(GrPaint* paint,
241 GrProcessorTestData* d,
242 int maxStages,
243 int maxTreeLevels) {
244 // Randomly choose to either create a linear pipeline of procs or create one proc tree
245 const float procTreeProbability = 0.5f;
246 if (d->fRandom->nextF() < procTreeProbability) {
247 std::unique_ptr<GrFragmentProcessor> fp(create_random_proc_tree(d, 2, maxTreeLevels));
248 if (fp) {
249 paint->setColorFragmentProcessor(std::move(fp));
250 }
251 } else {
252 if (maxStages >= 1) {
253 if (std::unique_ptr<GrFragmentProcessor> fp = GrFragmentProcessorTestFactory::Make(d)) {
254 paint->setColorFragmentProcessor(std::move(fp));
255 }
256 }
257 if (maxStages >= 2) {
258 if (std::unique_ptr<GrFragmentProcessor> fp = GrFragmentProcessorTestFactory::Make(d)) {
259 paint->setCoverageFragmentProcessor(std::move(fp));
260 }
261 }
262 }
263}
264
265#endif
266
267#if !defined(GR_TEST_UTILS)
269#else
270bool GrDrawingManager::ProgramUnitTest(GrDirectContext* direct, int maxStages, int maxLevels) {
271 GrProxyProvider* proxyProvider = direct->priv().proxyProvider();
272 const GrCaps* caps = direct->priv().caps();
273
274 GrProcessorTestData::ViewInfo views[2];
275
276 // setup arbitrary textures
278 {
279 static constexpr SkISize kDims = {34, 18};
282 auto proxy = proxyProvider->createProxy(format,
283 kDims,
285 1,
286 mipmapped,
290 /*label=*/{},
293 views[0] = {{std::move(proxy), kBottomLeft_GrSurfaceOrigin, swizzle},
295 }
296 {
297 static constexpr SkISize kDims = {16, 22};
300 auto proxy = proxyProvider->createProxy(format,
301 kDims,
303 1,
304 mipmapped,
308 /*label=*/{},
311 views[1] = {{std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle},
313 }
314
315 if (!std::get<0>(views[0]) || !std::get<0>(views[1])) {
316 SkDebugf("Could not allocate textures for test");
317 return false;
318 }
319
320 SkRandom random;
321 static const int NUM_TESTS = 1024;
322 for (int t = 0; t < NUM_TESTS; t++) {
323 // setup random render target(can fail)
324 auto surfaceDrawContext = random_surface_draw_context(direct, &random, caps);
325 if (!surfaceDrawContext) {
326 SkDebugf("Could not allocate surfaceDrawContext");
327 return false;
328 }
329
331 GrProcessorTestData ptd(&random, direct, /*maxTreeDepth=*/1, std::size(views), views);
332 set_random_color_coverage_stages(&paint, &ptd, maxStages, maxLevels);
333 set_random_xpf(&paint, &ptd);
334 GrDrawRandomOp(&random, surfaceDrawContext.get(), std::move(paint));
335 }
336 // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes)
337 direct->flush(GrFlushInfo());
338 direct->submit(GrSyncCpu::kNo);
339
340 // Validate that GrFPs work correctly without an input.
343 nullptr,
347 /*label=*/{});
348 if (!sdc) {
349 SkDebugf("Could not allocate a surfaceDrawContext");
350 return false;
351 }
352
353 int fpFactoryCnt = GrFragmentProcessorTestFactory::Count();
354 for (int i = 0; i < fpFactoryCnt; ++i) {
355 // Since FP factories internally randomize, call each 10 times.
356 for (int j = 0; j < 10; ++j) {
357 GrProcessorTestData ptd(&random, direct, /*maxTreeDepth=*/1, std::size(views),
358 views);
359
362 auto fp = GrFragmentProcessorTestFactory::MakeIdx(i, &ptd);
363 auto blockFP = BlockInputFragmentProcessor::Make(std::move(fp));
364 paint.setColorFragmentProcessor(std::move(blockFP));
365 GrDrawRandomOp(&random, sdc.get(), std::move(paint));
366
367 direct->flush(GrFlushInfo());
368 direct->submit(GrSyncCpu::kNo);
369 }
370 }
371
372 return true;
373}
374#endif
375
377 int maxStages = 6;
378#ifdef SK_GL
379 auto context = ctxInfo.directContext();
380 if (skiatest::IsGLContextType(ctxInfo.type())) {
381 GrGLGpu* gpu = static_cast<GrGLGpu*>(context->priv().getGpu());
382 if (kGLES_GrGLStandard == gpu->glStandard()) {
383 // We've had issues with driver crashes and HW limits being exceeded with many effects on
384 // Android devices. We have passes on ARM devices with the default number of stages.
385 // TODO When we run ES 3.00 GLSL in more places, test again
386#ifdef SK_BUILD_FOR_ANDROID
387 if (gpu->ctxInfo().vendor() != GrGLVendor::kARM) {
388 maxStages = 1;
389 }
390#endif
391 // On iOS we can exceed the maximum number of varyings. http://skbug.com/6627.
392#ifdef SK_BUILD_FOR_IOS
393 maxStages = 3;
394#endif
395 }
396 // On Angle D3D we will hit a limit of out variables if we use too many stages. This is
397 // particularly true on D3D9 with a low limit on varyings and the fact that every varying is
398 // packed as though it has 4 components.
399 if (ctxInfo.type() == skgpu::ContextType::kANGLE_D3D9_ES2) {
400 maxStages = 2;
401 } else if (ctxInfo.type() == skgpu::ContextType::kANGLE_D3D11_ES2) {
402 maxStages = 3;
403 }
404 }
405#endif
406 return maxStages;
407}
408
410 // A full tree with 5 levels (31 nodes) may cause a program that exceeds shader limits
411 // (e.g. uniform or varying limits); maxTreeLevels should be a number from 1 to 4 inclusive.
412 int maxTreeLevels = 4;
413 if (skiatest::IsGLContextType(ctxInfo.type())) {
414 // On iOS we can exceed the maximum number of varyings. http://skbug.com/6627.
415#ifdef SK_BUILD_FOR_IOS
416 maxTreeLevels = 2;
417#endif
418#if defined(SK_BUILD_FOR_ANDROID) && defined(SK_GL)
419 GrGLGpu* gpu = static_cast<GrGLGpu*>(ctxInfo.directContext()->priv().getGpu());
420 // Tecno Spark 3 Pro with Power VR Rogue GE8300 will fail shader compiles with
421 // no message if the shader is particularly long.
422 if (gpu->ctxInfo().vendor() == GrGLVendor::kImagination) {
423 maxTreeLevels = 3;
424 }
425#endif
426 if (ctxInfo.type() == skgpu::ContextType::kANGLE_D3D9_ES2 ||
428 // On Angle D3D we will hit a limit of out variables if we use too many stages.
429 maxTreeLevels = 2;
430 }
431 }
432 return maxTreeLevels;
433}
434
436 int maxStages = get_programs_max_stages(ctxInfo);
437 if (maxStages == 0) {
438 return;
439 }
440 int maxLevels = get_programs_max_levels(ctxInfo);
441 if (maxLevels == 0) {
442 return;
443 }
444
446 maxLevels));
447}
448
450 // Set a locale that would cause shader compilation to fail because of , as decimal separator.
451 // skbug 3330
452#ifdef SK_BUILD_FOR_WIN
453 GrAutoLocaleSetter als("sv-SE");
454#else
455 GrAutoLocaleSetter als("sv_SE.UTF-8");
456#endif
457
458 // We suppress prints to avoid spew
460 opts.fSuppressPrints = true;
461 sk_gpu_test::GrContextFactory debugFactory(opts);
463}
const char * options
reporter
Definition: FontMgrTest.cpp:39
GrFragmentProcessor::ProgramImpl ProgramImpl
@ kGLES_GrGLStandard
Definition: GrGLTypes.h:22
#define GR_DEFINE_FRAGMENT_PROCESSOR_TEST(...)
#define GR_DECLARE_FRAGMENT_PROCESSOR_TEST
void GrDrawRandomOp(SkRandom *random, skgpu::ganesh::SurfaceDrawContext *sdc, GrPaint &&paint)
Definition: GrTest.cpp:74
GrColorType
Definition: GrTypesPriv.h:540
GrSurfaceOrigin
Definition: GrTypes.h:147
@ kBottomLeft_GrSurfaceOrigin
Definition: GrTypes.h:149
@ kTopLeft_GrSurfaceOrigin
Definition: GrTypes.h:148
static const int kRenderTargetWidth
static const uint32_t kMaxKeySize
static int get_programs_max_stages(const sk_gpu_test::ContextInfo &ctxInfo)
static const int kRenderTargetHeight
static int get_programs_max_levels(const sk_gpu_test::ContextInfo &ctxInfo)
DEF_GANESH_TEST(Programs, reporter, options, CtsEnforcement::kNever)
static void test_programs(skiatest::Reporter *reporter, const sk_gpu_test::ContextInfo &ctxInfo)
static std::unique_ptr< skgpu::ganesh::SurfaceDrawContext > random_surface_draw_context(GrRecordingContext *rContext, SkRandom *random, const GrCaps *caps)
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkBlendMode
Definition: SkBlendMode.h:38
@ kLastMode
last valid value
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
std::unique_ptr< GrFragmentProcessor > clone() const override
const char * name() const override
static std::unique_ptr< GrFragmentProcessor > Make(std::unique_ptr< GrFragmentProcessor > fp)
std::unique_ptr< ProgramImpl > onMakeProgramImpl() const override
const GrCaps * caps() const
Definition: GrCaps.h:57
bool mipmapSupport() const
Definition: GrCaps.h:72
GrBackendFormat getDefaultBackendFormat(GrColorType, GrRenderable) const
Definition: GrCaps.cpp:400
virtual int getRenderTargetSampleCount(int requestedCount, const GrBackendFormat &) const =0
skgpu::Swizzle getReadSwizzle(const GrBackendFormat &format, GrColorType colorType) const
Definition: GrCaps.cpp:443
bool submit(GrSyncCpu sync=GrSyncCpu::kNo)
GrSemaphoresSubmitted flush(const GrFlushInfo &info)
GrDirectContextPriv priv()
static bool ProgramUnitTest(GrDirectContext *, int maxStages, int maxLevels)
GrFragmentProcessor(ClassID classID, OptimizationFlags optimizationFlags)
GrFragmentProcessor * childProcessor(int index)
void registerChild(std::unique_ptr< GrFragmentProcessor > child, SkSL::SampleUsage sampleUsage=SkSL::SampleUsage::PassThrough())
GrGLVendor vendor() const
Definition: GrGLContext.h:40
GrGLStandard glStandard() const
Definition: GrGLGpu.h:105
const GrGLContextInfo & ctxInfo() const
Definition: GrGLGpu.h:104
static const GrXPFactory * Get(SkBlendMode blendMode)
@ kBlockInputFragmentProcessor_ClassID
Definition: GrProcessor.h:30
sk_sp< GrTextureProxy > createProxy(const GrBackendFormat &, SkISize dimensions, GrRenderable, int renderTargetSampleCnt, skgpu::Mipmapped, SkBackingFit, skgpu::Budgeted, GrProtected, std::string_view label, GrInternalSurfaceFlags=GrInternalSurfaceFlags::kNone, UseAllocator useAllocator=UseAllocator::kYes)
GrProxyProvider * proxyProvider()
bool nextBool()
Definition: SkRandom.h:117
const char * c_str() const
Definition: SkString.h:133
GrDirectContext * directContext() const
skgpu::ContextType type() const
static std::unique_ptr< SurfaceDrawContext > Make(GrRecordingContext *, GrColorType, sk_sp< GrSurfaceProxy >, sk_sp< SkColorSpace >, GrSurfaceOrigin, const SkSurfaceProps &)
const Paint & paint
Definition: color_source.cc:38
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
static bool b
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint32_t uint32_t * format
static float max(float r, float g, float b)
Definition: hsl.cpp:49
std::unique_ptr< GrFragmentProcessor > Make(std::unique_ptr< GrFragmentProcessor > src, std::unique_ptr< GrFragmentProcessor > dst, SkBlendMode mode, bool shareBlendLogic=true)
const GrXPFactory * Get(SkBlendMode mode)
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
const uint32_t fp
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
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 mode
Definition: switches.h:228
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
const myers::Point & get< 0 >(const myers::Segment &s)
Definition: Myers.h:80
@ kANGLE_D3D11_ES2
ANGLE on Direct3D9 OpenGL ES 2 context.
@ kANGLE_D3D9_ES2
OpenGL ES context.
Mipmapped
Definition: GpuTypes.h:53
bool IsRenderingContext(skgpu::ContextType type)
Definition: ContextType.cpp:88
void RunWithGaneshTestContexts(GrContextTestFn *testFn, ContextTypeFilterFn *filter, Reporter *reporter, const GrContextOptions &options)
bool IsGLContextType(skgpu::ContextType type)
Definition: SkSize.h:16