GLProgramsTest.cpp revision b9086a026844e4cfd08b219e49ce3f12294cba98
1
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
9// This is a GPU-backend specific test. It relies on static intializers to work
10
11#include "SkTypes.h"
12
13#if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
14
15#include "gl/GrGpuGL.h"
16#include "GrBackendEffectFactory.h"
17#include "effects/GrConfigConversionEffect.h"
18
19#include "GrRandom.h"
20#include "Test.h"
21
22namespace {
23
24// GrRandoms nextU() values have patterns in the low bits
25// So using nextU() % array_count might never take some values.
26int random_int(GrRandom* r, int count) {
27    return (int)(r->nextF() * count);
28}
29
30bool random_bool(GrRandom* r) {
31    return r->nextF() > .5f;
32}
33
34typedef GrGLProgram::StageDesc StageDesc;
35
36const GrEffect* create_random_effect(GrRandom* random,
37                                     GrContext* context,
38                                     GrTexture* dummyTextures[]) {
39
40    // The new code uses SkRandom not GrRandom.
41    // TODO: Remove GrRandom.
42    SkRandom sk_random;
43    sk_random.setSeed(random->nextU());
44    GrEffect* effect = GrEffectTestFactory::CreateStage(&sk_random, context, dummyTextures);
45    GrAssert(effect);
46    return effect;
47}
48}
49
50bool GrGpuGL::programUnitTest() {
51
52    GrTextureDesc dummyDesc;
53    dummyDesc.fConfig = kSkia8888_PM_GrPixelConfig;
54    dummyDesc.fWidth = 34;
55    dummyDesc.fHeight = 18;
56    SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0));
57    dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
58    dummyDesc.fWidth = 16;
59    dummyDesc.fHeight = 22;
60    SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0));
61
62    // GrGLSLGeneration glslGeneration =
63            GrGetGLSLGeneration(this->glBinding(), this->glInterface());
64    static const int STAGE_OPTS[] = {
65        0,
66        StageDesc::kNoPerspective_OptFlagBit,
67    };
68
69    static const int NUM_TESTS = 512;
70
71    GrRandom random;
72    for (int t = 0; t < NUM_TESTS; ++t) {
73
74#if 0
75        GrPrintf("\nTest Program %d\n-------------\n", t);
76        static const int stop = -1;
77        if (t == stop) {
78            int breakpointhere = 9;
79        }
80#endif
81
82        ProgramDesc pdesc;
83        pdesc.fVertexLayout = 0;
84        pdesc.fEmitsPointSize = random.nextF() > .5f;
85        pdesc.fColorInput = random_int(&random, ProgramDesc::kColorInputCnt);
86        pdesc.fCoverageInput = random_int(&random, ProgramDesc::kColorInputCnt);
87
88        pdesc.fColorFilterXfermode = random_int(&random, SkXfermode::kCoeffModesCnt);
89
90        pdesc.fFirstCoverageStage = random_int(&random, GrDrawState::kNumStages);
91
92        pdesc.fVertexLayout |= random_bool(&random) ?
93                                    GrDrawTarget::kCoverage_VertexLayoutBit :
94                                    0;
95
96#if GR_GL_EXPERIMENTAL_GS
97        pdesc.fExperimentalGS = this->getCaps().geometryShaderSupport() &&
98                                random_bool(&random);
99#endif
100
101        bool edgeAA = random_bool(&random);
102        if (edgeAA) {
103            pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
104            if (this->getCaps().shaderDerivativeSupport()) {
105                pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
106            } else {
107                pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
108            }
109        } else {
110        }
111
112        if (this->getCaps().dualSourceBlendingSupport()) {
113            pdesc.fDualSrcOutput = random_int(&random, ProgramDesc::kDualSrcOutputCnt);
114        } else {
115            pdesc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput;
116        }
117
118        GrEffectStage stages[GrDrawState::kNumStages];
119
120        for (int s = 0; s < GrDrawState::kNumStages; ++s) {
121            StageDesc& stageDesc = pdesc.fStages[s];
122            // enable the stage?
123            if (random_bool(&random)) {
124                // use separate tex coords?
125                if (random_bool(&random)) {
126                    int t = random_int(&random, GrDrawState::kMaxTexCoords);
127                    pdesc.fVertexLayout |= StageTexCoordVertexLayoutBit(s, t);
128                }
129                stageDesc.setEnabled(true);
130            }
131            // use text-formatted verts?
132            if (random_bool(&random)) {
133                pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit;
134            }
135
136            stageDesc.fEffectKey = 0;
137            stageDesc.fOptFlags |= STAGE_OPTS[random_int(&random, GR_ARRAY_COUNT(STAGE_OPTS))];
138
139            if (stageDesc.isEnabled()) {
140                GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
141                SkAutoTUnref<const GrEffect> effect(create_random_effect(&random,
142                                                                         getContext(),
143                                                                         dummyTextures));
144                stages[s].setEffect(effect.get());
145                if (NULL != stages[s].getEffect()) {
146                    stageDesc.fEffectKey =
147                        stages[s].getEffect()->getFactory().glEffectKey(stages[s], this->glCaps());
148                }
149            }
150        }
151        const GrEffectStage* stagePtrs[GrDrawState::kNumStages];
152        for (int s = 0; s < GrDrawState::kNumStages; ++s) {
153            stagePtrs[s] = &stages[s];
154        }
155        SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this->glContextInfo(),
156                                                              pdesc,
157                                                              stagePtrs));
158        if (NULL == program.get()) {
159            return false;
160        }
161    }
162    return true;
163}
164
165static void GLProgramsTest(skiatest::Reporter* reporter, GrContext* context) {
166    GrGpuGL* shadersGpu = static_cast<GrGpuGL*>(context->getGpu());
167    REPORTER_ASSERT(reporter, shadersGpu->programUnitTest());
168}
169
170#include "TestClassDef.h"
171DEFINE_GPUTESTCLASS("GLPrograms", GLProgramsTestClass, GLProgramsTest)
172
173// This is evil evil evil. The linker may throw away whole translation units as dead code if it
174// thinks none of the functions are called. It will do this even if there are static initializers
175// in the unit that could pass pointers to functions from the unit out to other translation units!
176// We force some of the effects that would otherwise be discarded to link here.
177
178#include "SkLightingImageFilter.h"
179#include "SkMagnifierImageFilter.h"
180#include "SkColorMatrixFilter.h"
181
182void forceLinking();
183
184void forceLinking() {
185    SkLightingImageFilter::CreateDistantLitDiffuse(SkPoint3(0,0,0), 0, 0, 0);
186    SkMagnifierImageFilter mag(SkRect::MakeWH(SK_Scalar1, SK_Scalar1), SK_Scalar1);
187    GrEffectStage dummyStage;
188    GrConfigConversionEffect::InstallEffect(NULL,
189                                            false,
190                                            GrConfigConversionEffect::kNone_PMConversion,
191                                            SkMatrix::I(),
192                                            &dummyStage);
193    SkScalar matrix[20];
194    SkColorMatrixFilter cmf(matrix);
195}
196
197#endif
198