GLProgramsTest.cpp revision ac856c97acc84dcb54d9cdb068ec8a02b8869647
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 "GrAutoLocaleSetter.h" 16#include "GrBatchTest.h" 17#include "GrContextFactory.h" 18#include "GrInvariantOutput.h" 19#include "GrPipeline.h" 20#include "GrResourceProvider.h" 21#include "GrTest.h" 22#include "GrXferProcessor.h" 23#include "SkChecksum.h" 24#include "SkRandom.h" 25#include "Test.h" 26 27#include "batches/GrDrawBatch.h" 28 29#include "effects/GrConfigConversionEffect.h" 30#include "effects/GrPorterDuffXferProcessor.h" 31 32#include "gl/GrGLGpu.h" 33#include "gl/GrGLPathRendering.h" 34#include "gl/builders/GrGLProgramBuilder.h" 35 36/* 37 * A dummy processor which just tries to insert a massive key and verify that it can retrieve the 38 * whole thing correctly 39 */ 40static const uint32_t kMaxKeySize = 1024; 41 42class GLBigKeyProcessor : public GrGLFragmentProcessor { 43public: 44 GLBigKeyProcessor(const GrProcessor&) {} 45 46 virtual void emitCode(EmitArgs& args) override { 47 // pass through 48 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); 49 fsBuilder->codeAppendf("%s = %s;\n", args.fOutputColor, args.fInputColor); 50 } 51 52 static void GenKey(const GrProcessor& processor, const GrGLSLCaps&, GrProcessorKeyBuilder* b) { 53 for (uint32_t i = 0; i < kMaxKeySize; i++) { 54 b->add32(i); 55 } 56 } 57 58private: 59 typedef GrGLFragmentProcessor INHERITED; 60}; 61 62class BigKeyProcessor : public GrFragmentProcessor { 63public: 64 static GrFragmentProcessor* Create() { 65 GR_CREATE_STATIC_PROCESSOR(gBigKeyProcessor, BigKeyProcessor, ()) 66 return SkRef(gBigKeyProcessor); 67 } 68 69 const char* name() const override { return "Big Ole Key"; } 70 71 GrGLFragmentProcessor* onCreateGLInstance() const override { 72 return new GLBigKeyProcessor(*this); 73 } 74 75private: 76 BigKeyProcessor() { 77 this->initClassID<BigKeyProcessor>(); 78 } 79 virtual void onGetGLProcessorKey(const GrGLSLCaps& caps, 80 GrProcessorKeyBuilder* b) const override { 81 GLBigKeyProcessor::GenKey(*this, caps, b); 82 } 83 bool onIsEqual(const GrFragmentProcessor&) const override { return true; } 84 void onComputeInvariantOutput(GrInvariantOutput* inout) const override { } 85 86 GR_DECLARE_FRAGMENT_PROCESSOR_TEST; 87 88 typedef GrFragmentProcessor INHERITED; 89}; 90 91GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor); 92 93GrFragmentProcessor* BigKeyProcessor::TestCreate(GrProcessorTestData*) { 94 return BigKeyProcessor::Create(); 95} 96 97/* 98 * Begin test code 99 */ 100static const int kRenderTargetHeight = 1; 101static const int kRenderTargetWidth = 1; 102 103static GrRenderTarget* random_render_target(GrTextureProvider* textureProvider, SkRandom* random, 104 const GrCaps* caps) { 105 // setup render target 106 GrTextureParams params; 107 GrSurfaceDesc texDesc; 108 texDesc.fWidth = kRenderTargetWidth; 109 texDesc.fHeight = kRenderTargetHeight; 110 texDesc.fFlags = kRenderTarget_GrSurfaceFlag; 111 texDesc.fConfig = kRGBA_8888_GrPixelConfig; 112 texDesc.fOrigin = random->nextBool() == true ? kTopLeft_GrSurfaceOrigin : 113 kBottomLeft_GrSurfaceOrigin; 114 texDesc.fSampleCnt = random->nextBool() == true ? SkTMin(4, caps->maxSampleCount()) : 0; 115 116 GrUniqueKey key; 117 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); 118 GrUniqueKey::Builder builder(&key, kDomain, 2); 119 builder[0] = texDesc.fOrigin; 120 builder[1] = texDesc.fSampleCnt; 121 builder.finish(); 122 123 GrTexture* texture = textureProvider->findAndRefTextureByUniqueKey(key); 124 if (!texture) { 125 texture = textureProvider->createTexture(texDesc, true); 126 if (texture) { 127 textureProvider->assignUniqueKeyToTexture(key, texture); 128 } 129 } 130 return texture ? texture->asRenderTarget() : NULL; 131} 132 133static void set_random_xpf(GrPipelineBuilder* pipelineBuilder, GrProcessorTestData* d) { 134 SkAutoTUnref<const GrXPFactory> xpf(GrProcessorTestFactory<GrXPFactory>::CreateStage(d)); 135 SkASSERT(xpf); 136 pipelineBuilder->setXPFactory(xpf.get()); 137} 138 139static void set_random_color_coverage_stages(GrPipelineBuilder* pipelineBuilder, 140 GrProcessorTestData* d, int maxStages) { 141 int numProcs = d->fRandom->nextULessThan(maxStages + 1); 142 int numColorProcs = d->fRandom->nextULessThan(numProcs + 1); 143 144 for (int s = 0; s < numProcs;) { 145 SkAutoTUnref<const GrFragmentProcessor> fp( 146 GrProcessorTestFactory<GrFragmentProcessor>::CreateStage(d)); 147 SkASSERT(fp); 148 149 // finally add the stage to the correct pipeline in the drawstate 150 if (s < numColorProcs) { 151 pipelineBuilder->addColorFragmentProcessor(fp); 152 } else { 153 pipelineBuilder->addCoverageFragmentProcessor(fp); 154 } 155 ++s; 156 } 157} 158 159static void set_random_state(GrPipelineBuilder* pipelineBuilder, SkRandom* random) { 160 int state = 0; 161 for (int i = 1; i <= GrPipelineBuilder::kLast_Flag; i <<= 1) { 162 state |= random->nextBool() * i; 163 } 164 165 // If we don't have an MSAA rendertarget then we have to disable useHWAA 166 if ((state | GrPipelineBuilder::kHWAntialias_Flag) && 167 !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled()) { 168 state &= ~GrPipelineBuilder::kHWAntialias_Flag; 169 } 170 pipelineBuilder->enableState(state); 171} 172 173// right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()' 174static void set_random_stencil(GrPipelineBuilder* pipelineBuilder, SkRandom* random) { 175 GR_STATIC_CONST_SAME_STENCIL(kDoesWriteStencil, 176 kReplace_StencilOp, 177 kReplace_StencilOp, 178 kAlways_StencilFunc, 179 0xffff, 180 0xffff, 181 0xffff); 182 GR_STATIC_CONST_SAME_STENCIL(kDoesNotWriteStencil, 183 kKeep_StencilOp, 184 kKeep_StencilOp, 185 kNever_StencilFunc, 186 0xffff, 187 0xffff, 188 0xffff); 189 190 if (random->nextBool()) { 191 pipelineBuilder->setStencil(kDoesWriteStencil); 192 } else { 193 pipelineBuilder->setStencil(kDoesNotWriteStencil); 194 } 195} 196 197bool GrDrawTarget::programUnitTest(GrContext* context, int maxStages) { 198 // setup dummy textures 199 GrSurfaceDesc dummyDesc; 200 dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag; 201 dummyDesc.fConfig = kSkia8888_GrPixelConfig; 202 dummyDesc.fWidth = 34; 203 dummyDesc.fHeight = 18; 204 SkAutoTUnref<GrTexture> dummyTexture1( 205 context->textureProvider()->createTexture(dummyDesc, false, NULL, 0)); 206 dummyDesc.fFlags = kNone_GrSurfaceFlags; 207 dummyDesc.fConfig = kAlpha_8_GrPixelConfig; 208 dummyDesc.fWidth = 16; 209 dummyDesc.fHeight = 22; 210 SkAutoTUnref<GrTexture> dummyTexture2( 211 context->textureProvider()->createTexture(dummyDesc, false, NULL, 0)); 212 213 if (!dummyTexture1 || ! dummyTexture2) { 214 SkDebugf("Could not allocate dummy textures"); 215 return false; 216 } 217 218 GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()}; 219 220 // dummy scissor state 221 GrScissorState scissor; 222 223 // wide open clip 224 GrClip clip; 225 226 SkRandom random; 227 static const int NUM_TESTS = 2048; 228 for (int t = 0; t < NUM_TESTS; t++) { 229 // setup random render target(can fail) 230 SkAutoTUnref<GrRenderTarget> rt(random_render_target( 231 context->textureProvider(), &random, this->caps())); 232 if (!rt.get()) { 233 SkDebugf("Could not allocate render target"); 234 return false; 235 } 236 237 GrPipelineBuilder pipelineBuilder; 238 pipelineBuilder.setRenderTarget(rt.get()); 239 pipelineBuilder.setClip(clip); 240 241 SkAutoTUnref<GrDrawBatch> batch(GrRandomDrawBatch(&random, context)); 242 SkASSERT(batch); 243 244 GrProcessorDataManager procDataManager; 245 GrProcessorTestData ptd(&random, context, &procDataManager, fGpu->caps(), dummyTextures); 246 set_random_color_coverage_stages(&pipelineBuilder, &ptd, maxStages); 247 set_random_xpf(&pipelineBuilder, &ptd); 248 set_random_state(&pipelineBuilder, &random); 249 set_random_stencil(&pipelineBuilder, &random); 250 251 this->drawBatch(pipelineBuilder, batch); 252 } 253 254 // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes) 255 this->flush(); 256 return true; 257} 258 259DEF_GPUTEST(GLPrograms, reporter, factory) { 260 // Set a locale that would cause shader compilation to fail because of , as decimal separator. 261 // skbug 3330 262#ifdef SK_BUILD_FOR_WIN 263 GrAutoLocaleSetter als("sv-SE"); 264#else 265 GrAutoLocaleSetter als("sv_SE.UTF-8"); 266#endif 267 268 // We suppress prints to avoid spew 269 GrContextOptions opts; 270 opts.fSuppressPrints = true; 271 GrContextFactory debugFactory(opts); 272 for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) { 273 GrContext* context = debugFactory.get(static_cast<GrContextFactory::GLContextType>(type)); 274 if (context) { 275 GrGLGpu* gpu = static_cast<GrGLGpu*>(context->getGpu()); 276 277 /* 278 * For the time being, we only support the test with desktop GL or for android on 279 * ARM platforms 280 * TODO When we run ES 3.00 GLSL in more places, test again 281 */ 282 int maxStages; 283 if (kGL_GrGLStandard == gpu->glStandard() || 284 kARM_GrGLVendor == gpu->ctxInfo().vendor()) { 285 maxStages = 6; 286 } else if (kTegra3_GrGLRenderer == gpu->ctxInfo().renderer() || 287 kOther_GrGLRenderer == gpu->ctxInfo().renderer()) { 288 maxStages = 1; 289 } else { 290 return; 291 } 292#if SK_ANGLE 293 // Some long shaders run out of temporary registers in the D3D compiler on ANGLE. 294 if (type == GrContextFactory::kANGLE_GLContextType) { 295 maxStages = 2; 296 } 297#endif 298 GrTestTarget target; 299 context->getTestTarget(&target); 300 REPORTER_ASSERT(reporter, target.target()->programUnitTest(context, maxStages)); 301 } 302 } 303} 304 305#endif 306