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