blob: d15e087d03587070c57c1714145975a7550dc4da [file] [log] [blame]
bsalomon@google.com7e5c6242012-06-01 19:28:26 +00001#include "GrGpuGL.h"
2
twiz@google.com58071162012-07-18 21:41:50 +00003#include "effects/GrColorTableEffect.h"
bsalomon@google.com7e5c6242012-06-01 19:28:26 +00004#include "effects/GrConvolutionEffect.h"
tomhudson@google.com898e7b52012-06-01 20:42:15 +00005#include "effects/GrGradientEffects.h"
bsalomon@google.com7e5c6242012-06-01 19:28:26 +00006#include "effects/GrMorphologyEffect.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00007#include "SkLightingImageFilter.h"
bsalomon@google.com7e5c6242012-06-01 19:28:26 +00008#include "GrProgramStageFactory.h"
9#include "GrRandom.h"
10
11namespace {
12
13// GrRandoms nextU() values have patterns in the low bits
14// So using nextU() % array_count might never take some values.
15int random_int(GrRandom* r, int count) {
16 return (int)(r->nextF() * count);
17}
18
19// min is inclusive, max is exclusive
20int random_int(GrRandom* r, int min, int max) {
21 return (int)(r->nextF() * (max-min)) + min;
22}
23
24bool random_bool(GrRandom* r) {
25 return r->nextF() > .5f;
26}
27
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000028SkPoint3 random_point3(GrRandom* r) {
29 return SkPoint3(r->nextF(), r->nextF(), r->nextF());
30}
31
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000032typedef GrGLProgram::StageDesc StageDesc;
33// TODO: Effects should be able to register themselves for inclusion in the
34// randomly generated shaders. They should be able to configure themselves
35// randomly.
36GrCustomStage* create_random_effect(StageDesc* stageDesc,
37 GrRandom* random) {
38 enum EffectType {
39 kConvolution_EffectType,
40 kErode_EffectType,
41 kDilate_EffectType,
tomhudson@google.com898e7b52012-06-01 20:42:15 +000042 kRadialGradient_EffectType,
43 kRadial2Gradient_EffectType,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000044 kDiffuseDistant_EffectType,
45 kDiffusePoint_EffectType,
46 kDiffuseSpot_EffectType,
47 kSpecularDistant_EffectType,
48 kSpecularPoint_EffectType,
49 kSpecularSpot_EffectType,
tomhudson@google.com898e7b52012-06-01 20:42:15 +000050 kSweepGradient_EffectType,
twiz@google.com58071162012-07-18 21:41:50 +000051 kColorTable_EffectType,
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000052
53 kEffectCount
54 };
55
56 // TODO: Remove this when generator doesn't apply this non-custom-stage
57 // notion to custom stages automatically.
58 static const uint32_t kMulByAlphaMask =
59 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
60 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
61
62 static const Gr1DKernelEffect::Direction gKernelDirections[] = {
63 Gr1DKernelEffect::kX_Direction,
64 Gr1DKernelEffect::kY_Direction
65 };
66
67 // TODO: When matrices are property of the custom-stage then remove the
68 // no-persp flag code below.
69 int effect = random_int(random, kEffectCount);
70 switch (effect) {
71 case kConvolution_EffectType: {
72 int direction = random_int(random, 2);
73 int kernelRadius = random_int(random, 1, 4);
74 float kernel[GrConvolutionEffect::kMaxKernelWidth];
75 for (int i = 0; i < GrConvolutionEffect::kMaxKernelWidth; i++) {
76 kernel[i] = random->nextF();
77 }
78 // does not work with perspective or mul-by-alpha-mask
79 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
80 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
tomhudson@google.comc377baf2012-07-09 20:17:56 +000081 return SkNEW_ARGS(GrConvolutionEffect,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000082 (NULL,
83 gKernelDirections[direction],
tomhudson@google.comc377baf2012-07-09 20:17:56 +000084 kernelRadius,
85 kernel));
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000086 }
87 case kErode_EffectType: {
88 int direction = random_int(random, 2);
89 int kernelRadius = random_int(random, 1, 4);
90 // does not work with perspective or mul-by-alpha-mask
91 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
92 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
tomhudson@google.comc377baf2012-07-09 20:17:56 +000093 return SkNEW_ARGS(GrMorphologyEffect,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000094 (NULL,
95 gKernelDirections[direction],
tomhudson@google.comc377baf2012-07-09 20:17:56 +000096 kernelRadius,
97 GrContext::kErode_MorphologyType));
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000098 }
99 case kDilate_EffectType: {
100 int direction = random_int(random, 2);
101 int kernelRadius = random_int(random, 1, 4);
102 // does not work with perspective or mul-by-alpha-mask
103 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
104 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000105 return SkNEW_ARGS(GrMorphologyEffect,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000106 (NULL,
107 gKernelDirections[direction],
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000108 kernelRadius,
109 GrContext::kDilate_MorphologyType));
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000110 }
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000111 case kRadialGradient_EffectType: {
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000112 return SkNEW_ARGS(GrRadialGradient, (NULL));
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000113 }
114 case kRadial2Gradient_EffectType: {
115 float center;
116 do {
117 center = random->nextF();
118 } while (GR_Scalar1 == center);
119 float radius = random->nextF();
120 bool root = random_bool(random);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000121 return SkNEW_ARGS(GrRadial2Gradient, (NULL, center, radius, root));
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000122 }
123 case kSweepGradient_EffectType: {
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000124 return SkNEW_ARGS(GrSweepGradient, (NULL));
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000125 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000126 case kDiffuseDistant_EffectType: {
127 SkPoint3 direction = random_point3(random);
128 direction.normalize();
129 SkColor lightColor = random->nextU();
130 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
131 SkScalar kd = SkFloatToScalar(random->nextF());
132 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitDiffuse(direction, lightColor, surfaceScale, kd));
133 // does not work with perspective or mul-by-alpha-mask
134 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000135 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000136 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000137 return stage;
138 }
139 case kDiffusePoint_EffectType: {
140 SkPoint3 location = random_point3(random);
141 SkColor lightColor = random->nextU();
142 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
143 SkScalar kd = SkFloatToScalar(random->nextF());
144 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitDiffuse(location, lightColor, surfaceScale, kd));
145 // does not work with perspective or mul-by-alpha-mask
146 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000147 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000148 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000149 return stage;
150 }
151 case kDiffuseSpot_EffectType: {
152 SkPoint3 location = random_point3(random);
153 SkPoint3 target = random_point3(random);
154 SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
155 SkScalar specularExponent = SkFloatToScalar(random->nextF());
156 SkColor lightColor = random->nextU();
157 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
158 SkScalar ks = SkFloatToScalar(random->nextF());
159 SkScalar shininess = SkFloatToScalar(random->nextF());
160 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
161 location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
162 // does not work with perspective or mul-by-alpha-mask
163 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000164 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000165 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000166 return stage;
167 }
168 case kSpecularDistant_EffectType: {
169 SkPoint3 direction = random_point3(random);
170 direction.normalize();
171 SkColor lightColor = random->nextU();
172 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
173 SkScalar ks = SkFloatToScalar(random->nextF());
174 SkScalar shininess = SkFloatToScalar(random->nextF());
175 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitSpecular(direction, lightColor, surfaceScale, ks, shininess));
176 // does not work with perspective or mul-by-alpha-mask
177 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000178 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000179 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000180 return stage;
181 }
182 case kSpecularPoint_EffectType: {
183 SkPoint3 location = random_point3(random);
184 SkColor lightColor = random->nextU();
185 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
186 SkScalar ks = SkFloatToScalar(random->nextF());
187 SkScalar shininess = SkFloatToScalar(random->nextF());
188 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitSpecular(location, lightColor, surfaceScale, ks, shininess));
189 // does not work with perspective or mul-by-alpha-mask
190 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000191 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000192 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000193 return stage;
194 }
195 case kSpecularSpot_EffectType: {
196 SkPoint3 location = random_point3(random);
197 SkPoint3 target = random_point3(random);
198 SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
199 SkScalar specularExponent = SkFloatToScalar(random->nextF());
200 SkColor lightColor = random->nextU();
201 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
202 SkScalar ks = SkFloatToScalar(random->nextF());
203 SkScalar shininess = SkFloatToScalar(random->nextF());
204 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
205 location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
206 // does not work with perspective or mul-by-alpha-mask
207 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000208 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000209 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000210 return stage;
211 }
twiz@google.com58071162012-07-18 21:41:50 +0000212 case kColorTable_EffectType: {
213 return SkNEW_ARGS(GrColorTableEffect, (NULL));
214 }
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000215 default:
216 GrCrash("Unexpected custom effect type");
217 }
218 return NULL;
219}
220}
221
222bool GrGpuGL::programUnitTest() {
223
caryclark@google.comcf6285b2012-06-06 12:09:01 +0000224 // GrGLSLGeneration glslGeneration =
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000225 GrGetGLSLGeneration(this->glBinding(), this->glInterface());
226 static const int STAGE_OPTS[] = {
227 0,
228 StageDesc::kNoPerspective_OptFlagBit,
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000229 };
230 static const int IN_CONFIG_FLAGS[] = {
231 StageDesc::kNone_InConfigFlag,
232 StageDesc::kSwapRAndB_InConfigFlag,
233 StageDesc::kSwapRAndB_InConfigFlag |
234 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag,
235 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag,
236 StageDesc::kSmearAlpha_InConfigFlag,
237 StageDesc::kSmearRed_InConfigFlag,
238 };
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000239
240 static const int NUM_TESTS = 512;
241
242 GrRandom random;
243 for (int t = 0; t < NUM_TESTS; ++t) {
244
245#if 0
246 GrPrintf("\nTest Program %d\n-------------\n", t);
247 static const int stop = -1;
248 if (t == stop) {
249 int breakpointhere = 9;
250 }
251#endif
252
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000253 ProgramDesc pdesc;
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000254 pdesc.fVertexLayout = 0;
255 pdesc.fEmitsPointSize = random.nextF() > .5f;
256 pdesc.fColorInput = random_int(&random, ProgramDesc::kColorInputCnt);
257 pdesc.fCoverageInput = random_int(&random, ProgramDesc::kColorInputCnt);
258
259 pdesc.fColorFilterXfermode = random_int(&random, SkXfermode::kCoeffModesCnt);
260
261 pdesc.fFirstCoverageStage = random_int(&random, GrDrawState::kNumStages);
262
263 pdesc.fVertexLayout |= random_bool(&random) ?
264 GrDrawTarget::kCoverage_VertexLayoutBit :
265 0;
266
267#if GR_GL_EXPERIMENTAL_GS
268 pdesc.fExperimentalGS = this->getCaps().fGeometryShaderSupport &&
269 random_bool(&random);
270#endif
271 pdesc.fOutputConfig = random_int(&random, ProgramDesc::kOutputConfigCnt);
272
273 bool edgeAA = random_bool(&random);
274 if (edgeAA) {
275 pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
276 if (this->getCaps().fShaderDerivativeSupport) {
277 pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
278 } else {
279 pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
280 }
281 } else {
282 }
283
284 pdesc.fColorMatrixEnabled = random_bool(&random);
285
286 if (this->getCaps().fDualSourceBlendingSupport) {
287 pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
288 } else {
289 pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
290 }
291
292 SkAutoTUnref<GrCustomStage> customStages[GrDrawState::kNumStages];
293
294 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
tomhudson@google.comb213ed82012-06-25 15:22:12 +0000295 StageDesc& stage = pdesc.fStages[s];
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000296 // enable the stage?
297 if (random_bool(&random)) {
298 // use separate tex coords?
299 if (random_bool(&random)) {
300 int t = random_int(&random, GrDrawState::kMaxTexCoords);
301 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000302 }
tomhudson@google.comb213ed82012-06-25 15:22:12 +0000303 stage.setEnabled(true);
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000304 }
305 // use text-formatted verts?
306 if (random_bool(&random)) {
307 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
308 }
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000309
310 stage.fCustomStageKey = 0;
311
312 stage.fOptFlags = STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
313 stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000314
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000315 bool useCustomEffect = random_bool(&random);
316 if (useCustomEffect) {
317 customStages[s].reset(create_random_effect(&stage, &random));
318 if (NULL != customStages[s]) {
319 stage.fCustomStageKey =
320 customStages[s]->getFactory().glStageKey(*customStages[s]);
321 }
322 }
323 }
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000324 GR_STATIC_ASSERT(sizeof(customStages) ==
325 GrDrawState::kNumStages * sizeof(GrCustomStage*));
326 GrCustomStage** stages = reinterpret_cast<GrCustomStage**>(&customStages);
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000327 SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this->glContextInfo(), pdesc, stages));
328 if (NULL == program.get()) {
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000329 return false;
330 }
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000331 }
332 return true;
333}