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