aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkPM4fPriv.h
blob: aedb0ad20f57ab0aeaae2ae88dfb02fdfa76df11 (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
134
135
136
137
/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef SkPM4fPriv_DEFINED
#define SkPM4fPriv_DEFINED

#include "SkColorPriv.h"
#include "SkColorSpace.h"
#include "SkColorSpace_Base.h"
#include "SkFixedAlloc.h"
#include "SkPM4f.h"
#include "SkRasterPipeline.h"
#include "SkSRGB.h"

static inline Sk4f set_alpha(const Sk4f& px, float alpha) {
    return { px[0], px[1], px[2], alpha };
}

static inline float get_alpha(const Sk4f& px) {
    return px[3];
}


static inline Sk4f Sk4f_fromL32(uint32_t px) {
    return SkNx_cast<float>(Sk4b::Load(&px)) * (1/255.0f);
}

static inline Sk4f Sk4f_fromS32(uint32_t px) {
    return { sk_linear_from_srgb[(px >>  0) & 0xff],
             sk_linear_from_srgb[(px >>  8) & 0xff],
             sk_linear_from_srgb[(px >> 16) & 0xff],
                    (1/255.0f) * (px >> 24)          };
}

static inline uint32_t Sk4f_toL32(const Sk4f& px) {
    uint32_t l32;
    SkNx_cast<uint8_t>(Sk4f_round(px * 255.0f)).store(&l32);
    return l32;
}

static inline uint32_t Sk4f_toS32(const Sk4f& px) {
    Sk4i  rgb = sk_linear_to_srgb(px),
         srgb = { rgb[0], rgb[1], rgb[2], (int)(255.0f * px[3] + 0.5f) };

    uint32_t s32;
    SkNx_cast<uint8_t>(srgb).store(&s32);
    return s32;
}


// SkColor handling:
//   SkColor has an ordering of (b, g, r, a) if cast to an Sk4f, so the code swizzles r and b to
// produce the needed (r, g, b, a) ordering.
static inline Sk4f Sk4f_from_SkColor(SkColor color) {
    return swizzle_rb(Sk4f_fromS32(color));
}

static inline void assert_unit(float x) {
    SkASSERT(0 <= x && x <= 1);
}

static inline float exact_srgb_to_linear(float srgb) {
    assert_unit(srgb);
    float linear;
    if (srgb <= 0.04045) {
        linear = srgb / 12.92f;
    } else {
        linear = powf((srgb + 0.055f) / 1.055f, 2.4f);
    }
    assert_unit(linear);
    return linear;
}


// N.B. scratch_matrix_3x4 must live at least as long as p.
static inline bool append_gamut_transform(SkRasterPipeline* p, float scratch_matrix_3x4[12],
                                          SkColorSpace* src, SkColorSpace* dst) {
    if (src == dst) { return true; }
    if (!dst)       { return true; }   // Legacy modes intentionally ignore color gamut.
    if (!src)       { return true; }   // A null src color space means linear gamma, dst gamut.

    auto toXYZ = as_CSB(src)->  toXYZD50(),
       fromXYZ = as_CSB(dst)->fromXYZD50();
    if (!toXYZ || !fromXYZ) { return false; }  // Unsupported color space type.

    if (as_CSB(src)->toXYZD50Hash() == as_CSB(dst)->toXYZD50Hash()) { return true; }

    SkMatrix44 m44(*fromXYZ, *toXYZ);

    // Convert from 4x4 to (column-major) 3x4.
    auto ptr = scratch_matrix_3x4;
    *ptr++ = m44.get(0,0); *ptr++ = m44.get(1,0); *ptr++ = m44.get(2,0);
    *ptr++ = m44.get(0,1); *ptr++ = m44.get(1,1); *ptr++ = m44.get(2,1);
    *ptr++ = m44.get(0,2); *ptr++ = m44.get(1,2); *ptr++ = m44.get(2,2);
    *ptr++ = m44.get(0,3); *ptr++ = m44.get(1,3); *ptr++ = m44.get(2,3);

    p->append(SkRasterPipeline::matrix_3x4, scratch_matrix_3x4);
    // TODO: detect whether we can skip the clamps?
    p->append(SkRasterPipeline::clamp_0);
    p->append(SkRasterPipeline::clamp_a);
    return true;
}

static inline bool append_gamut_transform(SkRasterPipeline* p, SkFallbackAlloc* scratch,
                                          SkColorSpace* src, SkColorSpace* dst) {
    struct matrix_3x4 { float arr[12]; };
    return append_gamut_transform(p, scratch->make<matrix_3x4>()->arr, src, dst);
}

static inline SkPM4f SkPM4f_from_SkColor(SkColor color, SkColorSpace* dst) {
    SkColor4f color4f;
    if (dst) {
        // sRGB gamma, sRGB gamut.
        color4f = SkColor4f::FromColor(color);
        void* color4f_ptr = &color4f;

        float scratch_matrix_3x4[12];

        SkRasterPipeline p;
        p.append(SkRasterPipeline::constant_color, color4f_ptr);
        append_gamut_transform(&p, scratch_matrix_3x4,
                               SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named).get(), dst);
        p.append(SkRasterPipeline::store_f32, &color4f_ptr);

        p.compile()(0,0,1);
    } else {
        // Linear gamma, dst gamut.
        swizzle_rb(SkNx_cast<float>(Sk4b::Load(&color)) * (1/255.0f)).store(&color4f);
    }
    return color4f.premul();
}

#endif