blob: 9dbb708e1bd2ae70d1bd2984e66baeee4c41c799 [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"
6#include "GrProgramStageFactory.h"
7#include "GrRandom.h"
8
9namespace {
10
11// GrRandoms nextU() values have patterns in the low bits
12// So using nextU() % array_count might never take some values.
13int random_int(GrRandom* r, int count) {
14 return (int)(r->nextF() * count);
15}
16
17// min is inclusive, max is exclusive
18int random_int(GrRandom* r, int min, int max) {
19 return (int)(r->nextF() * (max-min)) + min;
20}
21
22bool random_bool(GrRandom* r) {
23 return r->nextF() > .5f;
24}
25
26typedef GrGLProgram::StageDesc StageDesc;
27// TODO: Effects should be able to register themselves for inclusion in the
28// randomly generated shaders. They should be able to configure themselves
29// randomly.
30GrCustomStage* create_random_effect(StageDesc* stageDesc,
31 GrRandom* random) {
32 enum EffectType {
33 kConvolution_EffectType,
34 kErode_EffectType,
35 kDilate_EffectType,
tomhudson@google.com898e7b52012-06-01 20:42:15 +000036 kRadialGradient_EffectType,
37 kRadial2Gradient_EffectType,
38 kSweepGradient_EffectType,
bsalomon@google.com7e5c6242012-06-01 19:28:26 +000039
40 kEffectCount
41 };
42
43 // TODO: Remove this when generator doesn't apply this non-custom-stage
44 // notion to custom stages automatically.
45 static const uint32_t kMulByAlphaMask =
46 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
47 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
48
49 static const Gr1DKernelEffect::Direction gKernelDirections[] = {
50 Gr1DKernelEffect::kX_Direction,
51 Gr1DKernelEffect::kY_Direction
52 };
53
54 // TODO: When matrices are property of the custom-stage then remove the
55 // no-persp flag code below.
56 int effect = random_int(random, kEffectCount);
57 switch (effect) {
58 case kConvolution_EffectType: {
59 int direction = random_int(random, 2);
60 int kernelRadius = random_int(random, 1, 4);
61 float kernel[GrConvolutionEffect::kMaxKernelWidth];
62 for (int i = 0; i < GrConvolutionEffect::kMaxKernelWidth; i++) {
63 kernel[i] = random->nextF();
64 }
65 // does not work with perspective or mul-by-alpha-mask
66 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
67 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
68 return new GrConvolutionEffect(gKernelDirections[direction],
69 kernelRadius,
70 kernel);
71 }
72 case kErode_EffectType: {
73 int direction = random_int(random, 2);
74 int kernelRadius = random_int(random, 1, 4);
75 // does not work with perspective or mul-by-alpha-mask
76 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
77 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
78 return new GrMorphologyEffect(gKernelDirections[direction],
79 kernelRadius,
80 GrContext::kErode_MorphologyType);
81 }
82 case kDilate_EffectType: {
83 int direction = random_int(random, 2);
84 int kernelRadius = random_int(random, 1, 4);
85 // does not work with perspective or mul-by-alpha-mask
86 stageDesc->fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
87 stageDesc->fInConfigFlags &= ~kMulByAlphaMask;
88 return new GrMorphologyEffect(gKernelDirections[direction],
89 kernelRadius,
90 GrContext::kDilate_MorphologyType);
91 }
tomhudson@google.com898e7b52012-06-01 20:42:15 +000092 case kRadialGradient_EffectType: {
93 return new GrRadialGradient();
94 }
95 case kRadial2Gradient_EffectType: {
96 float center;
97 do {
98 center = random->nextF();
99 } while (GR_Scalar1 == center);
100 float radius = random->nextF();
101 bool root = random_bool(random);
102 return new GrRadial2Gradient(center, radius, root);
103 }
104 case kSweepGradient_EffectType: {
105 return new GrSweepGradient();
106 }
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000107 default:
108 GrCrash("Unexpected custom effect type");
109 }
110 return NULL;
111}
112}
113
114bool GrGpuGL::programUnitTest() {
115
caryclark@google.comcf6285b2012-06-06 12:09:01 +0000116 // GrGLSLGeneration glslGeneration =
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000117 GrGetGLSLGeneration(this->glBinding(), this->glInterface());
118 static const int STAGE_OPTS[] = {
119 0,
120 StageDesc::kNoPerspective_OptFlagBit,
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000121 };
122 static const int IN_CONFIG_FLAGS[] = {
123 StageDesc::kNone_InConfigFlag,
124 StageDesc::kSwapRAndB_InConfigFlag,
125 StageDesc::kSwapRAndB_InConfigFlag |
126 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag,
127 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag,
128 StageDesc::kSmearAlpha_InConfigFlag,
129 StageDesc::kSmearRed_InConfigFlag,
130 };
131 GrGLProgram program;
132 ProgramDesc& pdesc = program.fProgramDesc;
133
134 static const int NUM_TESTS = 512;
135
136 GrRandom random;
137 for (int t = 0; t < NUM_TESTS; ++t) {
138
139#if 0
140 GrPrintf("\nTest Program %d\n-------------\n", t);
141 static const int stop = -1;
142 if (t == stop) {
143 int breakpointhere = 9;
144 }
145#endif
146
147 pdesc.fVertexLayout = 0;
148 pdesc.fEmitsPointSize = random.nextF() > .5f;
149 pdesc.fColorInput = random_int(&random, ProgramDesc::kColorInputCnt);
150 pdesc.fCoverageInput = random_int(&random, ProgramDesc::kColorInputCnt);
151
152 pdesc.fColorFilterXfermode = random_int(&random, SkXfermode::kCoeffModesCnt);
153
154 pdesc.fFirstCoverageStage = random_int(&random, GrDrawState::kNumStages);
155
156 pdesc.fVertexLayout |= random_bool(&random) ?
157 GrDrawTarget::kCoverage_VertexLayoutBit :
158 0;
159
160#if GR_GL_EXPERIMENTAL_GS
161 pdesc.fExperimentalGS = this->getCaps().fGeometryShaderSupport &&
162 random_bool(&random);
163#endif
164 pdesc.fOutputConfig = random_int(&random, ProgramDesc::kOutputConfigCnt);
165
166 bool edgeAA = random_bool(&random);
167 if (edgeAA) {
168 pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
169 if (this->getCaps().fShaderDerivativeSupport) {
170 pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
171 } else {
172 pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
173 }
174 } else {
175 }
176
177 pdesc.fColorMatrixEnabled = random_bool(&random);
178
179 if (this->getCaps().fDualSourceBlendingSupport) {
180 pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
181 } else {
182 pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
183 }
184
185 SkAutoTUnref<GrCustomStage> customStages[GrDrawState::kNumStages];
186
187 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
188 // enable the stage?
189 if (random_bool(&random)) {
190 // use separate tex coords?
191 if (random_bool(&random)) {
192 int t = random_int(&random, GrDrawState::kMaxTexCoords);
193 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
194 } else {
195 pdesc.fVertexLayout |= StagePosAsTexCoordVertexLayoutBit(s);
196 }
197 }
198 // use text-formatted verts?
199 if (random_bool(&random)) {
200 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
201 }
202 StageDesc& stage = pdesc.fStages[s];
203
204 stage.fCustomStageKey = 0;
205
206 stage.fOptFlags = STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
207 stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000208 stage.setEnabled(VertexUsesStage(s, pdesc.fVertexLayout));
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000209
bsalomon@google.com7e5c6242012-06-01 19:28:26 +0000210 bool useCustomEffect = random_bool(&random);
211 if (useCustomEffect) {
212 customStages[s].reset(create_random_effect(&stage, &random));
213 if (NULL != customStages[s]) {
214 stage.fCustomStageKey =
215 customStages[s]->getFactory().glStageKey(*customStages[s]);
216 }
217 }
218 }
219 CachedData cachedData;
220 GR_STATIC_ASSERT(sizeof(customStages) ==
221 GrDrawState::kNumStages * sizeof(GrCustomStage*));
222 GrCustomStage** stages = reinterpret_cast<GrCustomStage**>(&customStages);
223 if (!program.genProgram(this->glContextInfo(), stages, &cachedData)) {
224 return false;
225 }
226 DeleteProgram(this->glInterface(), &cachedData);
227 }
228 return true;
229}