blob: d7aea981c7da8e89e38dfda7f0e51d1625118b6b [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.comcf8fb1f2012-08-02 14:03:32 +00009// This is a GPU-backend specific test
10#if SK_SUPPORT_GPU
11
bsalomon@google.com5739d2c2012-05-31 15:07:19 +000012#include "gl/GrGpuGL.h"
bsalomon@google.comc3841b92012-08-02 18:11:43 +000013#include "effects/GrColorTableEffect.h"
14#include "effects/GrConvolutionEffect.h"
15#include "../effects/gradients/SkLinearGradient.h"
16#include "../effects/gradients/SkRadialGradient.h"
17#include "../effects/gradients/SkTwoPointRadialGradient.h"
18#include "../effects/gradients/SkTwoPointConicalGradient.h"
19#include "../effects/gradients/SkSweepGradient.h"
20#include "effects/GrMorphologyEffect.h"
21#include "SkLightingImageFilter.h"
22#include "GrProgramStageFactory.h"
23#include "GrRandom.h"
24#include "Test.h"
25
26namespace {
27
28// GrRandoms nextU() values have patterns in the low bits
29// So using nextU() % array_count might never take some values.
30int random_int(GrRandom* r, int count) {
31 return (int)(r->nextF() * count);
32}
33
34// min is inclusive, max is exclusive
35int random_int(GrRandom* r, int min, int max) {
36 return (int)(r->nextF() * (max-min)) + min;
37}
38
39bool random_bool(GrRandom* r) {
40 return r->nextF() > .5f;
41}
42
43SkPoint3 random_point3(GrRandom* r) {
44 return SkPoint3(r->nextF(), r->nextF(), r->nextF());
45}
46
47// populate a pair of arrays with colors and stop info, colorCount indicates
48// the max number of colors, and is set to the actual number on return
49void random_gradient(GrRandom* r, int* colorCount, SkColor* colors,
50 SkScalar** stops) {
51 int outColors = random_int(r, 1, *colorCount);
52
53 // if one color, omit stops, if two colors, randomly decide whether or not to
54 if (outColors == 1 || (outColors == 2 && random_bool(r))) *stops = NULL;
55
56 GrScalar stop = 0.f;
57 for (int i = 0; i < outColors; ++i) {
58 colors[i] = static_cast<SkColor>(r->nextF() * 0xffffffff);
59 if (*stops) {
60 (*stops)[i] = stop;
61 stop = i < outColors - 1 ? stop + r->nextF() * (1.f - stop) : 1.f;
62 }
63 }
64
65 *colorCount = outColors;
66}
67
68typedef GrGLProgram::StageDesc StageDesc;
69// TODO: Effects should be able to register themselves for inclusion in the
70// randomly generated shaders. They should be able to configure themselves
71// randomly.
72const GrCustomStage* create_random_effect(StageDesc* stageDesc, GrRandom* random,
73 GrContext* context) {
74 enum EffectType {
75 kConvolution_EffectType,
76 kErode_EffectType,
77 kDilate_EffectType,
78 kRadialGradient_EffectType,
79 kRadial2Gradient_EffectType,
80 kConical2Gradient_EffectType,
81 kDiffuseDistant_EffectType,
82 kDiffusePoint_EffectType,
83 kDiffuseSpot_EffectType,
84 kSpecularDistant_EffectType,
85 kSpecularPoint_EffectType,
86 kSpecularSpot_EffectType,
87 kSweepGradient_EffectType,
88 kColorTable_EffectType,
89
90 kEffectCount
91 };
92
93 // TODO: Remove this when generator doesn't apply this non-custom-stage
94 // notion to custom stages automatically.
95 static const uint32_t kMulByAlphaMask =
96 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
97 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
98
99 static const Gr1DKernelEffect::Direction gKernelDirections[] = {
100 Gr1DKernelEffect::kX_Direction,
101 Gr1DKernelEffect::kY_Direction
102 };
103
104 static const int kMaxGradientStops = 4;
105
106 // TODO: When matrices are property of the custom-stage then remove the
107 // no-persp flag code below.
108 int effect = random_int(random, kEffectCount);
109 switch (effect) {
110 case kConvolution_EffectType: {
111 int direction = random_int(random, 2);
112 int kernelRadius = random_int(random, 1, 4);
113 float kernel[GrConvolutionEffect::kMaxKernelWidth];
114 for (int i = 0; i < GrConvolutionEffect::kMaxKernelWidth; i++) {
115 kernel[i] = random->nextF();
116 }
117 // does not work with perspective or mul-by-alpha-mask
118 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
119 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
120 return SkNEW_ARGS(GrConvolutionEffect,
121 (NULL,
122 gKernelDirections[direction],
123 kernelRadius,
124 kernel));
125 }
126 case kErode_EffectType: {
127 int direction = random_int(random, 2);
128 int kernelRadius = random_int(random, 1, 4);
129 // does not work with perspective or mul-by-alpha-mask
130 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
131 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
132 return SkNEW_ARGS(GrMorphologyEffect,
133 (NULL,
134 gKernelDirections[direction],
135 kernelRadius,
136 GrContext::kErode_MorphologyType));
137 }
138 case kDilate_EffectType: {
139 int direction = random_int(random, 2);
140 int kernelRadius = random_int(random, 1, 4);
141 // does not work with perspective or mul-by-alpha-mask
142 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
143 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
144 return SkNEW_ARGS(GrMorphologyEffect,
145 (NULL,
146 gKernelDirections[direction],
147 kernelRadius,
148 GrContext::kDilate_MorphologyType));
149 }
150 case kRadialGradient_EffectType: {
151 SkPoint center = {random->nextF(), random->nextF()};
152 SkScalar radius = random->nextF();
153 int colorCount = kMaxGradientStops;
154 SkColor colors[kMaxGradientStops];
155 SkScalar stops[kMaxGradientStops];
156 SkScalar* stopsPtr = stops;
157 random_gradient(random, &colorCount, colors, &stopsPtr);
158 SkShader::TileMode tileMode = static_cast<SkShader::TileMode>(
159 random_int(random, SkShader::kTileModeCount));
160 SkAutoTUnref<SkGradientShaderBase> gradient(
161 static_cast<SkGradientShaderBase*>(SkGradientShader::CreateRadial(
162 center, radius, colors, stopsPtr, colorCount, tileMode, NULL)));
163 GrSamplerState sampler;
164 GrCustomStage* stage = gradient->asNewCustomStage(context, &sampler);
165 GrAssert(NULL != stage);
166 return stage;
167 }
168 case kRadial2Gradient_EffectType: {
169 SkPoint center1 = {random->nextF(), random->nextF()};
170 SkPoint center2 = {random->nextF(), random->nextF()};
171 SkScalar radius1 = random->nextF();
172 SkScalar radius2;
173 do {
174 radius2 = random->nextF();
175 } while (radius1 == radius2);
176 int colorCount = kMaxGradientStops;
177 SkColor colors[kMaxGradientStops];
178 SkScalar stops[kMaxGradientStops];
179 SkScalar* stopsPtr = stops;
180 random_gradient(random, &colorCount, colors, &stopsPtr);
181 SkShader::TileMode tileMode = static_cast<SkShader::TileMode>(
182 random_int(random, SkShader::kTileModeCount));
183 SkAutoTUnref<SkGradientShaderBase> gradient(
184 static_cast<SkGradientShaderBase*>(SkGradientShader::
185 CreateTwoPointRadial(center1, radius1, center2, radius2,
186 colors, stopsPtr, colorCount, tileMode, NULL)));
187 GrSamplerState sampler;
188 GrCustomStage* stage = gradient->asNewCustomStage(context, &sampler);
189 GrAssert(NULL != stage);
190 return stage;
191 }
192 case kConical2Gradient_EffectType: {
193 SkPoint center1 = {random->nextF(), random->nextF()};
194 SkScalar radius1 = random->nextF();
195 SkPoint center2;
196 SkScalar radius2;
197 do {
198 center1.set(random->nextF(), random->nextF());
199 radius2 = random->nextF();
200 } while (radius1 == radius2 && center1 == center2);
201 int colorCount = kMaxGradientStops;
202 SkColor colors[kMaxGradientStops];
203 SkScalar stops[kMaxGradientStops];
204 SkScalar* stopsPtr = stops;
205 random_gradient(random, &colorCount, colors, &stopsPtr);
206 SkShader::TileMode tileMode = static_cast<SkShader::TileMode>(
207 random_int(random, SkShader::kTileModeCount));
208 SkAutoTUnref<SkGradientShaderBase> gradient(
209 static_cast<SkGradientShaderBase*>(SkGradientShader::
210 CreateTwoPointConical(center1, radius1, center2, radius2,
211 colors, stopsPtr, colorCount, tileMode, NULL)));
212 GrSamplerState sampler;
213 GrCustomStage* stage = gradient->asNewCustomStage(context, &sampler);
214 GrAssert(NULL != stage);
215 return stage;
216 }
217 case kSweepGradient_EffectType: {
218 SkPoint center = {random->nextF(), random->nextF()};
219 SkScalar radius = random->nextF();
220 int colorCount = kMaxGradientStops;
221 SkColor colors[kMaxGradientStops];
222 SkScalar stops[kMaxGradientStops];
223 SkScalar* stopsPtr = stops;
224 random_gradient(random, &colorCount, colors, &stopsPtr);
225 SkAutoTUnref<SkGradientShaderBase> gradient(
226 static_cast<SkGradientShaderBase*>(SkGradientShader::CreateSweep(
227 center.fX, center.fY, colors, stopsPtr, colorCount, NULL)));
228 GrSamplerState sampler;
229 GrCustomStage* stage = gradient->asNewCustomStage(context, &sampler);
230 GrAssert(NULL != stage);
231 return stage;
232 }
233 case kDiffuseDistant_EffectType: {
234 SkPoint3 direction = random_point3(random);
235 direction.normalize();
236 SkColor lightColor = random->nextU();
237 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
238 SkScalar kd = SkFloatToScalar(random->nextF());
239 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitDiffuse(direction, lightColor, surfaceScale, kd));
240 // does not work with perspective or mul-by-alpha-mask
241 GrCustomStage* stage;
242 bool ok = filter->asNewCustomStage(&stage, NULL);
243 SkASSERT(ok);
244 return stage;
245 }
246 case kDiffusePoint_EffectType: {
247 SkPoint3 location = random_point3(random);
248 SkColor lightColor = random->nextU();
249 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
250 SkScalar kd = SkFloatToScalar(random->nextF());
251 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitDiffuse(location, lightColor, surfaceScale, kd));
252 // does not work with perspective or mul-by-alpha-mask
253 GrCustomStage* stage;
254 bool ok = filter->asNewCustomStage(&stage, NULL);
255 SkASSERT(ok);
256 return stage;
257 }
258 case kDiffuseSpot_EffectType: {
259 SkPoint3 location = random_point3(random);
260 SkPoint3 target = random_point3(random);
261 SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
262 SkScalar specularExponent = SkFloatToScalar(random->nextF());
263 SkColor lightColor = random->nextU();
264 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
265 SkScalar ks = SkFloatToScalar(random->nextF());
266 SkScalar shininess = SkFloatToScalar(random->nextF());
267 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
268 location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
269 // does not work with perspective or mul-by-alpha-mask
270 GrCustomStage* stage;
271 bool ok = filter->asNewCustomStage(&stage, NULL);
272 SkASSERT(ok);
273 return stage;
274 }
275 case kSpecularDistant_EffectType: {
276 SkPoint3 direction = random_point3(random);
277 direction.normalize();
278 SkColor lightColor = random->nextU();
279 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
280 SkScalar ks = SkFloatToScalar(random->nextF());
281 SkScalar shininess = SkFloatToScalar(random->nextF());
282 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitSpecular(direction, lightColor, surfaceScale, ks, shininess));
283 // does not work with perspective or mul-by-alpha-mask
284 GrCustomStage* stage;
285 bool ok = filter->asNewCustomStage(&stage, NULL);
286 SkASSERT(ok);
287 return stage;
288 }
289 case kSpecularPoint_EffectType: {
290 SkPoint3 location = random_point3(random);
291 SkColor lightColor = random->nextU();
292 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
293 SkScalar ks = SkFloatToScalar(random->nextF());
294 SkScalar shininess = SkFloatToScalar(random->nextF());
295 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitSpecular(location, lightColor, surfaceScale, ks, shininess));
296 // does not work with perspective or mul-by-alpha-mask
297 GrCustomStage* stage;
298 bool ok = filter->asNewCustomStage(&stage, NULL);
299 SkASSERT(ok);
300 return stage;
301 }
302 case kSpecularSpot_EffectType: {
303 SkPoint3 location = random_point3(random);
304 SkPoint3 target = random_point3(random);
305 SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
306 SkScalar specularExponent = SkFloatToScalar(random->nextF());
307 SkColor lightColor = random->nextU();
308 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
309 SkScalar ks = SkFloatToScalar(random->nextF());
310 SkScalar shininess = SkFloatToScalar(random->nextF());
311 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
312 location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
313 // does not work with perspective or mul-by-alpha-mask
314 GrCustomStage* stage;
315 bool ok = filter->asNewCustomStage(&stage, NULL);
316 SkASSERT(ok);
317 return stage;
318 }
319 case kColorTable_EffectType: {
320 return SkNEW_ARGS(GrColorTableEffect, (NULL));
321 }
322 default:
323 GrCrash("Unexpected custom effect type");
324 }
325 return NULL;
326}
327}
328
329bool GrGpuGL::programUnitTest() {
330
331 // GrGLSLGeneration glslGeneration =
332 GrGetGLSLGeneration(this->glBinding(), this->glInterface());
333 static const int STAGE_OPTS[] = {
334 0,
335 StageDesc::kNoPerspective_OptFlagBit,
336 };
337 static const int IN_CONFIG_FLAGS[] = {
338 StageDesc::kNone_InConfigFlag,
339 StageDesc::kSwapRAndB_InConfigFlag,
340 StageDesc::kSwapRAndB_InConfigFlag |
341 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag,
342 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag,
343 StageDesc::kSmearAlpha_InConfigFlag,
344 StageDesc::kSmearRed_InConfigFlag,
345 };
346
347 static const int NUM_TESTS = 512;
348
349 GrRandom random;
350 for (int t = 0; t < NUM_TESTS; ++t) {
351
352#if 0
353 GrPrintf("\nTest Program %d\n-------------\n", t);
354 static const int stop = -1;
355 if (t == stop) {
356 int breakpointhere = 9;
357 }
358#endif
359
360 ProgramDesc pdesc;
361 pdesc.fVertexLayout = 0;
362 pdesc.fEmitsPointSize = random.nextF() > .5f;
363 pdesc.fColorInput = random_int(&random, ProgramDesc::kColorInputCnt);
364 pdesc.fCoverageInput = random_int(&random, ProgramDesc::kColorInputCnt);
365
366 pdesc.fColorFilterXfermode = random_int(&random, SkXfermode::kCoeffModesCnt);
367
368 pdesc.fFirstCoverageStage = random_int(&random, GrDrawState::kNumStages);
369
370 pdesc.fVertexLayout |= random_bool(&random) ?
371 GrDrawTarget::kCoverage_VertexLayoutBit :
372 0;
373
374#if GR_GL_EXPERIMENTAL_GS
375 pdesc.fExperimentalGS = this->getCaps().fGeometryShaderSupport &&
376 random_bool(&random);
377#endif
378 pdesc.fOutputConfig = random_int(&random, ProgramDesc::kOutputConfigCnt);
379
380 bool edgeAA = random_bool(&random);
381 if (edgeAA) {
382 pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
383 if (this->getCaps().fShaderDerivativeSupport) {
384 pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
385 } else {
386 pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
387 }
388 } else {
389 }
390
391 pdesc.fColorMatrixEnabled = random_bool(&random);
392
393 if (this->getCaps().fDualSourceBlendingSupport) {
394 pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
395 } else {
396 pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
397 }
398
399 SkAutoTUnref<const GrCustomStage> customStages[GrDrawState::kNumStages];
400
401 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
402 StageDesc& stage = pdesc.fStages[s];
403 // enable the stage?
404 if (random_bool(&random)) {
405 // use separate tex coords?
406 if (random_bool(&random)) {
407 int t = random_int(&random, GrDrawState::kMaxTexCoords);
408 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
409 }
410 stage.setEnabled(true);
411 }
412 // use text-formatted verts?
413 if (random_bool(&random)) {
414 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
415 }
416
417 stage.fCustomStageKey = 0;
418
419 stage.fOptFlags = STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
420 stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];
421
422 bool useCustomEffect = random_bool(&random);
423 if (useCustomEffect) {
424 customStages[s].reset(create_random_effect(&stage, &random, getContext()));
425 if (NULL != customStages[s]) {
426 stage.fCustomStageKey =
427 customStages[s]->getFactory().glStageKey(*customStages[s], this->glCaps());
428 }
429 }
430 }
431 GR_STATIC_ASSERT(sizeof(customStages) ==
432 GrDrawState::kNumStages * sizeof(GrCustomStage*));
433 const GrCustomStage** stages = reinterpret_cast<const GrCustomStage**>(&customStages);
434 SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this->glContextInfo(),
435 pdesc,
436 stages));
437 if (NULL == program.get()) {
438 return false;
439 }
440 }
441 return true;
442}
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000443
444static void GLProgramsTest(skiatest::Reporter* reporter, GrContext* context) {
bsalomon@google.com5739d2c2012-05-31 15:07:19 +0000445 GrGpuGL* shadersGpu = static_cast<GrGpuGL*>(context->getGpu());
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000446 REPORTER_ASSERT(reporter, shadersGpu->programUnitTest());
447}
448
449
450#include "TestClassDef.h"
451DEFINE_GPUTESTCLASS("GLPrograms", GLProgramsTestClass, GLProgramsTest)
452
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000453#endif