|  | /* | 
|  | * Copyright 2016 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #ifndef skgpu_Swizzle_DEFINED | 
|  | #define skgpu_Swizzle_DEFINED | 
|  |  | 
|  | #include "include/core/SkColor.h" | 
|  | #include "include/core/SkString.h" | 
|  | #include "include/private/base/SkAssert.h" | 
|  | #include "include/private/base/SkTypeTraits.h" | 
|  |  | 
|  | #include <array> | 
|  | #include <cstddef> | 
|  | #include <cstdint> | 
|  | #include <type_traits> | 
|  |  | 
|  | class SkRasterPipeline; | 
|  | enum SkAlphaType : int; | 
|  |  | 
|  | namespace skgpu { | 
|  |  | 
|  | /** Represents a rgba swizzle. It can be converted either into a string or a eight bit int. */ | 
|  | class Swizzle { | 
|  | public: | 
|  | // Equivalent to "rgba", but Clang doesn't always manage to inline this | 
|  | // if we're too deep in the inlining already. | 
|  | constexpr Swizzle() : Swizzle(0x3210) {} | 
|  | explicit constexpr Swizzle(const char c[4]); | 
|  |  | 
|  | constexpr Swizzle(const Swizzle&) = default; | 
|  | constexpr Swizzle& operator=(const Swizzle& that) = default; | 
|  |  | 
|  | static constexpr Swizzle Concat(const Swizzle& a, const Swizzle& b); | 
|  |  | 
|  | constexpr bool operator==(const Swizzle& that) const { return fKey == that.fKey; } | 
|  | constexpr bool operator!=(const Swizzle& that) const { return !(*this == that); } | 
|  |  | 
|  | /** Compact representation of the swizzle suitable for a key. */ | 
|  | constexpr uint16_t asKey() const { return fKey; } | 
|  |  | 
|  | /** 4 char null terminated string consisting only of chars 'r', 'g', 'b', 'a', '0', and '1'. */ | 
|  | SkString asString() const; | 
|  |  | 
|  | constexpr char operator[](int i) const { return IToC(this->channelIndex(i)); } | 
|  |  | 
|  | // Returns a new swizzle that moves the swizzle component in index i to index 0 (e.g. "R") and | 
|  | // sets all other channels to 0. For a swizzle `s`, this is constructing "s[i]000". | 
|  | constexpr Swizzle selectChannelInR(int i) const; | 
|  |  | 
|  | /** Applies this swizzle to the input color and returns the swizzled color. */ | 
|  | constexpr std::array<float, 4> applyTo(std::array<float, 4> color) const; | 
|  |  | 
|  | /** Convenience version for SkRGBA colors. */ | 
|  | template <SkAlphaType AlphaType> | 
|  | constexpr SkRGBA4f<AlphaType> applyTo(SkRGBA4f<AlphaType> color) const { | 
|  | std::array<float, 4> result = this->applyTo(color.array()); | 
|  | return {result[0], result[1], result[2], result[3]}; | 
|  | } | 
|  |  | 
|  | void apply(SkRasterPipeline*) const; | 
|  |  | 
|  | static constexpr Swizzle RGBA() { return Swizzle("rgba"); } | 
|  | static constexpr Swizzle BGRA() { return Swizzle("bgra"); } | 
|  | static constexpr Swizzle RRRA() { return Swizzle("rrra"); } | 
|  | static constexpr Swizzle RGB1() { return Swizzle("rgb1"); } | 
|  |  | 
|  | using sk_is_trivially_relocatable = std::true_type; | 
|  |  | 
|  | private: | 
|  | friend class SwizzleCtorAccessor; | 
|  |  | 
|  | explicit constexpr Swizzle(uint16_t key) : fKey(key) {} | 
|  |  | 
|  | constexpr int channelIndex(int i) const { | 
|  | SkASSERT(i >= 0 && i < 4); | 
|  | return (fKey >> (4*i)) & 0xfU; | 
|  | } | 
|  |  | 
|  | static constexpr float ComponentIndexToFloat(std::array<float, 4>, size_t idx); | 
|  | static constexpr int CToI(char c); | 
|  | static constexpr char IToC(int idx); | 
|  |  | 
|  | uint16_t fKey; | 
|  |  | 
|  | static_assert(::sk_is_trivially_relocatable<decltype(fKey)>::value); | 
|  | }; | 
|  |  | 
|  | constexpr Swizzle::Swizzle(const char c[4]) | 
|  | : fKey(static_cast<uint16_t>((CToI(c[0]) << 0) | (CToI(c[1]) << 4) | (CToI(c[2]) << 8) | | 
|  | (CToI(c[3]) << 12))) {} | 
|  |  | 
|  | constexpr Swizzle Swizzle::selectChannelInR(int i) const { | 
|  | return Swizzle(static_cast<uint16_t>((this->channelIndex(i) << 0) | (CToI('0') << 4) | | 
|  | (CToI('0') << 8) | (CToI('0') << 12))); | 
|  | } | 
|  |  | 
|  | constexpr std::array<float, 4> Swizzle::applyTo(std::array<float, 4> color) const { | 
|  | uint32_t key = fKey; | 
|  | // Index of the input color that should be mapped to output r. | 
|  | size_t idx = (key & 15); | 
|  | float outR = ComponentIndexToFloat(color, idx); | 
|  | key >>= 4; | 
|  | idx = (key & 15); | 
|  | float outG = ComponentIndexToFloat(color, idx); | 
|  | key >>= 4; | 
|  | idx = (key & 15); | 
|  | float outB = ComponentIndexToFloat(color, idx); | 
|  | key >>= 4; | 
|  | idx = (key & 15); | 
|  | float outA = ComponentIndexToFloat(color, idx); | 
|  | return { outR, outG, outB, outA }; | 
|  | } | 
|  |  | 
|  | constexpr float Swizzle::ComponentIndexToFloat(std::array<float, 4> color, size_t idx) { | 
|  | if (idx <= 3) { | 
|  | return color[idx]; | 
|  | } | 
|  | if (idx == static_cast<size_t>(CToI('1'))) { | 
|  | return 1.0f; | 
|  | } | 
|  | if (idx == static_cast<size_t>(CToI('0'))) { | 
|  | return 0.0f; | 
|  | } | 
|  | SkUNREACHABLE; | 
|  | } | 
|  |  | 
|  | constexpr int Swizzle::CToI(char c) { | 
|  | switch (c) { | 
|  | // r...a must map to 0...3 because other methods use them as indices into fSwiz. | 
|  | case 'r': return 0; | 
|  | case 'g': return 1; | 
|  | case 'b': return 2; | 
|  | case 'a': return 3; | 
|  | case '0': return 4; | 
|  | case '1': return 5; | 
|  | default:  SkUNREACHABLE; | 
|  | } | 
|  | } | 
|  |  | 
|  | constexpr char Swizzle::IToC(int idx) { | 
|  | switch (idx) { | 
|  | case CToI('r'): return 'r'; | 
|  | case CToI('g'): return 'g'; | 
|  | case CToI('b'): return 'b'; | 
|  | case CToI('a'): return 'a'; | 
|  | case CToI('0'): return '0'; | 
|  | case CToI('1'): return '1'; | 
|  | default:        SkUNREACHABLE; | 
|  | } | 
|  | } | 
|  |  | 
|  | constexpr Swizzle Swizzle::Concat(const Swizzle& a, const Swizzle& b) { | 
|  | uint16_t key = 0; | 
|  | for (unsigned i = 0; i < 4; ++i) { | 
|  | int idx = (b.fKey >> (4U * i)) & 0xfU; | 
|  | if (idx != CToI('0') && idx != CToI('1')) { | 
|  | SkASSERT(idx >= 0 && idx < 4); | 
|  | // Get the index value stored in a at location idx. | 
|  | idx = ((a.fKey >> (4 * idx)) & 0xfU); | 
|  | } | 
|  | key |= (idx << (4U * i)); | 
|  | } | 
|  | return Swizzle(key); | 
|  | } | 
|  |  | 
|  | } // namespace skgpu | 
|  | #endif |