1 /* 2 * Copyright 2014 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 #include "SkColorSpaceXform_Base.h" 9 #include "SkColorSpaceXformPriv.h" 10 #include "SkColorTable.h" 11 #include "SkConvertPixels.h" 12 #include "SkHalf.h" 13 #include "SkImageInfoPriv.h" 14 #include "SkOpts.h" 15 #include "SkPM4fPriv.h" 16 #include "SkRasterPipeline.h" 17 #include "SkUnPreMultiply.h" 18 #include "SkUnPreMultiplyPriv.h" 19 #include "../jumper/SkJumper.h" 20 21 // Fast Path 1: The memcpy() case. 22 static inline bool can_memcpy(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) { 23 if (dstInfo.colorType() != srcInfo.colorType()) { 24 return false; 25 } 26 27 if (kAlpha_8_SkColorType == dstInfo.colorType()) { 28 return true; 29 } 30 31 if (dstInfo.alphaType() != srcInfo.alphaType() && 32 kOpaque_SkAlphaType != dstInfo.alphaType() && 33 kOpaque_SkAlphaType != srcInfo.alphaType()) 34 { 35 // We need to premultiply or unpremultiply. 36 return false; 37 } 38 39 return !dstInfo.colorSpace() || 40 SkColorSpace::Equals(dstInfo.colorSpace(), srcInfo.colorSpace()); 41 } 42 43 // Fast Path 2: Simple swizzles and premuls. 44 enum AlphaVerb { 45 kNothing_AlphaVerb, 46 kPremul_AlphaVerb, 47 kUnpremul_AlphaVerb, 48 }; 49 50 template <bool kSwapRB> 51 static void wrap_unpremultiply(uint32_t* dst, const void* src, int count) { 52 SkUnpremultiplyRow<kSwapRB>(dst, (const uint32_t*) src, count); 53 } 54 55 void swizzle_and_multiply(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, 56 const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB) { 57 void (*proc)(uint32_t* dst, const void* src, int count); 58 const bool swapRB = dstInfo.colorType() != srcInfo.colorType(); 59 AlphaVerb alphaVerb = kNothing_AlphaVerb; 60 if (kPremul_SkAlphaType == dstInfo.alphaType() && 61 kUnpremul_SkAlphaType == srcInfo.alphaType()) 62 { 63 alphaVerb = kPremul_AlphaVerb; 64 } else if (kUnpremul_SkAlphaType == dstInfo.alphaType() && 65 kPremul_SkAlphaType == srcInfo.alphaType()) { 66 alphaVerb = kUnpremul_AlphaVerb; 67 } 68 69 switch (alphaVerb) { 70 case kNothing_AlphaVerb: 71 // If we do not need to swap or multiply, we should hit the memcpy case. 72 SkASSERT(swapRB); 73 proc = SkOpts::RGBA_to_BGRA; 74 break; 75 case kPremul_AlphaVerb: 76 proc = swapRB ? SkOpts::RGBA_to_bgrA : SkOpts::RGBA_to_rgbA; 77 break; 78 case kUnpremul_AlphaVerb: 79 proc = swapRB ? wrap_unpremultiply<true> : wrap_unpremultiply<false>; 80 break; 81 } 82 83 for (int y = 0; y < dstInfo.height(); y++) { 84 proc((uint32_t*) dstPixels, srcPixels, dstInfo.width()); 85 dstPixels = SkTAddOffset<void>(dstPixels, dstRB); 86 srcPixels = SkTAddOffset<const void>(srcPixels, srcRB); 87 } 88 } 89 90 // Fast Path 3: Color space xform. 91 static inline bool optimized_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo, 92 SkTransferFunctionBehavior behavior) { 93 // Unpremultiplication is unsupported by SkColorSpaceXform. Note that if |src| is non-linearly 94 // premultiplied, we're always going to have to unpremultiply before doing anything. 95 if (kPremul_SkAlphaType == srcInfo.alphaType() && 96 (kUnpremul_SkAlphaType == dstInfo.alphaType() || 97 SkTransferFunctionBehavior::kIgnore == behavior)) { 98 return false; 99 } 100 101 switch (dstInfo.colorType()) { 102 case kRGBA_8888_SkColorType: 103 case kBGRA_8888_SkColorType: 104 case kRGBA_F16_SkColorType: 105 break; 106 default: 107 return false; 108 } 109 110 switch (srcInfo.colorType()) { 111 case kRGBA_8888_SkColorType: 112 case kBGRA_8888_SkColorType: 113 break; 114 default: 115 return false; 116 } 117 118 return true; 119 } 120 121 static inline void apply_color_xform(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, 122 const SkImageInfo& srcInfo, const void* srcPixels, 123 size_t srcRB, SkTransferFunctionBehavior behavior) { 124 SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType()); 125 SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(srcInfo.colorType()); 126 SkAlphaType xformAlpha; 127 switch (srcInfo.alphaType()) { 128 case kOpaque_SkAlphaType: 129 xformAlpha = kOpaque_SkAlphaType; 130 break; 131 case kPremul_SkAlphaType: 132 SkASSERT(kPremul_SkAlphaType == dstInfo.alphaType()); 133 134 // This signal means: copy the src alpha to the dst, do not premultiply (in this 135 // case because the pixels are already premultiplied). 136 xformAlpha = kUnpremul_SkAlphaType; 137 break; 138 case kUnpremul_SkAlphaType: 139 SkASSERT(kPremul_SkAlphaType == dstInfo.alphaType() || 140 kUnpremul_SkAlphaType == dstInfo.alphaType()); 141 142 xformAlpha = dstInfo.alphaType(); 143 break; 144 default: 145 SkASSERT(false); 146 xformAlpha = kUnpremul_SkAlphaType; 147 break; 148 } 149 150 std::unique_ptr<SkColorSpaceXform> xform = 151 SkColorSpaceXform_Base::New(srcInfo.colorSpace(), dstInfo.colorSpace(), behavior); 152 SkASSERT(xform); 153 154 for (int y = 0; y < dstInfo.height(); y++) { 155 SkAssertResult(xform->apply(dstFormat, dstPixels, srcFormat, srcPixels, dstInfo.width(), 156 xformAlpha)); 157 dstPixels = SkTAddOffset<void>(dstPixels, dstRB); 158 srcPixels = SkTAddOffset<const void>(srcPixels, srcRB); 159 } 160 } 161 162 // Fast Path 4: Index 8 sources. 163 template <typename T> 164 void do_index8(const SkImageInfo& dstInfo, T* dstPixels, size_t dstRB, 165 const SkImageInfo& srcInfo, const uint8_t* srcPixels, size_t srcRB, 166 SkColorTable* ctable, SkTransferFunctionBehavior behavior) { 167 T dstCTable[256]; 168 int count = ctable->count(); 169 SkImageInfo srcInfo8888 = srcInfo.makeColorType(kN32_SkColorType).makeWH(count, 1); 170 SkImageInfo dstInfoCT = dstInfo.makeWH(count, 1); 171 size_t rowBytes = count * sizeof(T); 172 SkConvertPixels(dstInfoCT, dstCTable, rowBytes, srcInfo8888, ctable->readColors(), rowBytes, 173 nullptr, behavior); 174 175 for (int y = 0; y < dstInfo.height(); y++) { 176 for (int x = 0; x < dstInfo.width(); x++) { 177 dstPixels[x] = dstCTable[srcPixels[x]]; 178 } 179 dstPixels = SkTAddOffset<T>(dstPixels, dstRB); 180 srcPixels = SkTAddOffset<const uint8_t>(srcPixels, srcRB); 181 } 182 } 183 184 void convert_from_index8(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, 185 const SkImageInfo& srcInfo, const uint8_t* srcPixels, size_t srcRB, 186 SkColorTable* ctable, SkTransferFunctionBehavior behavior) { 187 switch (dstInfo.colorType()) { 188 case kAlpha_8_SkColorType: 189 do_index8(dstInfo, (uint8_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable, 190 behavior); 191 break; 192 case kRGB_565_SkColorType: 193 case kARGB_4444_SkColorType: 194 do_index8(dstInfo, (uint16_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable, 195 behavior); 196 break; 197 case kRGBA_8888_SkColorType: 198 case kBGRA_8888_SkColorType: 199 do_index8(dstInfo, (uint32_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable, 200 behavior); 201 break; 202 case kRGBA_F16_SkColorType: 203 do_index8(dstInfo, (uint64_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable, 204 behavior); 205 break; 206 default: 207 SkASSERT(false); 208 } 209 } 210 211 // Fast Path 5: Alpha 8 dsts. 212 static void convert_to_alpha8(uint8_t* dst, size_t dstRB, const SkImageInfo& srcInfo, 213 const void* src, size_t srcRB, SkColorTable* ctable) { 214 if (srcInfo.isOpaque()) { 215 for (int y = 0; y < srcInfo.height(); ++y) { 216 memset(dst, 0xFF, srcInfo.width()); 217 dst = SkTAddOffset<uint8_t>(dst, dstRB); 218 } 219 return; 220 } 221 222 switch (srcInfo.colorType()) { 223 case kBGRA_8888_SkColorType: 224 case kRGBA_8888_SkColorType: { 225 auto src32 = (const uint32_t*) src; 226 for (int y = 0; y < srcInfo.height(); y++) { 227 for (int x = 0; x < srcInfo.width(); x++) { 228 dst[x] = src32[x] >> 24; 229 } 230 dst = SkTAddOffset<uint8_t>(dst, dstRB); 231 src32 = SkTAddOffset<const uint32_t>(src32, srcRB); 232 } 233 break; 234 } 235 case kARGB_4444_SkColorType: { 236 auto src16 = (const uint16_t*) src; 237 for (int y = 0; y < srcInfo.height(); y++) { 238 for (int x = 0; x < srcInfo.width(); x++) { 239 dst[x] = SkPacked4444ToA32(src16[x]); 240 } 241 dst = SkTAddOffset<uint8_t>(dst, dstRB); 242 src16 = SkTAddOffset<const uint16_t>(src16, srcRB); 243 } 244 break; 245 } 246 case kRGBA_F16_SkColorType: { 247 auto src64 = (const uint64_t*) src; 248 for (int y = 0; y < srcInfo.height(); y++) { 249 for (int x = 0; x < srcInfo.width(); x++) { 250 dst[x] = (uint8_t) (255.0f * SkHalfToFloat(src64[x] >> 48)); 251 } 252 dst = SkTAddOffset<uint8_t>(dst, dstRB); 253 src64 = SkTAddOffset<const uint64_t>(src64, srcRB); 254 } 255 break; 256 } 257 default: 258 SkASSERT(false); 259 break; 260 } 261 } 262 263 // Default: Use the pipeline. 264 static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB, 265 const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB, 266 bool isColorAware, SkTransferFunctionBehavior behavior) { 267 SkRasterPipeline_<256> pipeline; 268 switch (srcInfo.colorType()) { 269 case kRGBA_8888_SkColorType: 270 pipeline.append(SkRasterPipeline::load_8888, &srcRow); 271 break; 272 case kBGRA_8888_SkColorType: 273 pipeline.append(SkRasterPipeline::load_bgra, &srcRow); 274 break; 275 case kRGB_565_SkColorType: 276 pipeline.append(SkRasterPipeline::load_565, &srcRow); 277 break; 278 case kRGBA_F16_SkColorType: 279 pipeline.append(SkRasterPipeline::load_f16, &srcRow); 280 break; 281 case kGray_8_SkColorType: 282 pipeline.append(SkRasterPipeline::load_g8, &srcRow); 283 break; 284 case kARGB_4444_SkColorType: 285 pipeline.append(SkRasterPipeline::load_4444, &srcRow); 286 break; 287 default: 288 SkASSERT(false); 289 break; 290 } 291 292 SkAlphaType premulState = srcInfo.alphaType(); 293 if (kPremul_SkAlphaType == premulState && SkTransferFunctionBehavior::kIgnore == behavior) { 294 pipeline.append(SkRasterPipeline::unpremul); 295 premulState = kUnpremul_SkAlphaType; 296 } 297 298 SkColorSpaceTransferFn srcFn; 299 if (isColorAware && srcInfo.gammaCloseToSRGB()) { 300 pipeline.append_from_srgb(srcInfo.alphaType()); 301 } else if (isColorAware && !srcInfo.colorSpace()->gammaIsLinear()) { 302 SkAssertResult(srcInfo.colorSpace()->isNumericalTransferFn(&srcFn)); 303 pipeline.append(SkRasterPipeline::parametric_r, &srcFn); 304 pipeline.append(SkRasterPipeline::parametric_g, &srcFn); 305 pipeline.append(SkRasterPipeline::parametric_b, &srcFn); 306 } 307 308 float matrix[12]; 309 if (isColorAware) { 310 append_gamut_transform(&pipeline, matrix, srcInfo.colorSpace(), dstInfo.colorSpace(), 311 premulState); 312 } 313 314 SkAlphaType dat = dstInfo.alphaType(); 315 if (SkTransferFunctionBehavior::kRespect == behavior) { 316 if (kPremul_SkAlphaType == premulState && kUnpremul_SkAlphaType == dat) { 317 pipeline.append(SkRasterPipeline::unpremul); 318 premulState = kUnpremul_SkAlphaType; 319 } else if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat) { 320 pipeline.append(SkRasterPipeline::premul); 321 premulState = kPremul_SkAlphaType; 322 } 323 } 324 325 SkColorSpaceTransferFn dstFn; 326 if (isColorAware && dstInfo.gammaCloseToSRGB()) { 327 pipeline.append(SkRasterPipeline::to_srgb); 328 } else if (isColorAware && !dstInfo.colorSpace()->gammaIsLinear()) { 329 SkAssertResult(dstInfo.colorSpace()->isNumericalTransferFn(&dstFn)); 330 dstFn = dstFn.invert(); 331 pipeline.append(SkRasterPipeline::parametric_r, &dstFn); 332 pipeline.append(SkRasterPipeline::parametric_g, &dstFn); 333 pipeline.append(SkRasterPipeline::parametric_b, &dstFn); 334 } 335 336 if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat && 337 SkTransferFunctionBehavior::kIgnore == behavior) 338 { 339 pipeline.append(SkRasterPipeline::premul); 340 premulState = kPremul_SkAlphaType; 341 } 342 343 // The final premul state must equal the dst alpha type. Note that if we are "converting" 344 // opaque to another alpha type, there's no need to worry about multiplication. 345 SkASSERT(premulState == dat || kOpaque_SkAlphaType == srcInfo.alphaType()); 346 347 // We'll dither if we're decreasing precision below 32-bit. 348 float dither_rate = 0.0f; 349 if (srcInfo.bytesPerPixel() > dstInfo.bytesPerPixel()) { 350 switch (dstInfo.colorType()) { 351 case kRGB_565_SkColorType: dither_rate = 1/63.0f; break; 352 case kARGB_4444_SkColorType: dither_rate = 1/15.0f; break; 353 default: dither_rate = 0.0f; break; 354 } 355 } 356 if (dither_rate > 0) { 357 pipeline.append(SkRasterPipeline::dither, &dither_rate); 358 } 359 360 switch (dstInfo.colorType()) { 361 case kRGBA_8888_SkColorType: 362 pipeline.append(SkRasterPipeline::store_8888, &dstRow); 363 break; 364 case kBGRA_8888_SkColorType: 365 pipeline.append(SkRasterPipeline::store_bgra, &dstRow); 366 break; 367 case kRGB_565_SkColorType: 368 pipeline.append(SkRasterPipeline::store_565, &dstRow); 369 break; 370 case kRGBA_F16_SkColorType: 371 pipeline.append(SkRasterPipeline::store_f16, &dstRow); 372 break; 373 case kARGB_4444_SkColorType: 374 pipeline.append(SkRasterPipeline::store_4444, &dstRow); 375 break; 376 default: 377 SkASSERT(false); 378 break; 379 } 380 381 auto run = pipeline.compile(); 382 for (int y = 0; y < srcInfo.height(); ++y) { 383 run(0,y, srcInfo.width()); 384 // The pipeline has pointers to srcRow and dstRow, so we just need to update them in the 385 // loop to move between rows of src/dst. 386 dstRow = SkTAddOffset<void>(dstRow, dstRB); 387 srcRow = SkTAddOffset<const void>(srcRow, srcRB); 388 } 389 } 390 391 void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, 392 const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB, 393 SkColorTable* ctable, SkTransferFunctionBehavior behavior) { 394 SkASSERT(dstInfo.dimensions() == srcInfo.dimensions()); 395 SkASSERT(SkImageInfoValidConversion(dstInfo, srcInfo)); 396 397 // Fast Path 1: The memcpy() case. 398 if (can_memcpy(dstInfo, srcInfo)) { 399 SkRectMemcpy(dstPixels, dstRB, srcPixels, srcRB, dstInfo.minRowBytes(), dstInfo.height()); 400 return; 401 } 402 403 const bool isColorAware = dstInfo.colorSpace(); 404 SkASSERT(srcInfo.colorSpace() || !isColorAware); 405 406 // Fast Path 2: Simple swizzles and premuls. 407 if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel() && !isColorAware) { 408 swizzle_and_multiply(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB); 409 return; 410 } 411 412 // Fast Path 3: Color space xform. 413 if (isColorAware && optimized_color_xform(dstInfo, srcInfo, behavior)) { 414 apply_color_xform(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, behavior); 415 return; 416 } 417 418 // Fast Path 5: Alpha 8 dsts. 419 if (kAlpha_8_SkColorType == dstInfo.colorType()) { 420 convert_to_alpha8((uint8_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable); 421 return; 422 } 423 424 // Default: Use the pipeline. 425 convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, isColorAware, 426 behavior); 427 } 428