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