blob: 79c3faf0eeb94aa8e9b49dd15ab047254869d6c0 [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 "GrProgramStageFactory.h"
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +000017
bsalomon@google.comc3841b92012-08-02 18:11:43 +000018#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
bsalomon@google.comc3841b92012-08-02 18:11:43 +000038typedef GrGLProgram::StageDesc StageDesc;
39// TODO: Effects should be able to register themselves for inclusion in the
40// randomly generated shaders. They should be able to configure themselves
41// randomly.
bsalomon@google.comd4726202012-08-03 14:34:46 +000042const GrCustomStage* create_random_effect(StageDesc* stageDesc,
43 GrRandom* random,
44 GrContext* context,
45 GrTexture* dummyTextures[]) {
bsalomon@google.comc3841b92012-08-02 18:11:43 +000046
47 // TODO: Remove this when generator doesn't apply this non-custom-stage
48 // notion to custom stages automatically.
49 static const uint32_t kMulByAlphaMask =
50 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
51 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag;
52
bsalomon@google.comd4726202012-08-03 14:34:46 +000053 // The new code uses SkRandom not GrRandom.
54 // TODO: Remove GrRandom.
55 SkRandom sk_random;
56 sk_random.setSeed(random->nextU());
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +000057 GrCustomStage* stage = GrCustomStageTestFactory::CreateStage(&sk_random,
58 context,
59 dummyTextures);
60 GrAssert(stage);
61 return stage;
bsalomon@google.comc3841b92012-08-02 18:11:43 +000062}
63}
64
65bool GrGpuGL::programUnitTest() {
66
bsalomon@google.comd4726202012-08-03 14:34:46 +000067 GrTextureDesc dummyDesc;
68 dummyDesc.fConfig = kSkia8888_PM_GrPixelConfig;
69 dummyDesc.fWidth = 34;
70 dummyDesc.fHeight = 18;
71 SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
72 dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
73 dummyDesc.fWidth = 16;
74 dummyDesc.fHeight = 22;
75 SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));
76
bsalomon@google.comc3841b92012-08-02 18:11:43 +000077 // GrGLSLGeneration glslGeneration =
78 GrGetGLSLGeneration(this->glBinding(), this->glInterface());
79 static const int STAGE_OPTS[] = {
80 0,
81 StageDesc::kNoPerspective_OptFlagBit,
82 };
83 static const int IN_CONFIG_FLAGS[] = {
84 StageDesc::kNone_InConfigFlag,
85 StageDesc::kSwapRAndB_InConfigFlag,
86 StageDesc::kSwapRAndB_InConfigFlag |
87 StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag,
88 StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag,
89 StageDesc::kSmearAlpha_InConfigFlag,
90 StageDesc::kSmearRed_InConfigFlag,
91 };
92
93 static const int NUM_TESTS = 512;
94
95 GrRandom random;
96 for (int t = 0; t < NUM_TESTS; ++t) {
97
98#if 0
99 GrPrintf("\nTest Program %d\n-------------\n", t);
100 static const int stop = -1;
101 if (t == stop) {
102 int breakpointhere = 9;
103 }
104#endif
105
106 ProgramDesc pdesc;
107 pdesc.fVertexLayout = 0;
108 pdesc.fEmitsPointSize = random.nextF() > .5f;
109 pdesc.fColorInput = random_int(&random, ProgramDesc::kColorInputCnt);
110 pdesc.fCoverageInput = random_int(&random, ProgramDesc::kColorInputCnt);
111
112 pdesc.fColorFilterXfermode = random_int(&random, SkXfermode::kCoeffModesCnt);
113
114 pdesc.fFirstCoverageStage = random_int(&random, GrDrawState::kNumStages);
115
116 pdesc.fVertexLayout |= random_bool(&random) ?
117 GrDrawTarget::kCoverage_VertexLayoutBit :
118 0;
119
120#if GR_GL_EXPERIMENTAL_GS
121 pdesc.fExperimentalGS = this->getCaps().fGeometryShaderSupport &&
122 random_bool(&random);
123#endif
124 pdesc.fOutputConfig = random_int(&random, ProgramDesc::kOutputConfigCnt);
125
126 bool edgeAA = random_bool(&random);
127 if (edgeAA) {
128 pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
129 if (this->getCaps().fShaderDerivativeSupport) {
130 pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
131 } else {
132 pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
133 }
134 } else {
135 }
136
137 pdesc.fColorMatrixEnabled = random_bool(&random);
138
139 if (this->getCaps().fDualSourceBlendingSupport) {
140 pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
141 } else {
142 pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
143 }
144
145 SkAutoTUnref<const GrCustomStage> customStages[GrDrawState::kNumStages];
146
147 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
148 StageDesc& stage = pdesc.fStages[s];
149 // enable the stage?
150 if (random_bool(&random)) {
151 // use separate tex coords?
152 if (random_bool(&random)) {
153 int t = random_int(&random, GrDrawState::kMaxTexCoords);
154 pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
155 }
156 stage.setEnabled(true);
157 }
158 // use text-formatted verts?
159 if (random_bool(&random)) {
160 pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
161 }
162
163 stage.fCustomStageKey = 0;
164
bsalomon@google.comd4726202012-08-03 14:34:46 +0000165 stage.fOptFlags |= STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000166 stage.fInConfigFlags = IN_CONFIG_FLAGS[random_int(&random, GR_ARRAY_COUNT(IN_CONFIG_FLAGS))];
167
bsalomon@google.comd4726202012-08-03 14:34:46 +0000168 if (stage.isEnabled()) {
169 GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
170 customStages[s].reset(create_random_effect(&stage,
171 &random,
172 getContext(),
173 dummyTextures));
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000174 if (NULL != customStages[s]) {
175 stage.fCustomStageKey =
176 customStages[s]->getFactory().glStageKey(*customStages[s], this->glCaps());
177 }
178 }
179 }
180 GR_STATIC_ASSERT(sizeof(customStages) ==
181 GrDrawState::kNumStages * sizeof(GrCustomStage*));
182 const GrCustomStage** stages = reinterpret_cast<const GrCustomStage**>(&customStages);
183 SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this->glContextInfo(),
184 pdesc,
185 stages));
186 if (NULL == program.get()) {
187 return false;
188 }
189 }
190 return true;
191}
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000192
193static void GLProgramsTest(skiatest::Reporter* reporter, GrContext* context) {
bsalomon@google.com5739d2c2012-05-31 15:07:19 +0000194 GrGpuGL* shadersGpu = static_cast<GrGpuGL*>(context->getGpu());
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000195 REPORTER_ASSERT(reporter, shadersGpu->programUnitTest());
196}
197
198
199#include "TestClassDef.h"
200DEFINE_GPUTESTCLASS("GLPrograms", GLProgramsTestClass, GLProgramsTest)
201
bsalomon@google.coma1bf0ff2012-08-07 17:36:29 +0000202// This is evil evil evil. The linker may throw away whole translation units as dead code if it
203// thinks none of the functions are called. It will do this even if there are static initilializers
204// in the unit that could pass pointers to functions from the unit out to other translation units!
205// We force some of the effects that would otherwise be discarded to link here.
206
207#include "SkLightingImageFilter.h"
208
209void forceLinking();
210
211void forceLinking() {
212 SkLightingImageFilter::CreateDistantLitDiffuse(SkPoint3(0,0,0), 0, 0, 0);
213}
214
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000215#endif