Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
167 const GrBackendFormat format = caps->getDefaultBackendFormat(ct, GrRenderable::kYes);
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,
181 skgpu::Mipmapped::kNo,
182 GrProtected::kNo,
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) {
205 fp = GrFragmentProcessorTestFactory::Make(d);
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};
281 GrRenderable::kYes);
282 auto proxy = proxyProvider->createProxy(format,
283 kDims,
284 GrRenderable::kYes,
285 1,
286 mipmapped,
289 GrProtected::kNo,
290 /*label=*/{},
293 views[0] = {{std::move(proxy), kBottomLeft_GrSurfaceOrigin, swizzle},
295 }
296 {
297 static constexpr SkISize kDims = {16, 22};
299 GrRenderable::kNo);
300 auto proxy = proxyProvider->createProxy(format,
301 kDims,
302 GrRenderable::kNo,
303 1,
304 mipmapped,
307 GrProtected::kNo,
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 ||
427 ctxInfo.type() == skgpu::ContextType::kANGLE_D3D11_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
@ 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
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)
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
static std::unique_ptr< SkEncoder > Make(SkWStream *dst, const SkPixmap *src, const SkYUVAPixmaps *srcYUVA, const SkColorSpace *srcYUVAColorSpace, const SkJpegEncoder::Options &options)
#define INHERITED(method,...)
#define DEF_GANESH_TEST(name, reporter, options, ctsEnforcement)
Definition Test.h:393
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
std::unique_ptr< GrFragmentProcessor > clone() const override
const char * name() const override
bool onIsEqual(const GrFragmentProcessor &) const override
static std::unique_ptr< GrFragmentProcessor > Make(std::unique_ptr< GrFragmentProcessor > fp)
std::unique_ptr< ProgramImpl > onMakeProgramImpl() const override
void onAddToKey(const GrShaderCaps &, skgpu::KeyBuilder *) const override
const GrCaps * caps() const
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)
SkString invokeChild(int childIndex, EmitArgs &parentArgs, std::string_view skslCoords={})
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
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
const char * name
Definition fuchsia.cc:50
std::unique_ptr< GrFragmentProcessor > Make(std::unique_ptr< GrFragmentProcessor > src, std::unique_ptr< GrFragmentProcessor > dst, SkBlendMode mode, bool shareBlendLogic=true)
const uint32_t fp
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
Mipmapped
Definition GpuTypes.h:53
bool IsRenderingContext(skgpu::ContextType type)
void RunWithGaneshTestContexts(GrContextTestFn *testFn, ContextTypeFilterFn *filter, Reporter *reporter, const GrContextOptions &options)
bool IsGLContextType(skgpu::ContextType type)