SkPM4fPriv.h revision 77a7a1b57c16c97f056c1e50c03bdc954947778c
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 "SkColorPriv.h" 12#include "SkColorSpace.h" 13#include "SkColorSpace_Base.h" 14#include "SkArenaAlloc.h" 15#include "SkPM4f.h" 16#include "SkRasterPipeline.h" 17#include "SkSRGB.h" 18 19static inline Sk4f set_alpha(const Sk4f& px, float alpha) { 20 return { px[0], px[1], px[2], alpha }; 21} 22 23static inline float get_alpha(const Sk4f& px) { 24 return px[3]; 25} 26 27 28static inline Sk4f Sk4f_fromL32(uint32_t px) { 29 return SkNx_cast<float>(Sk4b::Load(&px)) * (1/255.0f); 30} 31 32static 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 39static 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 45static 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. 58static inline Sk4f Sk4f_from_SkColor(SkColor color) { 59 return swizzle_rb(Sk4f_fromS32(color)); 60} 61 62static inline void assert_unit(float x) { 63 SkASSERT(0 <= x && x <= 1); 64} 65 66static 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 78static 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 102// N.B. scratch_matrix_3x4 must live at least as long as p. 103static inline bool append_gamut_transform(SkRasterPipeline* p, float scratch_matrix_3x4[12], 104 SkColorSpace* src, SkColorSpace* dst) { 105 if (src == dst) { return true; } 106 if (!dst) { return true; } // Legacy modes intentionally ignore color gamut. 107 if (!src) { return true; } // A null src color space means linear gamma, dst gamut. 108 109 auto toXYZ = as_CSB(src)-> toXYZD50(), 110 fromXYZ = as_CSB(dst)->fromXYZD50(); 111 if (!toXYZ || !fromXYZ) { return false; } // Unsupported color space type. 112 113 if (as_CSB(src)->toXYZD50Hash() == as_CSB(dst)->toXYZD50Hash()) { return true; } 114 115 SkMatrix44 m44(*fromXYZ, *toXYZ); 116 117 // Convert from 4x4 to (column-major) 3x4. 118 auto ptr = scratch_matrix_3x4; 119 *ptr++ = m44.get(0,0); *ptr++ = m44.get(1,0); *ptr++ = m44.get(2,0); 120 *ptr++ = m44.get(0,1); *ptr++ = m44.get(1,1); *ptr++ = m44.get(2,1); 121 *ptr++ = m44.get(0,2); *ptr++ = m44.get(1,2); *ptr++ = m44.get(2,2); 122 *ptr++ = m44.get(0,3); *ptr++ = m44.get(1,3); *ptr++ = m44.get(2,3); 123 124 bool needs_clamp_0, needs_clamp_a; 125 analyze_3x4_matrix(scratch_matrix_3x4, &needs_clamp_0, &needs_clamp_a); 126 127 p->append(SkRasterPipeline::matrix_3x4, scratch_matrix_3x4); 128 if (needs_clamp_0) { p->append(SkRasterPipeline::clamp_0); } 129 if (needs_clamp_a) { p->append(SkRasterPipeline::clamp_a); } 130 return true; 131} 132 133static inline bool append_gamut_transform(SkRasterPipeline* p, SkArenaAlloc* scratch, 134 SkColorSpace* src, SkColorSpace* dst) { 135 return append_gamut_transform(p, scratch->makeArrayDefault<float>(12), src, dst); 136} 137 138static inline SkColor4f to_colorspace(const SkColor4f& c, SkColorSpace* src, SkColorSpace* dst) { 139 SkColor4f color4f = c; 140 if (src && dst) { 141 void* color4f_ptr = &color4f; 142 143 float scratch_matrix_3x4[12]; 144 145 SkRasterPipeline p; 146 p.append(SkRasterPipeline::constant_color, color4f_ptr); 147 append_gamut_transform(&p, scratch_matrix_3x4, src, dst); 148 p.append(SkRasterPipeline::store_f32, &color4f_ptr); 149 150 p.run(0,1); 151 } 152 return color4f; 153} 154 155static inline SkColor4f SkColor4f_from_SkColor(SkColor color, SkColorSpace* dst) { 156 SkColor4f color4f; 157 if (dst) { 158 // sRGB gamma, sRGB gamut. 159 color4f = to_colorspace(SkColor4f::FromColor(color), 160 SkColorSpace::MakeSRGB().get(), dst); 161 } else { 162 // Linear gamma, dst gamut. 163 swizzle_rb(SkNx_cast<float>(Sk4b::Load(&color)) * (1/255.0f)).store(&color4f); 164 } 165 return color4f; 166} 167 168static inline SkPM4f SkPM4f_from_SkColor(SkColor color, SkColorSpace* dst) { 169 return SkColor4f_from_SkColor(color, dst).premul(); 170} 171 172#endif 173