blob: fca908a58aebcfd2b7d329ef280b12a8cb9f174a [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"
rileya@google.comd7cc6512012-07-27 14:00:39 +00005#include "../effects/gradients/SkLinearGradient.h"
6#include "../effects/gradients/SkRadialGradient.h"
7#include "../effects/gradients/SkTwoPointRadialGradient.h"
8#include "../effects/gradients/SkTwoPointConicalGradient.h"
9#include "../effects/gradients/SkSweepGradient.h"
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000010#include "effects/GrMorphologyEffect.h"
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000011#include "SkLightingImageFilter.h"
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000012#include "GrProgramStageFactory.h"
13#include "GrRandom.h"
14
15namespace {
16
17// GrRandoms nextU() values have patterns in the low bits
18// So using nextU() % array_count might never take some values.
19int random_int(GrRandom* r, int count) {
20 return (int)(r->nextF() * count);
21}
22
23// min is inclusive, max is exclusive
24int random_int(GrRandom* r, int min, int max) {
25 return (int)(r->nextF() * (max-min)) + min;
26}
27
28bool random_bool(GrRandom* r) {
29 return r->nextF() > .5f;
30}
31
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000032SkPoint3 random_point3(GrRandom* r) {
33 return SkPoint3(r->nextF(), r->nextF(), r->nextF());
34}
35
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000036typedef GrGLProgram::StageDesc StageDesc;
37// TODO: Effects should be able to register themselves for inclusion in the
38// randomly generated shaders. They should be able to configure themselves
39// randomly.
40GrCustomStage* create_random_effect(StageDesc* stageDesc,
41 GrRandom* random) {
42 enum EffectType {
43 kConvolution_EffectType,
44 kErode_EffectType,
45 kDilate_EffectType,
tomhudson@google.com898e7b52012-06-01 20:42:15 +000046 kRadialGradient_EffectType,
47 kRadial2Gradient_EffectType,
senorblanco@chromium.org894790d2012-07-11 16:01:22 +000048 kDiffuseDistant_EffectType,
49 kDiffusePoint_EffectType,
50 kDiffuseSpot_EffectType,
51 kSpecularDistant_EffectType,
52 kSpecularPoint_EffectType,
53 kSpecularSpot_EffectType,
tomhudson@google.com898e7b52012-06-01 20:42:15 +000054 kSweepGradient_EffectType,
twiz@google.com58071162012-07-18 21:41:50 +000055 kColorTable_EffectType,
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000056
57 kEffectCount
58 };
59
60 // TODO: Remove this when generator doesn't apply this non-custom-stage
61 // notion to custom stages automatically.
62 static const uint32_t kMulByAlphaMask =
63 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
64 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
65
66 static const Gr1DKernelEffect::Direction gKernelDirections[] = {
67 Gr1DKernelEffect::kX_Direction,
68 Gr1DKernelEffect::kY_Direction
69 };
70
71 // TODO: When matrices are property of the custom-stage then remove the
72 // no-persp flag code below.
73 int effect = random_int(random, kEffectCount);
74 switch (effect) {
75 case kConvolution_EffectType: {
76 int direction = random_int(random, 2);
77 int kernelRadius = random_int(random, 1, 4);
78 float kernel[GrConvolutionEffect::kMaxKernelWidth];
79 for (int i = 0; i < GrConvolutionEffect::kMaxKernelWidth; i++) {
80 kernel[i] = random->nextF();
81 }
82 // does not work with perspective or mul-by-alpha-mask
83 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
84 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
tomhudson@google.comc377baf2012-07-09 20:17:56 +000085 return SkNEW_ARGS(GrConvolutionEffect,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000086 (NULL,
87 gKernelDirections[direction],
tomhudson@google.comc377baf2012-07-09 20:17:56 +000088 kernelRadius,
89 kernel));
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000090 }
91 case kErode_EffectType: {
92 int direction = random_int(random, 2);
93 int kernelRadius = random_int(random, 1, 4);
94 // does not work with perspective or mul-by-alpha-mask
95 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
96 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
tomhudson@google.comc377baf2012-07-09 20:17:56 +000097 return SkNEW_ARGS(GrMorphologyEffect,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +000098 (NULL,
99 gKernelDirections[direction],
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000100 kernelRadius,
101 GrContext::kErode_MorphologyType));
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000102 }
103 case kDilate_EffectType: {
104 int direction = random_int(random, 2);
105 int kernelRadius = random_int(random, 1, 4);
106 // does not work with perspective or mul-by-alpha-mask
107 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
108 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000109 return SkNEW_ARGS(GrMorphologyEffect,
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000110 (NULL,
111 gKernelDirections[direction],
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000112 kernelRadius,
113 GrContext::kDilate_MorphologyType));
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000114 }
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000115 case kRadialGradient_EffectType: {
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000116 return SkNEW_ARGS(GrRadialGradient, (NULL));
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000117 }
118 case kRadial2Gradient_EffectType: {
119 float center;
120 do {
121 center = random->nextF();
122 } while (GR_Scalar1 == center);
123 float radius = random->nextF();
124 bool root = random_bool(random);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000125 return SkNEW_ARGS(GrRadial2Gradient, (NULL, center, radius, root));
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000126 }
127 case kSweepGradient_EffectType: {
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000128 return SkNEW_ARGS(GrSweepGradient, (NULL));
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000129 }
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000130 case kDiffuseDistant_EffectType: {
131 SkPoint3 direction = random_point3(random);
132 direction.normalize();
133 SkColor lightColor = random->nextU();
134 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
135 SkScalar kd = SkFloatToScalar(random->nextF());
136 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitDiffuse(direction, lightColor, surfaceScale, kd));
137 // does not work with perspective or mul-by-alpha-mask
138 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000139 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000140 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000141 return stage;
142 }
143 case kDiffusePoint_EffectType: {
144 SkPoint3 location = random_point3(random);
145 SkColor lightColor = random->nextU();
146 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
147 SkScalar kd = SkFloatToScalar(random->nextF());
148 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitDiffuse(location, lightColor, surfaceScale, kd));
149 // does not work with perspective or mul-by-alpha-mask
150 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000151 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000152 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000153 return stage;
154 }
155 case kDiffuseSpot_EffectType: {
156 SkPoint3 location = random_point3(random);
157 SkPoint3 target = random_point3(random);
158 SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
159 SkScalar specularExponent = SkFloatToScalar(random->nextF());
160 SkColor lightColor = random->nextU();
161 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
162 SkScalar ks = SkFloatToScalar(random->nextF());
163 SkScalar shininess = SkFloatToScalar(random->nextF());
164 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
165 location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
166 // does not work with perspective or mul-by-alpha-mask
167 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000168 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000169 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000170 return stage;
171 }
172 case kSpecularDistant_EffectType: {
173 SkPoint3 direction = random_point3(random);
174 direction.normalize();
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::CreateDistantLitSpecular(direction, lightColor, surfaceScale, ks, shininess));
180 // does not work with perspective or mul-by-alpha-mask
181 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000182 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000183 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000184 return stage;
185 }
186 case kSpecularPoint_EffectType: {
187 SkPoint3 location = random_point3(random);
188 SkColor lightColor = random->nextU();
189 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
190 SkScalar ks = SkFloatToScalar(random->nextF());
191 SkScalar shininess = SkFloatToScalar(random->nextF());
192 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitSpecular(location, lightColor, surfaceScale, ks, shininess));
193 // does not work with perspective or mul-by-alpha-mask
194 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000195 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000196 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000197 return stage;
198 }
199 case kSpecularSpot_EffectType: {
200 SkPoint3 location = random_point3(random);
201 SkPoint3 target = random_point3(random);
202 SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
203 SkScalar specularExponent = SkFloatToScalar(random->nextF());
204 SkColor lightColor = random->nextU();
205 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
206 SkScalar ks = SkFloatToScalar(random->nextF());
207 SkScalar shininess = SkFloatToScalar(random->nextF());
208 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
209 location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
210 // does not work with perspective or mul-by-alpha-mask
211 GrCustomStage* stage;
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000212 bool ok = filter->asNewCustomStage(&stage, NULL);
senorblanco@chromium.orgc7623082012-07-12 14:39:07 +0000213 SkASSERT(ok);
senorblanco@chromium.org894790d2012-07-11 16:01:22 +0000214 return stage;
215 }
twiz@google.com58071162012-07-18 21:41:50 +0000216 case kColorTable_EffectType: {
217 return SkNEW_ARGS(GrColorTableEffect, (NULL));
218 }
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000219 default:
220 GrCrash("Unexpected custom effect type");
221 }
222 return NULL;
223}
224}
225
226bool GrGpuGL::programUnitTest() {
227
caryclark@google.comcf6285b2012-06-06 12:09:01 +0000228 // GrGLSLGeneration glslGeneration =
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000229 GrGetGLSLGeneration(this->glBinding(), this->glInterface());
230 static const int STAGE_OPTS[] = {
231 0,
232 StageDesc::kNoPerspective_OptFlagBit,
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000233 };
234 static const int IN_CONFIG_FLAGS[] = {
235 StageDesc::kNone_InConfigFlag,
236 StageDesc::kSwapRAndB_InConfigFlag,
237 StageDesc::kSwapRAndB_InConfigFlag |
238 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag,
239 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag,
240 StageDesc::kSmearAlpha_InConfigFlag,
241 StageDesc::kSmearRed_InConfigFlag,
242 };
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000243
244 static const int NUM_TESTS = 512;
245
246 GrRandom random;
247 for (int t = 0; t < NUM_TESTS; ++t) {
248
249#if 0
250 GrPrintf("\nTest Program %d\n-------------\n", t);
251 static const int stop = -1;
252 if (t == stop) {
253 int breakpointhere = 9;
254 }
255#endif
256
bsalomon@google.com9ba4fa62012-07-16 17:36:28 +0000257 ProgramDesc pdesc;
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000258 pdesc.fVertexLayout = 0;
259 pdesc.fEmitsPointSize = random.nextF() > .5f;
260 pdesc.fColorInput = random_int(&random, ProgramDesc::kColorInputCnt);
261 pdesc.fCoverageInput = random_int(&random, ProgramDesc::kColorInputCnt);
262
263 pdesc.fColorFilterXfermode = random_int(&random, SkXfermode::kCoeffModesCnt);
264
265 pdesc.fFirstCoverageStage = random_int(&random, GrDrawState::kNumStages);
266
267 pdesc.fVertexLayout |= random_bool(&random) ?
268 GrDrawTarget::kCoverage_VertexLayoutBit :
269 0;
270
271#if GR_GL_EXPERIMENTAL_GS
272 pdesc.fExperimentalGS = this->getCaps().fGeometryShaderSupport &&
273 random_bool(&random);
274#endif
275 pdesc.fOutputConfig = random_int(&random, ProgramDesc::kOutputConfigCnt);
276
277 bool edgeAA = random_bool(&random);
278 if (edgeAA) {
279 pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
280 if (this->getCaps().fShaderDerivativeSupport) {
281 pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
282 } else {
283 pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
284 }
285 } else {
286 }
287
288 pdesc.fColorMatrixEnabled = random_bool(&random);
289
290 if (this->getCaps().fDualSourceBlendingSupport) {
291 pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
292 } else {
293 pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
294 }
295
296 SkAutoTUnref<GrCustomStage> customStages[GrDrawState::kNumStages];
297
298 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
tomhudson@google.comb213ed82012-06-25 15:22:12 +0000299 StageDesc& stage = pdesc.fStages[s];
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000300 // enable the stage?
301 if (random_bool(&random)) {
302 // use separate tex coords?
303 if (random_bool(&random)) {
304 int t = random_int(&random, GrDrawState::kMaxTexCoords);
305 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000306 }
tomhudson@google.comb213ed82012-06-25 15:22:12 +0000307 stage.setEnabled(true);
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000308 }
309 // use text-formatted verts?
310 if (random_bool(&random)) {
311 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
312 }
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000313
314 stage.fCustomStageKey = 0;
315
316 stage.fOptFlags = STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
317 stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000318
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000319 bool useCustomEffect = random_bool(&random);
320 if (useCustomEffect) {
321 customStages[s].reset(create_random_effect(&stage, &random));
322 if (NULL != customStages[s]) {
323 stage.fCustomStageKey =
324 customStages[s]->getFactory().glStageKey(*customStages[s]);
325 }
326 }
327 }
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000328 GR_STATIC_ASSERT(sizeof(customStages) ==
329 GrDrawState::kNumStages * sizeof(GrCustomStage*));
330 GrCustomStage** stages = reinterpret_cast<GrCustomStage**>(&customStages);
bsalomon@google.comecb60aa2012-07-18 13:20:29 +0000331 SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this->glContextInfo(), pdesc, stages));
332 if (NULL == program.get()) {
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000333 return false;
334 }
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000335 }
336 return true;
337}