• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "gl/GrGpuGL.h"
16 #include "GrBackendEffectFactory.h"
17 #include "GrContextFactory.h"
18 #include "GrDrawEffect.h"
19 #include "effects/GrConfigConversionEffect.h"
20 
21 #include "SkChecksum.h"
22 #include "SkRandom.h"
23 #include "Test.h"
24 
setRandom(SkRandom * random,const GrGpuGL * gpu,const GrRenderTarget * dstRenderTarget,const GrTexture * dstCopyTexture,const GrEffectStage * stages[],int numColorStages,int numCoverageStages,int currAttribIndex)25 void GrGLProgramDesc::setRandom(SkRandom* random,
26                                 const GrGpuGL* gpu,
27                                 const GrRenderTarget* dstRenderTarget,
28                                 const GrTexture* dstCopyTexture,
29                                 const GrEffectStage* stages[],
30                                 int numColorStages,
31                                 int numCoverageStages,
32                                 int currAttribIndex) {
33     int numEffects = numColorStages + numCoverageStages;
34     size_t keyLength = KeyLength(numEffects);
35     fKey.reset(keyLength);
36     *this->atOffset<uint32_t, kLengthOffset>() = static_cast<uint32_t>(keyLength);
37     memset(this->header(), 0, kHeaderSize);
38 
39     KeyHeader* header = this->header();
40     header->fEmitsPointSize = random->nextBool();
41 
42     header->fPositionAttributeIndex = 0;
43 
44     // if the effects have used up all off the available attributes,
45     // don't try to use color or coverage attributes as input
46     do {
47         header->fColorInput = static_cast<GrGLProgramDesc::ColorInput>(
48                                   random->nextULessThan(kColorInputCnt));
49     } while (GrDrawState::kMaxVertexAttribCnt <= currAttribIndex &&
50              kAttribute_ColorInput == header->fColorInput);
51     header->fColorAttributeIndex = (header->fColorInput == kAttribute_ColorInput) ?
52                                         currAttribIndex++ :
53                                         -1;
54 
55     do {
56         header->fCoverageInput = static_cast<GrGLProgramDesc::ColorInput>(
57                                      random->nextULessThan(kColorInputCnt));
58     } while (GrDrawState::kMaxVertexAttribCnt <= currAttribIndex  &&
59              kAttribute_ColorInput == header->fCoverageInput);
60     header->fCoverageAttributeIndex = (header->fCoverageInput == kAttribute_ColorInput) ?
61                                         currAttribIndex++ :
62                                         -1;
63 
64 #if GR_GL_EXPERIMENTAL_GS
65     header->fExperimentalGS = gpu->caps()->geometryShaderSupport() && random->nextBool();
66 #endif
67 
68     header->fDiscardIfZeroCoverage = random->nextBool();
69 
70     bool useLocalCoords = random->nextBool() && currAttribIndex < GrDrawState::kMaxVertexAttribCnt;
71     header->fLocalCoordAttributeIndex = useLocalCoords ? currAttribIndex++ : -1;
72 
73     header->fColorEffectCnt = numColorStages;
74     header->fCoverageEffectCnt = numCoverageStages;
75 
76     bool dstRead = false;
77     bool fragPos = false;
78     bool vertexCode = false;
79     int numStages = numColorStages + numCoverageStages;
80     for (int s = 0; s < numStages; ++s) {
81         const GrBackendEffectFactory& factory = (*stages[s]->getEffect())->getFactory();
82         GrDrawEffect drawEffect(*stages[s], useLocalCoords);
83         this->effectKeys()[s] = factory.glEffectKey(drawEffect, gpu->glCaps());
84         if ((*stages[s]->getEffect())->willReadDstColor()) {
85             dstRead = true;
86         }
87         if ((*stages[s]->getEffect())->willReadFragmentPosition()) {
88             fragPos = true;
89         }
90         if ((*stages[s]->getEffect())->hasVertexCode()) {
91             vertexCode = true;
92         }
93     }
94 
95     if (dstRead) {
96         header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
97     } else {
98         header->fDstReadKey = 0;
99     }
100     if (fragPos) {
101         header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(dstRenderTarget,
102                                                                          gpu->glCaps());
103     } else {
104         header->fFragPosKey = 0;
105     }
106 
107     header->fHasVertexCode = vertexCode ||
108                              useLocalCoords ||
109                              kAttribute_ColorInput == header->fColorInput ||
110                              kAttribute_ColorInput == header->fCoverageInput;
111 
112     CoverageOutput coverageOutput;
113     bool illegalCoverageOutput;
114     do {
115         coverageOutput = static_cast<CoverageOutput>(random->nextULessThan(kCoverageOutputCnt));
116         illegalCoverageOutput = (!gpu->caps()->dualSourceBlendingSupport() &&
117                                  CoverageOutputUsesSecondaryOutput(coverageOutput)) ||
118                                 (!dstRead && kCombineWithDst_CoverageOutput == coverageOutput);
119     } while (illegalCoverageOutput);
120 
121     header->fCoverageOutput = coverageOutput;
122 
123     *this->checksum() = 0;
124     *this->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(fKey.get()), keyLength);
125     fInitialized = true;
126 }
127 
programUnitTest(int maxStages)128 bool GrGpuGL::programUnitTest(int maxStages) {
129 
130     GrTextureDesc dummyDesc;
131     dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit;
132     dummyDesc.fConfig = kSkia8888_GrPixelConfig;
133     dummyDesc.fWidth = 34;
134     dummyDesc.fHeight = 18;
135     SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
136     dummyDesc.fFlags = kNone_GrTextureFlags;
137     dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
138     dummyDesc.fWidth = 16;
139     dummyDesc.fHeight = 22;
140     SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));
141 
142     static const int NUM_TESTS = 512;
143 
144     SkRandom random;
145     for (int t = 0; t < NUM_TESTS; ++t) {
146 
147 #if 0
148         GrPrintf("\nTest Program %d\n-------------\n", t);
149         static const int stop = -1;
150         if (t == stop) {
151             int breakpointhere = 9;
152         }
153 #endif
154 
155         GrGLProgramDesc pdesc;
156 
157         int currAttribIndex = 1;  // we need to always leave room for position
158         int currTextureCoordSet = 0;
159         int attribIndices[2];
160         GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
161 
162         int numStages = random.nextULessThan(maxStages + 1);
163         int numColorStages = random.nextULessThan(numStages + 1);
164         int numCoverageStages = numStages - numColorStages;
165 
166         SkAutoSTMalloc<8, const GrEffectStage*> stages(numStages);
167 
168         bool useFixedFunctionTexturing = this->shouldUseFixedFunctionTexturing();
169 
170         for (int s = 0; s < numStages;) {
171             SkAutoTUnref<const GrEffectRef> effect(GrEffectTestFactory::CreateStage(
172                                                                             &random,
173                                                                             this->getContext(),
174                                                                             *this->caps(),
175                                                                             dummyTextures));
176             int numAttribs = (*effect)->numVertexAttribs();
177 
178             // If adding this effect would exceed the max attrib count then generate a
179             // new random effect.
180             if (currAttribIndex + numAttribs > GrDrawState::kMaxVertexAttribCnt) {
181                 continue;
182             }
183 
184 
185             // If adding this effect would exceed the max texture coord set count then generate a
186             // new random effect.
187             if (useFixedFunctionTexturing && !(*effect)->hasVertexCode()) {
188                 int numTransforms = (*effect)->numTransforms();
189                 if (currTextureCoordSet + numTransforms > this->glCaps().maxFixedFunctionTextureCoords()) {
190                     continue;
191                 }
192                 currTextureCoordSet += numTransforms;
193             }
194 
195             useFixedFunctionTexturing = useFixedFunctionTexturing && !(*effect)->hasVertexCode();
196 
197             for (int i = 0; i < numAttribs; ++i) {
198                 attribIndices[i] = currAttribIndex++;
199             }
200             GrEffectStage* stage = SkNEW_ARGS(GrEffectStage,
201                                               (effect.get(), attribIndices[0], attribIndices[1]));
202             stages[s] = stage;
203             ++s;
204         }
205         const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1];
206         pdesc.setRandom(&random,
207                         this,
208                         dummyTextures[0]->asRenderTarget(),
209                         dstTexture,
210                         stages.get(),
211                         numColorStages,
212                         numCoverageStages,
213                         currAttribIndex);
214 
215         SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this,
216                                                               pdesc,
217                                                               stages,
218                                                               stages + numColorStages));
219         for (int s = 0; s < numStages; ++s) {
220             SkDELETE(stages[s]);
221         }
222         if (NULL == program.get()) {
223             return false;
224         }
225     }
226     return true;
227 }
228 
GLProgramsTest(skiatest::Reporter * reporter,GrContextFactory * factory)229 static void GLProgramsTest(skiatest::Reporter* reporter, GrContextFactory* factory) {
230     for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
231         GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(type));
232         if (NULL != context) {
233             GrGpuGL* gpu = static_cast<GrGpuGL*>(context->getGpu());
234             int maxStages = 6;
235 #if SK_ANGLE
236             // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
237             if (type == GrContextFactory::kANGLE_GLContextType) {
238                 maxStages = 3;
239             }
240 #endif
241             REPORTER_ASSERT(reporter, gpu->programUnitTest(maxStages));
242         }
243     }
244 }
245 
246 #include "TestClassDef.h"
247 DEFINE_GPUTESTCLASS("GLPrograms", GLProgramsTestClass, GLProgramsTest)
248 
249 // This is evil evil evil. The linker may throw away whole translation units as dead code if it
250 // thinks none of the functions are called. It will do this even if there are static initializers
251 // in the unit that could pass pointers to functions from the unit out to other translation units!
252 // We force some of the effects that would otherwise be discarded to link here.
253 
254 #include "SkLightingImageFilter.h"
255 #include "SkMagnifierImageFilter.h"
256 #include "SkColorMatrixFilter.h"
257 #include "SkBitmapAlphaThresholdShader.h"
258 
259 void forceLinking();
260 
forceLinking()261 void forceLinking() {
262     SkLightingImageFilter::CreateDistantLitDiffuse(SkPoint3(0,0,0), 0, 0, 0);
263     SkMagnifierImageFilter mag(SkRect::MakeWH(SK_Scalar1, SK_Scalar1), SK_Scalar1);
264     GrConfigConversionEffect::Create(NULL,
265                                      false,
266                                      GrConfigConversionEffect::kNone_PMConversion,
267                                      SkMatrix::I());
268     SkScalar matrix[20];
269     SkColorMatrixFilter cmf(matrix);
270     SkBitmapAlphaThresholdShader::Create(SkBitmap(), SkRegion(), 0x80);
271 }
272 
273 #endif
274