GLProgramsTest.cpp revision 4324c3ba707a567d45628b80073c2e44d2d0e4e4
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 "GrBackendEffectFactory.h" 16#include "GrContextFactory.h" 17#include "GrDrawEffect.h" 18#include "effects/GrConfigConversionEffect.h" 19#include "gl/GrGpuGL.h" 20 21#include "SkChecksum.h" 22#include "SkRandom.h" 23#include "Test.h" 24 25void GrGLProgramDesc::setRandom(SkRandom* random, 26 const GrGpuGL* gpu, 27 const GrRenderTarget* dstRenderTarget, 28 const GrTexture* dstCopyTexture, 29 const GrEffectStage* stages[], 30 int numColorStages, 31 int numCoverageStages, 32 int currAttribIndex) { 33 int numEffects = numColorStages + numCoverageStages; 34 size_t keyLength = KeyLength(numEffects); 35 fKey.reset(keyLength); 36 *this->atOffset<uint32_t, kLengthOffset>() = static_cast<uint32_t>(keyLength); 37 memset(this->header(), 0, kHeaderSize); 38 39 KeyHeader* header = this->header(); 40 header->fEmitsPointSize = random->nextBool(); 41 42 header->fPositionAttributeIndex = 0; 43 44 // if the effects have used up all off the available attributes, 45 // don't try to use color or coverage attributes as input 46 do { 47 header->fColorInput = static_cast<GrGLProgramDesc::ColorInput>( 48 random->nextULessThan(kColorInputCnt)); 49 } while (GrDrawState::kMaxVertexAttribCnt <= currAttribIndex && 50 kAttribute_ColorInput == header->fColorInput); 51 header->fColorAttributeIndex = (header->fColorInput == kAttribute_ColorInput) ? 52 currAttribIndex++ : 53 -1; 54 55 do { 56 header->fCoverageInput = static_cast<GrGLProgramDesc::ColorInput>( 57 random->nextULessThan(kColorInputCnt)); 58 } while (GrDrawState::kMaxVertexAttribCnt <= currAttribIndex && 59 kAttribute_ColorInput == header->fCoverageInput); 60 header->fCoverageAttributeIndex = (header->fCoverageInput == kAttribute_ColorInput) ? 61 currAttribIndex++ : 62 -1; 63 64#if GR_GL_EXPERIMENTAL_GS 65 header->fExperimentalGS = gpu->caps()->geometryShaderSupport() && random->nextBool(); 66#endif 67 68 bool useLocalCoords = random->nextBool() && currAttribIndex < GrDrawState::kMaxVertexAttribCnt; 69 header->fLocalCoordAttributeIndex = useLocalCoords ? currAttribIndex++ : -1; 70 71 header->fColorEffectCnt = numColorStages; 72 header->fCoverageEffectCnt = numCoverageStages; 73 74 bool dstRead = false; 75 bool fragPos = false; 76 bool vertexCode = false; 77 int numStages = numColorStages + numCoverageStages; 78 for (int s = 0; s < numStages; ++s) { 79 const GrBackendEffectFactory& factory = (*stages[s]->getEffect())->getFactory(); 80 GrDrawEffect drawEffect(*stages[s], useLocalCoords); 81 this->effectKeys()[s] = factory.glEffectKey(drawEffect, gpu->glCaps()); 82 if ((*stages[s]->getEffect())->willReadDstColor()) { 83 dstRead = true; 84 } 85 if ((*stages[s]->getEffect())->willReadFragmentPosition()) { 86 fragPos = true; 87 } 88 if ((*stages[s]->getEffect())->hasVertexCode()) { 89 vertexCode = true; 90 } 91 } 92 93 if (dstRead) { 94 header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps()); 95 } else { 96 header->fDstReadKey = 0; 97 } 98 if (fragPos) { 99 header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(dstRenderTarget, 100 gpu->glCaps()); 101 } else { 102 header->fFragPosKey = 0; 103 } 104 105 header->fHasVertexCode = vertexCode || 106 useLocalCoords || 107 kAttribute_ColorInput == header->fColorInput || 108 kAttribute_ColorInput == header->fCoverageInput; 109 110 CoverageOutput coverageOutput; 111 bool illegalCoverageOutput; 112 do { 113 coverageOutput = static_cast<CoverageOutput>(random->nextULessThan(kCoverageOutputCnt)); 114 illegalCoverageOutput = (!gpu->caps()->dualSourceBlendingSupport() && 115 CoverageOutputUsesSecondaryOutput(coverageOutput)) || 116 (!dstRead && kCombineWithDst_CoverageOutput == coverageOutput); 117 } while (illegalCoverageOutput); 118 119 header->fCoverageOutput = coverageOutput; 120 121 *this->checksum() = 0; 122 *this->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(fKey.get()), keyLength); 123 fInitialized = true; 124} 125 126bool GrGpuGL::programUnitTest(int maxStages) { 127 128 GrTextureDesc dummyDesc; 129 dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit; 130 dummyDesc.fConfig = kSkia8888_GrPixelConfig; 131 dummyDesc.fWidth = 34; 132 dummyDesc.fHeight = 18; 133 SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0)); 134 dummyDesc.fFlags = kNone_GrTextureFlags; 135 dummyDesc.fConfig = kAlpha_8_GrPixelConfig; 136 dummyDesc.fWidth = 16; 137 dummyDesc.fHeight = 22; 138 SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0)); 139 140 static const int NUM_TESTS = 512; 141 142 SkRandom random; 143 for (int t = 0; t < NUM_TESTS; ++t) { 144 145#if 0 146 GrPrintf("\nTest Program %d\n-------------\n", t); 147 static const int stop = -1; 148 if (t == stop) { 149 int breakpointhere = 9; 150 } 151#endif 152 153 GrGLProgramDesc pdesc; 154 155 int currAttribIndex = 1; // we need to always leave room for position 156 int currTextureCoordSet = 0; 157 int attribIndices[2] = { 0, 0 }; 158 GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()}; 159 160 int numStages = random.nextULessThan(maxStages + 1); 161 int numColorStages = random.nextULessThan(numStages + 1); 162 int numCoverageStages = numStages - numColorStages; 163 164 SkAutoSTMalloc<8, const GrEffectStage*> stages(numStages); 165 166 bool useFixedFunctionTexturing = this->shouldUseFixedFunctionTexturing(); 167 168 for (int s = 0; s < numStages;) { 169 SkAutoTUnref<const GrEffectRef> effect(GrEffectTestFactory::CreateStage( 170 &random, 171 this->getContext(), 172 *this->caps(), 173 dummyTextures)); 174 SkASSERT(effect); 175 int numAttribs = (*effect)->numVertexAttribs(); 176 177 // If adding this effect would exceed the max attrib count then generate a 178 // new random effect. 179 if (currAttribIndex + numAttribs > GrDrawState::kMaxVertexAttribCnt) { 180 continue; 181 } 182 183 184 // If adding this effect would exceed the max texture coord set count then generate a 185 // new random effect. 186 if (useFixedFunctionTexturing && !(*effect)->hasVertexCode()) { 187 int numTransforms = (*effect)->numTransforms(); 188 if (currTextureCoordSet + numTransforms > this->glCaps().maxFixedFunctionTextureCoords()) { 189 continue; 190 } 191 currTextureCoordSet += numTransforms; 192 } 193 194 useFixedFunctionTexturing = useFixedFunctionTexturing && !(*effect)->hasVertexCode(); 195 196 for (int i = 0; i < numAttribs; ++i) { 197 attribIndices[i] = currAttribIndex++; 198 } 199 GrEffectStage* stage = SkNEW_ARGS(GrEffectStage, 200 (effect.get(), attribIndices[0], attribIndices[1])); 201 stages[s] = stage; 202 ++s; 203 } 204 const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1]; 205 pdesc.setRandom(&random, 206 this, 207 dummyTextures[0]->asRenderTarget(), 208 dstTexture, 209 stages.get(), 210 numColorStages, 211 numCoverageStages, 212 currAttribIndex); 213 214 SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this, 215 pdesc, 216 stages, 217 stages + numColorStages)); 218 for (int s = 0; s < numStages; ++s) { 219 SkDELETE(stages[s]); 220 } 221 if (NULL == program.get()) { 222 return false; 223 } 224 } 225 return true; 226} 227 228DEF_GPUTEST(GLPrograms, reporter, factory) { 229 for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) { 230 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(type)); 231 if (NULL != context) { 232 GrGpuGL* gpu = static_cast<GrGpuGL*>(context->getGpu()); 233 int maxStages = 6; 234#if SK_ANGLE 235 // Some long shaders run out of temporary registers in the D3D compiler on ANGLE. 236 if (type == GrContextFactory::kANGLE_GLContextType) { 237 maxStages = 3; 238 } 239#endif 240 REPORTER_ASSERT(reporter, gpu->programUnitTest(maxStages)); 241 } 242 } 243} 244 245// This is evil evil evil. The linker may throw away whole translation units as dead code if it 246// thinks none of the functions are called. It will do this even if there are static initializers 247// in the unit that could pass pointers to functions from the unit out to other translation units! 248// We force some of the effects that would otherwise be discarded to link here. 249 250#include "SkAlphaThresholdFilter.h" 251#include "SkColorMatrixFilter.h" 252#include "SkLightingImageFilter.h" 253#include "SkMagnifierImageFilter.h" 254 255void forceLinking(); 256 257void forceLinking() { 258 SkLightingImageFilter::CreateDistantLitDiffuse(SkPoint3(0,0,0), 0, 0, 0); 259 SkAlphaThresholdFilter::Create(SkRegion(), .5f, .5f); 260 SkMagnifierImageFilter mag(SkRect::MakeWH(SK_Scalar1, SK_Scalar1), SK_Scalar1); 261 GrConfigConversionEffect::Create(NULL, 262 false, 263 GrConfigConversionEffect::kNone_PMConversion, 264 SkMatrix::I()); 265 SkScalar matrix[20]; 266 SkAutoTUnref<SkColorMatrixFilter> cmf(SkColorMatrixFilter::Create(matrix)); 267} 268 269#endif 270