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