blob: dd562dda78ae375467d3ac27f819ef01a5b7932a [file] [log] [blame]
bsalomon@google.coma8e686e2011-08-16 15:45:58 +00001
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
bsalomon@google.comd4726202012-08-03 14:34:46 +00009// This is a GPU-backend specific test. It relies on static intializers to work
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000010
bsalomon@google.com2a48c3a2012-08-03 14:54:45 +000011#include "SkTypes.h"
12
13#if SK_SUPPORT_GPU && SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
14
bsalomon@google.com67b915d2013-02-04 16:13:32 +000015#include "GrContextFactory.h"
egdaniel605dd0f2014-11-12 08:35:25 -080016#include "GrInvariantOutput.h"
egdanielc0648242014-09-22 13:17:02 -070017#include "GrOptDrawState.h"
joshualitt2c93efe2014-11-06 12:57:13 -080018#include "GrTest.h"
egdaniel95131432014-12-09 11:15:43 -080019#include "GrXferProcessor.h"
bsalomon@google.com2db3ded2013-05-22 14:34:04 +000020#include "SkChecksum.h"
tfarina@chromium.org223137f2012-11-21 22:38:36 +000021#include "SkRandom.h"
bsalomon@google.comc3841b92012-08-02 18:11:43 +000022#include "Test.h"
joshualitt2c93efe2014-11-06 12:57:13 -080023#include "effects/GrConfigConversionEffect.h"
egdaniel95131432014-12-09 11:15:43 -080024#include "effects/GrPorterDuffXferProcessor.h"
joshualitt2c93efe2014-11-06 12:57:13 -080025#include "gl/GrGLPathRendering.h"
26#include "gl/GrGpuGL.h"
27#include "gl/builders/GrGLProgramBuilder.h"
bsalomon@google.comc3841b92012-08-02 18:11:43 +000028
joshualitt65171342014-10-09 07:25:36 -070029/*
bsalomon98b33eb2014-10-15 11:05:26 -070030 * A dummy processor which just tries to insert a massive key and verify that it can retrieve the
joshualitt65171342014-10-09 07:25:36 -070031 * whole thing correctly
32 */
33static const uint32_t kMaxKeySize = 1024;
34
joshualitt65171342014-10-09 07:25:36 -070035class GLBigKeyProcessor : public GrGLFragmentProcessor {
36public:
joshualitteb2a6762014-12-04 11:35:33 -080037 GLBigKeyProcessor(const GrProcessor&) {}
joshualittd9097592014-10-07 08:37:36 -070038
joshualitt15988992014-10-09 15:04:05 -070039 virtual void emitCode(GrGLFPBuilder* builder,
joshualitt65171342014-10-09 07:25:36 -070040 const GrFragmentProcessor& fp,
joshualitt65171342014-10-09 07:25:36 -070041 const char* outputColor,
42 const char* inputColor,
43 const TransformedCoordsArray&,
joshualitt267ce482014-11-25 14:52:21 -080044 const TextureSamplerArray&) {}
joshualitt65171342014-10-09 07:25:36 -070045
46 static void GenKey(const GrProcessor& processor, const GrGLCaps&, GrProcessorKeyBuilder* b) {
47 for (uint32_t i = 0; i < kMaxKeySize; i++) {
48 b->add32(i);
joshualittd9097592014-10-07 08:37:36 -070049 }
joshualittd9097592014-10-07 08:37:36 -070050 }
51
joshualitt65171342014-10-09 07:25:36 -070052private:
53 typedef GrGLFragmentProcessor INHERITED;
54};
55
joshualitteb2a6762014-12-04 11:35:33 -080056class BigKeyProcessor : public GrFragmentProcessor {
57public:
58 static GrFragmentProcessor* Create() {
59 GR_CREATE_STATIC_PROCESSOR(gBigKeyProcessor, BigKeyProcessor, ())
60 return SkRef(gBigKeyProcessor);
61 }
62
63 virtual const char* name() const SK_OVERRIDE { return "Big Ole Key"; }
64
65 virtual void getGLProcessorKey(const GrGLCaps& caps,
66 GrProcessorKeyBuilder* b) const SK_OVERRIDE {
67 GLBigKeyProcessor::GenKey(*this, caps, b);
68 }
69
70 virtual GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE {
71 return SkNEW_ARGS(GLBigKeyProcessor, (*this));
72 }
73
74private:
75 BigKeyProcessor() {
76 this->initClassID<BigKeyProcessor>();
77 }
78 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE { return true; }
79 virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE { }
80
81 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
82
83 typedef GrFragmentProcessor INHERITED;
84};
85
86GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BigKeyProcessor);
87
88GrFragmentProcessor* BigKeyProcessor::TestCreate(SkRandom*,
89 GrContext*,
90 const GrDrawTargetCaps&,
91 GrTexture*[]) {
92 return BigKeyProcessor::Create();
93}
94
joshualitt65171342014-10-09 07:25:36 -070095/*
96 * Begin test code
97 */
98static const int kRenderTargetHeight = 1;
99static const int kRenderTargetWidth = 1;
100
joshualitt2c93efe2014-11-06 12:57:13 -0800101static GrRenderTarget* random_render_target(GrContext* context,
joshualitt65171342014-10-09 07:25:36 -0700102 const GrCacheID& cacheId,
103 SkRandom* random) {
104 // setup render target
105 GrTextureParams params;
bsalomonf2703d82014-10-28 14:33:06 -0700106 GrSurfaceDesc texDesc;
joshualitt65171342014-10-09 07:25:36 -0700107 texDesc.fWidth = kRenderTargetWidth;
108 texDesc.fHeight = kRenderTargetHeight;
bsalomonf2703d82014-10-28 14:33:06 -0700109 texDesc.fFlags = kRenderTarget_GrSurfaceFlag;
joshualitt65171342014-10-09 07:25:36 -0700110 texDesc.fConfig = kRGBA_8888_GrPixelConfig;
111 texDesc.fOrigin = random->nextBool() == true ? kTopLeft_GrSurfaceOrigin :
112 kBottomLeft_GrSurfaceOrigin;
113
joshualitt2c93efe2014-11-06 12:57:13 -0800114 SkAutoTUnref<GrTexture> texture(context->findAndRefTexture(texDesc, cacheId, &params));
bsalomond27726e2014-10-12 05:40:00 -0700115 if (!texture) {
joshualitt2c93efe2014-11-06 12:57:13 -0800116 texture.reset(context->createTexture(&params, texDesc, cacheId, 0, 0));
bsalomond27726e2014-10-12 05:40:00 -0700117 if (!texture) {
joshualitt65171342014-10-09 07:25:36 -0700118 return NULL;
joshualittd9097592014-10-07 08:37:36 -0700119 }
joshualittd9097592014-10-07 08:37:36 -0700120 }
bsalomond27726e2014-10-12 05:40:00 -0700121 return SkRef(texture->asRenderTarget());
bsalomon@google.com91207482013-02-12 21:45:24 +0000122}
123
egdanielc2304142014-12-11 13:15:13 -0800124static void set_random_xpf(GrContext* context, const GrDrawTargetCaps& caps, GrDrawState* ds,
125 SkRandom* random, GrTexture* dummyTextures[]) {
126 SkAutoTUnref<const GrXPFactory> xpf(
127 GrProcessorTestFactory<GrXPFactory>::CreateStage(random, context, caps, dummyTextures));
128 SkASSERT(xpf);
129 ds->setXPFactory(xpf.get());
130}
131
joshualitt56995b52014-12-11 15:44:02 -0800132static const GrGeometryProcessor* get_random_gp(GrContext* context,
133 const GrDrawTargetCaps& caps,
134 SkRandom* random,
135 GrTexture* dummyTextures[]) {
136 return GrProcessorTestFactory<GrGeometryProcessor>::CreateStage(random,
137 context,
138 caps,
139 dummyTextures);
joshualitt65171342014-10-09 07:25:36 -0700140}
141
bsalomon861e1032014-12-16 07:33:49 -0800142static void set_random_color_coverage_stages(GrGLGpu* gpu,
joshualitt2c93efe2014-11-06 12:57:13 -0800143 GrDrawState* ds,
joshualitt65171342014-10-09 07:25:36 -0700144 int maxStages,
145 bool usePathRendering,
146 SkRandom* random,
147 GrTexture* dummyTextures[]) {
148 int numProcs = random->nextULessThan(maxStages + 1);
149 int numColorProcs = random->nextULessThan(numProcs + 1);
150
151 int currTextureCoordSet = 0;
152 for (int s = 0; s < numProcs;) {
bsalomonae59b772014-11-19 08:23:49 -0800153 SkAutoTUnref<const GrFragmentProcessor> fp(
joshualitt65171342014-10-09 07:25:36 -0700154 GrProcessorTestFactory<GrFragmentProcessor>::CreateStage(random,
155 gpu->getContext(),
156 *gpu->caps(),
157 dummyTextures));
158 SkASSERT(fp);
159
160 // don't add dst color reads to coverage stage
161 if (s >= numColorProcs && fp->willReadDstColor()) {
162 continue;
163 }
164
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()) {
172 continue;
173 }
174 currTextureCoordSet += numTransforms;
175 }
176
177 // finally add the stage to the correct pipeline in the drawstate
joshualitt65171342014-10-09 07:25:36 -0700178 if (s < numColorProcs) {
179 ds->addColorProcessor(fp);
180 } else {
181 ds->addCoverageProcessor(fp);
182 }
183 ++s;
184 }
185}
186
joshualitt2c93efe2014-11-06 12:57:13 -0800187static void set_random_state(GrDrawState* ds, SkRandom* random) {
joshualitt65171342014-10-09 07:25:36 -0700188 int state = 0;
joshualitt7a6184f2014-10-29 18:29:27 -0700189 for (int i = 1; i <= GrDrawState::kLast_StateBit; i <<= 1) {
joshualitt65171342014-10-09 07:25:36 -0700190 state |= random->nextBool() * i;
191 }
joshualitt2c93efe2014-11-06 12:57:13 -0800192 ds->enableState(state);
joshualitt65171342014-10-09 07:25:36 -0700193}
194
joshualitt65171342014-10-09 07:25:36 -0700195// right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'
joshualitt2c93efe2014-11-06 12:57:13 -0800196static void set_random_stencil(GrDrawState* ds, SkRandom* random) {
joshualitt65171342014-10-09 07:25:36 -0700197 GR_STATIC_CONST_SAME_STENCIL(kDoesWriteStencil,
198 kReplace_StencilOp,
199 kReplace_StencilOp,
200 kAlways_StencilFunc,
201 0xffff,
202 0xffff,
203 0xffff);
204 GR_STATIC_CONST_SAME_STENCIL(kDoesNotWriteStencil,
205 kKeep_StencilOp,
206 kKeep_StencilOp,
207 kNever_StencilFunc,
208 0xffff,
209 0xffff,
210 0xffff);
211
212 if (random->nextBool()) {
joshualitt2c93efe2014-11-06 12:57:13 -0800213 ds->setStencil(kDoesWriteStencil);
joshualitt65171342014-10-09 07:25:36 -0700214 } else {
joshualitt2c93efe2014-11-06 12:57:13 -0800215 ds->setStencil(kDoesNotWriteStencil);
joshualitt65171342014-10-09 07:25:36 -0700216 }
217}
joshualitt249af152014-09-15 11:41:13 -0700218
joshualitt2c93efe2014-11-06 12:57:13 -0800219bool GrDrawTarget::programUnitTest(int maxStages) {
bsalomon861e1032014-12-16 07:33:49 -0800220 GrGLGpu* gpu = static_cast<GrGLGpu*>(fContext->getGpu());
joshualitt65171342014-10-09 07:25:36 -0700221 // setup dummy textures
bsalomonf2703d82014-10-28 14:33:06 -0700222 GrSurfaceDesc dummyDesc;
223 dummyDesc.fFlags = kRenderTarget_GrSurfaceFlag;
bsalomon@google.comfec0bc32013-02-07 14:43:04 +0000224 dummyDesc.fConfig = kSkia8888_GrPixelConfig;
bsalomon@google.comd4726202012-08-03 14:34:46 +0000225 dummyDesc.fWidth = 34;
226 dummyDesc.fHeight = 18;
joshualitt2c93efe2014-11-06 12:57:13 -0800227 SkAutoTUnref<GrTexture> dummyTexture1(gpu->createTexture(dummyDesc, NULL, 0));
bsalomonf2703d82014-10-28 14:33:06 -0700228 dummyDesc.fFlags = kNone_GrSurfaceFlags;
bsalomon@google.comd4726202012-08-03 14:34:46 +0000229 dummyDesc.fConfig = kAlpha_8_GrPixelConfig;
230 dummyDesc.fWidth = 16;
231 dummyDesc.fHeight = 22;
joshualitt2c93efe2014-11-06 12:57:13 -0800232 SkAutoTUnref<GrTexture> dummyTexture2(gpu->createTexture(dummyDesc, NULL, 0));
bsalomon@google.comd4726202012-08-03 14:34:46 +0000233
bsalomone904c092014-07-17 10:50:59 -0700234 if (!dummyTexture1 || ! dummyTexture2) {
joshualitt65171342014-10-09 07:25:36 -0700235 SkDebugf("Could not allocate dummy textures");
bsalomone904c092014-07-17 10:50:59 -0700236 return false;
237 }
238
joshualitt65171342014-10-09 07:25:36 -0700239 GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
240
joshualitt54e0c122014-11-19 09:38:51 -0800241 // dummy scissor state
bsalomon3e791242014-12-17 13:43:13 -0800242 GrScissorState scissor;
joshualitt54e0c122014-11-19 09:38:51 -0800243
joshualitt65171342014-10-09 07:25:36 -0700244 // Setup texture cache id key
245 const GrCacheID::Domain glProgramsDomain = GrCacheID::GenerateDomain();
246 GrCacheID::Key key;
247 memset(&key, 0, sizeof(key));
248 key.fData32[0] = kRenderTargetWidth;
249 key.fData32[1] = kRenderTargetHeight;
250 GrCacheID glProgramsCacheID(glProgramsDomain, key);
251
252 // setup clip
joshualitt2c93efe2014-11-06 12:57:13 -0800253 SkRect screen = SkRect::MakeWH(SkIntToScalar(kRenderTargetWidth),
254 SkIntToScalar(kRenderTargetHeight));
joshualitt65171342014-10-09 07:25:36 -0700255
256 SkClipStack stack;
257 stack.clipDevRect(screen, SkRegion::kReplace_Op, false);
258
259 // wrap the SkClipStack in a GrClipData
260 GrClipData clipData;
261 clipData.fClipStack = &stack;
262 this->setClip(&clipData);
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000263
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000264 SkRandom random;
joshualitt65171342014-10-09 07:25:36 -0700265 static const int NUM_TESTS = 512;
266 for (int t = 0; t < NUM_TESTS;) {
267 // setup random render target(can fail)
joshualitt2c93efe2014-11-06 12:57:13 -0800268 SkAutoTUnref<GrRenderTarget> rt(random_render_target(fContext, glProgramsCacheID, &random));
269 if (!rt.get()) {
joshualitt65171342014-10-09 07:25:36 -0700270 SkDebugf("Could not allocate render target");
271 return false;
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000272 }
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000273
joshualitt9853cce2014-11-17 14:22:48 -0800274 GrDrawState ds;
275 ds.setRenderTarget(rt.get());
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000276
joshualitt65171342014-10-09 07:25:36 -0700277 // if path rendering we have to setup a couple of things like the draw type
joshualitt2c93efe2014-11-06 12:57:13 -0800278 bool usePathRendering = gpu->glCaps().pathRenderingSupport() && random.nextBool();
egdanielc0648242014-09-22 13:17:02 -0700279
egdanielae444962014-09-22 12:29:52 -0700280 GrGpu::DrawType drawType = usePathRendering ? GrGpu::kDrawPath_DrawType :
281 GrGpu::kDrawPoints_DrawType;
commit-bot@chromium.org8e919ad2013-10-21 14:48:23 +0000282
joshualitt65171342014-10-09 07:25:36 -0700283 // twiddle drawstate knobs randomly
joshualitt5478d422014-11-14 16:00:38 -0800284 bool hasGeometryProcessor = !usePathRendering;
joshualitt43893e42014-12-13 06:46:13 -0800285 SkAutoTUnref<const GrGeometryProcessor> gp;
286 SkAutoTUnref<const GrPathProcessor> pathProc;
joshualittbd769d02014-09-04 08:56:46 -0700287 if (hasGeometryProcessor) {
joshualitt43893e42014-12-13 06:46:13 -0800288 gp.reset(get_random_gp(fContext, gpu->glCaps(), &random, dummyTextures));
joshualitt56995b52014-12-11 15:44:02 -0800289 } else {
joshualitt43893e42014-12-13 06:46:13 -0800290 pathProc.reset(GrPathProcessor::Create(GrColor_WHITE));
joshualittd9097592014-10-07 08:37:36 -0700291 }
joshualitt2c93efe2014-11-06 12:57:13 -0800292 set_random_color_coverage_stages(gpu,
joshualitt9853cce2014-11-17 14:22:48 -0800293 &ds,
joshualitt2c93efe2014-11-06 12:57:13 -0800294 maxStages - hasGeometryProcessor,
295 usePathRendering,
296 &random,
297 dummyTextures);
egdanielc2304142014-12-11 13:15:13 -0800298
299 // creates a random xfer processor factory on the draw state
300 set_random_xpf(fContext, gpu->glCaps(), &ds, &random, dummyTextures);
301
joshualitt9853cce2014-11-17 14:22:48 -0800302 set_random_state(&ds, &random);
joshualitt9853cce2014-11-17 14:22:48 -0800303 set_random_stencil(&ds, &random);
joshualittd9097592014-10-07 08:37:36 -0700304
joshualitt65171342014-10-09 07:25:36 -0700305 GrDeviceCoordTexture dstCopy;
306
joshualitt56995b52014-12-11 15:44:02 -0800307 const GrPrimitiveProcessor* primProc;
308 if (hasGeometryProcessor) {
joshualitt43893e42014-12-13 06:46:13 -0800309 primProc = gp.get();
joshualitt56995b52014-12-11 15:44:02 -0800310 } else {
joshualitt43893e42014-12-13 06:46:13 -0800311 primProc = pathProc.get();
joshualitt56995b52014-12-11 15:44:02 -0800312 }
313 if (!this->setupDstReadIfNecessary(&ds, primProc, &dstCopy, NULL)) {
joshualitt65171342014-10-09 07:25:36 -0700314 SkDebugf("Couldn't setup dst read texture");
bsalomon848faf02014-07-11 10:01:02 -0700315 return false;
316 }
joshualitt79f8fae2014-10-28 17:59:26 -0700317
318 // create optimized draw state, setup readDst texture if required, and build a descriptor
319 // and program. ODS creation can fail, so we have to check
joshualitt56995b52014-12-11 15:44:02 -0800320 GrOptDrawState ods(ds, gp, pathProc, *gpu->caps(), scissor, &dstCopy, drawType);
bsalomon932f8662014-11-24 06:47:48 -0800321 if (ods.mustSkip()) {
joshualitt79f8fae2014-10-28 17:59:26 -0700322 continue;
joshualittd9097592014-10-07 08:37:36 -0700323 }
joshualittdafa4d02014-12-04 08:59:10 -0800324 ods.finalize(gpu);
325 SkAutoTUnref<GrGLProgram> program(GrGLProgramBuilder::CreateProgram(ods, gpu));
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000326 if (NULL == program.get()) {
joshualitt65171342014-10-09 07:25:36 -0700327 SkDebugf("Failed to create program!");
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000328 return false;
329 }
joshualitt249af152014-09-15 11:41:13 -0700330
joshualitt65171342014-10-09 07:25:36 -0700331 // because occasionally optimized drawstate creation will fail for valid reasons, we only
332 // want to increment on success
333 ++t;
bsalomon@google.comc3841b92012-08-02 18:11:43 +0000334 }
335 return true;
336}
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000337
tfarina@chromium.org4ee16bf2014-01-10 22:08:27 +0000338DEF_GPUTEST(GLPrograms, reporter, factory) {
bsalomon@google.com67b915d2013-02-04 16:13:32 +0000339 for (int type = 0; type < GrContextFactory::kLastGLContextType; ++type) {
340 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(type));
bsalomon49f085d2014-09-05 13:34:00 -0700341 if (context) {
bsalomon861e1032014-12-16 07:33:49 -0800342 GrGLGpu* gpu = static_cast<GrGLGpu*>(context->getGpu());
joshualitt9e87fa72014-10-09 13:12:35 -0700343
344 /*
345 * For the time being, we only support the test with desktop GL or for android on
346 * ARM platforms
347 * TODO When we run ES 3.00 GLSL in more places, test again
348 */
349 int maxStages;
350 if (kGL_GrGLStandard == gpu->glStandard() ||
351 kARM_GrGLVendor == gpu->ctxInfo().vendor()) {
352 maxStages = 6;
353 } else if (kTegra3_GrGLRenderer == gpu->ctxInfo().renderer() ||
354 kOther_GrGLRenderer == gpu->ctxInfo().renderer()) {
355 maxStages = 1;
356 } else {
357 return;
358 }
bsalomon@google.com042a2862013-02-04 18:39:24 +0000359#if SK_ANGLE
360 // Some long shaders run out of temporary registers in the D3D compiler on ANGLE.
361 if (type == GrContextFactory::kANGLE_GLContextType) {
362 maxStages = 3;
363 }
364#endif
joshualitt2c93efe2014-11-06 12:57:13 -0800365 GrTestTarget target;
366 context->getTestTarget(&target);
367 REPORTER_ASSERT(reporter, target.target()->programUnitTest(maxStages));
bsalomon@google.com67b915d2013-02-04 16:13:32 +0000368 }
369 }
bsalomon@google.coma8e686e2011-08-16 15:45:58 +0000370}
371
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000372#endif