Home | History | Annotate | Download | only in gradients
      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 Sk4fGradientPriv_DEFINED
      9 #define Sk4fGradientPriv_DEFINED
     10 
     11 #include "SkColor.h"
     12 #include "SkHalf.h"
     13 #include "SkImageInfo.h"
     14 #include "SkNx.h"
     15 #include "SkPM4f.h"
     16 #include "SkPM4fPriv.h"
     17 #include "SkUtils.h"
     18 
     19 // Templates shared by various 4f gradient flavors.
     20 
     21 namespace {
     22 
     23 enum class ApplyPremul { True, False };
     24 
     25 template <ApplyPremul>
     26 struct PremulTraits;
     27 
     28 template <>
     29 struct PremulTraits<ApplyPremul::False> {
     30     static Sk4f apply(const Sk4f& c) { return c; }
     31 };
     32 
     33 template <>
     34 struct PremulTraits<ApplyPremul::True> {
     35     static Sk4f apply(const Sk4f& c) {
     36         const float alpha = c[SkPM4f::A];
     37         // FIXME: portable swizzle?
     38         return c * Sk4f(alpha, alpha, alpha, 1);
     39     }
     40 };
     41 
     42 // Struct encapsulating various dest-dependent ops:
     43 //
     44 //   - load()       Load a SkPM4f value into Sk4f.  Normally called once per interval
     45 //                  advance.  Also applies a scale and swizzle suitable for DstType.
     46 //
     47 //   - store()      Store one Sk4f to dest.  Optionally handles premul, color space
     48 //                  conversion, etc.
     49 //
     50 //   - store(count) Store the Sk4f value repeatedly to dest, count times.
     51 //
     52 //   - store4x()    Store 4 Sk4f values to dest (opportunistic optimization).
     53 //
     54 template <typename dst, ApplyPremul premul>
     55 struct DstTraits;
     56 
     57 template <ApplyPremul premul>
     58 struct DstTraits<SkPMColor, premul> {
     59     using PM   = PremulTraits<premul>;
     60 
     61     // For L32, prescaling by 255 saves a per-pixel multiplication when premul is not needed.
     62     static Sk4f load(const SkPM4f& c) {
     63         return premul == ApplyPremul::False
     64             ? c.to4f_pmorder() * Sk4f(255)
     65             : c.to4f_pmorder();
     66     }
     67 
     68     static void store(const Sk4f& c, SkPMColor* dst, const Sk4f& bias) {
     69         if (premul == ApplyPremul::False) {
     70             // c is pre-scaled by 255 and pre-biased, just store.
     71             SkNx_cast<uint8_t>(c).store(dst);
     72         } else {
     73             *dst = Sk4f_toL32(PM::apply(c) + bias);
     74         }
     75     }
     76 
     77     static void store(const Sk4f& c, SkPMColor* dst, int n) {
     78         SkPMColor pmc;
     79         store(c, &pmc, Sk4f(0));
     80         sk_memset32(dst, pmc, n);
     81     }
     82 
     83     static void store4x(const Sk4f& c0, const Sk4f& c1,
     84                         const Sk4f& c2, const Sk4f& c3,
     85                         SkPMColor* dst,
     86                         const Sk4f& bias0,
     87                         const Sk4f& bias1) {
     88         if (premul == ApplyPremul::False) {
     89             // colors are pre-scaled and pre-biased.
     90             Sk4f_ToBytes((uint8_t*)dst, c0, c1, c2, c3);
     91         } else {
     92             store(c0, dst + 0, bias0);
     93             store(c1, dst + 1, bias1);
     94             store(c2, dst + 2, bias0);
     95             store(c3, dst + 3, bias1);
     96         }
     97     }
     98 
     99     static Sk4f pre_lerp_bias(const Sk4f& bias) {
    100         // We can apply the bias before interpolation when the colors are premultiplied.
    101         return premul == ApplyPremul::False ? bias : 0;
    102     }
    103 };
    104 
    105 template <ApplyPremul premul>
    106 struct DstTraits<SkPM4f, premul> {
    107     using PM   = PremulTraits<premul>;
    108 
    109     static Sk4f load(const SkPM4f& c) {
    110         return c.to4f();
    111     }
    112 
    113     static void store(const Sk4f& c, SkPM4f* dst, const Sk4f& /*bias*/) {
    114         PM::apply(c).store(dst->fVec);
    115     }
    116 
    117     static void store(const Sk4f& c, SkPM4f* dst, int n) {
    118         const Sk4f pmc = PM::apply(c);
    119         for (int i = 0; i < n; ++i) {
    120             pmc.store(dst[i].fVec);
    121         }
    122     }
    123 
    124     static void store4x(const Sk4f& c0, const Sk4f& c1,
    125                         const Sk4f& c2, const Sk4f& c3,
    126                         SkPM4f* dst,
    127                         const Sk4f& bias0, const Sk4f& bias1) {
    128         store(c0, dst + 0, bias0);
    129         store(c1, dst + 1, bias1);
    130         store(c2, dst + 2, bias0);
    131         store(c3, dst + 3, bias1);
    132     }
    133 
    134     static Sk4f pre_lerp_bias(const Sk4f& /*bias*/) {
    135         // For 4f dests we never bias.
    136         return 0;
    137     }
    138 };
    139 
    140 } // anonymous namespace
    141 
    142 #endif // Sk4fGradientPriv_DEFINED
    143