e5bbc92759b561fb8bc1eaa06c203b8deac8d6a4
[platform/upstream/libSkiaSharp.git] / tests / ProcessorTest.cpp
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
29     const char* name() const override { return "TestOp"; }
30
31     static std::unique_ptr<GrLegacyMeshDrawOp> Make() {
32         return std::unique_ptr<GrLegacyMeshDrawOp>(new TestOp);
33     }
34
35 private:
36     TestOp() : INHERITED(ClassID(), SkRect::MakeWH(100, 100), 0xFFFFFFFF) {}
37
38     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 {
50         Image(sk_sp<GrTexture> texture, GrIOType ioType) : fTexture(texture), fIOType(ioType) {}
51         sk_sp<GrTexture> fTexture;
52         GrIOType fIOType;
53     };
54     static sk_sp<GrFragmentProcessor> Make(sk_sp<GrFragmentProcessor> child) {
55         return sk_sp<GrFragmentProcessor>(new TestFP(std::move(child)));
56     }
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
64     const char* name() const override { return "test"; }
65
66     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:
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
90     TestFP(sk_sp<GrFragmentProcessor> child)
91             : INHERITED(kNone_OptimizationFlags), fSamplers(4), fBuffers(4), fImages(4) {
92         this->registerChildProcessor(std::move(child));
93     }
94
95     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
109     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>
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
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
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->makeDeferredRenderTargetContext(
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<GrLegacyMeshDrawOp> 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_addLegacyMeshDrawOp(
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
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
258 static GrColor4f texel_color4f(int i, int j) { return GrColor4f::FromGrColor(texel_color(i, j)); }
259
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->addLegacyMeshDrawOp(std::move(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
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->makeDeferredRenderTargetContext(
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     sk_sp<GrTextureProxy> proxies[2];
302
303     // Put premul data into the RGBA texture that the test FPs can optionally use.
304     std::unique_ptr<GrColor[]> rgbaData(new GrColor[256 * 256]);
305     for (int y = 0; y < 256; ++y) {
306         for (int x = 0; x < 256; ++x) {
307             rgbaData.get()[256 * y + x] =
308                     texel_color(random.nextULessThan(256), random.nextULessThan(256));
309         }
310     }
311     proxies[0] = GrSurfaceProxy::MakeDeferred(context->resourceProvider(), desc, SkBudgeted::kYes,
312                                               rgbaData.get(), 256 * sizeof(GrColor));
313
314     // Put random values into the alpha texture that the test FPs can optionally use.
315     desc.fConfig = kAlpha_8_GrPixelConfig;
316     std::unique_ptr<uint8_t[]> alphaData(new uint8_t[256 * 256]);
317     for (int y = 0; y < 256; ++y) {
318         for (int x = 0; x < 256; ++x) {
319             alphaData.get()[256 * y + x] = random.nextULessThan(256);
320         }
321     }
322     proxies[1] = GrSurfaceProxy::MakeDeferred(context->resourceProvider(), desc, SkBudgeted::kYes,
323                                               alphaData.get(), 256);
324     GrProcessorTestData testData(&random, context, rtc.get(), proxies);
325
326     // Use a different array of premul colors for the output of the fragment processor that preceeds
327     // the fragment processor under test.
328     for (int y = 0; y < 256; ++y) {
329         for (int x = 0; x < 256; ++x) {
330             rgbaData.get()[256 * y + x] = texel_color(x, y);
331         }
332     }
333     desc.fConfig = kRGBA_8888_GrPixelConfig;
334
335     sk_sp<GrTextureProxy> dataProxy = GrSurfaceProxy::MakeDeferred(context->resourceProvider(),
336                                                                    desc, SkBudgeted::kYes,
337                                                                    rgbaData.get(),
338                                                                    256 * sizeof(GrColor));
339
340     // Because processors factories configure themselves in random ways, this is not exhaustive.
341     for (int i = 0; i < FPFactory::Count(); ++i) {
342         int timesToInvokeFactory = 5;
343         // Increase the number of attempts if the FP has child FPs since optimizations likely depend
344         // on child optimizations being present.
345         sk_sp<GrFragmentProcessor> fp = FPFactory::MakeIdx(i, &testData);
346         for (int j = 0; j < fp->numChildProcessors(); ++j) {
347             // This value made a reasonable trade off between time and coverage when this test was
348             // written.
349             timesToInvokeFactory *= FPFactory::Count() / 2;
350         }
351         for (int j = 0; j < timesToInvokeFactory; ++j) {
352             fp = FPFactory::MakeIdx(i, &testData);
353             if (!fp->hasConstantOutputForConstantInput() && !fp->preservesOpaqueInput() &&
354                 !fp->compatibleWithCoverageAsAlpha()) {
355                 continue;
356             }
357             test_draw_op(rtc.get(), fp, dataProxy);
358             memset(rgbaData.get(), 0x0, sizeof(GrColor) * 256 * 256);
359             rtc->readPixels(
360                     SkImageInfo::Make(256, 256, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
361                     rgbaData.get(), 0, 0, 0);
362             bool passing = true;
363             if (0) {  // Useful to see what FPs are being tested.
364                 SkString children;
365                 for (int c = 0; c < fp->numChildProcessors(); ++c) {
366                     if (!c) {
367                         children.append("(");
368                     }
369                     children.append(fp->childProcessor(c).name());
370                     children.append(c == fp->numChildProcessors() - 1 ? ")" : ", ");
371                 }
372                 SkDebugf("%s %s\n", fp->name(), children.c_str());
373             }
374             for (int y = 0; y < 256 && passing; ++y) {
375                 for (int x = 0; x < 256 && passing; ++x) {
376                     GrColor input = texel_color(x, y);
377                     GrColor output = rgbaData.get()[y * 256 + x];
378                     if (fp->compatibleWithCoverageAsAlpha()) {
379                         // A modulating processor is allowed to modulate either the input color or
380                         // just the input alpha.
381                         bool legalColorModulation =
382                                 GrColorUnpackA(output) <= GrColorUnpackA(input) &&
383                                 GrColorUnpackR(output) <= GrColorUnpackR(input) &&
384                                 GrColorUnpackG(output) <= GrColorUnpackG(input) &&
385                                 GrColorUnpackB(output) <= GrColorUnpackB(input);
386                         bool legalAlphaModulation =
387                                 GrColorUnpackA(output) <= GrColorUnpackA(input) &&
388                                 GrColorUnpackR(output) <= GrColorUnpackA(input) &&
389                                 GrColorUnpackG(output) <= GrColorUnpackA(input) &&
390                                 GrColorUnpackB(output) <= GrColorUnpackA(input);
391                         if (!legalColorModulation && !legalAlphaModulation) {
392                             ERRORF(reporter,
393                                    "\"Modulating\" processor %s made color/alpha value larger. "
394                                    "Input: 0x%08x, Output: 0x%08x.",
395                                    fp->name(), input, output);
396                             passing = false;
397                         }
398                     }
399                     GrColor4f input4f = texel_color4f(x, y);
400                     GrColor4f output4f = GrColor4f::FromGrColor(output);
401                     GrColor4f expected4f;
402                     if (fp->hasConstantOutputForConstantInput(input4f, &expected4f)) {
403                         float rDiff = fabsf(output4f.fRGBA[0] - expected4f.fRGBA[0]);
404                         float gDiff = fabsf(output4f.fRGBA[1] - expected4f.fRGBA[1]);
405                         float bDiff = fabsf(output4f.fRGBA[2] - expected4f.fRGBA[2]);
406                         float aDiff = fabsf(output4f.fRGBA[3] - expected4f.fRGBA[3]);
407                         static constexpr float kTol = 4 / 255.f;
408                         if (rDiff > kTol || gDiff > kTol || bDiff > kTol || aDiff > kTol) {
409                             ERRORF(reporter,
410                                    "Processor %s claimed output for const input doesn't match "
411                                    "actual output. Error: %f, Tolerance: %f, input: (%f, %f, %f, "
412                                    "%f), actual: (%f, %f, %f, %f), expected(%f, %f, %f, %f)",
413                                    fp->name(), SkTMax(rDiff, SkTMax(gDiff, SkTMax(bDiff, aDiff))),
414                                    kTol, input4f.fRGBA[0], input4f.fRGBA[1], input4f.fRGBA[2],
415                                    input4f.fRGBA[3], output4f.fRGBA[0], output4f.fRGBA[1],
416                                    output4f.fRGBA[2], output4f.fRGBA[3], expected4f.fRGBA[0],
417                                    expected4f.fRGBA[1], expected4f.fRGBA[2], expected4f.fRGBA[3]);
418                             passing = false;
419                         }
420                     }
421                     if (GrColorIsOpaque(input) && fp->preservesOpaqueInput() &&
422                         !GrColorIsOpaque(output)) {
423                         ERRORF(reporter,
424                                "Processor %s claimed opaqueness is preserved but it is not. Input: "
425                                "0x%08x, Output: 0x%08x.",
426                                fp->name(), input, output);
427                         passing = false;
428                     }
429                     if (!passing) {
430                         ERRORF(reporter, "Seed: 0x%08x, Processor details: %s",
431                                seed, fp->dumpInfo().c_str());
432                     }
433                 }
434             }
435         }
436     }
437 }
438 #endif  // GR_TEST_UTILS
439 #endif  // SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
440 #endif  // SK_SUPPORT_GPU