blob: 82804450b0d21491563f5384971760a9f4cb883a [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,
80 (gKernelDirections[direction],
81 kernelRadius,
82 kernel));
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000083 }
84 case kErode_EffectType: {
85 int direction = random_int(random, 2);
86 int kernelRadius = random_int(random, 1, 4);
87 // does not work with perspective or mul-by-alpha-mask
88 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
89 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
tomhudson@google.comc377baf2012-07-09 20:17:56 +000090 return SkNEW_ARGS(GrMorphologyEffect,
91 (gKernelDirections[direction],
92 kernelRadius,
93 GrContext::kErode_MorphologyType));
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000094 }
95 case kDilate_EffectType: {
96 int direction = random_int(random, 2);
97 int kernelRadius = random_int(random, 1, 4);
98 // does not work with perspective or mul-by-alpha-mask
99 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
100 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000101 return SkNEW_ARGS(GrMorphologyEffect,
102 (gKernelDirections[direction],
103 kernelRadius,
104 GrContext::kDilate_MorphologyType));
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000105 }
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000106 case kRadialGradient_EffectType: {
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000107 return SkNEW(GrRadialGradient);
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000108 }
109 case kRadial2Gradient_EffectType: {
110 float center;
111 do {
112 center = random->nextF();
113 } while (GR_Scalar1 == center);
114 float radius = random->nextF();
115 bool root = random_bool(random);
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000116 return SkNEW_ARGS(GrRadial2Gradient, (center, radius, root));
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000117 }
118 case kSweepGradient_EffectType: {
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000119 return SkNEW(GrSweepGradient);
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000120 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000121 case kDiffuseDistant_EffectType: {
122 SkPoint3 direction = random_point3(random);
123 direction.normalize();
124 SkColor lightColor = random->nextU();
125 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
126 SkScalar kd = SkFloatToScalar(random->nextF());
127 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitDiffuse(direction, lightColor, surfaceScale, kd));
128 // does not work with perspective or mul-by-alpha-mask
129 GrCustomStage* stage;
130 SkASSERT(filter->asNewCustomStage(&stage));
131 return stage;
132 }
133 case kDiffusePoint_EffectType: {
134 SkPoint3 location = random_point3(random);
135 SkColor lightColor = random->nextU();
136 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
137 SkScalar kd = SkFloatToScalar(random->nextF());
138 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitDiffuse(location, lightColor, surfaceScale, kd));
139 // does not work with perspective or mul-by-alpha-mask
140 GrCustomStage* stage;
141 SkASSERT(filter->asNewCustomStage(&stage));
142 return stage;
143 }
144 case kDiffuseSpot_EffectType: {
145 SkPoint3 location = random_point3(random);
146 SkPoint3 target = random_point3(random);
147 SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
148 SkScalar specularExponent = SkFloatToScalar(random->nextF());
149 SkColor lightColor = random->nextU();
150 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
151 SkScalar ks = SkFloatToScalar(random->nextF());
152 SkScalar shininess = SkFloatToScalar(random->nextF());
153 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
154 location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
155 // does not work with perspective or mul-by-alpha-mask
156 GrCustomStage* stage;
157 SkASSERT(filter->asNewCustomStage(&stage));
158 return stage;
159 }
160 case kSpecularDistant_EffectType: {
161 SkPoint3 direction = random_point3(random);
162 direction.normalize();
163 SkColor lightColor = random->nextU();
164 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
165 SkScalar ks = SkFloatToScalar(random->nextF());
166 SkScalar shininess = SkFloatToScalar(random->nextF());
167 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitSpecular(direction, lightColor, surfaceScale, ks, shininess));
168 // does not work with perspective or mul-by-alpha-mask
169 GrCustomStage* stage;
170 SkASSERT(filter->asNewCustomStage(&stage));
171 return stage;
172 }
173 case kSpecularPoint_EffectType: {
174 SkPoint3 location = random_point3(random);
175 SkColor lightColor = random->nextU();
176 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
177 SkScalar ks = SkFloatToScalar(random->nextF());
178 SkScalar shininess = SkFloatToScalar(random->nextF());
179 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitSpecular(location, lightColor, surfaceScale, ks, shininess));
180 // does not work with perspective or mul-by-alpha-mask
181 GrCustomStage* stage;
182 SkASSERT(filter->asNewCustomStage(&stage));
183 return stage;
184 }
185 case kSpecularSpot_EffectType: {
186 SkPoint3 location = random_point3(random);
187 SkPoint3 target = random_point3(random);
188 SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
189 SkScalar specularExponent = SkFloatToScalar(random->nextF());
190 SkColor lightColor = random->nextU();
191 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
192 SkScalar ks = SkFloatToScalar(random->nextF());
193 SkScalar shininess = SkFloatToScalar(random->nextF());
194 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
195 location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
196 // does not work with perspective or mul-by-alpha-mask
197 GrCustomStage* stage;
198 SkASSERT(filter->asNewCustomStage(&stage));
199 return stage;
200 }
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000201 default:
202 GrCrash("Unexpected custom effect type");
203 }
204 return NULL;
205}
206}
207
208bool GrGpuGL::programUnitTest() {
209
caryclark@google.comcf6285b2012-06-06 12:09:01 +0000210 // GrGLSLGeneration glslGeneration =
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000211 GrGetGLSLGeneration(this->glBinding(), this->glInterface());
212 static const int STAGE_OPTS[] = {
213 0,
214 StageDesc::kNoPerspective_OptFlagBit,
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000215 };
216 static const int IN_CONFIG_FLAGS[] = {
217 StageDesc::kNone_InConfigFlag,
218 StageDesc::kSwapRAndB_InConfigFlag,
219 StageDesc::kSwapRAndB_InConfigFlag |
220 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag,
221 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag,
222 StageDesc::kSmearAlpha_InConfigFlag,
223 StageDesc::kSmearRed_InConfigFlag,
224 };
225 GrGLProgram program;
226 ProgramDesc& pdesc = program.fProgramDesc;
227
228 static const int NUM_TESTS = 512;
229
230 GrRandom random;
231 for (int t = 0; t < NUM_TESTS; ++t) {
232
233#if 0
234 GrPrintf("\nTest Program %d\n-------------\n", t);
235 static const int stop = -1;
236 if (t == stop) {
237 int breakpointhere = 9;
238 }
239#endif
240
241 pdesc.fVertexLayout = 0;
242 pdesc.fEmitsPointSize = random.nextF() > .5f;
243 pdesc.fColorInput = random_int(&random, ProgramDesc::kColorInputCnt);
244 pdesc.fCoverageInput = random_int(&random, ProgramDesc::kColorInputCnt);
245
246 pdesc.fColorFilterXfermode = random_int(&random, SkXfermode::kCoeffModesCnt);
247
248 pdesc.fFirstCoverageStage = random_int(&random, GrDrawState::kNumStages);
249
250 pdesc.fVertexLayout |= random_bool(&random) ?
251 GrDrawTarget::kCoverage_VertexLayoutBit :
252 0;
253
254#if GR_GL_EXPERIMENTAL_GS
255 pdesc.fExperimentalGS = this->getCaps().fGeometryShaderSupport &&
256 random_bool(&random);
257#endif
258 pdesc.fOutputConfig = random_int(&random, ProgramDesc::kOutputConfigCnt);
259
260 bool edgeAA = random_bool(&random);
261 if (edgeAA) {
262 pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
263 if (this->getCaps().fShaderDerivativeSupport) {
264 pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
265 } else {
266 pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
267 }
268 } else {
269 }
270
271 pdesc.fColorMatrixEnabled = random_bool(&random);
272
273 if (this->getCaps().fDualSourceBlendingSupport) {
274 pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
275 } else {
276 pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
277 }
278
279 SkAutoTUnref<GrCustomStage> customStages[GrDrawState::kNumStages];
280
281 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
tomhudson@google.comb213ed82012-06-25 15:22:12 +0000282 StageDesc& stage = pdesc.fStages[s];
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000283 // enable the stage?
284 if (random_bool(&random)) {
285 // use separate tex coords?
286 if (random_bool(&random)) {
287 int t = random_int(&random, GrDrawState::kMaxTexCoords);
288 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000289 }
tomhudson@google.comb213ed82012-06-25 15:22:12 +0000290 stage.setEnabled(true);
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000291 }
292 // use text-formatted verts?
293 if (random_bool(&random)) {
294 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
295 }
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000296
297 stage.fCustomStageKey = 0;
298
299 stage.fOptFlags = STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
300 stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000301
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000302 bool useCustomEffect = random_bool(&random);
303 if (useCustomEffect) {
304 customStages[s].reset(create_random_effect(&stage, &random));
305 if (NULL != customStages[s]) {
306 stage.fCustomStageKey =
307 customStages[s]->getFactory().glStageKey(*customStages[s]);
308 }
309 }
310 }
311 CachedData cachedData;
312 GR_STATIC_ASSERT(sizeof(customStages) ==
313 GrDrawState::kNumStages * sizeof(GrCustomStage*));
314 GrCustomStage** stages = reinterpret_cast<GrCustomStage**>(&customStages);
315 if (!program.genProgram(this->glContextInfo(), stages, &cachedData)) {
316 return false;
317 }
318 DeleteProgram(this->glInterface(), &cachedData);
319 }
320 return true;
321}