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