blob: 1228b4ef472770e4444df267729723179cb8f62c [file] [log] [blame]
bsalomon@google.coma8e686e2011-08-16 15:45:58 +00001
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
bsalomon@google.comd4726202012-08-03 14:34:46 +00009// This is a GPU-backend specific test. It relies on static intializers to work
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000010
bsalomon@google.com2a48c3a2012-08-03 14:54:45 +000011#include "SkTypes.h"
12
13#if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
14
bsalomon@google.com5739d2c2012-05-31 15:07:19 +000015#include "gl/GrGpuGL.h"
bsalomon@google.comc3841b92012-08-02 18:11:43 +000016#include "SkLightingImageFilter.h"
17#include "GrProgramStageFactory.h"
18#include "GrRandom.h"
19#include "Test.h"
20
21namespace {
22
23// GrRandoms nextU() values have patterns in the low bits
24// So using nextU() % array_count might never take some values.
25int random_int(GrRandom* r, int count) {
26 return (int)(r->nextF() * count);
27}
28
29// min is inclusive, max is exclusive
30int random_int(GrRandom* r, int min, int max) {
31 return (int)(r->nextF() * (max-min)) + min;
32}
33
34bool random_bool(GrRandom* r) {
35 return r->nextF() > .5f;
36}
37
38SkPoint3 random_point3(GrRandom* r) {
39 return SkPoint3(r->nextF(), r->nextF(), r->nextF());
40}
41
bsalomon@google.comc3841b92012-08-02 18:11:43 +000042typedef GrGLProgram::StageDesc StageDesc;
43// TODO: Effects should be able to register themselves for inclusion in the
44// randomly generated shaders. They should be able to configure themselves
45// randomly.
bsalomon@google.comd4726202012-08-03 14:34:46 +000046const GrCustomStage* create_random_effect(StageDesc* stageDesc,
47 GrRandom* random,
48 GrContext* context,
49 GrTexture* dummyTextures[]) {
bsalomon@google.comc3841b92012-08-02 18:11:43 +000050 enum EffectType {
bsalomon@google.comd4726202012-08-03 14:34:46 +000051 /**
52 * Lighting effects don't work in unit test because they assume they insert functions and
53 * assume the names are unique. This breaks when there are two light effects in the same
54 * shader.
55 */
56 /*
bsalomon@google.comc3841b92012-08-02 18:11:43 +000057 kDiffuseDistant_EffectType,
58 kDiffusePoint_EffectType,
59 kDiffuseSpot_EffectType,
60 kSpecularDistant_EffectType,
61 kSpecularPoint_EffectType,
62 kSpecularSpot_EffectType,
bsalomon@google.comd4726202012-08-03 14:34:46 +000063 */
64
bsalomon@google.comc3841b92012-08-02 18:11:43 +000065 kEffectCount
66 };
67
68 // TODO: Remove this when generator doesn't apply this non-custom-stage
69 // notion to custom stages automatically.
70 static const uint32_t kMulByAlphaMask =
71 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
72 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
73
bsalomon@google.comd4726202012-08-03 14:34:46 +000074 // The new code uses SkRandom not GrRandom.
75 // TODO: Remove GrRandom.
76 SkRandom sk_random;
77 sk_random.setSeed(random->nextU());
78
79 bool useFactory = random_bool(random);
80 if (useFactory) {
81 GrCustomStage* stage = GrCustomStageTestFactory::CreateStage(&sk_random,
82 context,
83 dummyTextures);
84 GrAssert(stage);
85 return stage;
86 }
87
bsalomon@google.comc3841b92012-08-02 18:11:43 +000088
89 // TODO: When matrices are property of the custom-stage then remove the
90 // no-persp flag code below.
91 int effect = random_int(random, kEffectCount);
bsalomon@google.com0a7672f2012-08-03 18:12:20 +000092/* switch (effect) {
bsalomon@google.comc3841b92012-08-02 18:11:43 +000093 case kDiffuseDistant_EffectType: {
94 SkPoint3 direction = random_point3(random);
95 direction.normalize();
96 SkColor lightColor = random->nextU();
97 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
98 SkScalar kd = SkFloatToScalar(random->nextF());
99 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitDiffuse(direction, lightColor, surfaceScale, kd));
100 // does not work with perspective or mul-by-alpha-mask
101 GrCustomStage* stage;
102 bool ok = filter->asNewCustomStage(&stage, NULL);
103 SkASSERT(ok);
104 return stage;
105 }
106 case kDiffusePoint_EffectType: {
107 SkPoint3 location = random_point3(random);
108 SkColor lightColor = random->nextU();
109 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
110 SkScalar kd = SkFloatToScalar(random->nextF());
111 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitDiffuse(location, lightColor, surfaceScale, kd));
112 // does not work with perspective or mul-by-alpha-mask
113 GrCustomStage* stage;
114 bool ok = filter->asNewCustomStage(&stage, NULL);
115 SkASSERT(ok);
116 return stage;
117 }
118 case kDiffuseSpot_EffectType: {
119 SkPoint3 location = random_point3(random);
120 SkPoint3 target = random_point3(random);
121 SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
122 SkScalar specularExponent = SkFloatToScalar(random->nextF());
123 SkColor lightColor = random->nextU();
124 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
125 SkScalar ks = SkFloatToScalar(random->nextF());
126 SkScalar shininess = SkFloatToScalar(random->nextF());
127 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
128 location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
129 // does not work with perspective or mul-by-alpha-mask
130 GrCustomStage* stage;
131 bool ok = filter->asNewCustomStage(&stage, NULL);
132 SkASSERT(ok);
133 return stage;
134 }
135 case kSpecularDistant_EffectType: {
136 SkPoint3 direction = random_point3(random);
137 direction.normalize();
138 SkColor lightColor = random->nextU();
139 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
140 SkScalar ks = SkFloatToScalar(random->nextF());
141 SkScalar shininess = SkFloatToScalar(random->nextF());
142 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitSpecular(direction, lightColor, surfaceScale, ks, shininess));
143 // does not work with perspective or mul-by-alpha-mask
144 GrCustomStage* stage;
145 bool ok = filter->asNewCustomStage(&stage, NULL);
146 SkASSERT(ok);
147 return stage;
148 }
149 case kSpecularPoint_EffectType: {
150 SkPoint3 location = random_point3(random);
151 SkColor lightColor = random->nextU();
152 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
153 SkScalar ks = SkFloatToScalar(random->nextF());
154 SkScalar shininess = SkFloatToScalar(random->nextF());
155 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitSpecular(location, lightColor, surfaceScale, ks, shininess));
156 // does not work with perspective or mul-by-alpha-mask
157 GrCustomStage* stage;
158 bool ok = filter->asNewCustomStage(&stage, NULL);
159 SkASSERT(ok);
160 return stage;
161 }
162 case kSpecularSpot_EffectType: {
163 SkPoint3 location = random_point3(random);
164 SkPoint3 target = random_point3(random);
165 SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
166 SkScalar specularExponent = SkFloatToScalar(random->nextF());
167 SkColor lightColor = random->nextU();
168 SkScalar surfaceScale = SkFloatToScalar(random->nextF());
169 SkScalar ks = SkFloatToScalar(random->nextF());
170 SkScalar shininess = SkFloatToScalar(random->nextF());
171 SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
172 location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
173 // does not work with perspective or mul-by-alpha-mask
174 GrCustomStage* stage;
175 bool ok = filter->asNewCustomStage(&stage, NULL);
176 SkASSERT(ok);
177 return stage;
178 }
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000179 default:
180 GrCrash("Unexpected custom effect type");
181 }
bsalomon@google.com0a7672f2012-08-03 18:12:20 +0000182 */
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000183 return NULL;
184}
185}
186
187bool GrGpuGL::programUnitTest() {
188
bsalomon@google.comd4726202012-08-03 14:34:46 +0000189 GrTextureDesc dummyDesc;
190 dummyDesc.fConfig = kSkia8888_PM_GrPixelConfig;
191 dummyDesc.fWidth = 34;
192 dummyDesc.fHeight = 18;
193 SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
194 dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
195 dummyDesc.fWidth = 16;
196 dummyDesc.fHeight = 22;
197 SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));
198
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000199 // GrGLSLGeneration glslGeneration =
200 GrGetGLSLGeneration(this->glBinding(), this->glInterface());
201 static const int STAGE_OPTS[] = {
202 0,
203 StageDesc::kNoPerspective_OptFlagBit,
204 };
205 static const int IN_CONFIG_FLAGS[] = {
206 StageDesc::kNone_InConfigFlag,
207 StageDesc::kSwapRAndB_InConfigFlag,
208 StageDesc::kSwapRAndB_InConfigFlag |
209 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag,
210 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag,
211 StageDesc::kSmearAlpha_InConfigFlag,
212 StageDesc::kSmearRed_InConfigFlag,
213 };
214
215 static const int NUM_TESTS = 512;
216
217 GrRandom random;
218 for (int t = 0; t < NUM_TESTS; ++t) {
219
220#if 0
221 GrPrintf("\nTest Program %d\n-------------\n", t);
222 static const int stop = -1;
223 if (t == stop) {
224 int breakpointhere = 9;
225 }
226#endif
227
228 ProgramDesc pdesc;
229 pdesc.fVertexLayout = 0;
230 pdesc.fEmitsPointSize = random.nextF() > .5f;
231 pdesc.fColorInput = random_int(&random, ProgramDesc::kColorInputCnt);
232 pdesc.fCoverageInput = random_int(&random, ProgramDesc::kColorInputCnt);
233
234 pdesc.fColorFilterXfermode = random_int(&random, SkXfermode::kCoeffModesCnt);
235
236 pdesc.fFirstCoverageStage = random_int(&random, GrDrawState::kNumStages);
237
238 pdesc.fVertexLayout |= random_bool(&random) ?
239 GrDrawTarget::kCoverage_VertexLayoutBit :
240 0;
241
242#if GR_GL_EXPERIMENTAL_GS
243 pdesc.fExperimentalGS = this->getCaps().fGeometryShaderSupport &&
244 random_bool(&random);
245#endif
246 pdesc.fOutputConfig = random_int(&random, ProgramDesc::kOutputConfigCnt);
247
248 bool edgeAA = random_bool(&random);
249 if (edgeAA) {
250 pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
251 if (this->getCaps().fShaderDerivativeSupport) {
252 pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
253 } else {
254 pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
255 }
256 } else {
257 }
258
259 pdesc.fColorMatrixEnabled = random_bool(&random);
260
261 if (this->getCaps().fDualSourceBlendingSupport) {
262 pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
263 } else {
264 pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
265 }
266
267 SkAutoTUnref<const GrCustomStage> customStages[GrDrawState::kNumStages];
268
269 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
270 StageDesc& stage = pdesc.fStages[s];
271 // enable the stage?
272 if (random_bool(&random)) {
273 // use separate tex coords?
274 if (random_bool(&random)) {
275 int t = random_int(&random, GrDrawState::kMaxTexCoords);
276 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
277 }
278 stage.setEnabled(true);
279 }
280 // use text-formatted verts?
281 if (random_bool(&random)) {
282 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
283 }
284
285 stage.fCustomStageKey = 0;
286
bsalomon@google.comd4726202012-08-03 14:34:46 +0000287 stage.fOptFlags |= STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000288 stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];
289
bsalomon@google.comd4726202012-08-03 14:34:46 +0000290 if (stage.isEnabled()) {
291 GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
292 customStages[s].reset(create_random_effect(&stage,
293 &random,
294 getContext(),
295 dummyTextures));
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000296 if (NULL != customStages[s]) {
297 stage.fCustomStageKey =
298 customStages[s]->getFactory().glStageKey(*customStages[s], this->glCaps());
299 }
300 }
301 }
302 GR_STATIC_ASSERT(sizeof(customStages) ==
303 GrDrawState::kNumStages * sizeof(GrCustomStage*));
304 const GrCustomStage** stages = reinterpret_cast<const GrCustomStage**>(&customStages);
305 SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this->glContextInfo(),
306 pdesc,
307 stages));
308 if (NULL == program.get()) {
309 return false;
310 }
311 }
312 return true;
313}
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000314
315static void GLProgramsTest(skiatest::Reporter* reporter, GrContext* context) {
bsalomon@google.com5739d2c2012-05-31 15:07:19 +0000316 GrGpuGL* shadersGpu = static_cast<GrGpuGL*>(context->getGpu());
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000317 REPORTER_ASSERT(reporter, shadersGpu->programUnitTest());
318}
319
320
321#include "TestClassDef.h"
322DEFINE_GPUTESTCLASS("GLPrograms", GLProgramsTestClass, GLProgramsTest)
323
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000324#endif