aboutsummaryrefslogtreecommitdiffhomepage
path: root/gm/gammaencodedpremul.cpp
blob: 1d7bb5702f493d67073589333b5f56ed12e98394 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Copyright 2017 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkColorPriv.h"
#include "SkColorSpaceXform.h"
#include "SkColorSpaceXformPriv.h"
#include "SkOpts.h"
#include "SkUtils.h"

static void clamp_to_alpha(uint32_t* pixels, int count) {
    for (int i = 0; i < count; i++) {
        uint8_t a = SkGetPackedA32(pixels[i]);
        uint8_t r = SkGetPackedR32(pixels[i]);
        uint8_t g = SkGetPackedG32(pixels[i]);
        uint8_t b = SkGetPackedB32(pixels[i]);
        pixels[i] = SkPackARGB32(a,
                                 SkTMin(a, r),
                                 SkTMin(a, g),
                                 SkTMin(a, b));
    }
}

class GammaEncodedPremulGM : public skiagm::GM {
public:
    GammaEncodedPremulGM(sk_sp<SkColorSpace> dst, sk_sp<SkColorSpace> src, const char* desc)
        : fDstSpace(dst)
        , fSrcSpace(src)
        , fXform(SkColorSpaceXform::New(src.get(), dst.get()))
        , fName(SkStringPrintf("gamma_encoded_premul_dst-v-src_%s", desc))
    {
        int i = 0;
        for (int r = 0; r < kColorSteps; r++) {
            for (int g = 0; g < kColorSteps; g++) {
                for (int b = 0; b < kColorSteps; b++) {
                    fColors[i++] = SkColorSetRGB(r * kColorScale,
                                                 g * kColorScale,
                                                 b * kColorScale);
                }
            }
        }

    }

protected:
    virtual SkISize onISize() override {
        return SkISize::Make(kAlphaMax, kNumColors * 2 * kStripeHeight);
    }

    SkString onShortName() override {
        return fName;
    }

    void onDraw(SkCanvas* canvas) override {
        if (canvas->imageInfo().isOpaque()) {
            return;
        }

        SkBitmap bitmap;
        SkImageInfo bitmapInfo = SkImageInfo::MakeN32Premul(kAlphaMax, 1,
                canvas->imageInfo().refColorSpace());
        bitmap.allocPixels(bitmapInfo);
        uint32_t* pixels = bitmap.getAddr32(0, 0);

        for (int i = 0; i < kNumColors; i++) {
            // Create an entire row of the same color, with the alpha from 0 to kAlphaMax.
            uint32_t row[kAlphaMax];
            sk_memset32(row, fColors[i], kAlphaMax);
            for (int a = 0; a < kAlphaMax; a++) {
                row[a] = (row[a] & 0x00FFFFFF) | (a << 24);
            }

            // Tranform row to dst, then premultiply.
            fXform->apply(select_xform_format(kN32_SkColorType), pixels,
                          SkColorSpaceXform::kBGRA_8888_ColorFormat, row, kAlphaMax,
                          kUnpremul_SkAlphaType);
            SkOpts::RGBA_to_rgbA(pixels, pixels, kAlphaMax);
            bitmap.notifyPixelsChanged();

            // Write the dst space premultiplied row to the canvas.
            for (int j = 0; j < kStripeHeight; j++) {
                canvas->drawBitmap(bitmap, 0, 2 * i * kStripeHeight + j);
            }

            // Premultiply, then transform the row to dst.
            SkOpts::RGBA_to_rgbA(pixels, row, kAlphaMax);
            fXform->apply(select_xform_format(kN32_SkColorType), pixels,
                          SkColorSpaceXform::kBGRA_8888_ColorFormat, pixels, kAlphaMax,
                          kUnpremul_SkAlphaType);
            clamp_to_alpha(pixels, kAlphaMax);
            bitmap.notifyPixelsChanged();

            // Write the src space premultiplied row to the canvas.
            for (int j = 0; j < kStripeHeight; j++) {
                canvas->drawBitmap(bitmap, 0, (2 * i + 1) * kStripeHeight + j);
            }
        }
    }

private:
    static constexpr int kColorSteps = 4;
    static constexpr int kNumColors = kColorSteps * kColorSteps * kColorSteps;
    static constexpr int kColorScale = 255 / (kColorSteps - 1);
    static constexpr int kStripeHeight = 10;
    static constexpr int kAlphaMax = 255;

    sk_sp<SkColorSpace>                fDstSpace;
    sk_sp<SkColorSpace>                fSrcSpace;
    std::unique_ptr<SkColorSpaceXform> fXform;
    SkString                           fName;
    SkColor                            fColors[kNumColors];

    typedef GM INHERITED;
};

DEF_GM(return new GammaEncodedPremulGM(SkColorSpace::MakeSRGB(),
        SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kRec2020_Gamut),
        "toWideGamut");)
DEF_GM(return new GammaEncodedPremulGM(SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
        SkColorSpace::kRec2020_Gamut), SkColorSpace::MakeSRGB(), "fromWideGamut");)
DEF_GM(return new GammaEncodedPremulGM(SkColorSpace::MakeSRGB(),
        SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, SkColorSpace::kSRGB_Gamut),
        "toLinear");)
DEF_GM(return new GammaEncodedPremulGM(
        SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, SkColorSpace::kSRGB_Gamut),
        SkColorSpace::MakeSRGB(), "fromLinear");)
DEF_GM(return new GammaEncodedPremulGM(
        SkColorSpace::MakeRGB({ 1.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
        SkColorSpace::kSRGB_Gamut), SkColorSpace::MakeSRGB(), "from1.8");)