Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(61)

Side by Side Diff: src/opts/SkColorXform_opts.h

Issue 2130013002: Make all color xforms 'fast' (step 1) (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Further fixes Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2016 Google Inc. 2 * Copyright 2016 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #ifndef SkColorXform_opts_DEFINED 8 #ifndef SkColorXform_opts_DEFINED
9 #define SkColorXform_opts_DEFINED 9 #define SkColorXform_opts_DEFINED
10 10
(...skipping 10 matching lines...) Expand all
21 auto x2 = x.rsqrt(), // x^(-1/2) 21 auto x2 = x.rsqrt(), // x^(-1/2)
22 x32 = x2.rsqrt().rsqrt().rsqrt().rsqrt(), // x^(-1/32) 22 x32 = x2.rsqrt().rsqrt().rsqrt().rsqrt(), // x^(-1/32)
23 x64 = x32.rsqrt(); // x^(+1/64) 23 x64 = x32.rsqrt(); // x^(+1/64)
24 24
25 // 29 = 32 - 2 - 1 25 // 29 = 32 - 2 - 1
26 return 255.0f * x2.invert() * x32 * x64.invert(); 26 return 255.0f * x2.invert() * x32 * x64.invert();
27 } 27 }
28 28
29 static Sk4f linear_to_srgb(const Sk4f& x) { 29 static Sk4f linear_to_srgb(const Sk4f& x) {
30 // Approximation of the sRGB gamma curve (within 1 when scaled to 8-bit pixe ls). 30 // Approximation of the sRGB gamma curve (within 1 when scaled to 8-bit pixe ls).
31 // For 0.00000f <= x < 0.00349f, 12.92 * x 31 // For 0.00000f <= x < 0.00349f, 12.92*x
32 // For 0.00349f <= x <= 1.00000f, 0.679*(x.^0.5) + 0.423*x.^(0.25) - 0.10 1 32 // For 0.00349f <= x <= 1.00000f, 0.679*(x.^0.5) + 0.423*x.^(0.25) - 0.10 1
33 // Note that 0.00349 was selected because it is a point where both functions produce the 33 // Note that 0.00349 was selected because it is a point where both functions produce the
34 // same pixel value when rounded. 34 // same pixel value when rounded.
35 auto rsqrt = x.rsqrt(), 35 auto rsqrt = x.rsqrt(),
36 sqrt = rsqrt.invert(), 36 sqrt = rsqrt.invert(),
37 ftrt = rsqrt.rsqrt(); 37 ftrt = rsqrt.rsqrt();
38 38
39 auto hi = (-0.101115084998961f * 255.0f) + 39 auto hi = (-0.101115084998961f * 255.0f) +
40 (+0.678513029959381f * 255.0f) * sqrt + 40 (+0.678513029959381f * 255.0f) * sqrt +
41 (+0.422602055039580f * 255.0f) * ftrt; 41 (+0.422602055039580f * 255.0f) * ftrt;
42 42
43 auto lo = (12.92f * 255.0f) * x; 43 auto lo = (12.92f * 255.0f) * x;
44 44
45 auto mask = (x < 0.00349f); 45 auto mask = (x < 0.00349f);
46 return mask.thenElse(lo, hi); 46 return mask.thenElse(lo, hi);
47 } 47 }
48 48
49 static Sk4f clamp_0_to_255(const Sk4f& x) { 49 static Sk4f clamp_0_to_255(const Sk4f& x) {
50 // The order of the arguments is important here. We want to make sure that NaN 50 // The order of the arguments is important here. We want to make sure that NaN
51 // clamps to zero. Note that max(NaN, 0) = 0, while max(0, NaN) = NaN. 51 // clamps to zero. Note that max(NaN, 0) = 0, while max(0, NaN) = NaN.
52 return Sk4f::Min(Sk4f::Max(x, 0.0f), 255.0f); 52 return Sk4f::Min(Sk4f::Max(x, 0.0f), 255.0f);
53 } 53 }
54 54
55 template <const float (&linear_from_curve)[256], Sk4f (*linear_to_curve)(const S k4f&)> 55 enum DstGamma {
56 kSRGB_DstGamma,
57 k2Dot2_DstGamma,
58 kTable_DstGamma,
59 };
60
61 template <DstGamma kDstGamma>
56 static void color_xform_RGB1(uint32_t* dst, const uint32_t* src, int len, 62 static void color_xform_RGB1(uint32_t* dst, const uint32_t* src, int len,
57 const float matrix[16]) { 63 const float* const srcTables[3], const float matrix [16],
64 const uint8_t* const dstTables[3]) {
58 Sk4f rXgXbX = Sk4f::Load(matrix + 0), 65 Sk4f rXgXbX = Sk4f::Load(matrix + 0),
59 rYgYbY = Sk4f::Load(matrix + 4), 66 rYgYbY = Sk4f::Load(matrix + 4),
60 rZgZbZ = Sk4f::Load(matrix + 8); 67 rZgZbZ = Sk4f::Load(matrix + 8);
61 68
62 if (len >= 4) { 69 if (len >= 4) {
63 Sk4f reds, greens, blues; 70 Sk4f reds, greens, blues;
64 auto load_next_4 = [&reds, &greens, &blues, &src, &len] { 71 auto load_next_4 = [&reds, &greens, &blues, &src, &len, &srcTables] {
65 reds = Sk4f{linear_from_curve[(src[0] >> 0) & 0xFF], 72 reds = Sk4f{srcTables[0][(src[0] >> 0) & 0xFF],
66 linear_from_curve[(src[1] >> 0) & 0xFF], 73 srcTables[0][(src[1] >> 0) & 0xFF],
67 linear_from_curve[(src[2] >> 0) & 0xFF], 74 srcTables[0][(src[2] >> 0) & 0xFF],
68 linear_from_curve[(src[3] >> 0) & 0xFF]}; 75 srcTables[0][(src[3] >> 0) & 0xFF]};
69 greens = Sk4f{linear_from_curve[(src[0] >> 8) & 0xFF], 76 greens = Sk4f{srcTables[1][(src[0] >> 8) & 0xFF],
70 linear_from_curve[(src[1] >> 8) & 0xFF], 77 srcTables[1][(src[1] >> 8) & 0xFF],
71 linear_from_curve[(src[2] >> 8) & 0xFF], 78 srcTables[1][(src[2] >> 8) & 0xFF],
72 linear_from_curve[(src[3] >> 8) & 0xFF]}; 79 srcTables[1][(src[3] >> 8) & 0xFF]};
73 blues = Sk4f{linear_from_curve[(src[0] >> 16) & 0xFF], 80 blues = Sk4f{srcTables[2][(src[0] >> 16) & 0xFF],
74 linear_from_curve[(src[1] >> 16) & 0xFF], 81 srcTables[2][(src[1] >> 16) & 0xFF],
75 linear_from_curve[(src[2] >> 16) & 0xFF], 82 srcTables[2][(src[2] >> 16) & 0xFF],
76 linear_from_curve[(src[3] >> 16) & 0xFF]}; 83 srcTables[2][(src[3] >> 16) & 0xFF]};
77 src += 4; 84 src += 4;
78 len -= 4; 85 len -= 4;
79 }; 86 };
80 87
81 Sk4f dstReds, dstGreens, dstBlues; 88 Sk4f dstReds, dstGreens, dstBlues;
82 auto transform_4 = [&reds, &greens, &blues, &dstReds, &dstGreens, &dstBl ues, &rXgXbX, 89 auto transform_4 = [&reds, &greens, &blues, &dstReds, &dstGreens, &dstBl ues, &rXgXbX,
83 &rYgYbY, &rZgZbZ] { 90 &rYgYbY, &rZgZbZ] {
84 dstReds = rXgXbX[0]*reds + rYgYbY[0]*greens + rZgZbZ[0]*blues; 91 dstReds = rXgXbX[0]*reds + rYgYbY[0]*greens + rZgZbZ[0]*blues;
85 dstGreens = rXgXbX[1]*reds + rYgYbY[1]*greens + rZgZbZ[1]*blues; 92 dstGreens = rXgXbX[1]*reds + rYgYbY[1]*greens + rZgZbZ[1]*blues;
86 dstBlues = rXgXbX[2]*reds + rYgYbY[2]*greens + rZgZbZ[2]*blues; 93 dstBlues = rXgXbX[2]*reds + rYgYbY[2]*greens + rZgZbZ[2]*blues;
87 }; 94 };
88 95
89 auto store_4 = [&dstReds, &dstGreens, &dstBlues, &dst] { 96 auto store_4 = [&dstReds, &dstGreens, &dstBlues, &dst, &dstTables] {
90 dstReds = linear_to_curve(dstReds); 97 if (kSRGB_DstGamma == kDstGamma || k2Dot2_DstGamma == kDstGamma) {
91 dstGreens = linear_to_curve(dstGreens); 98 Sk4f (*linear_to_curve)(const Sk4f&) =
92 dstBlues = linear_to_curve(dstBlues); 99 (kSRGB_DstGamma == kDstGamma) ? linear_to_srgb : linear_ to_2dot2;
93 100
94 dstReds = clamp_0_to_255(dstReds); 101 dstReds = linear_to_curve(dstReds);
95 dstGreens = clamp_0_to_255(dstGreens); 102 dstGreens = linear_to_curve(dstGreens);
96 dstBlues = clamp_0_to_255(dstBlues); 103 dstBlues = linear_to_curve(dstBlues);
97 104
98 auto rgba = (Sk4i{(int)0xFF000000} ) 105 dstReds = clamp_0_to_255(dstReds);
99 | (SkNx_cast<int>(dstReds) ) 106 dstGreens = clamp_0_to_255(dstGreens);
100 | (SkNx_cast<int>(dstGreens) << 8) 107 dstBlues = clamp_0_to_255(dstBlues);
101 | (SkNx_cast<int>(dstBlues) << 16); 108
102 rgba.store(dst); 109 auto rgba = (SkNx_cast<int>(dstReds) )
110 | (SkNx_cast<int>(dstGreens) << 8)
111 | (SkNx_cast<int>(dstBlues) << 16)
112 | (Sk4i{ 0xFF << 24});
113 rgba.store(dst);
114 } else {
115 Sk4f scaledReds = Sk4f::Min(Sk4f::Max(1023.0f * dstReds, 0.0 f), 1023.0f);
116 Sk4f scaledGreens = Sk4f::Min(Sk4f::Max(1023.0f * dstGreens, 0.0 f), 1023.0f);
117 Sk4f scaledBlues = Sk4f::Min(Sk4f::Max(1023.0f * dstBlues, 0.0 f), 1023.0f);
118
119 Sk4i indicesReds = SkNx_cast<int>(scaledReds);
mtklein_C 2016/07/08 13:47:24 Is there any benefit to rounding here? SkNx_cast<
msarett 2016/07/09 13:15:52 I think we should round. I'll follow up with a fi
120 Sk4i indicesGreens = SkNx_cast<int>(scaledGreens);
121 Sk4i indicesBlues = SkNx_cast<int>(scaledBlues);
122
123 dst[0] = dstTables[0][indicesReds [0]]
124 | dstTables[1][indicesGreens[0]] << 8
125 | dstTables[2][indicesBlues [0]] << 16
126 | 0xFF << 24;
127 dst[1] = dstTables[0][indicesReds [1]]
128 | dstTables[1][indicesGreens[1]] << 8
129 | dstTables[2][indicesBlues [1]] << 16
130 | 0xFF << 24;
131 dst[2] = dstTables[0][indicesReds [2]]
132 | dstTables[1][indicesGreens[2]] << 8
133 | dstTables[2][indicesBlues [2]] << 16
134 | 0xFF << 24;
135 dst[3] = dstTables[0][indicesReds [3]]
136 | dstTables[1][indicesGreens[3]] << 8
137 | dstTables[2][indicesBlues [3]] << 16
138 | 0xFF << 24;
139 }
140
103 dst += 4; 141 dst += 4;
104 }; 142 };
105 143
106 load_next_4(); 144 load_next_4();
107 145
108 while (len >= 4) { 146 while (len >= 4) {
109 transform_4(); 147 transform_4();
110 load_next_4(); 148 load_next_4();
111 store_4(); 149 store_4();
112 } 150 }
113 151
114 transform_4(); 152 transform_4();
115 store_4(); 153 store_4();
116 } 154 }
117 155
118 while (len > 0) { 156 while (len > 0) {
119 // Splat r,g,b across a register each. 157 // Splat r,g,b across a register each.
120 auto r = Sk4f{linear_from_curve[(*src >> 0) & 0xFF]}, 158 auto r = Sk4f{srcTables[0][(*src >> 0) & 0xFF]},
121 g = Sk4f{linear_from_curve[(*src >> 8) & 0xFF]}, 159 g = Sk4f{srcTables[1][(*src >> 8) & 0xFF]},
122 b = Sk4f{linear_from_curve[(*src >> 16) & 0xFF]}; 160 b = Sk4f{srcTables[2][(*src >> 16) & 0xFF]};
123 161
124 // Apply transformation matrix to dst gamut. 162 // Apply transformation matrix to dst gamut.
125 auto dstPixel = rXgXbX*r + rYgYbY*g + rZgZbZ*b; 163 auto dstPixel = rXgXbX*r + rYgYbY*g + rZgZbZ*b;
126 164
127 // Convert to dst gamma. 165 if (kSRGB_DstGamma == kDstGamma || k2Dot2_DstGamma == kDstGamma) {
128 dstPixel = linear_to_curve(dstPixel); 166 Sk4f (*linear_to_curve)(const Sk4f&) =
167 (kSRGB_DstGamma == kDstGamma) ? linear_to_srgb : linear_to_2 dot2;
129 168
130 // Clamp floats to byte range. 169 dstPixel = linear_to_curve(dstPixel);
131 dstPixel = clamp_0_to_255(dstPixel);
132 170
133 // Convert to bytes and store to memory. 171 dstPixel = clamp_0_to_255(dstPixel);
134 uint32_t rgba; 172
135 SkNx_cast<uint8_t>(dstPixel).store(&rgba); 173 uint32_t rgba;
136 rgba |= 0xFF000000; 174 SkNx_cast<uint8_t>(dstPixel).store(&rgba);
137 *dst = rgba; 175 rgba |= 0xFF000000;
176 *dst = rgba;
177 } else {
178 Sk4f scaledPixel = Sk4f::Min(Sk4f::Max(1023.0f * dstPixel, 0.0f), 10 23.0f);
179
180 Sk4i indices = SkNx_cast<int>(scaledPixel);
181
182 *dst = dstTables[0][indices[0]]
183 | dstTables[1][indices[1]] << 8
184 | dstTables[2][indices[2]] << 16
185 | 0xFF << 24;
186 }
138 187
139 dst += 1; 188 dst += 1;
140 src += 1; 189 src += 1;
141 len -= 1; 190 len -= 1;
142 } 191 }
143 } 192 }
144 193
145 static void color_xform_RGB1_srgb_to_2dot2(uint32_t* dst, const uint32_t* src, i nt len, 194 static void color_xform_RGB1_to_2dot2(uint32_t* dst, const uint32_t* src, int le n,
146 const float matrix[16]) { 195 const float* const srcTables[3], const flo at matrix[16]) {
147 color_xform_RGB1<sk_linear_from_srgb, linear_to_2dot2>(dst, src, len, matrix ); 196 color_xform_RGB1<k2Dot2_DstGamma>(dst, src, len, srcTables, matrix, nullptr) ;
148 } 197 }
149 198
150 static void color_xform_RGB1_2dot2_to_2dot2(uint32_t* dst, const uint32_t* src, int len, 199 static void color_xform_RGB1_to_srgb(uint32_t* dst, const uint32_t* src, int len ,
151 const float matrix[16]) { 200 const float* const srcTables[3], const floa t matrix[16]) {
152 color_xform_RGB1<sk_linear_from_2dot2, linear_to_2dot2>(dst, src, len, matri x); 201 color_xform_RGB1<kSRGB_DstGamma>(dst, src, len, srcTables, matrix, nullptr);
153 } 202 }
154 203
155 static void color_xform_RGB1_srgb_to_srgb(uint32_t* dst, const uint32_t* src, in t len, 204 static void color_xform_RGB1_to_table(uint32_t* dst, const uint32_t* src, int le n,
156 const float matrix[16]) { 205 const float* const srcTables[3], const flo at matrix[16],
157 color_xform_RGB1<sk_linear_from_srgb, linear_to_srgb>(dst, src, len, matrix) ; 206 const uint8_t* const dstTables[3]) {
158 } 207 color_xform_RGB1<kTable_DstGamma>(dst, src, len, srcTables, matrix, dstTable s);
159
160 static void color_xform_RGB1_2dot2_to_srgb(uint32_t* dst, const uint32_t* src, i nt len,
161 const float matrix[16]) {
162 color_xform_RGB1<sk_linear_from_2dot2, linear_to_srgb>(dst, src, len, matrix );
163 } 208 }
164 209
165 } // namespace SK_OPTS_NS 210 } // namespace SK_OPTS_NS
166 211
167 #endif // SkColorXform_opts_DEFINED 212 #endif // SkColorXform_opts_DEFINED
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698