1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2018 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot@header {
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #include "GrClip.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #include "GrContext.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #include "GrContextPriv.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #include "GrProxyProvider.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    #include "GrRenderTargetContext.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot@class {
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static bool TestForPreservingPMConversions(GrContext* context) {
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static constexpr int kSize = 256;
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static constexpr GrPixelConfig kConfig = kRGBA_8888_GrPixelConfig;
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkAutoTMalloc<uint32_t> data(kSize * kSize * 3);
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t* srcData = data.get();
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t* firstRead = data.get() + kSize * kSize;
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        uint32_t* secondRead = data.get() + 2 * kSize * kSize;
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Fill with every possible premultiplied A, color channel value. There will be 256-y
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // duplicate values in row y. We set r, g, and b to the same value since they are handled
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // identically.
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int y = 0; y < kSize; ++y) {
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int x = 0; x < kSize; ++x) {
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                uint8_t* color = reinterpret_cast<uint8_t*>(&srcData[kSize*y + x]);
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                color[3] = y;
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                color[2] = SkTMin(x, y);
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                color[1] = SkTMin(x, y);
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                color[0] = SkTMin(x, y);
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkImageInfo ii = SkImageInfo::Make(kSize, kSize,
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        sk_sp<GrRenderTargetContext> readRTC(context->makeDeferredRenderTargetContext(
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                              SkBackingFit::kExact,
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                              kSize, kSize,
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                              kConfig, nullptr));
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        sk_sp<GrRenderTargetContext> tempRTC(context->makeDeferredRenderTargetContext(
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                              SkBackingFit::kExact,
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                              kSize, kSize,
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                              kConfig, nullptr));
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!readRTC || !readRTC->asTextureProxy() || !tempRTC) {
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return false;
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Adding discard to appease vulkan validation warning about loading uninitialized data on
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // draw
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        readRTC->discard();
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrSurfaceDesc desc;
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        desc.fOrigin = kTopLeft_GrSurfaceOrigin;
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        desc.fWidth = kSize;
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        desc.fHeight = kSize;
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        desc.fConfig = kConfig;
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        sk_sp<GrTextureProxy> dataProxy = proxyProvider->createTextureProxy(desc, SkBudgeted::kYes,
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                            data, 0);
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!dataProxy) {
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return false;
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static const SkRect kRect = SkRect::MakeIWH(kSize, kSize);
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // We do a PM->UPM draw from dataTex to readTex and read the data. Then we do a UPM->PM draw
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // from readTex to tempTex followed by a PM->UPM draw to readTex and finally read the data.
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // We then verify that two reads produced the same values.
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrPaint paint1;
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrPaint paint2;
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        GrPaint paint3;
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        std::unique_ptr<GrFragmentProcessor> pmToUPM(
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                new GrConfigConversionEffect(PMConversion::kToUnpremul));
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        std::unique_ptr<GrFragmentProcessor> upmToPM(
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                new GrConfigConversionEffect(PMConversion::kToPremul));
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        paint1.addColorTextureProcessor(dataProxy, SkMatrix::I());
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        paint1.addColorFragmentProcessor(pmToUPM->clone());
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        paint1.setPorterDuffXPFactory(SkBlendMode::kSrc);
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        readRTC->fillRectToRect(GrNoClip(), std::move(paint1), GrAA::kNo, SkMatrix::I(), kRect,
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                kRect);
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!readRTC->readPixels(ii, firstRead, 0, 0, 0)) {
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return false;
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // Adding discard to appease vulkan validation warning about loading uninitialized data on
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // draw
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        tempRTC->discard();
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        paint2.addColorTextureProcessor(readRTC->asTextureProxyRef(), SkMatrix::I());
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        paint2.addColorFragmentProcessor(std::move(upmToPM));
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        paint2.setPorterDuffXPFactory(SkBlendMode::kSrc);
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        tempRTC->fillRectToRect(GrNoClip(), std::move(paint2), GrAA::kNo, SkMatrix::I(), kRect,
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                kRect);
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        paint3.addColorTextureProcessor(tempRTC->asTextureProxyRef(), SkMatrix::I());
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        paint3.addColorFragmentProcessor(std::move(pmToUPM));
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        paint3.setPorterDuffXPFactory(SkBlendMode::kSrc);
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        readRTC->fillRectToRect(GrNoClip(), std::move(paint3), GrAA::kNo, SkMatrix::I(), kRect,
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                kRect);
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!readRTC->readPixels(ii, secondRead, 0, 0, 0)) {
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return false;
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int y = 0; y < kSize; ++y) {
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int x = 0; x <= y; ++x) {
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (firstRead[kSize * y + x] != secondRead[kSize * y + x]) {
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    return false;
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return true;
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot@make {
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                     PMConversion pmConversion) {
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!fp) {
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return nullptr;
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        std::unique_ptr<GrFragmentProcessor> ccFP(new GrConfigConversionEffect(pmConversion));
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        std::unique_ptr<GrFragmentProcessor> fpPipeline[] = { std::move(fp), std::move(ccFP) };
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return GrFragmentProcessor::RunInSeries(fpPipeline, 2);
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotlayout(key) in PMConversion pmConversion;
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot@emitCode {
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fragBuilder->forceHighPrecision();
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid main() {
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Aggressively round to the nearest exact (N / 255) floating point value. This lets us find a
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // round-trip preserving pair on some GPUs that do odd byte to float conversion.
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_OutColor = floor(sk_InColor * 255 + 0.5) / 255;
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    @switch (pmConversion) {
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case PMConversion::kToPremul:
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            sk_OutColor.rgb = floor(sk_OutColor.rgb * sk_OutColor.a * 255 + 0.5) / 255;
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        case PMConversion::kToUnpremul:
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            sk_OutColor.rgb = sk_OutColor.a <= 0.0 ?
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                          half3(0) :
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                          floor(sk_OutColor.rgb / sk_OutColor.a * 255 + 0.5) / 255;
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            break;
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot@test(data) {
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    PMConversion pmConv = static_cast<PMConversion>(data->fRandom->nextULessThan(
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                             (int) PMConversion::kPMConversionCnt));
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return std::unique_ptr<GrFragmentProcessor>(new GrConfigConversionEffect(pmConv));
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
169