• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkTypes.h"
9 #include "Test.h"
10 
11 #if SK_SUPPORT_GPU
12 #include "GrClip.h"
13 #include "GrContext.h"
14 #include "GrGpuResource.h"
15 #include "GrPipelineBuilder.h"
16 #include "GrRenderTargetContext.h"
17 #include "GrRenderTargetContextPriv.h"
18 #include "GrResourceProvider.h"
19 #include "glsl/GrGLSLFragmentProcessor.h"
20 #include "glsl/GrGLSLFragmentShaderBuilder.h"
21 #include "ops/GrNonAAFillRectOp.h"
22 #include "ops/GrTestMeshDrawOp.h"
23 #include <random>
24 
25 namespace {
26 class TestOp : public GrTestMeshDrawOp {
27 public:
28     DEFINE_OP_CLASS_ID
name() const29     const char* name() const override { return "TestOp"; }
30 
Make()31     static std::unique_ptr<GrMeshDrawOp> Make() {
32         return std::unique_ptr<GrMeshDrawOp>(new TestOp);
33     }
34 
35 private:
TestOp()36     TestOp() : INHERITED(ClassID(), SkRect::MakeWH(100, 100), 0xFFFFFFFF) {}
37 
onPrepareDraws(Target * target) const38     void onPrepareDraws(Target* target) const override { return; }
39 
40     typedef GrTestMeshDrawOp INHERITED;
41 };
42 
43 /**
44  * FP used to test ref/IO counts on owned GrGpuResources. Can also be a parent FP to test counts
45  * of resources owned by child FPs.
46  */
47 class TestFP : public GrFragmentProcessor {
48 public:
49     struct Image {
Image__anonb044195a0111::TestFP::Image50         Image(sk_sp<GrTexture> texture, GrIOType ioType) : fTexture(texture), fIOType(ioType) {}
51         sk_sp<GrTexture> fTexture;
52         GrIOType fIOType;
53     };
Make(sk_sp<GrFragmentProcessor> child)54     static sk_sp<GrFragmentProcessor> Make(sk_sp<GrFragmentProcessor> child) {
55         return sk_sp<GrFragmentProcessor>(new TestFP(std::move(child)));
56     }
Make(GrContext * context,const SkTArray<sk_sp<GrTextureProxy>> & proxies,const SkTArray<sk_sp<GrBuffer>> & buffers,const SkTArray<Image> & images)57     static sk_sp<GrFragmentProcessor> Make(GrContext* context,
58                                            const SkTArray<sk_sp<GrTextureProxy>>& proxies,
59                                            const SkTArray<sk_sp<GrBuffer>>& buffers,
60                                            const SkTArray<Image>& images) {
61         return sk_sp<GrFragmentProcessor>(new TestFP(context, proxies, buffers, images));
62     }
63 
name() const64     const char* name() const override { return "test"; }
65 
onGetGLSLProcessorKey(const GrShaderCaps &,GrProcessorKeyBuilder * b) const66     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
67         // We don't really care about reusing these.
68         static int32_t gKey = 0;
69         b->add32(sk_atomic_inc(&gKey));
70     }
71 
72 private:
TestFP(GrContext * context,const SkTArray<sk_sp<GrTextureProxy>> & proxies,const SkTArray<sk_sp<GrBuffer>> & buffers,const SkTArray<Image> & images)73     TestFP(GrContext* context,
74            const SkTArray<sk_sp<GrTextureProxy>>& proxies,
75            const SkTArray<sk_sp<GrBuffer>>& buffers,
76            const SkTArray<Image>& images)
77             : INHERITED(kNone_OptimizationFlags), fSamplers(4), fBuffers(4), fImages(4) {
78         for (const auto& proxy : proxies) {
79             this->addTextureSampler(&fSamplers.emplace_back(context->resourceProvider(), proxy));
80         }
81         for (const auto& buffer : buffers) {
82             this->addBufferAccess(&fBuffers.emplace_back(kRGBA_8888_GrPixelConfig, buffer.get()));
83         }
84         for (const Image& image : images) {
85             this->addImageStorageAccess(&fImages.emplace_back(
86                     image.fTexture, image.fIOType, GrSLMemoryModel::kNone, GrSLRestrict::kNo));
87         }
88     }
89 
TestFP(sk_sp<GrFragmentProcessor> child)90     TestFP(sk_sp<GrFragmentProcessor> child)
91             : INHERITED(kNone_OptimizationFlags), fSamplers(4), fBuffers(4), fImages(4) {
92         this->registerChildProcessor(std::move(child));
93     }
94 
onCreateGLSLInstance() const95     virtual GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
96         class TestGLSLFP : public GrGLSLFragmentProcessor {
97         public:
98             TestGLSLFP() {}
99             void emitCode(EmitArgs& args) override {
100                 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
101                 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, args.fInputColor);
102             }
103 
104         private:
105         };
106         return new TestGLSLFP();
107     }
108 
onIsEqual(const GrFragmentProcessor &) const109     bool onIsEqual(const GrFragmentProcessor&) const override { return false; }
110 
111     GrTAllocator<TextureSampler> fSamplers;
112     GrTAllocator<BufferAccess> fBuffers;
113     GrTAllocator<ImageStorageAccess> fImages;
114     typedef GrFragmentProcessor INHERITED;
115 };
116 }
117 
118 template <typename T>
testingOnly_getIORefCnts(const T * resource,int * refCnt,int * readCnt,int * writeCnt)119 inline void testingOnly_getIORefCnts(const T* resource, int* refCnt, int* readCnt, int* writeCnt) {
120     *refCnt = resource->fRefCnt;
121     *readCnt = resource->fPendingReads;
122     *writeCnt = resource->fPendingWrites;
123 }
124 
testingOnly_getIORefCnts(GrTextureProxy * proxy,int * refCnt,int * readCnt,int * writeCnt)125 void testingOnly_getIORefCnts(GrTextureProxy* proxy, int* refCnt, int* readCnt, int* writeCnt) {
126     *refCnt = proxy->getBackingRefCnt_TestOnly();
127     *readCnt = proxy->getPendingReadCnt_TestOnly();
128     *writeCnt = proxy->getPendingWriteCnt_TestOnly();
129 }
130 
DEF_GPUTEST_FOR_ALL_CONTEXTS(ProcessorRefTest,reporter,ctxInfo)131 DEF_GPUTEST_FOR_ALL_CONTEXTS(ProcessorRefTest, reporter, ctxInfo) {
132     GrContext* context = ctxInfo.grContext();
133 
134     GrTextureDesc desc;
135     desc.fConfig = kRGBA_8888_GrPixelConfig;
136     desc.fWidth = 10;
137     desc.fHeight = 10;
138 
139     for (int parentCnt = 0; parentCnt < 2; parentCnt++) {
140         sk_sp<GrRenderTargetContext> renderTargetContext(context->makeRenderTargetContext(
141                 SkBackingFit::kApprox, 1, 1, kRGBA_8888_GrPixelConfig, nullptr));
142         {
143             bool texelBufferSupport = context->caps()->shaderCaps()->texelBufferSupport();
144             bool imageLoadStoreSupport = context->caps()->shaderCaps()->imageLoadStoreSupport();
145             sk_sp<GrTextureProxy> proxy1(GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
146                                                                       desc,
147                                                                       SkBackingFit::kExact,
148                                                                       SkBudgeted::kYes));
149             sk_sp<GrTexture> texture2(
150                     context->resourceProvider()->createTexture(desc, SkBudgeted::kYes));
151             sk_sp<GrTexture> texture3(
152                     context->resourceProvider()->createTexture(desc, SkBudgeted::kYes));
153             sk_sp<GrTexture> texture4(
154                     context->resourceProvider()->createTexture(desc, SkBudgeted::kYes));
155             sk_sp<GrBuffer> buffer(texelBufferSupport
156                                            ? context->resourceProvider()->createBuffer(
157                                                      1024, GrBufferType::kTexel_GrBufferType,
158                                                      GrAccessPattern::kStatic_GrAccessPattern, 0)
159                                            : nullptr);
160             {
161                 SkTArray<sk_sp<GrTextureProxy>> proxies;
162                 SkTArray<sk_sp<GrBuffer>> buffers;
163                 SkTArray<TestFP::Image> images;
164                 proxies.push_back(proxy1);
165                 if (texelBufferSupport) {
166                     buffers.push_back(buffer);
167                 }
168                 if (imageLoadStoreSupport) {
169                     images.emplace_back(texture2, GrIOType::kRead_GrIOType);
170                     images.emplace_back(texture3, GrIOType::kWrite_GrIOType);
171                     images.emplace_back(texture4, GrIOType::kRW_GrIOType);
172                 }
173                 std::unique_ptr<GrMeshDrawOp> op(TestOp::Make());
174                 GrPaint paint;
175                 auto fp = TestFP::Make(context,
176                                        std::move(proxies), std::move(buffers), std::move(images));
177                 for (int i = 0; i < parentCnt; ++i) {
178                     fp = TestFP::Make(std::move(fp));
179                 }
180                 paint.addColorFragmentProcessor(std::move(fp));
181                 renderTargetContext->priv().testingOnly_addMeshDrawOp(
182                         std::move(paint), GrAAType::kNone, std::move(op));
183             }
184             int refCnt, readCnt, writeCnt;
185 
186             testingOnly_getIORefCnts(proxy1.get(), &refCnt, &readCnt, &writeCnt);
187             REPORTER_ASSERT(reporter, 1 == refCnt);
188             REPORTER_ASSERT(reporter, 1 == readCnt);
189             REPORTER_ASSERT(reporter, 0 == writeCnt);
190 
191             if (texelBufferSupport) {
192                 testingOnly_getIORefCnts(buffer.get(), &refCnt, &readCnt, &writeCnt);
193                 REPORTER_ASSERT(reporter, 1 == refCnt);
194                 REPORTER_ASSERT(reporter, 1 == readCnt);
195                 REPORTER_ASSERT(reporter, 0 == writeCnt);
196             }
197 
198             if (imageLoadStoreSupport) {
199                 testingOnly_getIORefCnts(texture2.get(), &refCnt, &readCnt, &writeCnt);
200                 REPORTER_ASSERT(reporter, 1 == refCnt);
201                 REPORTER_ASSERT(reporter, 1 == readCnt);
202                 REPORTER_ASSERT(reporter, 0 == writeCnt);
203 
204                 testingOnly_getIORefCnts(texture3.get(), &refCnt, &readCnt, &writeCnt);
205                 REPORTER_ASSERT(reporter, 1 == refCnt);
206                 REPORTER_ASSERT(reporter, 0 == readCnt);
207                 REPORTER_ASSERT(reporter, 1 == writeCnt);
208 
209                 testingOnly_getIORefCnts(texture4.get(), &refCnt, &readCnt, &writeCnt);
210                 REPORTER_ASSERT(reporter, 1 == refCnt);
211                 REPORTER_ASSERT(reporter, 1 == readCnt);
212                 REPORTER_ASSERT(reporter, 1 == writeCnt);
213             }
214 
215             context->flush();
216 
217             testingOnly_getIORefCnts(proxy1.get(), &refCnt, &readCnt, &writeCnt);
218             REPORTER_ASSERT(reporter, 1 == refCnt);
219             REPORTER_ASSERT(reporter, 0 == readCnt);
220             REPORTER_ASSERT(reporter, 0 == writeCnt);
221 
222             if (texelBufferSupport) {
223                 testingOnly_getIORefCnts(buffer.get(), &refCnt, &readCnt, &writeCnt);
224                 REPORTER_ASSERT(reporter, 1 == refCnt);
225                 REPORTER_ASSERT(reporter, 0 == readCnt);
226                 REPORTER_ASSERT(reporter, 0 == writeCnt);
227             }
228 
229             if (texelBufferSupport) {
230                 testingOnly_getIORefCnts(texture2.get(), &refCnt, &readCnt, &writeCnt);
231                 REPORTER_ASSERT(reporter, 1 == refCnt);
232                 REPORTER_ASSERT(reporter, 0 == readCnt);
233                 REPORTER_ASSERT(reporter, 0 == writeCnt);
234 
235                 testingOnly_getIORefCnts(texture3.get(), &refCnt, &readCnt, &writeCnt);
236                 REPORTER_ASSERT(reporter, 1 == refCnt);
237                 REPORTER_ASSERT(reporter, 0 == readCnt);
238                 REPORTER_ASSERT(reporter, 0 == writeCnt);
239 
240                 testingOnly_getIORefCnts(texture4.get(), &refCnt, &readCnt, &writeCnt);
241                 REPORTER_ASSERT(reporter, 1 == refCnt);
242                 REPORTER_ASSERT(reporter, 0 == readCnt);
243                 REPORTER_ASSERT(reporter, 0 == writeCnt);
244             }
245         }
246     }
247 }
248 
249 // This test uses the random GrFragmentProcessor test factory, which relies on static initializers.
250 #if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
251 
texel_color(int i,int j)252 static GrColor texel_color(int i, int j) {
253     SkASSERT((unsigned)i < 256 && (unsigned)j < 256);
254     GrColor color = GrColorPackRGBA(j, (uint8_t)(i + j), (uint8_t)(2 * j - i), i);
255     return GrPremulColor(color);
256 }
257 
texel_color4f(int i,int j)258 static GrColor4f texel_color4f(int i, int j) { return GrColor4f::FromGrColor(texel_color(i, j)); }
259 
test_draw_op(GrRenderTargetContext * rtc,sk_sp<GrFragmentProcessor> fp,sk_sp<GrTextureProxy> inputDataProxy)260 void test_draw_op(GrRenderTargetContext* rtc, sk_sp<GrFragmentProcessor> fp,
261                   sk_sp<GrTextureProxy> inputDataProxy) {
262     GrResourceProvider* resourceProvider = rtc->resourceProvider();
263 
264     GrPaint paint;
265     paint.addColorTextureProcessor(resourceProvider, std::move(inputDataProxy),
266                                    nullptr, SkMatrix::I());
267     paint.addColorFragmentProcessor(std::move(fp));
268     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
269     GrPipelineBuilder pb(std::move(paint), GrAAType::kNone);
270     auto op =
271             GrNonAAFillRectOp::Make(GrColor_WHITE, SkMatrix::I(),
272                                     SkRect::MakeWH(rtc->width(), rtc->height()), nullptr, nullptr);
273     rtc->addMeshDrawOp(pb, GrNoClip(), std::move(op));
274 }
275 
276 #include "SkCommandLineFlags.h"
277 DEFINE_bool(randomProcessorTest, false, "Use non-deterministic seed for random processor tests?");
278 
279 #if GR_TEST_UTILS
DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorOptimizationValidationTest,reporter,ctxInfo)280 DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorOptimizationValidationTest, reporter, ctxInfo) {
281     GrContext* context = ctxInfo.grContext();
282     using FPFactory = GrProcessorTestFactory<GrFragmentProcessor>;
283 
284     uint32_t seed = 0;
285     if (FLAGS_randomProcessorTest) {
286         std::random_device rd;
287         seed = rd();
288     }
289     // If a non-deterministic bot fails this test, check the output to see what seed it used, then
290     // hard-code that value here:
291     SkRandom random(seed);
292 
293     sk_sp<GrRenderTargetContext> rtc = context->makeRenderTargetContext(
294             SkBackingFit::kExact, 256, 256, kRGBA_8888_GrPixelConfig, nullptr);
295     GrSurfaceDesc desc;
296     desc.fWidth = 256;
297     desc.fHeight = 256;
298     desc.fFlags = kRenderTarget_GrSurfaceFlag;
299     desc.fConfig = kRGBA_8888_GrPixelConfig;
300 
301     // Put premul data into the RGBA texture that the test FPs can optionally use.
302     std::unique_ptr<GrColor[]> rgbaData(new GrColor[256 * 256]);
303     for (int y = 0; y < 256; ++y) {
304         for (int x = 0; x < 256; ++x) {
305             rgbaData.get()[256 * y + x] =
306                     texel_color(random.nextULessThan(256), random.nextULessThan(256));
307         }
308     }
309     sk_sp<GrTexture> tex0(context->resourceProvider()->createTexture(
310             desc, SkBudgeted::kYes, rgbaData.get(), 256 * sizeof(GrColor)));
311 
312     // Put random values into the alpha texture that the test FPs can optionally use.
313     desc.fConfig = kAlpha_8_GrPixelConfig;
314     std::unique_ptr<uint8_t[]> alphaData(new uint8_t[256 * 256]);
315     for (int y = 0; y < 256; ++y) {
316         for (int x = 0; x < 256; ++x) {
317             alphaData.get()[256 * y + x] = random.nextULessThan(256);
318         }
319     }
320     sk_sp<GrTexture> tex1(context->resourceProvider()->createTexture(desc, SkBudgeted::kYes,
321                                                                      alphaData.get(), 256));
322     GrTexture* textures[] = {tex0.get(), tex1.get()};
323     GrProcessorTestData testData(&random, context, rtc.get(), textures);
324 
325     // Use a different array of premul colors for the output of the fragment processor that preceeds
326     // the fragment processor under test.
327     for (int y = 0; y < 256; ++y) {
328         for (int x = 0; x < 256; ++x) {
329             rgbaData.get()[256 * y + x] = texel_color(x, y);
330         }
331     }
332     desc.fConfig = kRGBA_8888_GrPixelConfig;
333 
334     sk_sp<GrTextureProxy> dataProxy = GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
335                                                                    desc, SkBudgeted::kYes,
336                                                                    rgbaData.get(),
337                                                                    256 * sizeof(GrColor));
338 
339     // Because processors factories configure themselves in random ways, this is not exhaustive.
340     for (int i = 0; i < FPFactory::Count(); ++i) {
341         int timesToInvokeFactory = 5;
342         // Increase the number of attempts if the FP has child FPs since optimizations likely depend
343         // on child optimizations being present.
344         sk_sp<GrFragmentProcessor> fp = FPFactory::MakeIdx(i, &testData);
345         for (int j = 0; j < fp->numChildProcessors(); ++j) {
346             // This value made a reasonable trade off between time and coverage when this test was
347             // written.
348             timesToInvokeFactory *= FPFactory::Count() / 2;
349         }
350         for (int j = 0; j < timesToInvokeFactory; ++j) {
351             fp = FPFactory::MakeIdx(i, &testData);
352             if (!fp->hasConstantOutputForConstantInput() && !fp->preservesOpaqueInput() &&
353                 !fp->compatibleWithCoverageAsAlpha()) {
354                 continue;
355             }
356             test_draw_op(rtc.get(), fp, dataProxy);
357             memset(rgbaData.get(), 0x0, sizeof(GrColor) * 256 * 256);
358             rtc->readPixels(
359                     SkImageInfo::Make(256, 256, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
360                     rgbaData.get(), 0, 0, 0);
361             bool passing = true;
362             if (0) {  // Useful to see what FPs are being tested.
363                 SkString children;
364                 for (int c = 0; c < fp->numChildProcessors(); ++c) {
365                     if (!c) {
366                         children.append("(");
367                     }
368                     children.append(fp->childProcessor(c).name());
369                     children.append(c == fp->numChildProcessors() - 1 ? ")" : ", ");
370                 }
371                 SkDebugf("%s %s\n", fp->name(), children.c_str());
372             }
373             for (int y = 0; y < 256 && passing; ++y) {
374                 for (int x = 0; x < 256 && passing; ++x) {
375                     GrColor input = texel_color(x, y);
376                     GrColor output = rgbaData.get()[y * 256 + x];
377                     if (fp->compatibleWithCoverageAsAlpha()) {
378                         // A modulating processor is allowed to modulate either the input color or
379                         // just the input alpha.
380                         bool legalColorModulation =
381                                 GrColorUnpackA(output) <= GrColorUnpackA(input) &&
382                                 GrColorUnpackR(output) <= GrColorUnpackR(input) &&
383                                 GrColorUnpackG(output) <= GrColorUnpackG(input) &&
384                                 GrColorUnpackB(output) <= GrColorUnpackB(input);
385                         bool legalAlphaModulation =
386                                 GrColorUnpackA(output) <= GrColorUnpackA(input) &&
387                                 GrColorUnpackR(output) <= GrColorUnpackA(input) &&
388                                 GrColorUnpackG(output) <= GrColorUnpackA(input) &&
389                                 GrColorUnpackB(output) <= GrColorUnpackA(input);
390                         if (!legalColorModulation && !legalAlphaModulation) {
391                             ERRORF(reporter,
392                                    "\"Modulating\" processor %s made color/alpha value larger. "
393                                    "Input: 0x%08x, Output: 0x%08x.",
394                                    fp->name(), input, output);
395                             passing = false;
396                         }
397                     }
398                     GrColor4f input4f = texel_color4f(x, y);
399                     GrColor4f output4f = GrColor4f::FromGrColor(output);
400                     GrColor4f expected4f;
401                     if (fp->hasConstantOutputForConstantInput(input4f, &expected4f)) {
402                         float rDiff = fabsf(output4f.fRGBA[0] - expected4f.fRGBA[0]);
403                         float gDiff = fabsf(output4f.fRGBA[1] - expected4f.fRGBA[1]);
404                         float bDiff = fabsf(output4f.fRGBA[2] - expected4f.fRGBA[2]);
405                         float aDiff = fabsf(output4f.fRGBA[3] - expected4f.fRGBA[3]);
406                         static constexpr float kTol = 4 / 255.f;
407                         if (rDiff > kTol || gDiff > kTol || bDiff > kTol || aDiff > kTol) {
408                             ERRORF(reporter,
409                                    "Processor %s claimed output for const input doesn't match "
410                                    "actual output. Error: %f, Tolerance: %f, input: (%f, %f, %f, "
411                                    "%f), actual: (%f, %f, %f, %f), expected(%f, %f, %f, %f)",
412                                    fp->name(), SkTMax(rDiff, SkTMax(gDiff, SkTMax(bDiff, aDiff))),
413                                    kTol, input4f.fRGBA[0], input4f.fRGBA[1], input4f.fRGBA[2],
414                                    input4f.fRGBA[3], output4f.fRGBA[0], output4f.fRGBA[1],
415                                    output4f.fRGBA[2], output4f.fRGBA[3], expected4f.fRGBA[0],
416                                    expected4f.fRGBA[1], expected4f.fRGBA[2], expected4f.fRGBA[3]);
417                             passing = false;
418                         }
419                     }
420                     if (GrColorIsOpaque(input) && fp->preservesOpaqueInput() &&
421                         !GrColorIsOpaque(output)) {
422                         ERRORF(reporter,
423                                "Processor %s claimed opaqueness is preserved but it is not. Input: "
424                                "0x%08x, Output: 0x%08x.",
425                                fp->name(), input, output);
426                         passing = false;
427                     }
428                     if (!passing) {
429                         ERRORF(reporter, "Seed: 0x%08x, Processor details: %s",
430                                seed, fp->dumpInfo().c_str());
431                     }
432                 }
433             }
434         }
435     }
436 }
437 #endif  // GR_TEST_UTILS
438 #endif  // SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
439 #endif  // SK_SUPPORT_GPU
440