• 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 "GrBackendProcessorFactory.h"
16 #include "GrContextFactory.h"
17 #include "GrOptDrawState.h"
18 #include "effects/GrConfigConversionEffect.h"
19 #include "gl/GrGLPathRendering.h"
20 #include "gl/GrGpuGL.h"
21 #include "SkChecksum.h"
22 #include "SkRandom.h"
23 #include "Test.h"
24 
get_stage_stats(const GrFragmentStage stage,bool * readsDst,bool * readsFragPosition,bool * requiresVertexShader)25 static void get_stage_stats(const GrFragmentStage stage, bool* readsDst,
26                             bool* readsFragPosition, bool* requiresVertexShader) {
27     if (stage.getFragmentProcessor()->willReadDstColor()) {
28         *readsDst = true;
29     }
30     if (stage.getProcessor()->willReadFragmentPosition()) {
31         *readsFragPosition = true;
32     }
33 }
34 
setRandom(SkRandom * random,GrGpuGL * gpu,const GrRenderTarget * dstRenderTarget,const GrTexture * dstCopyTexture,const GrGeometryStage * geometryProcessor,const GrFragmentStage * stages[],int numColorStages,int numCoverageStages,int currAttribIndex,GrGpu::DrawType drawType)35 bool GrGLProgramDesc::setRandom(SkRandom* random,
36                                 GrGpuGL* gpu,
37                                 const GrRenderTarget* dstRenderTarget,
38                                 const GrTexture* dstCopyTexture,
39                                 const GrGeometryStage* geometryProcessor,
40                                 const GrFragmentStage* stages[],
41                                 int numColorStages,
42                                 int numCoverageStages,
43                                 int currAttribIndex,
44                                 GrGpu::DrawType drawType) {
45     bool isPathRendering = GrGpu::IsPathRenderingDrawType(drawType);
46     bool useLocalCoords = !isPathRendering &&
47                           random->nextBool() &&
48                           currAttribIndex < GrDrawState::kMaxVertexAttribCnt;
49 
50     int numStages = numColorStages + numCoverageStages;
51     fKey.reset();
52 
53     GR_STATIC_ASSERT(0 == kEffectKeyOffsetsAndLengthOffset % sizeof(uint32_t));
54 
55     // Make room for everything up to and including the array of offsets to effect keys.
56     fKey.push_back_n(kEffectKeyOffsetsAndLengthOffset + 2 * sizeof(uint16_t) * (numStages +
57             (geometryProcessor ? 1 : 0)));
58 
59     bool dstRead = false;
60     bool fragPos = false;
61     bool vertexShader = SkToBool(geometryProcessor);
62     int offset = 0;
63     if (geometryProcessor) {
64         const GrGeometryStage* stage = geometryProcessor;
65         uint16_t* offsetAndSize = reinterpret_cast<uint16_t*>(fKey.begin() +
66                                                               kEffectKeyOffsetsAndLengthOffset +
67                                                               offset * 2 * sizeof(uint16_t));
68         uint32_t effectKeyOffset = fKey.count();
69         if (effectKeyOffset > SK_MaxU16) {
70             fKey.reset();
71             return false;
72         }
73         GrProcessorKeyBuilder b(&fKey);
74         uint16_t effectKeySize;
75         if (!GetProcessorKey(*stage, gpu->glCaps(), useLocalCoords, &b, &effectKeySize)) {
76             fKey.reset();
77             return false;
78         }
79         vertexShader = true;
80         fragPos = stage->getProcessor()->willReadFragmentPosition();
81         offsetAndSize[0] = effectKeyOffset;
82         offsetAndSize[1] = effectKeySize;
83         offset++;
84     }
85 
86     for (int s = 0; s < numStages; ++s, ++offset) {
87         const GrFragmentStage* stage = stages[s];
88         uint16_t* offsetAndSize = reinterpret_cast<uint16_t*>(fKey.begin() +
89                                                               kEffectKeyOffsetsAndLengthOffset +
90                                                               offset * 2 * sizeof(uint16_t));
91         uint32_t effectKeyOffset = fKey.count();
92         if (effectKeyOffset > SK_MaxU16) {
93             fKey.reset();
94             return false;
95         }
96         GrProcessorKeyBuilder b(&fKey);
97         uint16_t effectKeySize;
98         if (!GetProcessorKey(*stages[s], gpu->glCaps(), useLocalCoords, &b, &effectKeySize)) {
99             fKey.reset();
100             return false;
101         }
102         get_stage_stats(*stage, &dstRead, &fragPos, &vertexShader);
103         offsetAndSize[0] = effectKeyOffset;
104         offsetAndSize[1] = effectKeySize;
105     }
106 
107     KeyHeader* header = this->header();
108     memset(header, 0, kHeaderSize);
109     header->fEmitsPointSize = random->nextBool();
110 
111     header->fPositionAttributeIndex = 0;
112 
113     // if the effects have used up all off the available attributes,
114     // don't try to use color or coverage attributes as input
115     do {
116         header->fColorInput = static_cast<GrGLProgramDesc::ColorInput>(
117                                      random->nextULessThan(kColorInputCnt));
118     } while ((GrDrawState::kMaxVertexAttribCnt <= currAttribIndex || isPathRendering) &&
119              kAttribute_ColorInput == header->fColorInput);
120     header->fColorAttributeIndex = (header->fColorInput == kAttribute_ColorInput) ?
121                                         currAttribIndex++ :
122                                         -1;
123 
124     do {
125         header->fCoverageInput = static_cast<GrGLProgramDesc::ColorInput>(
126                                      random->nextULessThan(kColorInputCnt));
127     } while ((GrDrawState::kMaxVertexAttribCnt <= currAttribIndex || isPathRendering)  &&
128              kAttribute_ColorInput == header->fCoverageInput);
129     header->fCoverageAttributeIndex = (header->fCoverageInput == kAttribute_ColorInput) ?
130                                         currAttribIndex++ :
131                                         -1;
132     bool useGS = random->nextBool();
133 #if GR_GL_EXPERIMENTAL_GS
134     header->fExperimentalGS = gpu->caps()->geometryShaderSupport() && useGS;
135 #else
136     (void) useGS;
137 #endif
138 
139     header->fLocalCoordAttributeIndex = useLocalCoords ? currAttribIndex++ : -1;
140 
141     header->fColorEffectCnt = numColorStages;
142     header->fCoverageEffectCnt = numCoverageStages;
143 
144     if (dstRead) {
145         header->fDstReadKey = SkToU8(GrGLFragmentShaderBuilder::KeyForDstRead(dstCopyTexture,
146                                                                       gpu->glCaps()));
147     } else {
148         header->fDstReadKey = 0;
149     }
150     if (fragPos) {
151         header->fFragPosKey = SkToU8(GrGLFragmentShaderBuilder::KeyForFragmentPosition(dstRenderTarget,
152                                                                                gpu->glCaps()));
153     } else {
154         header->fFragPosKey = 0;
155     }
156 
157     header->fUseFragShaderOnly = isPathRendering && gpu->glPathRendering()->texturingMode() ==
158                                                     GrGLPathRendering::FixedFunction_TexturingMode;
159     header->fHasGeometryProcessor = vertexShader;
160 
161     GrOptDrawState::PrimaryOutputType primaryOutput;
162     GrOptDrawState::SecondaryOutputType secondaryOutput;
163     if (!dstRead) {
164         primaryOutput = GrOptDrawState::kModulate_PrimaryOutputType;
165     } else {
166         primaryOutput = static_cast<GrOptDrawState::PrimaryOutputType>(
167             random->nextULessThan(GrOptDrawState::kPrimaryOutputTypeCnt));
168     }
169 
170     if (GrOptDrawState::kCombineWithDst_PrimaryOutputType == primaryOutput ||
171         !gpu->caps()->dualSourceBlendingSupport()) {
172         secondaryOutput = GrOptDrawState::kNone_SecondaryOutputType;
173     } else {
174         secondaryOutput = static_cast<GrOptDrawState::SecondaryOutputType>(
175             random->nextULessThan(GrOptDrawState::kSecondaryOutputTypeCnt));
176     }
177 
178     header->fPrimaryOutputType = primaryOutput;
179     header->fSecondaryOutputType = secondaryOutput;
180 
181     this->finalize();
182     return true;
183 }
184 
185 // TODO clean this up, we have to do this to test geometry processors but there has got to be
186 // a better way.  In the mean time, we actually fill out these generic vertex attribs below with
187 // the correct vertex attribs from the GP.  We have to ensure, however, we don't try to add more
188 // than two attributes.
189 GrVertexAttrib genericVertexAttribs[] = {
190     { kVec2f_GrVertexAttribType, 0,   kPosition_GrVertexAttribBinding },
191     { kVec2f_GrVertexAttribType, 0,   kGeometryProcessor_GrVertexAttribBinding },
192     { kVec2f_GrVertexAttribType, 0,   kGeometryProcessor_GrVertexAttribBinding }
193 };
194 
195 /*
196  * convert sl type to vertexattrib type, not a complete implementation, only use for debugging
197  */
convert_sltype_to_attribtype(GrSLType type)198 GrVertexAttribType convert_sltype_to_attribtype(GrSLType type) {
199     switch (type) {
200         case kFloat_GrSLType:
201             return kFloat_GrVertexAttribType;
202         case kVec2f_GrSLType:
203             return kVec2f_GrVertexAttribType;
204         case kVec3f_GrSLType:
205             return kVec3f_GrVertexAttribType;
206         case kVec4f_GrSLType:
207             return kVec4f_GrVertexAttribType;
208         default:
209             SkFAIL("Type isn't convertible");
210             return kFloat_GrVertexAttribType;
211     }
212 }
213 // TODO end test hack
214 
215 
programUnitTest(int maxStages)216 bool GrGpuGL::programUnitTest(int maxStages) {
217 
218     GrTextureDesc dummyDesc;
219     dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit;
220     dummyDesc.fConfig = kSkia8888_GrPixelConfig;
221     dummyDesc.fWidth = 34;
222     dummyDesc.fHeight = 18;
223     SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
224     dummyDesc.fFlags = kNone_GrTextureFlags;
225     dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
226     dummyDesc.fWidth = 16;
227     dummyDesc.fHeight = 22;
228     SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));
229 
230     if (!dummyTexture1 || ! dummyTexture2) {
231         return false;
232     }
233 
234     static const int NUM_TESTS = 512;
235 
236     SkRandom random;
237     for (int t = 0; t < NUM_TESTS; ++t) {
238 
239 #if 0
240         GrPrintf("\nTest Program %d\n-------------\n", t);
241         static const int stop = -1;
242         if (t == stop) {
243             int breakpointhere = 9;
244         }
245 #endif
246 
247         GrGLProgramDesc pdesc;
248 
249         int currAttribIndex = 1;  // we need to always leave room for position
250         int currTextureCoordSet = 0;
251         GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
252 
253         int numStages = random.nextULessThan(maxStages + 1);
254         int numColorStages = random.nextULessThan(numStages + 1);
255         int numCoverageStages = numStages - numColorStages;
256 
257         SkAutoSTMalloc<8, const GrFragmentStage*> stages(numStages);
258 
259         bool usePathRendering = this->glCaps().pathRenderingSupport() && random.nextBool();
260 
261         GrGpu::DrawType drawType = usePathRendering ? GrGpu::kDrawPath_DrawType :
262                                                       GrGpu::kDrawPoints_DrawType;
263 
264         SkAutoTDelete<GrGeometryStage> geometryProcessor;
265         bool hasGeometryProcessor = usePathRendering ? false : random.nextBool();
266         if (hasGeometryProcessor) {
267             while (true) {
268                 SkAutoTUnref<const GrGeometryProcessor> effect(
269                         GrProcessorTestFactory<GrGeometryProcessor>::CreateStage(&random, this->getContext(), *this->caps(),
270                                                          dummyTextures));
271                 SkASSERT(effect);
272                 // Only geometryProcessor can use vertex shader
273                 GrGeometryStage* stage = SkNEW_ARGS(GrGeometryStage, (effect.get()));
274                 geometryProcessor.reset(stage);
275 
276                 // we have to set dummy vertex attribs
277                 const GrGeometryProcessor::VertexAttribArray& v = effect->getVertexAttribs();
278                 int numVertexAttribs = v.count();
279 
280                 SkASSERT(GrGeometryProcessor::kMaxVertexAttribs == 2 &&
281                          GrGeometryProcessor::kMaxVertexAttribs >= numVertexAttribs);
282                 size_t runningStride = GrVertexAttribTypeSize(genericVertexAttribs[0].fType);
283                 for (int i = 0; i < numVertexAttribs; i++) {
284                     genericVertexAttribs[i + 1].fOffset = runningStride;
285                     genericVertexAttribs[i + 1].fType =
286                             convert_sltype_to_attribtype(v[i].getType());
287                     runningStride += GrVertexAttribTypeSize(genericVertexAttribs[i + 1].fType);
288                 }
289 
290                 // update the vertex attributes with the ds
291                 GrDrawState* ds = this->drawState();
292                 ds->setVertexAttribs<genericVertexAttribs>(numVertexAttribs + 1, runningStride);
293                 currAttribIndex = numVertexAttribs + 1;
294                 break;
295             }
296         }
297         for (int s = 0; s < numStages;) {
298             SkAutoTUnref<const GrFragmentProcessor> effect(
299                     GrProcessorTestFactory<GrFragmentProcessor>::CreateStage(
300                                                                             &random,
301                                                                             this->getContext(),
302                                                                             *this->caps(),
303                                                                             dummyTextures));
304             SkASSERT(effect);
305 
306             // If adding this effect would exceed the max texture coord set count then generate a
307             // new random effect.
308             if (usePathRendering && this->glPathRendering()->texturingMode() ==
309                                     GrGLPathRendering::FixedFunction_TexturingMode) {;
310                 int numTransforms = effect->numTransforms();
311                 if (currTextureCoordSet + numTransforms > this->glCaps().maxFixedFunctionTextureCoords()) {
312                     continue;
313                 }
314                 currTextureCoordSet += numTransforms;
315             }
316             GrFragmentStage* stage = SkNEW_ARGS(GrFragmentStage, (effect.get()));
317 
318             stages[s] = stage;
319             ++s;
320         }
321         const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1];
322         if (!pdesc.setRandom(&random,
323                              this,
324                              dummyTextures[0]->asRenderTarget(),
325                              dstTexture,
326                              geometryProcessor.get(),
327                              stages.get(),
328                              numColorStages,
329                              numCoverageStages,
330                              currAttribIndex,
331                              drawType)) {
332             return false;
333         }
334 
335         SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this,
336                                                               pdesc,
337                                                               geometryProcessor.get(),
338                                                               stages,
339                                                               stages + numColorStages));
340         for (int s = 0; s < numStages; ++s) {
341             SkDELETE(stages[s]);
342         }
343         if (NULL == program.get()) {
344             return false;
345         }
346 
347         // We have to reset the drawstate because we might have added a gp
348         this->drawState()->reset();
349     }
350     return true;
351 }
352 
DEF_GPUTEST(GLPrograms,reporter,factory)353 DEF_GPUTEST(GLPrograms, reporter, factory) {
354     for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
355         GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(type));
356         if (context) {
357             GrGpuGL* gpu = static_cast<GrGpuGL*>(context->getGpu());
358             int maxStages = 6;
359 #if SK_ANGLE
360             // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
361             if (type == GrContextFactory::kANGLE_GLContextType) {
362                 maxStages = 3;
363             }
364 #endif
365             REPORTER_ASSERT(reporter, gpu->programUnitTest(maxStages));
366         }
367     }
368 }
369 
370 // This is evil evil evil. The linker may throw away whole translation units as dead code if it
371 // thinks none of the functions are called. It will do this even if there are static initializers
372 // in the unit that could pass pointers to functions from the unit out to other translation units!
373 // We force some of the effects that would otherwise be discarded to link here.
374 
375 #include "SkAlphaThresholdFilter.h"
376 #include "SkColorMatrixFilter.h"
377 #include "SkLightingImageFilter.h"
378 #include "SkMagnifierImageFilter.h"
379 
380 void forceLinking();
381 
forceLinking()382 void forceLinking() {
383     SkLightingImageFilter::CreateDistantLitDiffuse(SkPoint3(0,0,0), 0, 0, 0);
384     SkAlphaThresholdFilter::Create(SkRegion(), .5f, .5f);
385     SkAutoTUnref<SkImageFilter> mag(SkMagnifierImageFilter::Create(
386         SkRect::MakeWH(SK_Scalar1, SK_Scalar1), SK_Scalar1));
387     GrConfigConversionEffect::Create(NULL,
388                                      false,
389                                      GrConfigConversionEffect::kNone_PMConversion,
390                                      SkMatrix::I());
391     SkScalar matrix[20];
392     SkAutoTUnref<SkColorMatrixFilter> cmf(SkColorMatrixFilter::Create(matrix));
393 }
394 
395 #endif
396