1 
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 // This is a GPU-backend specific test. It relies on static intializers to work
10 
11 #include "SkTypes.h"
12 
13 #if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
14 
15 #include "GrAutoLocaleSetter.h"
16 #include "GrBatch.h"
17 #include "GrBatchTest.h"
18 #include "GrContextFactory.h"
19 #include "GrInvariantOutput.h"
20 #include "GrPipeline.h"
21 #include "GrTest.h"
22 #include "GrXferProcessor.h"
23 #include "SkChecksum.h"
24 #include "SkRandom.h"
25 #include "Test.h"
26 #include "effects/GrConfigConversionEffect.h"
27 #include "effects/GrPorterDuffXferProcessor.h"
28 #include "gl/GrGLGpu.h"
29 #include "gl/GrGLPathRendering.h"
30 #include "gl/builders/GrGLProgramBuilder.h"
31 
32 /*
33  * A dummy processor which just tries to insert a massive key and verify that it can retrieve the
34  * whole thing correctly
35  */
36 static const uint32_t kMaxKeySize = 1024;
37 
38 class GLBigKeyProcessor : public GrGLFragmentProcessor {
39 public:
GLBigKeyProcessor(const GrProcessor &)40     GLBigKeyProcessor(const GrProcessor&) {}
41 
emitCode(GrGLFPBuilder * builder,const GrFragmentProcessor & fp,const char * outputColor,const char * inputColor,const TransformedCoordsArray &,const TextureSamplerArray &)42     virtual void emitCode(GrGLFPBuilder* builder,
43                           const GrFragmentProcessor& fp,
44                           const char* outputColor,
45                           const char* inputColor,
46                           const TransformedCoordsArray&,
47                           const TextureSamplerArray&) {
48         // pass through
49         GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
50         fsBuilder->codeAppendf("%s = %s;\n", outputColor, inputColor);
51     }
52 
GenKey(const GrProcessor & processor,const GrGLSLCaps &,GrProcessorKeyBuilder * b)53     static void GenKey(const GrProcessor& processor, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
54         for (uint32_t i = 0; i < kMaxKeySize; i++) {
55             b->add32(i);
56         }
57     }
58 
59 private:
60     typedef GrGLFragmentProcessor INHERITED;
61 };
62 
63 class BigKeyProcessor : public GrFragmentProcessor {
64 public:
Create()65     static GrFragmentProcessor* Create() {
66         GR_CREATE_STATIC_PROCESSOR(gBigKeyProcessor, BigKeyProcessor, ())
67         return SkRef(gBigKeyProcessor);
68     }
69 
name() const70     const char* name() const override { return "Big Ole Key"; }
71 
getGLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const72     virtual void getGLProcessorKey(const GrGLSLCaps& caps,
73                                    GrProcessorKeyBuilder* b) const override {
74         GLBigKeyProcessor::GenKey(*this, caps, b);
75     }
76 
createGLInstance() const77     GrGLFragmentProcessor* createGLInstance() const override {
78         return SkNEW_ARGS(GLBigKeyProcessor, (*this));
79     }
80 
81 private:
BigKeyProcessor()82     BigKeyProcessor() {
83         this->initClassID<BigKeyProcessor>();
84     }
onIsEqual(const GrFragmentProcessor &) const85     bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
onComputeInvariantOutput(GrInvariantOutput * inout) const86     void onComputeInvariantOutput(GrInvariantOutput* inout) const override { }
87 
88     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
89 
90     typedef GrFragmentProcessor INHERITED;
91 };
92 
93 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor);
94 
TestCreate(SkRandom *,GrContext *,const GrDrawTargetCaps &,GrTexture * [])95 GrFragmentProcessor* BigKeyProcessor::TestCreate(SkRandom*,
96                                                  GrContext*,
97                                                  const GrDrawTargetCaps&,
98                                                  GrTexture*[]) {
99     return BigKeyProcessor::Create();
100 }
101 
102 /*
103  * Begin test code
104  */
105 static const int kRenderTargetHeight = 1;
106 static const int kRenderTargetWidth = 1;
107 
random_render_target(GrContext * context,SkRandom * random,const GrDrawTargetCaps * caps)108 static GrRenderTarget* random_render_target(GrContext* context, SkRandom* random,
109                                             const GrDrawTargetCaps* caps) {
110     // setup render target
111     GrTextureParams params;
112     GrSurfaceDesc texDesc;
113     texDesc.fWidth = kRenderTargetWidth;
114     texDesc.fHeight = kRenderTargetHeight;
115     texDesc.fFlags = kRenderTarget_GrSurfaceFlag;
116     texDesc.fConfig = kRGBA_8888_GrPixelConfig;
117     texDesc.fOrigin = random->nextBool() == true ? kTopLeft_GrSurfaceOrigin :
118                                                    kBottomLeft_GrSurfaceOrigin;
119     texDesc.fSampleCnt = random->nextBool() == true ? SkTMin(4, caps->maxSampleCount()) : 0;
120 
121     GrUniqueKey key;
122     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
123     GrUniqueKey::Builder builder(&key, kDomain, 2);
124     builder[0] = texDesc.fOrigin;
125     builder[1] = texDesc.fSampleCnt;
126     builder.finish();
127 
128     GrTexture* texture = context->textureProvider()->findAndRefTextureByUniqueKey(key);
129     if (!texture) {
130         texture = context->textureProvider()->createTexture(texDesc, true);
131         if (texture) {
132             context->textureProvider()->assignUniqueKeyToTexture(key, texture);
133         }
134     }
135     return texture ? texture->asRenderTarget() : NULL;
136 }
137 
set_random_xpf(GrContext * context,const GrDrawTargetCaps & caps,GrPipelineBuilder * pipelineBuilder,SkRandom * random,GrTexture * dummyTextures[])138 static void set_random_xpf(GrContext* context, const GrDrawTargetCaps& caps,
139                            GrPipelineBuilder* pipelineBuilder, SkRandom* random,
140                            GrTexture* dummyTextures[]) {
141     SkAutoTUnref<const GrXPFactory> xpf(
142         GrProcessorTestFactory<GrXPFactory>::CreateStage(random, context, caps, dummyTextures));
143     SkASSERT(xpf);
144     pipelineBuilder->setXPFactory(xpf.get());
145 }
146 
set_random_color_coverage_stages(GrGLGpu * gpu,GrPipelineBuilder * pipelineBuilder,int maxStages,SkRandom * random,GrTexture * dummyTextures[])147 static void set_random_color_coverage_stages(GrGLGpu* gpu,
148                                              GrPipelineBuilder* pipelineBuilder,
149                                              int maxStages,
150                                              SkRandom* random,
151                                              GrTexture* dummyTextures[]) {
152     int numProcs = random->nextULessThan(maxStages + 1);
153     int numColorProcs = random->nextULessThan(numProcs + 1);
154 
155     for (int s = 0; s < numProcs;) {
156         SkAutoTUnref<const GrFragmentProcessor> fp(
157                 GrProcessorTestFactory<GrFragmentProcessor>::CreateStage(random,
158                                                                          gpu->getContext(),
159                                                                          *gpu->caps(),
160                                                                          dummyTextures));
161         SkASSERT(fp);
162 
163         // finally add the stage to the correct pipeline in the drawstate
164         if (s < numColorProcs) {
165             pipelineBuilder->addColorProcessor(fp);
166         } else {
167             pipelineBuilder->addCoverageProcessor(fp);
168         }
169         ++s;
170     }
171 }
172 
set_random_state(GrPipelineBuilder * pipelineBuilder,SkRandom * random)173 static void set_random_state(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
174     int state = 0;
175     for (int i = 1; i <= GrPipelineBuilder::kLast_Flag; i <<= 1) {
176         state |= random->nextBool() * i;
177     }
178 
179     // If we don't have an MSAA rendertarget then we have to disable useHWAA
180     if ((state | GrPipelineBuilder::kHWAntialias_Flag) &&
181         !pipelineBuilder->getRenderTarget()->isMultisampled()) {
182         state &= ~GrPipelineBuilder::kHWAntialias_Flag;
183     }
184     pipelineBuilder->enableState(state);
185 }
186 
187 // right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'
set_random_stencil(GrPipelineBuilder * pipelineBuilder,SkRandom * random)188 static void set_random_stencil(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
189     GR_STATIC_CONST_SAME_STENCIL(kDoesWriteStencil,
190                                  kReplace_StencilOp,
191                                  kReplace_StencilOp,
192                                  kAlways_StencilFunc,
193                                  0xffff,
194                                  0xffff,
195                                  0xffff);
196     GR_STATIC_CONST_SAME_STENCIL(kDoesNotWriteStencil,
197                                  kKeep_StencilOp,
198                                  kKeep_StencilOp,
199                                  kNever_StencilFunc,
200                                  0xffff,
201                                  0xffff,
202                                  0xffff);
203 
204     if (random->nextBool()) {
205         pipelineBuilder->setStencil(kDoesWriteStencil);
206     } else {
207         pipelineBuilder->setStencil(kDoesNotWriteStencil);
208     }
209 }
210 
programUnitTest(int maxStages)211 bool GrDrawTarget::programUnitTest(int maxStages) {
212     GrGLGpu* gpu = static_cast<GrGLGpu*>(fContext->getGpu());
213     // setup dummy textures
214     GrSurfaceDesc dummyDesc;
215     dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
216     dummyDesc.fConfig = kSkia8888_GrPixelConfig;
217     dummyDesc.fWidth = 34;
218     dummyDesc.fHeight = 18;
219     SkAutoTUnref<GrTexture> dummyTexture1(gpu->createTexture(dummyDesc, false, NULL, 0));
220     dummyDesc.fFlags = kNone_GrSurfaceFlags;
221     dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
222     dummyDesc.fWidth = 16;
223     dummyDesc.fHeight = 22;
224     SkAutoTUnref<GrTexture> dummyTexture2(gpu->createTexture(dummyDesc, false, NULL, 0));
225 
226     if (!dummyTexture1 || ! dummyTexture2) {
227         SkDebugf("Could not allocate dummy textures");
228         return false;
229     }
230 
231     GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
232 
233     // dummy scissor state
234     GrScissorState scissor;
235 
236     // wide open clip
237     GrClip clip;
238 
239     SkRandom random;
240     static const int NUM_TESTS = 2048;
241     for (int t = 0; t < NUM_TESTS; t++) {
242         // setup random render target(can fail)
243         SkAutoTUnref<GrRenderTarget> rt(random_render_target(fContext, &random, this->caps()));
244         if (!rt.get()) {
245             SkDebugf("Could not allocate render target");
246             return false;
247         }
248 
249         GrPipelineBuilder pipelineBuilder;
250         pipelineBuilder.setRenderTarget(rt.get());
251         pipelineBuilder.setClip(clip);
252 
253         SkAutoTUnref<GrBatch> batch(GrRandomBatch(&random, fContext));
254         SkASSERT(batch);
255 
256         set_random_color_coverage_stages(gpu,
257                                          &pipelineBuilder,
258                                          maxStages,
259                                          &random,
260                                          dummyTextures);
261 
262         // creates a random xfer processor factory on the draw state
263         set_random_xpf(fContext, gpu->glCaps(), &pipelineBuilder, &random, dummyTextures);
264 
265         set_random_state(&pipelineBuilder, &random);
266         set_random_stencil(&pipelineBuilder, &random);
267 
268         this->drawBatch(&pipelineBuilder, batch);
269     }
270 
271     // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes)
272     this->flush();
273     return true;
274 }
275 
DEF_GPUTEST(GLPrograms,reporter,factory)276 DEF_GPUTEST(GLPrograms, reporter, factory) {
277     // Set a locale that would cause shader compilation to fail because of , as decimal separator.
278     // skbug 3330
279 #ifdef SK_BUILD_FOR_WIN
280     GrAutoLocaleSetter als("sv-SE");
281 #else
282     GrAutoLocaleSetter als("sv_SE.UTF-8");
283 #endif
284 
285     // We suppress prints to avoid spew
286     GrContext::Options opts;
287     opts.fSuppressPrints = true;
288     GrContextFactory debugFactory(opts);
289     for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
290         GrContext* context = debugFactory.get(static_cast<GrContextFactory::GLContextType>(type));
291         if (context) {
292             GrGLGpu* gpu = static_cast<GrGLGpu*>(context->getGpu());
293 
294             /*
295              * For the time being, we only support the test with desktop GL or for android on
296              * ARM platforms
297              * TODO When we run ES 3.00 GLSL in more places, test again
298              */
299             int maxStages;
300             if (kGL_GrGLStandard == gpu->glStandard() ||
301                 kARM_GrGLVendor == gpu->ctxInfo().vendor()) {
302                 maxStages = 6;
303             } else if (kTegra3_GrGLRenderer == gpu->ctxInfo().renderer() ||
304                        kOther_GrGLRenderer == gpu->ctxInfo().renderer()) {
305                 maxStages = 1;
306             } else {
307                 return;
308             }
309 #if SK_ANGLE
310             // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
311             if (type == GrContextFactory::kANGLE_GLContextType) {
312                 maxStages = 2;
313             }
314 #endif
315             GrTestTarget target;
316             context->getTestTarget(&target);
317             REPORTER_ASSERT(reporter, target.target()->programUnitTest(maxStages));
318         }
319     }
320 }
321 
322 #endif
323