GLProgramsTest.cpp revision a13e202563979fd5076936606dcc1d660da8c632
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 "GrDrawingManager.h" 19#include "GrInvariantOutput.h" 20#include "GrPipeline.h" 21#include "GrResourceProvider.h" 22#include "GrTest.h" 23#include "GrXferProcessor.h" 24#include "SkChecksum.h" 25#include "SkRandom.h" 26#include "Test.h" 27 28#include "batches/GrDrawBatch.h" 29 30#include "effects/GrConfigConversionEffect.h" 31#include "effects/GrPorterDuffXferProcessor.h" 32#include "effects/GrXfermodeFragmentProcessor.h" 33 34#include "gl/GrGLFragmentProcessor.h" 35#include "gl/GrGLGpu.h" 36#include "gl/GrGLPathRendering.h" 37#include "gl/builders/GrGLProgramBuilder.h" 38 39/* 40 * A dummy processor which just tries to insert a massive key and verify that it can retrieve the 41 * whole thing correctly 42 */ 43static const uint32_t kMaxKeySize = 1024; 44 45class GLBigKeyProcessor : public GrGLFragmentProcessor { 46public: 47 GLBigKeyProcessor(const GrProcessor&) {} 48 49 virtual void emitCode(EmitArgs& args) override { 50 // pass through 51 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder(); 52 if (args.fInputColor) { 53 fsBuilder->codeAppendf("%s = %s;\n", args.fOutputColor, args.fInputColor); 54 } else { 55 fsBuilder->codeAppendf("%s = vec4(1.0);\n", args.fOutputColor); 56 } 57 } 58 59 static void GenKey(const GrProcessor& processor, const GrGLSLCaps&, GrProcessorKeyBuilder* b) { 60 for (uint32_t i = 0; i < kMaxKeySize; i++) { 61 b->add32(i); 62 } 63 } 64 65private: 66 typedef GrGLFragmentProcessor INHERITED; 67}; 68 69class BigKeyProcessor : public GrFragmentProcessor { 70public: 71 static GrFragmentProcessor* Create() { 72 return new BigKeyProcessor; 73 } 74 75 const char* name() const override { return "Big Ole Key"; } 76 77 GrGLFragmentProcessor* onCreateGLInstance() const override { 78 return new GLBigKeyProcessor(*this); 79 } 80 81private: 82 BigKeyProcessor() { 83 this->initClassID<BigKeyProcessor>(); 84 } 85 virtual void onGetGLProcessorKey(const GrGLSLCaps& caps, 86 GrProcessorKeyBuilder* b) const override { 87 GLBigKeyProcessor::GenKey(*this, caps, b); 88 } 89 bool onIsEqual(const GrFragmentProcessor&) const override { return true; } 90 void onComputeInvariantOutput(GrInvariantOutput* inout) const override { } 91 92 GR_DECLARE_FRAGMENT_PROCESSOR_TEST; 93 94 typedef GrFragmentProcessor INHERITED; 95}; 96 97GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor); 98 99const GrFragmentProcessor* BigKeyProcessor::TestCreate(GrProcessorTestData*) { 100 return BigKeyProcessor::Create(); 101} 102 103////////////////////////////////////////////////////////////////////////////// 104 105class BlockInputFragmentProcessor : public GrFragmentProcessor { 106public: 107 static GrFragmentProcessor* Create(const GrFragmentProcessor* fp) { 108 return new BlockInputFragmentProcessor(fp); 109 } 110 111 const char* name() const override { return "Block Input"; } 112 113 GrGLFragmentProcessor* onCreateGLInstance() const override { return new GLFP; } 114 115private: 116 class GLFP : public GrGLFragmentProcessor { 117 public: 118 void emitCode(EmitArgs& args) override { 119 this->emitChild(0, nullptr, args); 120 } 121 122 private: 123 typedef GrGLFragmentProcessor INHERITED; 124 }; 125 126 BlockInputFragmentProcessor(const GrFragmentProcessor* child) { 127 this->initClassID<BlockInputFragmentProcessor>(); 128 this->registerChildProcessor(child); 129 } 130 131 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {} 132 133 bool onIsEqual(const GrFragmentProcessor&) const override { return true; } 134 135 void onComputeInvariantOutput(GrInvariantOutput* inout) const override { 136 inout->setToOther(kRGBA_GrColorComponentFlags, GrColor_WHITE, 137 GrInvariantOutput::kWillNot_ReadInput); 138 this->childProcessor(0).computeInvariantOutput(inout); 139 } 140 141 typedef GrFragmentProcessor INHERITED; 142}; 143 144////////////////////////////////////////////////////////////////////////////// 145 146/* 147 * Begin test code 148 */ 149static const int kRenderTargetHeight = 1; 150static const int kRenderTargetWidth = 1; 151 152static GrRenderTarget* random_render_target(GrTextureProvider* textureProvider, SkRandom* random, 153 const GrCaps* caps) { 154 // setup render target 155 GrTextureParams params; 156 GrSurfaceDesc texDesc; 157 texDesc.fWidth = kRenderTargetWidth; 158 texDesc.fHeight = kRenderTargetHeight; 159 texDesc.fFlags = kRenderTarget_GrSurfaceFlag; 160 texDesc.fConfig = kRGBA_8888_GrPixelConfig; 161 texDesc.fOrigin = random->nextBool() == true ? kTopLeft_GrSurfaceOrigin : 162 kBottomLeft_GrSurfaceOrigin; 163 texDesc.fSampleCnt = random->nextBool() == true ? SkTMin(4, caps->maxSampleCount()) : 0; 164 165 GrUniqueKey key; 166 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); 167 GrUniqueKey::Builder builder(&key, kDomain, 2); 168 builder[0] = texDesc.fOrigin; 169 builder[1] = texDesc.fSampleCnt; 170 builder.finish(); 171 172 GrTexture* texture = textureProvider->findAndRefTextureByUniqueKey(key); 173 if (!texture) { 174 texture = textureProvider->createTexture(texDesc, true); 175 if (texture) { 176 textureProvider->assignUniqueKeyToTexture(key, texture); 177 } 178 } 179 return texture ? texture->asRenderTarget() : nullptr; 180} 181 182static void set_random_xpf(GrPipelineBuilder* pipelineBuilder, GrProcessorTestData* d) { 183 SkAutoTUnref<const GrXPFactory> xpf(GrProcessorTestFactory<GrXPFactory>::Create(d)); 184 SkASSERT(xpf); 185 pipelineBuilder->setXPFactory(xpf.get()); 186} 187 188static const GrFragmentProcessor* create_random_proc_tree(GrProcessorTestData* d, 189 int minLevels, int maxLevels) { 190 SkASSERT(1 <= minLevels); 191 SkASSERT(minLevels <= maxLevels); 192 193 // Return a leaf node if maxLevels is 1 or if we randomly chose to terminate. 194 // If returning a leaf node, make sure that it doesn't have children (e.g. another 195 // GrComposeEffect) 196 const float terminateProbability = 0.3f; 197 if (1 == minLevels) { 198 bool terminate = (1 == maxLevels) || (d->fRandom->nextF() < terminateProbability); 199 if (terminate) { 200 const GrFragmentProcessor* fp; 201 while (true) { 202 fp = GrProcessorTestFactory<GrFragmentProcessor>::Create(d); 203 SkASSERT(fp); 204 if (0 == fp->numChildProcessors()) { 205 break; 206 } 207 fp->unref(); 208 } 209 return fp; 210 } 211 } 212 // If we didn't terminate, choose either the left or right subtree to fulfill 213 // the minLevels requirement of this tree; the other child can have as few levels as it wants. 214 // Also choose a random xfer mode that's supported by CreateFrom2Procs(). 215 if (minLevels > 1) { 216 --minLevels; 217 } 218 SkAutoTUnref<const GrFragmentProcessor> minLevelsChild(create_random_proc_tree(d, minLevels, 219 maxLevels - 1)); 220 SkAutoTUnref<const GrFragmentProcessor> otherChild(create_random_proc_tree(d, 1, 221 maxLevels - 1)); 222 SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(d->fRandom->nextRangeU(0, 223 SkXfermode::kLastCoeffMode)); 224 const GrFragmentProcessor* fp; 225 if (d->fRandom->nextF() < 0.5f) { 226 fp = GrXfermodeFragmentProcessor::CreateFromTwoProcessors(minLevelsChild, otherChild, mode); 227 SkASSERT(fp); 228 } else { 229 fp = GrXfermodeFragmentProcessor::CreateFromTwoProcessors(otherChild, minLevelsChild, mode); 230 SkASSERT(fp); 231 } 232 return fp; 233} 234 235static void set_random_color_coverage_stages(GrPipelineBuilder* pipelineBuilder, 236 GrProcessorTestData* d, int maxStages) { 237 // Randomly choose to either create a linear pipeline of procs or create one proc tree 238 const float procTreeProbability = 0.5f; 239 if (d->fRandom->nextF() < procTreeProbability) { 240 // A full tree with 5 levels (31 nodes) may exceed the max allowed length of the gl 241 // processor key; maxTreeLevels should be a number from 1 to 4 inclusive. 242 const int maxTreeLevels = 4; 243 SkAutoTUnref<const GrFragmentProcessor> fp( 244 create_random_proc_tree(d, 2, maxTreeLevels)); 245 pipelineBuilder->addColorFragmentProcessor(fp); 246 } else { 247 int numProcs = d->fRandom->nextULessThan(maxStages + 1); 248 int numColorProcs = d->fRandom->nextULessThan(numProcs + 1); 249 250 for (int s = 0; s < numProcs;) { 251 SkAutoTUnref<const GrFragmentProcessor> fp( 252 GrProcessorTestFactory<GrFragmentProcessor>::Create(d)); 253 SkASSERT(fp); 254 255 // finally add the stage to the correct pipeline in the drawstate 256 if (s < numColorProcs) { 257 pipelineBuilder->addColorFragmentProcessor(fp); 258 } else { 259 pipelineBuilder->addCoverageFragmentProcessor(fp); 260 } 261 ++s; 262 } 263 } 264} 265 266static void set_random_state(GrPipelineBuilder* pipelineBuilder, SkRandom* random) { 267 int state = 0; 268 for (int i = 1; i <= GrPipelineBuilder::kLast_Flag; i <<= 1) { 269 state |= random->nextBool() * i; 270 } 271 272 // If we don't have an MSAA rendertarget then we have to disable useHWAA 273 if ((state | GrPipelineBuilder::kHWAntialias_Flag) && 274 !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled()) { 275 state &= ~GrPipelineBuilder::kHWAntialias_Flag; 276 } 277 pipelineBuilder->enableState(state); 278} 279 280// right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()' 281static void set_random_stencil(GrPipelineBuilder* pipelineBuilder, SkRandom* random) { 282 GR_STATIC_CONST_SAME_STENCIL(kDoesWriteStencil, 283 kReplace_StencilOp, 284 kReplace_StencilOp, 285 kAlways_StencilFunc, 286 0xffff, 287 0xffff, 288 0xffff); 289 GR_STATIC_CONST_SAME_STENCIL(kDoesNotWriteStencil, 290 kKeep_StencilOp, 291 kKeep_StencilOp, 292 kNever_StencilFunc, 293 0xffff, 294 0xffff, 295 0xffff); 296 297 if (random->nextBool()) { 298 pipelineBuilder->setStencil(kDoesWriteStencil); 299 } else { 300 pipelineBuilder->setStencil(kDoesNotWriteStencil); 301 } 302} 303 304bool GrDrawingManager::ProgramUnitTest(GrContext* context, GrDrawTarget* drawTarget, int maxStages) { 305 306 GrDrawingManager* drawingManager = context->drawingManager(); 307 308 // setup dummy textures 309 GrSurfaceDesc dummyDesc; 310 dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag; 311 dummyDesc.fConfig = kSkia8888_GrPixelConfig; 312 dummyDesc.fWidth = 34; 313 dummyDesc.fHeight = 18; 314 SkAutoTUnref<GrTexture> dummyTexture1( 315 context->textureProvider()->createTexture(dummyDesc, false, nullptr, 0)); 316 dummyDesc.fFlags = kNone_GrSurfaceFlags; 317 dummyDesc.fConfig = kAlpha_8_GrPixelConfig; 318 dummyDesc.fWidth = 16; 319 dummyDesc.fHeight = 22; 320 SkAutoTUnref<GrTexture> dummyTexture2( 321 context->textureProvider()->createTexture(dummyDesc, false, nullptr, 0)); 322 323 if (!dummyTexture1 || ! dummyTexture2) { 324 SkDebugf("Could not allocate dummy textures"); 325 return false; 326 } 327 328 GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()}; 329 330 // dummy scissor state 331 GrScissorState scissor; 332 333 // wide open clip 334 GrClip clip; 335 336 SkRandom random; 337 static const int NUM_TESTS = 2048; 338 for (int t = 0; t < NUM_TESTS; t++) { 339 // setup random render target(can fail) 340 SkAutoTUnref<GrRenderTarget> rt(random_render_target( 341 context->textureProvider(), &random, context->caps())); 342 if (!rt.get()) { 343 SkDebugf("Could not allocate render target"); 344 return false; 345 } 346 347 GrPipelineBuilder pipelineBuilder; 348 pipelineBuilder.setRenderTarget(rt.get()); 349 pipelineBuilder.setClip(clip); 350 351 SkAutoTUnref<GrDrawBatch> batch(GrRandomDrawBatch(&random, context)); 352 SkASSERT(batch); 353 354 GrProcessorTestData ptd(&random, context, context->caps(), dummyTextures); 355 set_random_color_coverage_stages(&pipelineBuilder, &ptd, maxStages); 356 set_random_xpf(&pipelineBuilder, &ptd); 357 set_random_state(&pipelineBuilder, &random); 358 set_random_stencil(&pipelineBuilder, &random); 359 360 drawTarget->drawBatch(pipelineBuilder, batch); 361 } 362 // Flush everything, test passes if flush is successful(ie, no asserts are hit, no crashes) 363 drawingManager->flush(); 364 365 // Validate that GrFPs work correctly without an input. 366 GrSurfaceDesc rtDesc; 367 rtDesc.fWidth = kRenderTargetWidth; 368 rtDesc.fHeight = kRenderTargetHeight; 369 rtDesc.fFlags = kRenderTarget_GrSurfaceFlag; 370 rtDesc.fConfig = kRGBA_8888_GrPixelConfig; 371 SkAutoTUnref<GrRenderTarget> rt( 372 context->textureProvider()->createTexture(rtDesc, false)->asRenderTarget()); 373 int fpFactoryCnt = GrProcessorTestFactory<GrFragmentProcessor>::Count(); 374 for (int i = 0; i < fpFactoryCnt; ++i) { 375 // Since FP factories internally randomize, call each 10 times. 376 for (int j = 0; j < 10; ++j) { 377 SkAutoTUnref<GrDrawBatch> batch(GrRandomDrawBatch(&random, context)); 378 SkASSERT(batch); 379 GrProcessorTestData ptd(&random, context, context->caps(), dummyTextures); 380 GrPipelineBuilder builder; 381 builder.setXPFactory(GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode))->unref(); 382 builder.setRenderTarget(rt); 383 builder.setClip(clip); 384 385 SkAutoTUnref<const GrFragmentProcessor> fp( 386 GrProcessorTestFactory<GrFragmentProcessor>::CreateIdx(i, &ptd)); 387 SkAutoTUnref<const GrFragmentProcessor> blockFP( 388 BlockInputFragmentProcessor::Create(fp)); 389 builder.addColorFragmentProcessor(blockFP); 390 391 drawTarget->drawBatch(builder, batch); 392 drawingManager->flush(); 393 } 394 } 395 396 return true; 397} 398 399DEF_GPUTEST(GLPrograms, reporter, factory) { 400 // Set a locale that would cause shader compilation to fail because of , as decimal separator. 401 // skbug 3330 402#ifdef SK_BUILD_FOR_WIN 403 GrAutoLocaleSetter als("sv-SE"); 404#else 405 GrAutoLocaleSetter als("sv_SE.UTF-8"); 406#endif 407 408 // We suppress prints to avoid spew 409 GrContextOptions opts; 410 opts.fSuppressPrints = true; 411 GrContextFactory debugFactory(opts); 412 for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) { 413 GrContext* context = debugFactory.get(static_cast<GrContextFactory::GLContextType>(type)); 414 if (context) { 415 GrGLGpu* gpu = static_cast<GrGLGpu*>(context->getGpu()); 416 417 /* 418 * For the time being, we only support the test with desktop GL or for android on 419 * ARM platforms 420 * TODO When we run ES 3.00 GLSL in more places, test again 421 */ 422 int maxStages; 423 if (kGL_GrGLStandard == gpu->glStandard() || 424 kARM_GrGLVendor == gpu->ctxInfo().vendor()) { 425 maxStages = 6; 426 } else if (kTegra3_GrGLRenderer == gpu->ctxInfo().renderer() || 427 kOther_GrGLRenderer == gpu->ctxInfo().renderer()) { 428 maxStages = 1; 429 } else { 430 return; 431 } 432#if SK_ANGLE 433 // Some long shaders run out of temporary registers in the D3D compiler on ANGLE. 434 if (type == GrContextFactory::kANGLE_GLContextType) { 435 maxStages = 2; 436 } 437#endif 438#if SK_COMMAND_BUFFER 439 // Some long shaders run out of temporary registers in the D3D compiler on ANGLE. 440 // TODO(hendrikw): This only needs to happen with the ANGLE comand buffer backend. 441 if (type == GrContextFactory::kCommandBuffer_GLContextType) { 442 maxStages = 2; 443 } 444#endif 445 GrTestTarget testTarget; 446 context->getTestTarget(&testTarget); 447 REPORTER_ASSERT(reporter, GrDrawingManager::ProgramUnitTest( 448 context, testTarget.target(), maxStages)); 449 } 450 } 451} 452 453#endif 454