blob: 199cc4989d7e3f67f251ec20cec0034dc05524bd [file] [log] [blame]
bsalomon@google.coma8e686e2011-08-16 15:45:58 +00001
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
bsalomon@google.comd4726202012-08-03 14:34:46 +00009// This is a GPU-backend specific test. It relies on static intializers to work
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000010
bsalomon@google.com2a48c3a2012-08-03 14:54:45 +000011#include "SkTypes.h"
12
13#if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
14
bsalomon@google.com5739d2c2012-05-31 15:07:19 +000015#include "gl/GrGpuGL.h"
bsalomon@google.comc3841b92012-08-02 18:11:43 +000016#include "effects/GrColorTableEffect.h"
17#include "effects/GrConvolutionEffect.h"
bsalomon@google.comc3841b92012-08-02 18:11:43 +000018#include "effects/GrMorphologyEffect.h"
19#include "SkLightingImageFilter.h"
20#include "GrProgramStageFactory.h"
21#include "GrRandom.h"
22#include "Test.h"
23
24namespace {
25
26// GrRandoms nextU() values have patterns in the low bits
27// So using nextU() % array_count might never take some values.
28int random_int(GrRandom* r, int count) {
29 return (int)(r->nextF() * count);
30}
31
32// min is inclusive, max is exclusive
33int random_int(GrRandom* r, int min, int max) {
34 return (int)(r->nextF() * (max-min)) + min;
35}
36
37bool random_bool(GrRandom* r) {
38 return r->nextF() > .5f;
39}
40
41SkPoint3 random_point3(GrRandom* r) {
42 return SkPoint3(r->nextF(), r->nextF(), r->nextF());
43}
44
bsalomon@google.comc3841b92012-08-02 18:11:43 +000045typedef GrGLProgram::StageDesc StageDesc;
46// TODO: Effects should be able to register themselves for inclusion in the
47// randomly generated shaders. They should be able to configure themselves
48// randomly.
bsalomon@google.comd4726202012-08-03 14:34:46 +000049const GrCustomStage* create_random_effect(StageDesc* stageDesc,
50 GrRandom* random,
51 GrContext* context,
52 GrTexture* dummyTextures[]) {
bsalomon@google.comc3841b92012-08-02 18:11:43 +000053 enum EffectType {
54 kConvolution_EffectType,
55 kErode_EffectType,
56 kDilate_EffectType,
bsalomon@google.comd4726202012-08-03 14:34:46 +000057 /**
58 * Lighting effects don't work in unit test because they assume they insert functions and
59 * assume the names are unique. This breaks when there are two light effects in the same
60 * shader.
61 */
62 /*
bsalomon@google.comc3841b92012-08-02 18:11:43 +000063 kDiffuseDistant_EffectType,
64 kDiffusePoint_EffectType,
65 kDiffuseSpot_EffectType,
66 kSpecularDistant_EffectType,
67 kSpecularPoint_EffectType,
68 kSpecularSpot_EffectType,
bsalomon@google.comd4726202012-08-03 14:34:46 +000069 */
70
bsalomon@google.comc3841b92012-08-02 18:11:43 +000071 kColorTable_EffectType,
72
73 kEffectCount
74 };
75
76 // TODO: Remove this when generator doesn't apply this non-custom-stage
77 // notion to custom stages automatically.
78 static const uint32_t kMulByAlphaMask =
79 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
80 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
81
82 static const Gr1DKernelEffect::Direction gKernelDirections[] = {
83 Gr1DKernelEffect::kX_Direction,
84 Gr1DKernelEffect::kY_Direction
85 };
86
bsalomon@google.comd4726202012-08-03 14:34:46 +000087 // The new code uses SkRandom not GrRandom.
88 // TODO: Remove GrRandom.
89 SkRandom sk_random;
90 sk_random.setSeed(random->nextU());
91
92 bool useFactory = random_bool(random);
93 if (useFactory) {
94 GrCustomStage* stage = GrCustomStageTestFactory::CreateStage(&sk_random,
95 context,
96 dummyTextures);
97 GrAssert(stage);
98 return stage;
99 }
100
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000101
102 // TODO: When matrices are property of the custom-stage then remove the
103 // no-persp flag code below.
104 int effect = random_int(random, kEffectCount);
105 switch (effect) {
106 case kConvolution_EffectType: {
107 int direction = random_int(random, 2);
108 int kernelRadius = random_int(random, 1, 4);
109 float kernel[GrConvolutionEffect::kMaxKernelWidth];
110 for (int i = 0; i < GrConvolutionEffect::kMaxKernelWidth; i++) {
111 kernel[i] = random->nextF();
112 }
113 // does not work with perspective or mul-by-alpha-mask
114 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
115 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
116 return SkNEW_ARGS(GrConvolutionEffect,
117 (NULL,
118 gKernelDirections[direction],
119 kernelRadius,
120 kernel));
121 }
122 case kErode_EffectType: {
123 int direction = random_int(random, 2);
124 int kernelRadius = random_int(random, 1, 4);
125 // does not work with perspective or mul-by-alpha-mask
126 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
127 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
128 return SkNEW_ARGS(GrMorphologyEffect,
129 (NULL,
130 gKernelDirections[direction],
131 kernelRadius,
132 GrContext::kErode_MorphologyType));
133 }
134 case kDilate_EffectType: {
135 int direction = random_int(random, 2);
136 int kernelRadius = random_int(random, 1, 4);
137 // does not work with perspective or mul-by-alpha-mask
138 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
139 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
140 return SkNEW_ARGS(GrMorphologyEffect,
141 (NULL,
142 gKernelDirections[direction],
143 kernelRadius,
144 GrContext::kDilate_MorphologyType));
145 }
bsalomon@google.comd4726202012-08-03 14:34:46 +0000146 /*
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000147 case kDiffuseDistant_EffectType: {
148 SkPoint3 direction = random_point3(random);
149 direction.normalize();
150 SkColor lightColor = random->nextU();
151 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
152 SkScalar kd = SkFloatToScalar(random->nextF());
153 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitDiffuse(direction, lightColor, surfaceScale, kd));
154 // does not work with perspective or mul-by-alpha-mask
155 GrCustomStage* stage;
156 bool ok = filter->asNewCustomStage(&stage, NULL);
157 SkASSERT(ok);
158 return stage;
159 }
160 case kDiffusePoint_EffectType: {
161 SkPoint3 location = random_point3(random);
162 SkColor lightColor = random->nextU();
163 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
164 SkScalar kd = SkFloatToScalar(random->nextF());
165 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitDiffuse(location, lightColor, surfaceScale, kd));
166 // does not work with perspective or mul-by-alpha-mask
167 GrCustomStage* stage;
168 bool ok = filter->asNewCustomStage(&stage, NULL);
169 SkASSERT(ok);
170 return stage;
171 }
172 case kDiffuseSpot_EffectType: {
173 SkPoint3 location = random_point3(random);
174 SkPoint3 target = random_point3(random);
175 SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
176 SkScalar specularExponent = SkFloatToScalar(random->nextF());
177 SkColor lightColor = random->nextU();
178 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
179 SkScalar ks = SkFloatToScalar(random->nextF());
180 SkScalar shininess = SkFloatToScalar(random->nextF());
181 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
182 location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
183 // does not work with perspective or mul-by-alpha-mask
184 GrCustomStage* stage;
185 bool ok = filter->asNewCustomStage(&stage, NULL);
186 SkASSERT(ok);
187 return stage;
188 }
189 case kSpecularDistant_EffectType: {
190 SkPoint3 direction = random_point3(random);
191 direction.normalize();
192 SkColor lightColor = random->nextU();
193 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
194 SkScalar ks = SkFloatToScalar(random->nextF());
195 SkScalar shininess = SkFloatToScalar(random->nextF());
196 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitSpecular(direction, lightColor, surfaceScale, ks, shininess));
197 // does not work with perspective or mul-by-alpha-mask
198 GrCustomStage* stage;
199 bool ok = filter->asNewCustomStage(&stage, NULL);
200 SkASSERT(ok);
201 return stage;
202 }
203 case kSpecularPoint_EffectType: {
204 SkPoint3 location = random_point3(random);
205 SkColor lightColor = random->nextU();
206 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
207 SkScalar ks = SkFloatToScalar(random->nextF());
208 SkScalar shininess = SkFloatToScalar(random->nextF());
209 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitSpecular(location, lightColor, surfaceScale, ks, shininess));
210 // does not work with perspective or mul-by-alpha-mask
211 GrCustomStage* stage;
212 bool ok = filter->asNewCustomStage(&stage, NULL);
213 SkASSERT(ok);
214 return stage;
215 }
216 case kSpecularSpot_EffectType: {
217 SkPoint3 location = random_point3(random);
218 SkPoint3 target = random_point3(random);
219 SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
220 SkScalar specularExponent = SkFloatToScalar(random->nextF());
221 SkColor lightColor = random->nextU();
222 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
223 SkScalar ks = SkFloatToScalar(random->nextF());
224 SkScalar shininess = SkFloatToScalar(random->nextF());
225 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
226 location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
227 // does not work with perspective or mul-by-alpha-mask
228 GrCustomStage* stage;
229 bool ok = filter->asNewCustomStage(&stage, NULL);
230 SkASSERT(ok);
231 return stage;
232 }
bsalomon@google.comd4726202012-08-03 14:34:46 +0000233 */
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000234 case kColorTable_EffectType: {
bsalomon@google.comd4726202012-08-03 14:34:46 +0000235 GrTexture* alphaTexture = dummyTextures[GrCustomStageTestFactory::kAlphaTextureIdx];
236 return SkNEW_ARGS(GrColorTableEffect, (alphaTexture));
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000237 }
238 default:
239 GrCrash("Unexpected custom effect type");
240 }
241 return NULL;
242}
243}
244
245bool GrGpuGL::programUnitTest() {
246
bsalomon@google.comd4726202012-08-03 14:34:46 +0000247 GrTextureDesc dummyDesc;
248 dummyDesc.fConfig = kSkia8888_PM_GrPixelConfig;
249 dummyDesc.fWidth = 34;
250 dummyDesc.fHeight = 18;
251 SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
252 dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
253 dummyDesc.fWidth = 16;
254 dummyDesc.fHeight = 22;
255 SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));
256
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000257 // GrGLSLGeneration glslGeneration =
258 GrGetGLSLGeneration(this->glBinding(), this->glInterface());
259 static const int STAGE_OPTS[] = {
260 0,
261 StageDesc::kNoPerspective_OptFlagBit,
262 };
263 static const int IN_CONFIG_FLAGS[] = {
264 StageDesc::kNone_InConfigFlag,
265 StageDesc::kSwapRAndB_InConfigFlag,
266 StageDesc::kSwapRAndB_InConfigFlag |
267 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag,
268 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag,
269 StageDesc::kSmearAlpha_InConfigFlag,
270 StageDesc::kSmearRed_InConfigFlag,
271 };
272
273 static const int NUM_TESTS = 512;
274
275 GrRandom random;
276 for (int t = 0; t < NUM_TESTS; ++t) {
277
278#if 0
279 GrPrintf("\nTest Program %d\n-------------\n", t);
280 static const int stop = -1;
281 if (t == stop) {
282 int breakpointhere = 9;
283 }
284#endif
285
286 ProgramDesc pdesc;
287 pdesc.fVertexLayout = 0;
288 pdesc.fEmitsPointSize = random.nextF() > .5f;
289 pdesc.fColorInput = random_int(&random, ProgramDesc::kColorInputCnt);
290 pdesc.fCoverageInput = random_int(&random, ProgramDesc::kColorInputCnt);
291
292 pdesc.fColorFilterXfermode = random_int(&random, SkXfermode::kCoeffModesCnt);
293
294 pdesc.fFirstCoverageStage = random_int(&random, GrDrawState::kNumStages);
295
296 pdesc.fVertexLayout |= random_bool(&random) ?
297 GrDrawTarget::kCoverage_VertexLayoutBit :
298 0;
299
300#if GR_GL_EXPERIMENTAL_GS
301 pdesc.fExperimentalGS = this->getCaps().fGeometryShaderSupport &&
302 random_bool(&random);
303#endif
304 pdesc.fOutputConfig = random_int(&random, ProgramDesc::kOutputConfigCnt);
305
306 bool edgeAA = random_bool(&random);
307 if (edgeAA) {
308 pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
309 if (this->getCaps().fShaderDerivativeSupport) {
310 pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
311 } else {
312 pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
313 }
314 } else {
315 }
316
317 pdesc.fColorMatrixEnabled = random_bool(&random);
318
319 if (this->getCaps().fDualSourceBlendingSupport) {
320 pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
321 } else {
322 pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
323 }
324
325 SkAutoTUnref<const GrCustomStage> customStages[GrDrawState::kNumStages];
326
327 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
328 StageDesc& stage = pdesc.fStages[s];
329 // enable the stage?
330 if (random_bool(&random)) {
331 // use separate tex coords?
332 if (random_bool(&random)) {
333 int t = random_int(&random, GrDrawState::kMaxTexCoords);
334 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
335 }
336 stage.setEnabled(true);
337 }
338 // use text-formatted verts?
339 if (random_bool(&random)) {
340 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
341 }
342
343 stage.fCustomStageKey = 0;
344
bsalomon@google.comd4726202012-08-03 14:34:46 +0000345 stage.fOptFlags |= STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000346 stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];
347
bsalomon@google.comd4726202012-08-03 14:34:46 +0000348 if (stage.isEnabled()) {
349 GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
350 customStages[s].reset(create_random_effect(&stage,
351 &random,
352 getContext(),
353 dummyTextures));
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000354 if (NULL != customStages[s]) {
355 stage.fCustomStageKey =
356 customStages[s]->getFactory().glStageKey(*customStages[s], this->glCaps());
357 }
358 }
359 }
360 GR_STATIC_ASSERT(sizeof(customStages) ==
361 GrDrawState::kNumStages * sizeof(GrCustomStage*));
362 const GrCustomStage** stages = reinterpret_cast<const GrCustomStage**>(&customStages);
363 SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this->glContextInfo(),
364 pdesc,
365 stages));
366 if (NULL == program.get()) {
367 return false;
368 }
369 }
370 return true;
371}
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000372
373static void GLProgramsTest(skiatest::Reporter* reporter, GrContext* context) {
bsalomon@google.com5739d2c2012-05-31 15:07:19 +0000374 GrGpuGL* shadersGpu = static_cast<GrGpuGL*>(context->getGpu());
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000375 REPORTER_ASSERT(reporter, shadersGpu->programUnitTest());
376}
377
378
379#include "TestClassDef.h"
380DEFINE_GPUTESTCLASS("GLPrograms", GLProgramsTestClass, GLProgramsTest)
381
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000382#endif