Home | History | Annotate | Download | only in core
      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 SkPM4fPriv_DEFINED
      9 #define SkPM4fPriv_DEFINED
     10 
     11 #include "SkColorData.h"
     12 #include "SkColorSpace.h"
     13 #include "SkArenaAlloc.h"
     14 #include "SkPM4f.h"
     15 #include "SkRasterPipeline.h"
     16 #include "SkSRGB.h"
     17 #include "../jumper/SkJumper.h"
     18 
     19 static inline Sk4f set_alpha(const Sk4f& px, float alpha) {
     20     return { px[0], px[1], px[2], alpha };
     21 }
     22 
     23 static inline float get_alpha(const Sk4f& px) {
     24     return px[3];
     25 }
     26 
     27 
     28 static inline Sk4f Sk4f_fromL32(uint32_t px) {
     29     return SkNx_cast<float>(Sk4b::Load(&px)) * (1/255.0f);
     30 }
     31 
     32 static inline Sk4f Sk4f_fromS32(uint32_t px) {
     33     return { sk_linear_from_srgb[(px >>  0) & 0xff],
     34              sk_linear_from_srgb[(px >>  8) & 0xff],
     35              sk_linear_from_srgb[(px >> 16) & 0xff],
     36                     (1/255.0f) * (px >> 24)          };
     37 }
     38 
     39 static inline uint32_t Sk4f_toL32(const Sk4f& px) {
     40     uint32_t l32;
     41     SkNx_cast<uint8_t>(Sk4f_round(px * 255.0f)).store(&l32);
     42     return l32;
     43 }
     44 
     45 static inline uint32_t Sk4f_toS32(const Sk4f& px) {
     46     Sk4i  rgb = sk_linear_to_srgb(px),
     47          srgb = { rgb[0], rgb[1], rgb[2], (int)(255.0f * px[3] + 0.5f) };
     48 
     49     uint32_t s32;
     50     SkNx_cast<uint8_t>(srgb).store(&s32);
     51     return s32;
     52 }
     53 
     54 
     55 // SkColor handling:
     56 //   SkColor has an ordering of (b, g, r, a) if cast to an Sk4f, so the code swizzles r and b to
     57 // produce the needed (r, g, b, a) ordering.
     58 static inline Sk4f Sk4f_from_SkColor(SkColor color) {
     59     return swizzle_rb(Sk4f_fromS32(color));
     60 }
     61 
     62 static inline void assert_unit(float x) {
     63     SkASSERT(0 <= x && x <= 1);
     64 }
     65 
     66 static inline float exact_srgb_to_linear(float srgb) {
     67     assert_unit(srgb);
     68     float linear;
     69     if (srgb <= 0.04045) {
     70         linear = srgb / 12.92f;
     71     } else {
     72         linear = powf((srgb + 0.055f) / 1.055f, 2.4f);
     73     }
     74     assert_unit(linear);
     75     return linear;
     76 }
     77 
     78 static inline void analyze_3x4_matrix(const float matrix[12],
     79                                       bool* can_underflow, bool* can_overflow) {
     80     // | 0 3 6  9 |   |r|   |x|
     81     // | 1 4 7 10 | x |g| = |y|
     82     // | 2 5 8 11 |   |b|   |z|
     83     //                |1|
     84     // We'll find min/max bounds on each of x,y,z assuming r,g,b are all in [0,1].
     85     // If any can be <0, we'll set can_underflow; if any can be >1, can_overflow.
     86     bool underflow = false,
     87           overflow = false;
     88     for (int i = 0; i < 3; i++) {
     89         SkScalar min = matrix[i+9],
     90                  max = matrix[i+9];
     91         (matrix[i+0] < 0 ? min : max) += matrix[i+0];
     92         (matrix[i+3] < 0 ? min : max) += matrix[i+3];
     93         (matrix[i+6] < 0 ? min : max) += matrix[i+6];
     94         underflow = underflow || min < 0;
     95         overflow  =  overflow || max > 1;
     96     }
     97     *can_underflow = underflow;
     98     *can_overflow  =  overflow;
     99 }
    100 
    101 // N.B. scratch_matrix_3x4 must live at least as long as p.
    102 // Returns false if no gamut tranformation was necessary.
    103 static inline bool append_gamut_transform_noclamp(SkRasterPipeline* p,
    104                                                   float scratch_matrix_3x4[12],
    105                                                   SkColorSpace* src,
    106                                                   SkColorSpace* dst) {
    107     if (src == dst || !dst || !src) {
    108         return false;
    109     }
    110 
    111     const SkMatrix44 *fromSrc = src->  toXYZD50(),
    112                        *toDst = dst->fromXYZD50();
    113     if (!fromSrc || !toDst) {
    114         SkDEBUGFAIL("We can't handle non-XYZ color spaces in append_gamut_transform().");
    115         return false;
    116     }
    117 
    118     // Slightly more sophisticated version of if (src == dst)
    119     if (src->toXYZD50Hash() == dst->toXYZD50Hash()) {
    120         return false;
    121     }
    122 
    123     // Convert from 4x4 to (column-major) 3x4.
    124     SkMatrix44 m44(*toDst, *fromSrc);
    125     auto ptr = scratch_matrix_3x4;
    126     *ptr++ = m44.get(0,0); *ptr++ = m44.get(1,0); *ptr++ = m44.get(2,0);
    127     *ptr++ = m44.get(0,1); *ptr++ = m44.get(1,1); *ptr++ = m44.get(2,1);
    128     *ptr++ = m44.get(0,2); *ptr++ = m44.get(1,2); *ptr++ = m44.get(2,2);
    129     *ptr++ = m44.get(0,3); *ptr++ = m44.get(1,3); *ptr++ = m44.get(2,3);
    130 
    131     p->append(SkRasterPipeline::matrix_3x4, scratch_matrix_3x4);
    132     return true;
    133 }
    134 
    135 
    136 // N.B. scratch_matrix_3x4 must live at least as long as p.
    137 static inline void append_gamut_transform(SkRasterPipeline* p,
    138                                           float scratch_matrix_3x4[12],
    139                                           SkColorSpace* src,
    140                                           SkColorSpace* dst,
    141                                           SkAlphaType alphaType) {
    142     if (append_gamut_transform_noclamp(p, scratch_matrix_3x4, src, dst)) {
    143         bool needs_clamp_0, needs_clamp_1;
    144         analyze_3x4_matrix(scratch_matrix_3x4, &needs_clamp_0, &needs_clamp_1);
    145 
    146         if (needs_clamp_0) { p->append(SkRasterPipeline::clamp_0); }
    147         if (needs_clamp_1) {
    148             (kPremul_SkAlphaType == alphaType) ? p->append(SkRasterPipeline::clamp_a)
    149                                                : p->append(SkRasterPipeline::clamp_1);
    150         }
    151     }
    152 }
    153 
    154 static inline void append_gamut_transform(SkRasterPipeline* p,
    155                                           SkArenaAlloc* alloc,
    156                                           SkColorSpace* src,
    157                                           SkColorSpace* dst,
    158                                           SkAlphaType alphaType) {
    159     append_gamut_transform(p, alloc->makeArrayDefault<float>(12), src, dst, alphaType);
    160 }
    161 
    162 static inline SkColor4f to_colorspace(const SkColor4f& c, SkColorSpace* src, SkColorSpace* dst) {
    163     SkColor4f color4f = c;
    164     if (src && dst && !SkColorSpace::Equals(src, dst)) {
    165         SkJumper_MemoryCtx color4f_ptr = { &color4f, 0 };
    166 
    167         float scratch_matrix_3x4[12];
    168 
    169         SkSTArenaAlloc<256> alloc;
    170         SkRasterPipeline p(&alloc);
    171         p.append_constant_color(&alloc, color4f);
    172         append_gamut_transform(&p, scratch_matrix_3x4, src, dst, kUnpremul_SkAlphaType);
    173         p.append(SkRasterPipeline::store_f32, &color4f_ptr);
    174 
    175         p.run(0,0,1,1);
    176     }
    177     return color4f;
    178 }
    179 
    180 static inline SkColor4f SkColor4f_from_SkColor(SkColor color, SkColorSpace* dst) {
    181     SkColor4f color4f;
    182     if (dst) {
    183         // sRGB gamma, sRGB gamut.
    184         color4f = to_colorspace(SkColor4f::FromColor(color),
    185                                 SkColorSpace::MakeSRGB().get(), dst);
    186     } else {
    187         // Linear gamma, dst gamut.
    188         swizzle_rb(SkNx_cast<float>(Sk4b::Load(&color)) * (1/255.0f)).store(&color4f);
    189     }
    190     return color4f;
    191 }
    192 
    193 static inline SkPM4f SkPM4f_from_SkColor(SkColor color, SkColorSpace* dst) {
    194     return SkColor4f_from_SkColor(color, dst).premul();
    195 }
    196 
    197 #endif
    198