SkPM4fPriv.h revision c789b61167dd98efc3c3bfcf9673eef24c2e57f4
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#ifndef SkPM4fPriv_DEFINED
9#define SkPM4fPriv_DEFINED
10
11#include "SkColorPriv.h"
12#include "SkColorSpace.h"
13#include "SkColorSpace_Base.h"
14#include "SkFixedAlloc.h"
15#include "SkPM4f.h"
16#include "SkRasterPipeline.h"
17#include "SkSRGB.h"
18
19static inline Sk4f set_alpha(const Sk4f& px, float alpha) {
20    return { px[0], px[1], px[2], alpha };
21}
22
23static inline float get_alpha(const Sk4f& px) {
24    return px[3];
25}
26
27
28static inline Sk4f Sk4f_fromL32(uint32_t px) {
29    return SkNx_cast<float>(Sk4b::Load(&px)) * (1/255.0f);
30}
31
32static inline Sk4f Sk4f_fromS32(uint32_t px) {
33    return { sk_linear_from_srgb[(px >>  0) & 0xff],
34             sk_linear_from_srgb[(px >>  8) & 0xff],
35             sk_linear_from_srgb[(px >> 16) & 0xff],
36                    (1/255.0f) * (px >> 24)          };
37}
38
39static inline uint32_t Sk4f_toL32(const Sk4f& px) {
40    uint32_t l32;
41    SkNx_cast<uint8_t>(Sk4f_round(px * 255.0f)).store(&l32);
42    return l32;
43}
44
45static inline uint32_t Sk4f_toS32(const Sk4f& px) {
46    Sk4i  rgb = sk_linear_to_srgb(px),
47         srgb = { rgb[0], rgb[1], rgb[2], (int)(255.0f * px[3] + 0.5f) };
48
49    uint32_t s32;
50    SkNx_cast<uint8_t>(srgb).store(&s32);
51    return s32;
52}
53
54
55// SkColor handling:
56//   SkColor has an ordering of (b, g, r, a) if cast to an Sk4f, so the code swizzles r and b to
57// produce the needed (r, g, b, a) ordering.
58static inline Sk4f Sk4f_from_SkColor(SkColor color) {
59    return swizzle_rb(Sk4f_fromS32(color));
60}
61
62static inline void assert_unit(float x) {
63    SkASSERT(0 <= x && x <= 1);
64}
65
66static inline float exact_srgb_to_linear(float srgb) {
67    assert_unit(srgb);
68    float linear;
69    if (srgb <= 0.04045) {
70        linear = srgb / 12.92f;
71    } else {
72        linear = powf((srgb + 0.055f) / 1.055f, 2.4f);
73    }
74    assert_unit(linear);
75    return linear;
76}
77
78
79// N.B. scratch_matrix_3x4 must live at least as long as p.
80static inline bool append_gamut_transform(SkRasterPipeline* p, float scratch_matrix_3x4[12],
81                                          SkColorSpace* src, SkColorSpace* dst) {
82    if (src == dst) { return true; }
83    if (!dst)       { return true; }   // Legacy modes intentionally ignore color gamut.
84    if (!src)       { return true; }   // A null src color space means linear gamma, dst gamut.
85
86    auto toXYZ = as_CSB(src)->  toXYZD50(),
87       fromXYZ = as_CSB(dst)->fromXYZD50();
88    if (!toXYZ || !fromXYZ) { return false; }  // Unsupported color space type.
89
90    if (as_CSB(src)->toXYZD50Hash() == as_CSB(dst)->toXYZD50Hash()) { return true; }
91
92    SkMatrix44 m44(*fromXYZ, *toXYZ);
93
94    // Convert from 4x4 to (column-major) 3x4.
95    auto ptr = scratch_matrix_3x4;
96    *ptr++ = m44.get(0,0); *ptr++ = m44.get(1,0); *ptr++ = m44.get(2,0);
97    *ptr++ = m44.get(0,1); *ptr++ = m44.get(1,1); *ptr++ = m44.get(2,1);
98    *ptr++ = m44.get(0,2); *ptr++ = m44.get(1,2); *ptr++ = m44.get(2,2);
99    *ptr++ = m44.get(0,3); *ptr++ = m44.get(1,3); *ptr++ = m44.get(2,3);
100
101    p->append(SkRasterPipeline::matrix_3x4, scratch_matrix_3x4);
102    // TODO: detect whether we can skip the clamps?
103    p->append(SkRasterPipeline::clamp_0);
104    p->append(SkRasterPipeline::clamp_a);
105    return true;
106}
107
108static inline bool append_gamut_transform(SkRasterPipeline* p, SkFallbackAlloc* scratch,
109                                          SkColorSpace* src, SkColorSpace* dst) {
110    struct matrix_3x4 { float arr[12]; };
111    return append_gamut_transform(p, scratch->make<matrix_3x4>()->arr, src, dst);
112}
113
114static inline SkColor4f SkColor4f_from_SkColor(SkColor color, SkColorSpace* dst) {
115    SkColor4f color4f;
116    if (dst) {
117        // sRGB gamma, sRGB gamut.
118        color4f = SkColor4f::FromColor(color);
119        void* color4f_ptr = &color4f;
120
121        float scratch_matrix_3x4[12];
122
123        SkRasterPipeline p;
124        p.append(SkRasterPipeline::constant_color, color4f_ptr);
125        append_gamut_transform(&p, scratch_matrix_3x4,
126                               SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named).get(), dst);
127        p.append(SkRasterPipeline::store_f32, &color4f_ptr);
128
129        p.run(0,0,1);
130    } else {
131        // Linear gamma, dst gamut.
132        swizzle_rb(SkNx_cast<float>(Sk4b::Load(&color)) * (1/255.0f)).store(&color4f);
133    }
134    return color4f;
135}
136
137static inline SkPM4f SkPM4f_from_SkColor(SkColor color, SkColorSpace* dst) {
138    return SkColor4f_from_SkColor(color, dst).premul();
139}
140
141#endif
142