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 "SkColorData.h" 9 #include "SkColorSpacePriv.h" 10 #include "SkColorSpaceXformSteps.h" 11 #include "SkConvertPixels.h" 12 #include "SkHalf.h" 13 #include "SkImageInfoPriv.h" 14 #include "SkOpts.h" 15 #include "SkRasterPipeline.h" 16 17 static bool rect_memcpy(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, 18 const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB, 19 const SkColorSpaceXformSteps& steps) { 20 // We can copy the pixels when no color type, alpha type, or color space changes. 21 if (dstInfo.colorType() != srcInfo.colorType()) { 22 return false; 23 } 24 if (dstInfo.colorType() != kAlpha_8_SkColorType 25 && steps.flags.mask() != 0b00000) { 26 return false; 27 } 28 29 SkRectMemcpy(dstPixels, dstRB, 30 srcPixels, srcRB, dstInfo.minRowBytes(), dstInfo.height()); 31 return true; 32 } 33 34 static bool swizzle_or_premul(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, 35 const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB, 36 const SkColorSpaceXformSteps& steps) { 37 auto is_8888 = [](SkColorType ct) { 38 return ct == kRGBA_8888_SkColorType || ct == kBGRA_8888_SkColorType; 39 }; 40 if (!is_8888(dstInfo.colorType()) || 41 !is_8888(srcInfo.colorType()) || 42 steps.flags.linearize || 43 steps.flags.gamut_transform || 44 steps.flags.unpremul || 45 steps.flags.encode) { 46 return false; 47 } 48 49 const bool swapRB = dstInfo.colorType() != srcInfo.colorType(); 50 51 void (*fn)(uint32_t*, const uint32_t*, int) = nullptr; 52 53 if (steps.flags.premul) { 54 fn = swapRB ? SkOpts::RGBA_to_bgrA 55 : SkOpts::RGBA_to_rgbA; 56 } else { 57 // If we're not swizzling, we ought to have used rect_memcpy(). 58 SkASSERT(swapRB); 59 fn = SkOpts::RGBA_to_BGRA; 60 } 61 62 for (int y = 0; y < dstInfo.height(); y++) { 63 fn((uint32_t*)dstPixels, (const uint32_t*)srcPixels, dstInfo.width()); 64 dstPixels = SkTAddOffset<void>(dstPixels, dstRB); 65 srcPixels = SkTAddOffset<const void>(srcPixels, srcRB); 66 } 67 return true; 68 } 69 70 static bool convert_to_alpha8(const SkImageInfo& dstInfo, void* vdst, size_t dstRB, 71 const SkImageInfo& srcInfo, const void* src, size_t srcRB, 72 const SkColorSpaceXformSteps&) { 73 if (dstInfo.colorType() != kAlpha_8_SkColorType) { 74 return false; 75 } 76 auto dst = (uint8_t*)vdst; 77 78 switch (srcInfo.colorType()) { 79 case kUnknown_SkColorType: 80 case kAlpha_8_SkColorType: { 81 // Unknown should never happen. 82 // Alpha8 should have been handled by rect_memcpy(). 83 SkASSERT(false); 84 return false; 85 } 86 87 case kGray_8_SkColorType: 88 case kRGB_565_SkColorType: 89 case kRGB_888x_SkColorType: 90 case kRGB_101010x_SkColorType: { 91 for (int y = 0; y < srcInfo.height(); ++y) { 92 memset(dst, 0xFF, srcInfo.width()); 93 dst = SkTAddOffset<uint8_t>(dst, dstRB); 94 } 95 return true; 96 } 97 98 case kARGB_4444_SkColorType: { 99 auto src16 = (const uint16_t*) src; 100 for (int y = 0; y < srcInfo.height(); y++) { 101 for (int x = 0; x < srcInfo.width(); x++) { 102 dst[x] = SkPacked4444ToA32(src16[x]); 103 } 104 dst = SkTAddOffset<uint8_t>(dst, dstRB); 105 src16 = SkTAddOffset<const uint16_t>(src16, srcRB); 106 } 107 return true; 108 } 109 110 case kBGRA_8888_SkColorType: 111 case kRGBA_8888_SkColorType: { 112 auto src32 = (const uint32_t*) src; 113 for (int y = 0; y < srcInfo.height(); y++) { 114 for (int x = 0; x < srcInfo.width(); x++) { 115 dst[x] = src32[x] >> 24; 116 } 117 dst = SkTAddOffset<uint8_t>(dst, dstRB); 118 src32 = SkTAddOffset<const uint32_t>(src32, srcRB); 119 } 120 return true; 121 } 122 123 case kRGBA_1010102_SkColorType: { 124 auto src32 = (const uint32_t*) src; 125 for (int y = 0; y < srcInfo.height(); y++) { 126 for (int x = 0; x < srcInfo.width(); x++) { 127 dst[x] = (src32[x] >> 30) * 0x55; 128 } 129 dst = SkTAddOffset<uint8_t>(dst, dstRB); 130 src32 = SkTAddOffset<const uint32_t>(src32, srcRB); 131 } 132 return true; 133 } 134 135 case kRGBA_F16_SkColorType: { 136 auto src64 = (const uint64_t*) src; 137 for (int y = 0; y < srcInfo.height(); y++) { 138 for (int x = 0; x < srcInfo.width(); x++) { 139 dst[x] = (uint8_t) (255.0f * SkHalfToFloat(src64[x] >> 48)); 140 } 141 dst = SkTAddOffset<uint8_t>(dst, dstRB); 142 src64 = SkTAddOffset<const uint64_t>(src64, srcRB); 143 } 144 return true; 145 } 146 147 case kRGBA_F32_SkColorType: { 148 auto rgba = (const float*)src; 149 for (int y = 0; y < srcInfo.height(); y++) { 150 for (int x = 0; x < srcInfo.width(); x++) { 151 dst[x] = (uint8_t)(255.0f * rgba[4*x+3]); 152 } 153 dst = SkTAddOffset<uint8_t>(dst, dstRB); 154 rgba = SkTAddOffset<const float>(rgba, srcRB); 155 } 156 return true; 157 } 158 } 159 return false; 160 } 161 162 // Default: Use the pipeline. 163 static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB, 164 const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB, 165 const SkColorSpaceXformSteps& steps) { 166 167 SkRasterPipeline_MemoryCtx src = { (void*)srcRow, (int)(srcRB / srcInfo.bytesPerPixel()) }, 168 dst = { (void*)dstRow, (int)(dstRB / dstInfo.bytesPerPixel()) }; 169 170 SkRasterPipeline_<256> pipeline; 171 pipeline.append_load(srcInfo.colorType(), &src); 172 steps.apply(&pipeline, srcInfo.colorType()); 173 174 pipeline.append_gamut_clamp_if_normalized(dstInfo); 175 176 // We'll dither if we're decreasing precision below 32-bit. 177 float dither_rate = 0.0f; 178 if (srcInfo.bytesPerPixel() > dstInfo.bytesPerPixel()) { 179 switch (dstInfo.colorType()) { 180 case kRGB_565_SkColorType: dither_rate = 1/63.0f; break; 181 case kARGB_4444_SkColorType: dither_rate = 1/15.0f; break; 182 default: dither_rate = 0.0f; break; 183 } 184 } 185 if (dither_rate > 0) { 186 pipeline.append(SkRasterPipeline::dither, &dither_rate); 187 } 188 189 pipeline.append_store(dstInfo.colorType(), &dst); 190 pipeline.run(0,0, srcInfo.width(), srcInfo.height()); 191 } 192 193 void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, 194 const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB) { 195 SkASSERT(dstInfo.dimensions() == srcInfo.dimensions()); 196 SkASSERT(SkImageInfoValidConversion(dstInfo, srcInfo)); 197 198 SkColorSpaceXformSteps steps{srcInfo.colorSpace(), srcInfo.alphaType(), 199 dstInfo.colorSpace(), dstInfo.alphaType()}; 200 201 for (auto fn : {rect_memcpy, swizzle_or_premul, convert_to_alpha8}) { 202 if (fn(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, steps)) { 203 return; 204 } 205 } 206 convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, steps); 207 } 208