b2204b4b2b68f2f3a98f1c54757a7e471d23dd69
[platform/upstream/libSkiaSharp.git] / tests / GLProgramsTest.cpp
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 "GrContextFactory.h"
17 #include "GrInvariantOutput.h"
18 #include "GrPipeline.h"
19 #include "GrTest.h"
20 #include "GrXferProcessor.h"
21 #include "SkChecksum.h"
22 #include "SkRandom.h"
23 #include "Test.h"
24 #include "effects/GrConfigConversionEffect.h"
25 #include "effects/GrPorterDuffXferProcessor.h"
26 #include "gl/GrGLGpu.h"
27 #include "gl/GrGLPathRendering.h"
28 #include "gl/builders/GrGLProgramBuilder.h"
29
30 /*
31  * A dummy processor which just tries to insert a massive key and verify that it can retrieve the
32  * whole thing correctly
33  */
34 static const uint32_t kMaxKeySize = 1024;
35
36 class GLBigKeyProcessor : public GrGLFragmentProcessor {
37 public:
38     GLBigKeyProcessor(const GrProcessor&) {}
39
40     virtual void emitCode(GrGLFPBuilder* builder,
41                           const GrFragmentProcessor& fp,
42                           const char* outputColor,
43                           const char* inputColor,
44                           const TransformedCoordsArray&,
45                           const TextureSamplerArray&) {}
46
47     static void GenKey(const GrProcessor& processor, const GrGLCaps&, GrProcessorKeyBuilder* b) {
48         for (uint32_t i = 0; i < kMaxKeySize; i++) {
49             b->add32(i);
50         }
51     }
52
53 private:
54     typedef GrGLFragmentProcessor INHERITED;
55 };
56
57 class BigKeyProcessor : public GrFragmentProcessor {
58 public:
59     static GrFragmentProcessor* Create() {
60         GR_CREATE_STATIC_PROCESSOR(gBigKeyProcessor, BigKeyProcessor, ())
61         return SkRef(gBigKeyProcessor);
62     }
63
64     const char* name() const SK_OVERRIDE { return "Big Ole Key"; }
65
66     virtual void getGLProcessorKey(const GrGLCaps& caps,
67                                    GrProcessorKeyBuilder* b) const SK_OVERRIDE {
68         GLBigKeyProcessor::GenKey(*this, caps, b);
69     }
70
71     GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE {
72         return SkNEW_ARGS(GLBigKeyProcessor, (*this));
73     }
74
75 private:
76     BigKeyProcessor() {
77         this->initClassID<BigKeyProcessor>();
78     }
79     bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE { return true; }
80     void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE { }
81
82     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
83
84     typedef GrFragmentProcessor INHERITED;
85 };
86
87 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor);
88
89 GrFragmentProcessor* BigKeyProcessor::TestCreate(SkRandom*,
90                                                  GrContext*,
91                                                  const GrDrawTargetCaps&,
92                                                  GrTexture*[]) {
93     return BigKeyProcessor::Create();
94 }
95
96 /*
97  * Begin test code
98  */
99 static const int kRenderTargetHeight = 1;
100 static const int kRenderTargetWidth = 1;
101
102 static GrRenderTarget* random_render_target(GrContext* context, SkRandom* random) {
103     // setup render target
104     GrTextureParams params;
105     GrSurfaceDesc texDesc;
106     texDesc.fWidth = kRenderTargetWidth;
107     texDesc.fHeight = kRenderTargetHeight;
108     texDesc.fFlags = kRenderTarget_GrSurfaceFlag;
109     texDesc.fConfig = kRGBA_8888_GrPixelConfig;
110     texDesc.fOrigin = random->nextBool() == true ? kTopLeft_GrSurfaceOrigin :
111                                                    kBottomLeft_GrSurfaceOrigin;
112     GrUniqueKey key;
113     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
114     GrUniqueKey::Builder builder(&key, kDomain, 1);
115     builder[0] = texDesc.fOrigin;
116     builder.finish();
117
118     GrTexture* texture = context->findAndRefCachedTexture(key);
119     if (!texture) {
120         texture = context->createTexture(texDesc, true);
121         if (texture) {
122             context->addResourceToCache(key, texture);
123         }
124     }
125     return texture ? texture->asRenderTarget() : NULL;
126 }
127
128 static void set_random_xpf(GrContext* context, const GrDrawTargetCaps& caps,
129                            GrPipelineBuilder* pipelineBuilder, SkRandom* random,
130                            GrTexture* dummyTextures[]) {
131     SkAutoTUnref<const GrXPFactory> xpf(
132         GrProcessorTestFactory<GrXPFactory>::CreateStage(random, context, caps, dummyTextures));
133     SkASSERT(xpf);
134     pipelineBuilder->setXPFactory(xpf.get());
135 }
136
137 static const GrGeometryProcessor* get_random_gp(GrContext* context,
138                                                 const GrDrawTargetCaps& caps,
139                                                 SkRandom* random,
140                                                 GrTexture* dummyTextures[]) {
141     return GrProcessorTestFactory<GrGeometryProcessor>::CreateStage(random,
142                                                                     context,
143                                                                     caps,
144                                                                     dummyTextures);
145 }
146
147 static void set_random_color_coverage_stages(GrGLGpu* gpu,
148                                              GrPipelineBuilder* pipelineBuilder,
149                                              int maxStages,
150                                              bool usePathRendering,
151                                              SkRandom* random,
152                                              GrTexture* dummyTextures[]) {
153     int numProcs = random->nextULessThan(maxStages + 1);
154     int numColorProcs = random->nextULessThan(numProcs + 1);
155
156     int currTextureCoordSet = 0;
157     for (int s = 0; s < numProcs;) {
158         SkAutoTUnref<const GrFragmentProcessor> fp(
159                 GrProcessorTestFactory<GrFragmentProcessor>::CreateStage(random,
160                                                                          gpu->getContext(),
161                                                                          *gpu->caps(),
162                                                                          dummyTextures));
163         SkASSERT(fp);
164
165         // If adding this effect would exceed the max texture coord set count then generate a
166         // new random effect.
167         if (usePathRendering && gpu->glPathRendering()->texturingMode() ==
168                                 GrGLPathRendering::FixedFunction_TexturingMode) {;
169             int numTransforms = fp->numTransforms();
170             if (currTextureCoordSet + numTransforms >
171                 gpu->glCaps().maxFixedFunctionTextureCoords()) {
172                 continue;
173             }
174             currTextureCoordSet += numTransforms;
175         }
176
177         // finally add the stage to the correct pipeline in the drawstate
178         if (s < numColorProcs) {
179             pipelineBuilder->addColorProcessor(fp);
180         } else {
181             pipelineBuilder->addCoverageProcessor(fp);
182         }
183         ++s;
184     }
185 }
186
187 static void set_random_state(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
188     int state = 0;
189     for (int i = 1; i <= GrPipelineBuilder::kLast_StateBit; i <<= 1) {
190         state |= random->nextBool() * i;
191     }
192     pipelineBuilder->enableState(state);
193 }
194
195 // right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'
196 static void set_random_stencil(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
197     GR_STATIC_CONST_SAME_STENCIL(kDoesWriteStencil,
198                                  kReplace_StencilOp,
199                                  kReplace_StencilOp,
200                                  kAlways_StencilFunc,
201                                  0xffff,
202                                  0xffff,
203                                  0xffff);
204     GR_STATIC_CONST_SAME_STENCIL(kDoesNotWriteStencil,
205                                  kKeep_StencilOp,
206                                  kKeep_StencilOp,
207                                  kNever_StencilFunc,
208                                  0xffff,
209                                  0xffff,
210                                  0xffff);
211
212     if (random->nextBool()) {
213         pipelineBuilder->setStencil(kDoesWriteStencil);
214     } else {
215         pipelineBuilder->setStencil(kDoesNotWriteStencil);
216     }
217 }
218
219 bool GrDrawTarget::programUnitTest(int maxStages) {
220     GrGLGpu* gpu = static_cast<GrGLGpu*>(fContext->getGpu());
221     // setup dummy textures
222     GrSurfaceDesc dummyDesc;
223     dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
224     dummyDesc.fConfig = kSkia8888_GrPixelConfig;
225     dummyDesc.fWidth = 34;
226     dummyDesc.fHeight = 18;
227     SkAutoTUnref<GrTexture> dummyTexture1(gpu->createTexture(dummyDesc, false, NULL, 0));
228     dummyDesc.fFlags = kNone_GrSurfaceFlags;
229     dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
230     dummyDesc.fWidth = 16;
231     dummyDesc.fHeight = 22;
232     SkAutoTUnref<GrTexture> dummyTexture2(gpu->createTexture(dummyDesc, false, NULL, 0));
233
234     if (!dummyTexture1 || ! dummyTexture2) {
235         SkDebugf("Could not allocate dummy textures");
236         return false;
237     }
238
239     GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
240
241     // dummy scissor state
242     GrScissorState scissor;
243
244     // setup clip
245     SkRect screen = SkRect::MakeWH(SkIntToScalar(kRenderTargetWidth),
246                                    SkIntToScalar(kRenderTargetHeight));
247
248     SkClipStack stack;
249     stack.clipDevRect(screen, SkRegion::kReplace_Op, false);
250
251     // wrap the SkClipStack in a GrClip
252     GrClip clip;
253     clip.setClipStack(&stack);
254
255     SkRandom random;
256     static const int NUM_TESTS = 512;
257     for (int t = 0; t < NUM_TESTS;) {
258         // setup random render target(can fail)
259         SkAutoTUnref<GrRenderTarget> rt(random_render_target(fContext, &random));
260         if (!rt.get()) {
261             SkDebugf("Could not allocate render target");
262             return false;
263         }
264
265         GrPipelineBuilder pipelineBuilder;
266         pipelineBuilder.setRenderTarget(rt.get());
267         pipelineBuilder.setClip(clip);
268
269         // if path rendering we have to setup a couple of things like the draw type
270         bool usePathRendering = gpu->glCaps().pathRenderingSupport() && random.nextBool();
271
272         // twiddle drawstate knobs randomly
273         bool hasGeometryProcessor = !usePathRendering;
274         SkAutoTUnref<const GrGeometryProcessor> gp;
275         SkAutoTUnref<const GrPathProcessor> pathProc;
276         if (hasGeometryProcessor) {
277             gp.reset(get_random_gp(fContext, gpu->glCaps(), &random, dummyTextures));
278         } else {
279             pathProc.reset(GrPathProcessor::Create(GrColor_WHITE));
280         }
281         set_random_color_coverage_stages(gpu,
282                                          &pipelineBuilder,
283                                          maxStages - hasGeometryProcessor,
284                                          usePathRendering,
285                                          &random,
286                                          dummyTextures);
287
288         // creates a random xfer processor factory on the draw state 
289         set_random_xpf(fContext, gpu->glCaps(), &pipelineBuilder, &random, dummyTextures);
290
291         set_random_state(&pipelineBuilder, &random);
292         set_random_stencil(&pipelineBuilder, &random);
293
294         GrDeviceCoordTexture dstCopy;
295
296         const GrPrimitiveProcessor* primProc;
297         if (hasGeometryProcessor) {
298             primProc = gp.get();
299         } else {
300             primProc = pathProc.get();
301         }
302
303         const GrProcOptInfo& colorPOI = pipelineBuilder.colorProcInfo(primProc);
304         const GrProcOptInfo& coveragePOI = pipelineBuilder.coverageProcInfo(primProc);
305
306         if (!this->setupDstReadIfNecessary(pipelineBuilder, colorPOI, coveragePOI, &dstCopy,
307                                            NULL)) {
308             SkDebugf("Couldn't setup dst read texture");
309             return false;
310         }
311
312         // create optimized draw state, setup readDst texture if required, and build a descriptor
313         // and program.  ODS creation can fail, so we have to check
314         GrPipeline pipeline(pipelineBuilder, colorPOI, coveragePOI,
315                             *gpu->caps(), scissor, &dstCopy);
316         if (pipeline.mustSkip()) {
317             continue;
318         }
319         GrBatchTracker bt;
320         primProc->initBatchTracker(&bt, pipeline.getInitBatchTracker());
321
322         GrProgramDesc desc;
323         gpu->buildProgramDesc(&desc, *primProc, pipeline, bt);
324
325         GrGpu::DrawArgs args(primProc, &pipeline, &desc, &bt);
326         SkAutoTUnref<GrGLProgram> program(GrGLProgramBuilder::CreateProgram(args, gpu));
327
328         if (NULL == program.get()) {
329             SkDebugf("Failed to create program!");
330             return false;
331         }
332
333         // because occasionally optimized drawstate creation will fail for valid reasons, we only
334         // want to increment on success
335         ++t;
336     }
337     return true;
338 }
339
340 DEF_GPUTEST(GLPrograms, reporter, factory) {
341     // Set a locale that would cause shader compilation to fail because of , as decimal separator.
342     // skbug 3330
343 #ifdef SK_BUILD_FOR_WIN
344     GrAutoLocaleSetter als("sv-SE");
345 #else
346     GrAutoLocaleSetter als("sv_SE.UTF-8");
347 #endif
348
349     for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
350         GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(type));
351         if (context) {
352             GrGLGpu* gpu = static_cast<GrGLGpu*>(context->getGpu());
353
354             /*
355              * For the time being, we only support the test with desktop GL or for android on
356              * ARM platforms
357              * TODO When we run ES 3.00 GLSL in more places, test again
358              */
359             int maxStages;
360             if (kGL_GrGLStandard == gpu->glStandard() ||
361                 kARM_GrGLVendor == gpu->ctxInfo().vendor()) {
362                 maxStages = 6;
363             } else if (kTegra3_GrGLRenderer == gpu->ctxInfo().renderer() ||
364                        kOther_GrGLRenderer == gpu->ctxInfo().renderer()) {
365                 maxStages = 1;
366             } else {
367                 return;
368             }
369 #if SK_ANGLE
370             // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
371             if (type == GrContextFactory::kANGLE_GLContextType) {
372                 maxStages = 2;
373             }
374 #endif
375             GrTestTarget target;
376             context->getTestTarget(&target);
377             REPORTER_ASSERT(reporter, target.target()->programUnitTest(maxStages));
378         }
379     }
380 }
381
382 #endif