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