3 * Copyright 2011 Google Inc.
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
9 // This is a GPU-backend specific test. It relies on static intializers to work
13 #if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
15 #include "GrAutoLocaleSetter.h"
16 #include "GrContextFactory.h"
17 #include "GrInvariantOutput.h"
18 #include "GrPipeline.h"
20 #include "GrXferProcessor.h"
21 #include "SkChecksum.h"
24 #include "effects/GrConfigConversionEffect.h"
25 #include "effects/GrPorterDuffXferProcessor.h"
26 #include "gl/GrGLGpu.h"
27 #include "gl/GrGLPathRendering.h"
28 #include "gl/builders/GrGLProgramBuilder.h"
31 * A dummy processor which just tries to insert a massive key and verify that it can retrieve the
32 * whole thing correctly
34 static const uint32_t kMaxKeySize = 1024;
36 class GLBigKeyProcessor : public GrGLFragmentProcessor {
38 GLBigKeyProcessor(const GrProcessor&) {}
40 virtual void emitCode(GrGLFPBuilder* builder,
41 const GrFragmentProcessor& fp,
42 const char* outputColor,
43 const char* inputColor,
44 const TransformedCoordsArray&,
45 const TextureSamplerArray&) {}
47 static void GenKey(const GrProcessor& processor, const GrGLCaps&, GrProcessorKeyBuilder* b) {
48 for (uint32_t i = 0; i < kMaxKeySize; i++) {
54 typedef GrGLFragmentProcessor INHERITED;
57 class BigKeyProcessor : public GrFragmentProcessor {
59 static GrFragmentProcessor* Create() {
60 GR_CREATE_STATIC_PROCESSOR(gBigKeyProcessor, BigKeyProcessor, ())
61 return SkRef(gBigKeyProcessor);
64 const char* name() const SK_OVERRIDE { return "Big Ole Key"; }
66 virtual void getGLProcessorKey(const GrGLCaps& caps,
67 GrProcessorKeyBuilder* b) const SK_OVERRIDE {
68 GLBigKeyProcessor::GenKey(*this, caps, b);
71 GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE {
72 return SkNEW_ARGS(GLBigKeyProcessor, (*this));
77 this->initClassID<BigKeyProcessor>();
79 bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE { return true; }
80 void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE { }
82 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
84 typedef GrFragmentProcessor INHERITED;
87 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor);
89 GrFragmentProcessor* BigKeyProcessor::TestCreate(SkRandom*,
91 const GrDrawTargetCaps&,
93 return BigKeyProcessor::Create();
99 static const int kRenderTargetHeight = 1;
100 static const int kRenderTargetWidth = 1;
102 static GrRenderTarget* random_render_target(GrContext* context, SkRandom* random) {
103 // setup render target
104 GrTextureParams params;
105 GrSurfaceDesc texDesc;
106 texDesc.fWidth = kRenderTargetWidth;
107 texDesc.fHeight = kRenderTargetHeight;
108 texDesc.fFlags = kRenderTarget_GrSurfaceFlag;
109 texDesc.fConfig = kRGBA_8888_GrPixelConfig;
110 texDesc.fOrigin = random->nextBool() == true ? kTopLeft_GrSurfaceOrigin :
111 kBottomLeft_GrSurfaceOrigin;
113 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
114 GrUniqueKey::Builder builder(&key, kDomain, 1);
115 builder[0] = texDesc.fOrigin;
118 GrTexture* texture = context->findAndRefCachedTexture(key);
120 texture = context->createTexture(texDesc, true);
122 context->addResourceToCache(key, texture);
125 return texture ? texture->asRenderTarget() : NULL;
128 static void set_random_xpf(GrContext* context, const GrDrawTargetCaps& caps,
129 GrPipelineBuilder* pipelineBuilder, SkRandom* random,
130 GrTexture* dummyTextures[]) {
131 SkAutoTUnref<const GrXPFactory> xpf(
132 GrProcessorTestFactory<GrXPFactory>::CreateStage(random, context, caps, dummyTextures));
134 pipelineBuilder->setXPFactory(xpf.get());
137 static const GrGeometryProcessor* get_random_gp(GrContext* context,
138 const GrDrawTargetCaps& caps,
140 GrTexture* dummyTextures[]) {
141 return GrProcessorTestFactory<GrGeometryProcessor>::CreateStage(random,
147 static void set_random_color_coverage_stages(GrGLGpu* gpu,
148 GrPipelineBuilder* pipelineBuilder,
150 bool usePathRendering,
152 GrTexture* dummyTextures[]) {
153 int numProcs = random->nextULessThan(maxStages + 1);
154 int numColorProcs = random->nextULessThan(numProcs + 1);
156 int currTextureCoordSet = 0;
157 for (int s = 0; s < numProcs;) {
158 SkAutoTUnref<const GrFragmentProcessor> fp(
159 GrProcessorTestFactory<GrFragmentProcessor>::CreateStage(random,
165 // If adding this effect would exceed the max texture coord set count then generate a
166 // new random effect.
167 if (usePathRendering && gpu->glPathRendering()->texturingMode() ==
168 GrGLPathRendering::FixedFunction_TexturingMode) {;
169 int numTransforms = fp->numTransforms();
170 if (currTextureCoordSet + numTransforms >
171 gpu->glCaps().maxFixedFunctionTextureCoords()) {
174 currTextureCoordSet += numTransforms;
177 // finally add the stage to the correct pipeline in the drawstate
178 if (s < numColorProcs) {
179 pipelineBuilder->addColorProcessor(fp);
181 pipelineBuilder->addCoverageProcessor(fp);
187 static void set_random_state(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
189 for (int i = 1; i <= GrPipelineBuilder::kLast_StateBit; i <<= 1) {
190 state |= random->nextBool() * i;
192 pipelineBuilder->enableState(state);
195 // right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'
196 static void set_random_stencil(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
197 GR_STATIC_CONST_SAME_STENCIL(kDoesWriteStencil,
204 GR_STATIC_CONST_SAME_STENCIL(kDoesNotWriteStencil,
212 if (random->nextBool()) {
213 pipelineBuilder->setStencil(kDoesWriteStencil);
215 pipelineBuilder->setStencil(kDoesNotWriteStencil);
219 bool GrDrawTarget::programUnitTest(int maxStages) {
220 GrGLGpu* gpu = static_cast<GrGLGpu*>(fContext->getGpu());
221 // setup dummy textures
222 GrSurfaceDesc dummyDesc;
223 dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
224 dummyDesc.fConfig = kSkia8888_GrPixelConfig;
225 dummyDesc.fWidth = 34;
226 dummyDesc.fHeight = 18;
227 SkAutoTUnref<GrTexture> dummyTexture1(gpu->createTexture(dummyDesc, false, NULL, 0));
228 dummyDesc.fFlags = kNone_GrSurfaceFlags;
229 dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
230 dummyDesc.fWidth = 16;
231 dummyDesc.fHeight = 22;
232 SkAutoTUnref<GrTexture> dummyTexture2(gpu->createTexture(dummyDesc, false, NULL, 0));
234 if (!dummyTexture1 || ! dummyTexture2) {
235 SkDebugf("Could not allocate dummy textures");
239 GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
241 // dummy scissor state
242 GrScissorState scissor;
245 SkRect screen = SkRect::MakeWH(SkIntToScalar(kRenderTargetWidth),
246 SkIntToScalar(kRenderTargetHeight));
249 stack.clipDevRect(screen, SkRegion::kReplace_Op, false);
251 // wrap the SkClipStack in a GrClip
253 clip.setClipStack(&stack);
256 static const int NUM_TESTS = 512;
257 for (int t = 0; t < NUM_TESTS;) {
258 // setup random render target(can fail)
259 SkAutoTUnref<GrRenderTarget> rt(random_render_target(fContext, &random));
261 SkDebugf("Could not allocate render target");
265 GrPipelineBuilder pipelineBuilder;
266 pipelineBuilder.setRenderTarget(rt.get());
267 pipelineBuilder.setClip(clip);
269 // if path rendering we have to setup a couple of things like the draw type
270 bool usePathRendering = gpu->glCaps().pathRenderingSupport() && random.nextBool();
272 // twiddle drawstate knobs randomly
273 bool hasGeometryProcessor = !usePathRendering;
274 SkAutoTUnref<const GrGeometryProcessor> gp;
275 SkAutoTUnref<const GrPathProcessor> pathProc;
276 if (hasGeometryProcessor) {
277 gp.reset(get_random_gp(fContext, gpu->glCaps(), &random, dummyTextures));
279 pathProc.reset(GrPathProcessor::Create(GrColor_WHITE));
281 set_random_color_coverage_stages(gpu,
283 maxStages - hasGeometryProcessor,
288 // creates a random xfer processor factory on the draw state
289 set_random_xpf(fContext, gpu->glCaps(), &pipelineBuilder, &random, dummyTextures);
291 set_random_state(&pipelineBuilder, &random);
292 set_random_stencil(&pipelineBuilder, &random);
294 GrDeviceCoordTexture dstCopy;
296 const GrPrimitiveProcessor* primProc;
297 if (hasGeometryProcessor) {
300 primProc = pathProc.get();
303 const GrProcOptInfo& colorPOI = pipelineBuilder.colorProcInfo(primProc);
304 const GrProcOptInfo& coveragePOI = pipelineBuilder.coverageProcInfo(primProc);
306 if (!this->setupDstReadIfNecessary(pipelineBuilder, colorPOI, coveragePOI, &dstCopy,
308 SkDebugf("Couldn't setup dst read texture");
312 // create optimized draw state, setup readDst texture if required, and build a descriptor
313 // and program. ODS creation can fail, so we have to check
314 GrPipeline pipeline(pipelineBuilder, colorPOI, coveragePOI,
315 *gpu->caps(), scissor, &dstCopy);
316 if (pipeline.mustSkip()) {
320 primProc->initBatchTracker(&bt, pipeline.getInitBatchTracker());
323 gpu->buildProgramDesc(&desc, *primProc, pipeline, bt);
325 GrGpu::DrawArgs args(primProc, &pipeline, &desc, &bt);
326 SkAutoTUnref<GrGLProgram> program(GrGLProgramBuilder::CreateProgram(args, gpu));
328 if (NULL == program.get()) {
329 SkDebugf("Failed to create program!");
333 // because occasionally optimized drawstate creation will fail for valid reasons, we only
334 // want to increment on success
340 DEF_GPUTEST(GLPrograms, reporter, factory) {
341 // Set a locale that would cause shader compilation to fail because of , as decimal separator.
343 #ifdef SK_BUILD_FOR_WIN
344 GrAutoLocaleSetter als("sv-SE");
346 GrAutoLocaleSetter als("sv_SE.UTF-8");
349 for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
350 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(type));
352 GrGLGpu* gpu = static_cast<GrGLGpu*>(context->getGpu());
355 * For the time being, we only support the test with desktop GL or for android on
357 * TODO When we run ES 3.00 GLSL in more places, test again
360 if (kGL_GrGLStandard == gpu->glStandard() ||
361 kARM_GrGLVendor == gpu->ctxInfo().vendor()) {
363 } else if (kTegra3_GrGLRenderer == gpu->ctxInfo().renderer() ||
364 kOther_GrGLRenderer == gpu->ctxInfo().renderer()) {
370 // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
371 if (type == GrContextFactory::kANGLE_GLContextType) {
376 context->getTestTarget(&target);
377 REPORTER_ASSERT(reporter, target.target()->programUnitTest(maxStages));