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. It relies on static intializers to work
9
10 #include "SkTypes.h"
11
12 #if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
13
14 #include "GrAutoLocaleSetter.h"
15 #include "GrContextFactory.h"
16 #include "GrContextPriv.h"
17 #include "GrDrawOpTest.h"
18 #include "GrDrawingManager.h"
19 #include "GrPipeline.h"
20 #include "GrRenderTargetContextPriv.h"
21 #include "GrResourceProvider.h"
22 #include "GrTest.h"
23 #include "GrXferProcessor.h"
24 #include "SkChecksum.h"
25 #include "SkRandom.h"
26 #include "Test.h"
27
28 #include "ops/GrDrawOp.h"
29
30 #include "effects/GrConfigConversionEffect.h"
31 #include "effects/GrPorterDuffXferProcessor.h"
32 #include "effects/GrXfermodeFragmentProcessor.h"
33
34 #include "gl/GrGLGpu.h"
35 #include "glsl/GrGLSLFragmentProcessor.h"
36 #include "glsl/GrGLSLFragmentShaderBuilder.h"
37 #include "glsl/GrGLSLProgramBuilder.h"
38
39 /*
40 * A dummy processor which just tries to insert a massive key and verify that it can retrieve the
41 * whole thing correctly
42 */
43 static const uint32_t kMaxKeySize = 1024;
44
45 class GLBigKeyProcessor : public GrGLSLFragmentProcessor {
46 public:
emitCode(EmitArgs & args)47 void emitCode(EmitArgs& args) override {
48 // pass through
49 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
50 if (args.fInputColor) {
51 fragBuilder->codeAppendf("%s = %s;\n", args.fOutputColor, args.fInputColor);
52 } else {
53 fragBuilder->codeAppendf("%s = vec4(1.0);\n", args.fOutputColor);
54 }
55 }
56
GenKey(const GrProcessor &,const GrShaderCaps &,GrProcessorKeyBuilder * b)57 static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder* b) {
58 for (uint32_t i = 0; i < kMaxKeySize; i++) {
59 b->add32(i);
60 }
61 }
62
63 private:
64 typedef GrGLSLFragmentProcessor INHERITED;
65 };
66
67 class BigKeyProcessor : public GrFragmentProcessor {
68 public:
Make()69 static sk_sp<GrFragmentProcessor> Make() {
70 return sk_sp<GrFragmentProcessor>(new BigKeyProcessor);
71 }
72
name() const73 const char* name() const override { return "Big Ole Key"; }
74
onCreateGLSLInstance() const75 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
76 return new GLBigKeyProcessor;
77 }
78
79 private:
BigKeyProcessor()80 BigKeyProcessor() : INHERITED(kNone_OptimizationFlags) { this->initClassID<BigKeyProcessor>(); }
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const81 virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
82 GrProcessorKeyBuilder* b) const override {
83 GLBigKeyProcessor::GenKey(*this, caps, b);
84 }
onIsEqual(const GrFragmentProcessor &) const85 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
86
87 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
88
89 typedef GrFragmentProcessor INHERITED;
90 };
91
92 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor);
93
94 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData *)95 sk_sp<GrFragmentProcessor> BigKeyProcessor::TestCreate(GrProcessorTestData*) {
96 return BigKeyProcessor::Make();
97 }
98 #endif
99
100 //////////////////////////////////////////////////////////////////////////////
101
102 class BlockInputFragmentProcessor : public GrFragmentProcessor {
103 public:
Make(sk_sp<GrFragmentProcessor> fp)104 static sk_sp<GrFragmentProcessor> Make(sk_sp<GrFragmentProcessor> fp) {
105 return sk_sp<GrFragmentProcessor>(new BlockInputFragmentProcessor(fp));
106 }
107
name() const108 const char* name() const override { return "Block Input"; }
109
onCreateGLSLInstance() const110 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLFP; }
111
112 private:
113 class GLFP : public GrGLSLFragmentProcessor {
114 public:
emitCode(EmitArgs & args)115 void emitCode(EmitArgs& args) override {
116 this->emitChild(0, nullptr, args);
117 }
118
119 private:
120 typedef GrGLSLFragmentProcessor INHERITED;
121 };
122
BlockInputFragmentProcessor(sk_sp<GrFragmentProcessor> child)123 BlockInputFragmentProcessor(sk_sp<GrFragmentProcessor> child)
124 : INHERITED(kNone_OptimizationFlags) {
125 this->initClassID<BlockInputFragmentProcessor>();
126 this->registerChildProcessor(std::move(child));
127 }
128
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const129 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {}
130
onIsEqual(const GrFragmentProcessor &) const131 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
132
133 typedef GrFragmentProcessor INHERITED;
134 };
135
136 //////////////////////////////////////////////////////////////////////////////
137
138 /*
139 * Begin test code
140 */
141 static const int kRenderTargetHeight = 1;
142 static const int kRenderTargetWidth = 1;
143
random_render_target_context(GrContext * context,SkRandom * random,const GrCaps * caps)144 static sk_sp<GrRenderTargetContext> random_render_target_context(GrContext* context,
145 SkRandom* random,
146 const GrCaps* caps) {
147 GrSurfaceOrigin origin = random->nextBool() ? kTopLeft_GrSurfaceOrigin
148 : kBottomLeft_GrSurfaceOrigin;
149 int sampleCnt = random->nextBool() ? SkTMin(4, caps->maxSampleCount()) : 0;
150
151 sk_sp<GrRenderTargetContext> renderTargetContext(context->makeRenderTargetContext(
152 SkBackingFit::kExact,
153 kRenderTargetWidth,
154 kRenderTargetHeight,
155 kRGBA_8888_GrPixelConfig,
156 nullptr,
157 sampleCnt,
158 origin));
159 return renderTargetContext;
160 }
161
162 #if GR_TEST_UTILS
set_random_xpf(GrPaint * paint,GrProcessorTestData * d)163 static void set_random_xpf(GrPaint* paint, GrProcessorTestData* d) {
164 paint->setXPFactory(GrXPFactoryTestFactory::Get(d));
165 }
166
create_random_proc_tree(GrProcessorTestData * d,int minLevels,int maxLevels)167 static sk_sp<GrFragmentProcessor> create_random_proc_tree(GrProcessorTestData* d,
168 int minLevels, int maxLevels) {
169 SkASSERT(1 <= minLevels);
170 SkASSERT(minLevels <= maxLevels);
171
172 // Return a leaf node if maxLevels is 1 or if we randomly chose to terminate.
173 // If returning a leaf node, make sure that it doesn't have children (e.g. another
174 // GrComposeEffect)
175 const float terminateProbability = 0.3f;
176 if (1 == minLevels) {
177 bool terminate = (1 == maxLevels) || (d->fRandom->nextF() < terminateProbability);
178 if (terminate) {
179 sk_sp<GrFragmentProcessor> fp;
180 while (true) {
181 fp = GrProcessorTestFactory<GrFragmentProcessor>::Make(d);
182 SkASSERT(fp);
183 if (0 == fp->numChildProcessors()) {
184 break;
185 }
186 }
187 return fp;
188 }
189 }
190 // If we didn't terminate, choose either the left or right subtree to fulfill
191 // the minLevels requirement of this tree; the other child can have as few levels as it wants.
192 // Also choose a random xfer mode.
193 if (minLevels > 1) {
194 --minLevels;
195 }
196 sk_sp<GrFragmentProcessor> minLevelsChild(create_random_proc_tree(d, minLevels, maxLevels - 1));
197 sk_sp<GrFragmentProcessor> otherChild(create_random_proc_tree(d, 1, maxLevels - 1));
198 SkBlendMode mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0,
199 (int)SkBlendMode::kLastMode));
200 sk_sp<GrFragmentProcessor> fp;
201 if (d->fRandom->nextF() < 0.5f) {
202 fp = GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(minLevelsChild),
203 std::move(otherChild), mode);
204 SkASSERT(fp);
205 } else {
206 fp = GrXfermodeFragmentProcessor::MakeFromTwoProcessors(std::move(otherChild),
207 std::move(minLevelsChild), mode);
208 SkASSERT(fp);
209 }
210 return fp;
211 }
212
set_random_color_coverage_stages(GrPaint * paint,GrProcessorTestData * d,int maxStages)213 static void set_random_color_coverage_stages(GrPaint* paint,
214 GrProcessorTestData* d,
215 int maxStages) {
216 // Randomly choose to either create a linear pipeline of procs or create one proc tree
217 const float procTreeProbability = 0.5f;
218 if (d->fRandom->nextF() < procTreeProbability) {
219 // A full tree with 5 levels (31 nodes) may cause a program that exceeds shader limits
220 // (e.g. uniform or varying limits); maxTreeLevels should be a number from 1 to 4 inclusive.
221 const int maxTreeLevels = 4;
222 sk_sp<GrFragmentProcessor> fp(create_random_proc_tree(d, 2, maxTreeLevels));
223 paint->addColorFragmentProcessor(std::move(fp));
224 } else {
225 int numProcs = d->fRandom->nextULessThan(maxStages + 1);
226 int numColorProcs = d->fRandom->nextULessThan(numProcs + 1);
227
228 for (int s = 0; s < numProcs;) {
229 sk_sp<GrFragmentProcessor> fp(GrProcessorTestFactory<GrFragmentProcessor>::Make(d));
230 SkASSERT(fp);
231
232 // finally add the stage to the correct pipeline in the drawstate
233 if (s < numColorProcs) {
234 paint->addColorFragmentProcessor(std::move(fp));
235 } else {
236 paint->addCoverageFragmentProcessor(std::move(fp));
237 }
238 ++s;
239 }
240 }
241 }
242
set_random_state(GrPaint * paint,SkRandom * random)243 static bool set_random_state(GrPaint* paint, SkRandom* random) {
244 if (random->nextBool()) {
245 paint->setDisableOutputConversionToSRGB(true);
246 }
247 if (random->nextBool()) {
248 paint->setAllowSRGBInputs(true);
249 }
250 return random->nextBool();
251 }
252
253 // right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'
get_random_stencil(SkRandom * random)254 static const GrUserStencilSettings* get_random_stencil(SkRandom* random) {
255 static constexpr GrUserStencilSettings kDoesWriteStencil(
256 GrUserStencilSettings::StaticInit<
257 0xffff,
258 GrUserStencilTest::kAlways,
259 0xffff,
260 GrUserStencilOp::kReplace,
261 GrUserStencilOp::kReplace,
262 0xffff>()
263 );
264 static constexpr GrUserStencilSettings kDoesNotWriteStencil(
265 GrUserStencilSettings::StaticInit<
266 0xffff,
267 GrUserStencilTest::kNever,
268 0xffff,
269 GrUserStencilOp::kKeep,
270 GrUserStencilOp::kKeep,
271 0xffff>()
272 );
273
274 if (random->nextBool()) {
275 return &kDoesWriteStencil;
276 } else {
277 return &kDoesNotWriteStencil;
278 }
279 }
280 #endif
281
282 #if !GR_TEST_UTILS
ProgramUnitTest(GrContext *,int)283 bool GrDrawingManager::ProgramUnitTest(GrContext*, int) { return true; }
284 #else
ProgramUnitTest(GrContext * context,int maxStages)285 bool GrDrawingManager::ProgramUnitTest(GrContext* context, int maxStages) {
286 GrDrawingManager* drawingManager = context->contextPriv().drawingManager();
287
288 // setup dummy textures
289 GrSurfaceDesc dummyDesc;
290 dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
291 dummyDesc.fConfig = kRGBA_8888_GrPixelConfig;
292 dummyDesc.fWidth = 34;
293 dummyDesc.fHeight = 18;
294 sk_sp<GrTexture> dummyTexture1(
295 context->resourceProvider()->createTexture(dummyDesc, SkBudgeted::kNo, nullptr, 0));
296 dummyDesc.fFlags = kNone_GrSurfaceFlags;
297 dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
298 dummyDesc.fWidth = 16;
299 dummyDesc.fHeight = 22;
300 sk_sp<GrTexture> dummyTexture2(
301 context->resourceProvider()->createTexture(dummyDesc, SkBudgeted::kNo, nullptr, 0));
302
303 if (!dummyTexture1 || ! dummyTexture2) {
304 SkDebugf("Could not allocate dummy textures");
305 return false;
306 }
307
308 GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
309
310 // dummy scissor state
311 GrScissorState scissor;
312
313 SkRandom random;
314 static const int NUM_TESTS = 1024;
315 for (int t = 0; t < NUM_TESTS; t++) {
316 // setup random render target(can fail)
317 sk_sp<GrRenderTargetContext> renderTargetContext(random_render_target_context(
318 context, &random, context->caps()));
319 if (!renderTargetContext) {
320 SkDebugf("Could not allocate renderTargetContext");
321 return false;
322 }
323
324 GrPaint grPaint;
325
326 std::unique_ptr<GrMeshDrawOp> op(GrRandomDrawOp(&random, context));
327 SkASSERT(op);
328
329 GrProcessorTestData ptd(&random, context, renderTargetContext.get(), dummyTextures);
330 set_random_color_coverage_stages(&grPaint, &ptd, maxStages);
331 set_random_xpf(&grPaint, &ptd);
332 bool snapToCenters = set_random_state(&grPaint, &random);
333 const GrUserStencilSettings* uss = get_random_stencil(&random);
334 // We don't use kHW because we will hit an assertion if the render target is not
335 // multisampled
336 static constexpr GrAAType kAATypes[] = {GrAAType::kNone, GrAAType::kCoverage};
337 GrAAType aaType = kAATypes[random.nextULessThan(SK_ARRAY_COUNT(kAATypes))];
338
339 renderTargetContext->priv().testingOnly_addMeshDrawOp(std::move(grPaint), aaType,
340 std::move(op), uss, snapToCenters);
341 }
342 // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes)
343 drawingManager->flush();
344
345 // Validate that GrFPs work correctly without an input.
346 sk_sp<GrRenderTargetContext> renderTargetContext(context->makeRenderTargetContext(
347 SkBackingFit::kExact,
348 kRenderTargetWidth,
349 kRenderTargetHeight,
350 kRGBA_8888_GrPixelConfig,
351 nullptr));
352 if (!renderTargetContext) {
353 SkDebugf("Could not allocate a renderTargetContext");
354 return false;
355 }
356
357 int fpFactoryCnt = GrProcessorTestFactory<GrFragmentProcessor>::Count();
358 for (int i = 0; i < fpFactoryCnt; ++i) {
359 // Since FP factories internally randomize, call each 10 times.
360 for (int j = 0; j < 10; ++j) {
361 std::unique_ptr<GrMeshDrawOp> op(GrRandomDrawOp(&random, context));
362 SkASSERT(op);
363 GrProcessorTestData ptd(&random, context, renderTargetContext.get(), dummyTextures);
364 GrPaint grPaint;
365 grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
366
367 sk_sp<GrFragmentProcessor> fp(
368 GrProcessorTestFactory<GrFragmentProcessor>::MakeIdx(i, &ptd));
369 sk_sp<GrFragmentProcessor> blockFP(
370 BlockInputFragmentProcessor::Make(std::move(fp)));
371 grPaint.addColorFragmentProcessor(std::move(blockFP));
372
373 renderTargetContext->priv().testingOnly_addMeshDrawOp(
374 std::move(grPaint), GrAAType::kNone, std::move(op));
375 drawingManager->flush();
376 }
377 }
378
379 return true;
380 }
381 #endif
382
get_glprograms_max_stages(GrContext * context)383 static int get_glprograms_max_stages(GrContext* context) {
384 GrGLGpu* gpu = static_cast<GrGLGpu*>(context->getGpu());
385 /*
386 * For the time being, we only support the test with desktop GL or for android on
387 * ARM platforms
388 * TODO When we run ES 3.00 GLSL in more places, test again
389 */
390 if (kGL_GrGLStandard == gpu->glStandard() ||
391 kARM_GrGLVendor == gpu->ctxInfo().vendor()) {
392 return 6;
393 } else if (kTegra3_GrGLRenderer == gpu->ctxInfo().renderer() ||
394 kOther_GrGLRenderer == gpu->ctxInfo().renderer()) {
395 return 1;
396 }
397 return 0;
398 }
399
test_glprograms_native(skiatest::Reporter * reporter,const sk_gpu_test::ContextInfo & ctxInfo)400 static void test_glprograms_native(skiatest::Reporter* reporter,
401 const sk_gpu_test::ContextInfo& ctxInfo) {
402 int maxStages = get_glprograms_max_stages(ctxInfo.grContext());
403 if (maxStages == 0) {
404 return;
405 }
406 REPORTER_ASSERT(reporter, GrDrawingManager::ProgramUnitTest(ctxInfo.grContext(), maxStages));
407 }
408
test_glprograms_other_contexts(skiatest::Reporter * reporter,const sk_gpu_test::ContextInfo & ctxInfo)409 static void test_glprograms_other_contexts(
410 skiatest::Reporter* reporter,
411 const sk_gpu_test::ContextInfo& ctxInfo) {
412 int maxStages = get_glprograms_max_stages(ctxInfo.grContext());
413 #ifdef SK_BUILD_FOR_WIN
414 // Some long shaders run out of temporary registers in the D3D compiler on ANGLE and
415 // command buffer.
416 maxStages = SkTMin(maxStages, 2);
417 #endif
418 if (maxStages == 0) {
419 return;
420 }
421 REPORTER_ASSERT(reporter, GrDrawingManager::ProgramUnitTest(ctxInfo.grContext(), maxStages));
422 }
423
is_native_gl_context_type(sk_gpu_test::GrContextFactory::ContextType type)424 static bool is_native_gl_context_type(sk_gpu_test::GrContextFactory::ContextType type) {
425 return type == sk_gpu_test::GrContextFactory::kGL_ContextType ||
426 type == sk_gpu_test::GrContextFactory::kGLES_ContextType;
427 }
428
is_other_rendering_gl_context_type(sk_gpu_test::GrContextFactory::ContextType type)429 static bool is_other_rendering_gl_context_type(sk_gpu_test::GrContextFactory::ContextType type) {
430 return !is_native_gl_context_type(type) &&
431 kOpenGL_GrBackend == sk_gpu_test::GrContextFactory::ContextTypeBackend(type) &&
432 sk_gpu_test::GrContextFactory::IsRenderingContext(type);
433 }
434
435 DEF_GPUTEST(GLPrograms, reporter, /*factory*/) {
436 // Set a locale that would cause shader compilation to fail because of , as decimal separator.
437 // skbug 3330
438 #ifdef SK_BUILD_FOR_WIN
439 GrAutoLocaleSetter als("sv-SE");
440 #else
441 GrAutoLocaleSetter als("sv_SE.UTF-8");
442 #endif
443
444 // We suppress prints to avoid spew
445 GrContextOptions opts;
446 opts.fSuppressPrints = true;
447 sk_gpu_test::GrContextFactory debugFactory(opts);
448 skiatest::RunWithGPUTestContexts(test_glprograms_native, &is_native_gl_context_type,
449 reporter, &debugFactory);
450 skiatest::RunWithGPUTestContexts(test_glprograms_other_contexts,
451 &is_other_rendering_gl_context_type, reporter, &debugFactory);
452 }
453
454 #endif
455