blob: 004013a55a04eddbf34afc385bd31827670bd3c3 [file] [log] [blame]
bsalomon@google.com7e5c6242012-06-01 19:28:26 +00001#include "GrGpuGL.h"
2
3#include "effects/GrConvolutionEffect.h"
tomhudson@google.com898e7b52012-06-01 20:42:15 +00004#include "effects/GrGradientEffects.h"
bsalomon@google.com7e5c6242012-06-01 19:28:26 +00005#include "effects/GrMorphologyEffect.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +00006#include "SkLightingImageFilter.h"
bsalomon@google.com7e5c6242012-06-01 19:28:26 +00007#include "GrProgramStageFactory.h"
8#include "GrRandom.h"
9
10namespace {
11
12// GrRandoms nextU() values have patterns in the low bits
13// So using nextU() % array_count might never take some values.
14int random_int(GrRandom* r, int count) {
15 return (int)(r->nextF() * count);
16}
17
18// min is inclusive, max is exclusive
19int random_int(GrRandom* r, int min, int max) {
20 return (int)(r->nextF() * (max-min)) + min;
21}
22
23bool random_bool(GrRandom* r) {
24 return r->nextF() > .5f;
25}
26
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000027SkPoint3 random_point3(GrRandom* r) {
28 return SkPoint3(r->nextF(), r->nextF(), r->nextF());
29}
30
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000031typedef GrGLProgram::StageDesc StageDesc;
32// TODO: Effects should be able to register themselves for inclusion in the
33// randomly generated shaders. They should be able to configure themselves
34// randomly.
35GrCustomStage* create_random_effect(StageDesc* stageDesc,
36 GrRandom* random) {
37 enum EffectType {
38 kConvolution_EffectType,
39 kErode_EffectType,
40 kDilate_EffectType,
tomhudson@google.com898e7b52012-06-01 20:42:15 +000041 kRadialGradient_EffectType,
42 kRadial2Gradient_EffectType,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000043 kDiffuseDistant_EffectType,
44 kDiffusePoint_EffectType,
45 kDiffuseSpot_EffectType,
46 kSpecularDistant_EffectType,
47 kSpecularPoint_EffectType,
48 kSpecularSpot_EffectType,
tomhudson@google.com898e7b52012-06-01 20:42:15 +000049 kSweepGradient_EffectType,
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000050
51 kEffectCount
52 };
53
54 // TODO: Remove this when generator doesn't apply this non-custom-stage
55 // notion to custom stages automatically.
56 static const uint32_t kMulByAlphaMask =
57 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
58 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
59
60 static const Gr1DKernelEffect::Direction gKernelDirections[] = {
61 Gr1DKernelEffect::kX_Direction,
62 Gr1DKernelEffect::kY_Direction
63 };
64
65 // TODO: When matrices are property of the custom-stage then remove the
66 // no-persp flag code below.
67 int effect = random_int(random, kEffectCount);
68 switch (effect) {
69 case kConvolution_EffectType: {
70 int direction = random_int(random, 2);
71 int kernelRadius = random_int(random, 1, 4);
72 float kernel[GrConvolutionEffect::kMaxKernelWidth];
73 for (int i = 0; i < GrConvolutionEffect::kMaxKernelWidth; i++) {
74 kernel[i] = random->nextF();
75 }
76 // does not work with perspective or mul-by-alpha-mask
77 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
78 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
tomhudson@google.comc377baf2012-07-09 20:17:56 +000079 return SkNEW_ARGS(GrConvolutionEffect,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000080 (NULL,
81 gKernelDirections[direction],
tomhudson@google.comc377baf2012-07-09 20:17:56 +000082 kernelRadius,
83 kernel));
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000084 }
85 case kErode_EffectType: {
86 int direction = random_int(random, 2);
87 int kernelRadius = random_int(random, 1, 4);
88 // does not work with perspective or mul-by-alpha-mask
89 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
90 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
tomhudson@google.comc377baf2012-07-09 20:17:56 +000091 return SkNEW_ARGS(GrMorphologyEffect,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000092 (NULL,
93 gKernelDirections[direction],
tomhudson@google.comc377baf2012-07-09 20:17:56 +000094 kernelRadius,
95 GrContext::kErode_MorphologyType));
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000096 }
97 case kDilate_EffectType: {
98 int direction = random_int(random, 2);
99 int kernelRadius = random_int(random, 1, 4);
100 // does not work with perspective or mul-by-alpha-mask
101 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
102 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000103 return SkNEW_ARGS(GrMorphologyEffect,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000104 (NULL,
105 gKernelDirections[direction],
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000106 kernelRadius,
107 GrContext::kDilate_MorphologyType));
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000108 }
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000109 case kRadialGradient_EffectType: {
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000110 return SkNEW_ARGS(GrRadialGradient, (NULL));
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000111 }
112 case kRadial2Gradient_EffectType: {
113 float center;
114 do {
115 center = random->nextF();
116 } while (GR_Scalar1 == center);
117 float radius = random->nextF();
118 bool root = random_bool(random);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000119 return SkNEW_ARGS(GrRadial2Gradient, (NULL, center, radius, root));
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000120 }
121 case kSweepGradient_EffectType: {
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000122 return SkNEW_ARGS(GrSweepGradient, (NULL));
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000123 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000124 case kDiffuseDistant_EffectType: {
125 SkPoint3 direction = random_point3(random);
126 direction.normalize();
127 SkColor lightColor = random->nextU();
128 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
129 SkScalar kd = SkFloatToScalar(random->nextF());
130 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitDiffuse(direction, lightColor, surfaceScale, kd));
131 // does not work with perspective or mul-by-alpha-mask
132 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000133 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000134 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000135 return stage;
136 }
137 case kDiffusePoint_EffectType: {
138 SkPoint3 location = random_point3(random);
139 SkColor lightColor = random->nextU();
140 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
141 SkScalar kd = SkFloatToScalar(random->nextF());
142 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitDiffuse(location, lightColor, surfaceScale, kd));
143 // does not work with perspective or mul-by-alpha-mask
144 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000145 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000146 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000147 return stage;
148 }
149 case kDiffuseSpot_EffectType: {
150 SkPoint3 location = random_point3(random);
151 SkPoint3 target = random_point3(random);
152 SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
153 SkScalar specularExponent = SkFloatToScalar(random->nextF());
154 SkColor lightColor = random->nextU();
155 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
156 SkScalar ks = SkFloatToScalar(random->nextF());
157 SkScalar shininess = SkFloatToScalar(random->nextF());
158 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
159 location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
160 // does not work with perspective or mul-by-alpha-mask
161 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000162 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000163 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000164 return stage;
165 }
166 case kSpecularDistant_EffectType: {
167 SkPoint3 direction = random_point3(random);
168 direction.normalize();
169 SkColor lightColor = random->nextU();
170 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
171 SkScalar ks = SkFloatToScalar(random->nextF());
172 SkScalar shininess = SkFloatToScalar(random->nextF());
173 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitSpecular(direction, lightColor, surfaceScale, ks, shininess));
174 // does not work with perspective or mul-by-alpha-mask
175 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000176 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000177 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000178 return stage;
179 }
180 case kSpecularPoint_EffectType: {
181 SkPoint3 location = random_point3(random);
182 SkColor lightColor = random->nextU();
183 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
184 SkScalar ks = SkFloatToScalar(random->nextF());
185 SkScalar shininess = SkFloatToScalar(random->nextF());
186 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitSpecular(location, lightColor, surfaceScale, ks, shininess));
187 // does not work with perspective or mul-by-alpha-mask
188 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000189 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000190 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000191 return stage;
192 }
193 case kSpecularSpot_EffectType: {
194 SkPoint3 location = random_point3(random);
195 SkPoint3 target = random_point3(random);
196 SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
197 SkScalar specularExponent = SkFloatToScalar(random->nextF());
198 SkColor lightColor = random->nextU();
199 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
200 SkScalar ks = SkFloatToScalar(random->nextF());
201 SkScalar shininess = SkFloatToScalar(random->nextF());
202 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
203 location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
204 // does not work with perspective or mul-by-alpha-mask
205 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000206 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000207 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000208 return stage;
209 }
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000210 default:
211 GrCrash("Unexpected custom effect type");
212 }
213 return NULL;
214}
215}
216
217bool GrGpuGL::programUnitTest() {
218
caryclark@google.comcf6285b2012-06-06 12:09:01 +0000219 // GrGLSLGeneration glslGeneration =
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000220 GrGetGLSLGeneration(this->glBinding(), this->glInterface());
221 static const int STAGE_OPTS[] = {
222 0,
223 StageDesc::kNoPerspective_OptFlagBit,
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000224 };
225 static const int IN_CONFIG_FLAGS[] = {
226 StageDesc::kNone_InConfigFlag,
227 StageDesc::kSwapRAndB_InConfigFlag,
228 StageDesc::kSwapRAndB_InConfigFlag |
229 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag,
230 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag,
231 StageDesc::kSmearAlpha_InConfigFlag,
232 StageDesc::kSmearRed_InConfigFlag,
233 };
234 GrGLProgram program;
235 ProgramDesc& pdesc = program.fProgramDesc;
236
237 static const int NUM_TESTS = 512;
238
239 GrRandom random;
240 for (int t = 0; t < NUM_TESTS; ++t) {
241
242#if 0
243 GrPrintf("\nTest Program %d\n-------------\n", t);
244 static const int stop = -1;
245 if (t == stop) {
246 int breakpointhere = 9;
247 }
248#endif
249
250 pdesc.fVertexLayout = 0;
251 pdesc.fEmitsPointSize = random.nextF() > .5f;
252 pdesc.fColorInput = random_int(&random, ProgramDesc::kColorInputCnt);
253 pdesc.fCoverageInput = random_int(&random, ProgramDesc::kColorInputCnt);
254
255 pdesc.fColorFilterXfermode = random_int(&random, SkXfermode::kCoeffModesCnt);
256
257 pdesc.fFirstCoverageStage = random_int(&random, GrDrawState::kNumStages);
258
259 pdesc.fVertexLayout |= random_bool(&random) ?
260 GrDrawTarget::kCoverage_VertexLayoutBit :
261 0;
262
263#if GR_GL_EXPERIMENTAL_GS
264 pdesc.fExperimentalGS = this->getCaps().fGeometryShaderSupport &&
265 random_bool(&random);
266#endif
267 pdesc.fOutputConfig = random_int(&random, ProgramDesc::kOutputConfigCnt);
268
269 bool edgeAA = random_bool(&random);
270 if (edgeAA) {
271 pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
272 if (this->getCaps().fShaderDerivativeSupport) {
273 pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
274 } else {
275 pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
276 }
277 } else {
278 }
279
280 pdesc.fColorMatrixEnabled = random_bool(&random);
281
282 if (this->getCaps().fDualSourceBlendingSupport) {
283 pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
284 } else {
285 pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
286 }
287
288 SkAutoTUnref<GrCustomStage> customStages[GrDrawState::kNumStages];
289
290 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
tomhudson@google.comb213ed82012-06-25 15:22:12 +0000291 StageDesc& stage = pdesc.fStages[s];
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000292 // enable the stage?
293 if (random_bool(&random)) {
294 // use separate tex coords?
295 if (random_bool(&random)) {
296 int t = random_int(&random, GrDrawState::kMaxTexCoords);
297 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000298 }
tomhudson@google.comb213ed82012-06-25 15:22:12 +0000299 stage.setEnabled(true);
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000300 }
301 // use text-formatted verts?
302 if (random_bool(&random)) {
303 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
304 }
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000305
306 stage.fCustomStageKey = 0;
307
308 stage.fOptFlags = STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
309 stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000310
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000311 bool useCustomEffect = random_bool(&random);
312 if (useCustomEffect) {
313 customStages[s].reset(create_random_effect(&stage, &random));
314 if (NULL != customStages[s]) {
315 stage.fCustomStageKey =
316 customStages[s]->getFactory().glStageKey(*customStages[s]);
317 }
318 }
319 }
320 CachedData cachedData;
321 GR_STATIC_ASSERT(sizeof(customStages) ==
322 GrDrawState::kNumStages * sizeof(GrCustomStage*));
323 GrCustomStage** stages = reinterpret_cast<GrCustomStage**>(&customStages);
324 if (!program.genProgram(this->glContextInfo(), stages, &cachedData)) {
325 return false;
326 }
327 DeleteProgram(this->glInterface(), &cachedData);
328 }
329 return true;
330}