1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2016 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef skgpu_Swizzle_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define skgpu_Swizzle_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTypeTraits.h"
15*c8dee2aaSAndroid Build Coastguard Worker
16*c8dee2aaSAndroid Build Coastguard Worker #include <array>
17*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
18*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
19*c8dee2aaSAndroid Build Coastguard Worker #include <type_traits>
20*c8dee2aaSAndroid Build Coastguard Worker
21*c8dee2aaSAndroid Build Coastguard Worker class SkRasterPipeline;
22*c8dee2aaSAndroid Build Coastguard Worker enum SkAlphaType : int;
23*c8dee2aaSAndroid Build Coastguard Worker
24*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu {
25*c8dee2aaSAndroid Build Coastguard Worker
26*c8dee2aaSAndroid Build Coastguard Worker /** Represents a rgba swizzle. It can be converted either into a string or a eight bit int. */
27*c8dee2aaSAndroid Build Coastguard Worker class Swizzle {
28*c8dee2aaSAndroid Build Coastguard Worker public:
29*c8dee2aaSAndroid Build Coastguard Worker // Equivalent to "rgba", but Clang doesn't always manage to inline this
30*c8dee2aaSAndroid Build Coastguard Worker // if we're too deep in the inlining already.
Swizzle()31*c8dee2aaSAndroid Build Coastguard Worker constexpr Swizzle() : Swizzle(0x3210) {}
32*c8dee2aaSAndroid Build Coastguard Worker explicit constexpr Swizzle(const char c[4]);
33*c8dee2aaSAndroid Build Coastguard Worker
34*c8dee2aaSAndroid Build Coastguard Worker constexpr Swizzle(const Swizzle&) = default;
35*c8dee2aaSAndroid Build Coastguard Worker constexpr Swizzle& operator=(const Swizzle& that) = default;
36*c8dee2aaSAndroid Build Coastguard Worker
37*c8dee2aaSAndroid Build Coastguard Worker static constexpr Swizzle Concat(const Swizzle& a, const Swizzle& b);
38*c8dee2aaSAndroid Build Coastguard Worker
39*c8dee2aaSAndroid Build Coastguard Worker constexpr bool operator==(const Swizzle& that) const { return fKey == that.fKey; }
40*c8dee2aaSAndroid Build Coastguard Worker constexpr bool operator!=(const Swizzle& that) const { return !(*this == that); }
41*c8dee2aaSAndroid Build Coastguard Worker
42*c8dee2aaSAndroid Build Coastguard Worker /** Compact representation of the swizzle suitable for a key. */
asKey()43*c8dee2aaSAndroid Build Coastguard Worker constexpr uint16_t asKey() const { return fKey; }
44*c8dee2aaSAndroid Build Coastguard Worker
45*c8dee2aaSAndroid Build Coastguard Worker /** 4 char null terminated string consisting only of chars 'r', 'g', 'b', 'a', '0', and '1'. */
46*c8dee2aaSAndroid Build Coastguard Worker SkString asString() const;
47*c8dee2aaSAndroid Build Coastguard Worker
48*c8dee2aaSAndroid Build Coastguard Worker constexpr char operator[](int i) const { return IToC(this->channelIndex(i)); }
49*c8dee2aaSAndroid Build Coastguard Worker
50*c8dee2aaSAndroid Build Coastguard Worker // Returns a new swizzle that moves the swizzle component in index i to index 0 (e.g. "R") and
51*c8dee2aaSAndroid Build Coastguard Worker // sets all other channels to 0. For a swizzle `s`, this is constructing "s[i]000".
52*c8dee2aaSAndroid Build Coastguard Worker constexpr Swizzle selectChannelInR(int i) const;
53*c8dee2aaSAndroid Build Coastguard Worker
54*c8dee2aaSAndroid Build Coastguard Worker /** Applies this swizzle to the input color and returns the swizzled color. */
55*c8dee2aaSAndroid Build Coastguard Worker constexpr std::array<float, 4> applyTo(std::array<float, 4> color) const;
56*c8dee2aaSAndroid Build Coastguard Worker
57*c8dee2aaSAndroid Build Coastguard Worker /** Convenience version for SkRGBA colors. */
58*c8dee2aaSAndroid Build Coastguard Worker template <SkAlphaType AlphaType>
applyTo(SkRGBA4f<AlphaType> color)59*c8dee2aaSAndroid Build Coastguard Worker constexpr SkRGBA4f<AlphaType> applyTo(SkRGBA4f<AlphaType> color) const {
60*c8dee2aaSAndroid Build Coastguard Worker std::array<float, 4> result = this->applyTo(color.array());
61*c8dee2aaSAndroid Build Coastguard Worker return {result[0], result[1], result[2], result[3]};
62*c8dee2aaSAndroid Build Coastguard Worker }
63*c8dee2aaSAndroid Build Coastguard Worker
64*c8dee2aaSAndroid Build Coastguard Worker void apply(SkRasterPipeline*) const;
65*c8dee2aaSAndroid Build Coastguard Worker
RGBA()66*c8dee2aaSAndroid Build Coastguard Worker static constexpr Swizzle RGBA() { return Swizzle("rgba"); }
BGRA()67*c8dee2aaSAndroid Build Coastguard Worker static constexpr Swizzle BGRA() { return Swizzle("bgra"); }
RRRA()68*c8dee2aaSAndroid Build Coastguard Worker static constexpr Swizzle RRRA() { return Swizzle("rrra"); }
RGB1()69*c8dee2aaSAndroid Build Coastguard Worker static constexpr Swizzle RGB1() { return Swizzle("rgb1"); }
70*c8dee2aaSAndroid Build Coastguard Worker
71*c8dee2aaSAndroid Build Coastguard Worker using sk_is_trivially_relocatable = std::true_type;
72*c8dee2aaSAndroid Build Coastguard Worker
73*c8dee2aaSAndroid Build Coastguard Worker private:
74*c8dee2aaSAndroid Build Coastguard Worker friend class SwizzleCtorAccessor;
75*c8dee2aaSAndroid Build Coastguard Worker
Swizzle(uint16_t key)76*c8dee2aaSAndroid Build Coastguard Worker explicit constexpr Swizzle(uint16_t key) : fKey(key) {}
77*c8dee2aaSAndroid Build Coastguard Worker
channelIndex(int i)78*c8dee2aaSAndroid Build Coastguard Worker constexpr int channelIndex(int i) const {
79*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(i >= 0 && i < 4);
80*c8dee2aaSAndroid Build Coastguard Worker return (fKey >> (4*i)) & 0xfU;
81*c8dee2aaSAndroid Build Coastguard Worker }
82*c8dee2aaSAndroid Build Coastguard Worker
83*c8dee2aaSAndroid Build Coastguard Worker static constexpr float ComponentIndexToFloat(std::array<float, 4>, size_t idx);
84*c8dee2aaSAndroid Build Coastguard Worker static constexpr int CToI(char c);
85*c8dee2aaSAndroid Build Coastguard Worker static constexpr char IToC(int idx);
86*c8dee2aaSAndroid Build Coastguard Worker
87*c8dee2aaSAndroid Build Coastguard Worker uint16_t fKey;
88*c8dee2aaSAndroid Build Coastguard Worker
89*c8dee2aaSAndroid Build Coastguard Worker static_assert(::sk_is_trivially_relocatable<decltype(fKey)>::value);
90*c8dee2aaSAndroid Build Coastguard Worker };
91*c8dee2aaSAndroid Build Coastguard Worker
Swizzle(const char c[4])92*c8dee2aaSAndroid Build Coastguard Worker constexpr Swizzle::Swizzle(const char c[4])
93*c8dee2aaSAndroid Build Coastguard Worker : fKey(static_cast<uint16_t>((CToI(c[0]) << 0) | (CToI(c[1]) << 4) | (CToI(c[2]) << 8) |
94*c8dee2aaSAndroid Build Coastguard Worker (CToI(c[3]) << 12))) {}
95*c8dee2aaSAndroid Build Coastguard Worker
selectChannelInR(int i)96*c8dee2aaSAndroid Build Coastguard Worker constexpr Swizzle Swizzle::selectChannelInR(int i) const {
97*c8dee2aaSAndroid Build Coastguard Worker return Swizzle(static_cast<uint16_t>((this->channelIndex(i) << 0) | (CToI('0') << 4) |
98*c8dee2aaSAndroid Build Coastguard Worker (CToI('0') << 8) | (CToI('0') << 12)));
99*c8dee2aaSAndroid Build Coastguard Worker }
100*c8dee2aaSAndroid Build Coastguard Worker
applyTo(std::array<float,4> color)101*c8dee2aaSAndroid Build Coastguard Worker constexpr std::array<float, 4> Swizzle::applyTo(std::array<float, 4> color) const {
102*c8dee2aaSAndroid Build Coastguard Worker uint32_t key = fKey;
103*c8dee2aaSAndroid Build Coastguard Worker // Index of the input color that should be mapped to output r.
104*c8dee2aaSAndroid Build Coastguard Worker size_t idx = (key & 15);
105*c8dee2aaSAndroid Build Coastguard Worker float outR = ComponentIndexToFloat(color, idx);
106*c8dee2aaSAndroid Build Coastguard Worker key >>= 4;
107*c8dee2aaSAndroid Build Coastguard Worker idx = (key & 15);
108*c8dee2aaSAndroid Build Coastguard Worker float outG = ComponentIndexToFloat(color, idx);
109*c8dee2aaSAndroid Build Coastguard Worker key >>= 4;
110*c8dee2aaSAndroid Build Coastguard Worker idx = (key & 15);
111*c8dee2aaSAndroid Build Coastguard Worker float outB = ComponentIndexToFloat(color, idx);
112*c8dee2aaSAndroid Build Coastguard Worker key >>= 4;
113*c8dee2aaSAndroid Build Coastguard Worker idx = (key & 15);
114*c8dee2aaSAndroid Build Coastguard Worker float outA = ComponentIndexToFloat(color, idx);
115*c8dee2aaSAndroid Build Coastguard Worker return { outR, outG, outB, outA };
116*c8dee2aaSAndroid Build Coastguard Worker }
117*c8dee2aaSAndroid Build Coastguard Worker
ComponentIndexToFloat(std::array<float,4> color,size_t idx)118*c8dee2aaSAndroid Build Coastguard Worker constexpr float Swizzle::ComponentIndexToFloat(std::array<float, 4> color, size_t idx) {
119*c8dee2aaSAndroid Build Coastguard Worker if (idx <= 3) {
120*c8dee2aaSAndroid Build Coastguard Worker return color[idx];
121*c8dee2aaSAndroid Build Coastguard Worker }
122*c8dee2aaSAndroid Build Coastguard Worker if (idx == static_cast<size_t>(CToI('1'))) {
123*c8dee2aaSAndroid Build Coastguard Worker return 1.0f;
124*c8dee2aaSAndroid Build Coastguard Worker }
125*c8dee2aaSAndroid Build Coastguard Worker if (idx == static_cast<size_t>(CToI('0'))) {
126*c8dee2aaSAndroid Build Coastguard Worker return 0.0f;
127*c8dee2aaSAndroid Build Coastguard Worker }
128*c8dee2aaSAndroid Build Coastguard Worker SkUNREACHABLE;
129*c8dee2aaSAndroid Build Coastguard Worker }
130*c8dee2aaSAndroid Build Coastguard Worker
CToI(char c)131*c8dee2aaSAndroid Build Coastguard Worker constexpr int Swizzle::CToI(char c) {
132*c8dee2aaSAndroid Build Coastguard Worker switch (c) {
133*c8dee2aaSAndroid Build Coastguard Worker // r...a must map to 0...3 because other methods use them as indices into fSwiz.
134*c8dee2aaSAndroid Build Coastguard Worker case 'r': return 0;
135*c8dee2aaSAndroid Build Coastguard Worker case 'g': return 1;
136*c8dee2aaSAndroid Build Coastguard Worker case 'b': return 2;
137*c8dee2aaSAndroid Build Coastguard Worker case 'a': return 3;
138*c8dee2aaSAndroid Build Coastguard Worker case '0': return 4;
139*c8dee2aaSAndroid Build Coastguard Worker case '1': return 5;
140*c8dee2aaSAndroid Build Coastguard Worker default: SkUNREACHABLE;
141*c8dee2aaSAndroid Build Coastguard Worker }
142*c8dee2aaSAndroid Build Coastguard Worker }
143*c8dee2aaSAndroid Build Coastguard Worker
IToC(int idx)144*c8dee2aaSAndroid Build Coastguard Worker constexpr char Swizzle::IToC(int idx) {
145*c8dee2aaSAndroid Build Coastguard Worker switch (idx) {
146*c8dee2aaSAndroid Build Coastguard Worker case CToI('r'): return 'r';
147*c8dee2aaSAndroid Build Coastguard Worker case CToI('g'): return 'g';
148*c8dee2aaSAndroid Build Coastguard Worker case CToI('b'): return 'b';
149*c8dee2aaSAndroid Build Coastguard Worker case CToI('a'): return 'a';
150*c8dee2aaSAndroid Build Coastguard Worker case CToI('0'): return '0';
151*c8dee2aaSAndroid Build Coastguard Worker case CToI('1'): return '1';
152*c8dee2aaSAndroid Build Coastguard Worker default: SkUNREACHABLE;
153*c8dee2aaSAndroid Build Coastguard Worker }
154*c8dee2aaSAndroid Build Coastguard Worker }
155*c8dee2aaSAndroid Build Coastguard Worker
Concat(const Swizzle & a,const Swizzle & b)156*c8dee2aaSAndroid Build Coastguard Worker constexpr Swizzle Swizzle::Concat(const Swizzle& a, const Swizzle& b) {
157*c8dee2aaSAndroid Build Coastguard Worker uint16_t key = 0;
158*c8dee2aaSAndroid Build Coastguard Worker for (unsigned i = 0; i < 4; ++i) {
159*c8dee2aaSAndroid Build Coastguard Worker int idx = (b.fKey >> (4U * i)) & 0xfU;
160*c8dee2aaSAndroid Build Coastguard Worker if (idx != CToI('0') && idx != CToI('1')) {
161*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(idx >= 0 && idx < 4);
162*c8dee2aaSAndroid Build Coastguard Worker // Get the index value stored in a at location idx.
163*c8dee2aaSAndroid Build Coastguard Worker idx = ((a.fKey >> (4 * idx)) & 0xfU);
164*c8dee2aaSAndroid Build Coastguard Worker }
165*c8dee2aaSAndroid Build Coastguard Worker key |= (idx << (4U * i));
166*c8dee2aaSAndroid Build Coastguard Worker }
167*c8dee2aaSAndroid Build Coastguard Worker return Swizzle(key);
168*c8dee2aaSAndroid Build Coastguard Worker }
169*c8dee2aaSAndroid Build Coastguard Worker
170*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu
171*c8dee2aaSAndroid Build Coastguard Worker #endif
172