aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--bench/CodecBench.cpp4
-rw-r--r--bench/ColorCodecBench.cpp66
-rw-r--r--dm/DM.cpp3
-rw-r--r--dm/DMSrcSink.cpp93
-rw-r--r--include/codec/SkCodec.h6
-rw-r--r--src/codec/SkJpegCodec.cpp269
-rw-r--r--src/codec/SkJpegCodec.h37
-rw-r--r--src/core/SkColorSpaceXform.cpp43
-rw-r--r--src/core/SkColorSpaceXform.h7
-rw-r--r--src/core/SkOpts.cpp3
-rw-r--r--src/core/SkOpts.h11
-rw-r--r--src/opts/SkColorXform_opts.h95
-rw-r--r--src/opts/SkOpts_sse41.cpp11
-rw-r--r--tests/ColorSpaceXformTest.cpp10
-rw-r--r--tools/viewer/ImageSlide.cpp22
15 files changed, 415 insertions, 265 deletions
diff --git a/bench/CodecBench.cpp b/bench/CodecBench.cpp
index fc52edfb07..9bd404db55 100644
--- a/bench/CodecBench.cpp
+++ b/bench/CodecBench.cpp
@@ -42,7 +42,9 @@ bool CodecBench::isSuitableFor(Backend backend) {
void CodecBench::onDelayedSetup() {
SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fData));
- fInfo = codec->getInfo().makeColorType(fColorType).makeAlphaType(fAlphaType);
+ fInfo = codec->getInfo().makeColorType(fColorType)
+ .makeAlphaType(fAlphaType)
+ .makeColorSpace(nullptr);
fPixelStorage.reset(fInfo.getSafeSize(fInfo.minRowBytes()));
}
diff --git a/bench/ColorCodecBench.cpp b/bench/ColorCodecBench.cpp
index e17d597abb..5079b482c7 100644
--- a/bench/ColorCodecBench.cpp
+++ b/bench/ColorCodecBench.cpp
@@ -41,32 +41,13 @@ bool ColorCodecBench::isSuitableFor(Backend backend) {
void ColorCodecBench::decodeAndXform() {
SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fEncoded.get()));
-#ifdef SK_DEBUG
- const SkCodec::Result result =
-#endif
- codec->startScanlineDecode(fSrcInfo);
- SkASSERT(SkCodec::kSuccess == result);
-
- sk_sp<SkColorSpace> srcSpace = sk_ref_sp(codec->getInfo().colorSpace());
- if (!srcSpace) {
- srcSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
- }
- std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(srcSpace, fDstSpace);
- SkASSERT(xform);
+ SkASSERT(codec);
- void* dst = fDst.get();
- for (int y = 0; y < fSrcInfo.height(); y++) {
#ifdef SK_DEBUG
- const int rows =
+ SkCodec::Result result =
#endif
- codec->getScanlines(fSrc.get(), 1, 0);
- SkASSERT(1 == rows);
-
- FLAGS_half ?
- xform->applyToF16((uint64_t*) dst, (uint32_t*) fSrc.get(), fSrcInfo.width()) :
- xform->applyTo8888((SkPMColor*) dst, (uint32_t*) fSrc.get(), fSrcInfo.width());
- dst = SkTAddOffset<void>(dst, fDstInfo.minRowBytes());
- }
+ codec->getPixels(fDstInfo, fDst.get(), fDstInfo.minRowBytes());
+ SkASSERT(SkCodec::kSuccess == result);
}
#if defined(SK_TEST_QCMS)
@@ -121,7 +102,7 @@ void ColorCodecBench::xformOnly() {
// Transform in place
FLAGS_half ?
xform->applyToF16((uint64_t*) dst, (uint32_t*) src, fSrcInfo.width()) :
- xform->applyTo8888((SkPMColor*) dst, (uint32_t*) src, fSrcInfo.width());
+ xform->applyToRGBA((SkPMColor*) dst, (uint32_t*) src, fSrcInfo.width());
dst = SkTAddOffset<void>(dst, fDstInfo.minRowBytes());
src = SkTAddOffset<void>(src, fSrcInfo.minRowBytes());
}
@@ -157,28 +138,12 @@ void ColorCodecBench::xformOnlyQCMS() {
void ColorCodecBench::onDelayedSetup() {
SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(fEncoded.get()));
- fSrcInfo = codec->getInfo().makeColorType(kRGBA_8888_SkColorType);
-
- fDstInfo = fSrcInfo;
- if (FLAGS_half) {
- fDstInfo = fDstInfo.makeColorType(kRGBA_F16_SkColorType);
- }
- fDst.reset(fDstInfo.getSafeSize(fDstInfo.minRowBytes()));
-
- if (FLAGS_xform_only) {
- fSrc.reset(fSrcInfo.getSafeSize(fSrcInfo.minRowBytes()));
- codec->getPixels(fSrcInfo, fSrc.get(), fSrcInfo.minRowBytes());
- } else {
- // Set-up a row buffer to decode into before transforming to dst.
- fSrc.reset(fSrcInfo.minRowBytes());
- }
-
fSrcData = codec->getICCData();
sk_sp<SkData> dstData = SkData::MakeFromFileName(
GetResourcePath("monitor_profiles/HP_ZR30w.icc").c_str());
SkASSERT(dstData);
-
+ fDstSpace = nullptr;
#if defined(SK_TEST_QCMS)
if (FLAGS_qcms) {
fDstSpaceQCMS.reset(FLAGS_srgb ?
@@ -196,6 +161,25 @@ void ColorCodecBench::onDelayedSetup() {
SkColorSpace::NewICC(dstData->data(), dstData->size());
SkASSERT(fDstSpace);
}
+
+ fSrcInfo = codec->getInfo().makeColorType(kRGBA_8888_SkColorType);
+
+ fDstInfo = fSrcInfo.makeColorSpace(fDstSpace);
+ if (FLAGS_half) {
+ fDstInfo = fDstInfo.makeColorType(kRGBA_F16_SkColorType);
+ }
+ fDst.reset(fDstInfo.getSafeSize(fDstInfo.minRowBytes()));
+
+ if (FLAGS_xform_only) {
+ fSrc.reset(fSrcInfo.getSafeSize(fSrcInfo.minRowBytes()));
+ codec->getPixels(fSrcInfo, fSrc.get(), fSrcInfo.minRowBytes());
+ }
+#if defined(SK_TEST_QCMS)
+ else if (FLAGS_qcms) {
+ // Set-up a row buffer to decode into before transforming to dst.
+ fSrc.reset(fSrcInfo.minRowBytes());
+ }
+#endif
}
void ColorCodecBench::onDraw(int n, SkCanvas*) {
diff --git a/dm/DM.cpp b/dm/DM.cpp
index 7a1e5959c8..772cfe054d 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -777,7 +777,8 @@ static bool gather_srcs() {
push_src("image", "color_codec_sRGB_kF16", src);
#if defined(SK_TEST_QCMS)
- src = new ColorCodecSrc(colorImage, ColorCodecSrc::kQCMS_HPZR30w_Mode, kN32_SkColorType);
+ src = new ColorCodecSrc(colorImage, ColorCodecSrc::kQCMS_HPZR30w_Mode,
+ kRGBA_8888_SkColorType);
push_src("image", "color_codec_QCMS_HPZR30w", src);
#endif
}
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index f3f5f78b57..c03a8c4c98 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -867,75 +867,46 @@ Error ColorCodecSrc::draw(SkCanvas* canvas) const {
return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
}
- SkImageInfo info = codec->getInfo().makeColorType(fColorType);
- SkBitmap bitmap;
- if (!bitmap.tryAllocPixels(info)) {
- return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(),
- info.width(), info.height());
+ // Load the dst ICC profile. This particular dst is fairly similar to Adobe RGB.
+ sk_sp<SkData> dstData = SkData::MakeFromFileName(
+ GetResourcePath("monitor_profiles/HP_ZR30w.icc").c_str());
+ if (!dstData) {
+ return "Cannot read monitor profile. Is the resource path set correctly?";
}
- SkImageInfo decodeInfo = info;
- size_t srcRowBytes = sizeof(SkPMColor) * info.width();
- SkAutoMalloc src(srcRowBytes * info.height());
- void* srcPixels = src.get();
- if (kBaseline_Mode == fMode) {
- srcPixels = bitmap.getPixels();
- } else {
- decodeInfo = decodeInfo.makeColorType(kRGBA_8888_SkColorType);
+ sk_sp<SkColorSpace> dstSpace = nullptr;
+ if (kDst_sRGB_Mode == fMode) {
+ dstSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+ } else if (kDst_HPZR30w_Mode == fMode) {
+ dstSpace = SkColorSpace::NewICC(dstData->data(), dstData->size());
}
- SkCodec::Result r = codec->getPixels(decodeInfo, srcPixels, srcRowBytes);
- if (SkCodec::kSuccess != r) {
- return SkStringPrintf("Couldn't getPixels %s. Error code %d", fPath.c_str(), r);
+ SkImageInfo decodeInfo = codec->getInfo().makeColorType(fColorType).makeColorSpace(dstSpace);
+ SkImageInfo bitmapInfo = decodeInfo;
+ if (kRGBA_8888_SkColorType == decodeInfo.colorType() ||
+ kBGRA_8888_SkColorType == decodeInfo.colorType())
+ {
+ bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType);
}
- // Load the dst ICC profile. This particular dst is fairly similar to Adobe RGB.
- sk_sp<SkData> dstData = SkData::MakeFromFileName(
- GetResourcePath("monitor_profiles/HP_ZR30w.icc").c_str());
- if (!dstData) {
- return "Cannot read monitor profile. Is the resource path set correctly?";
+ SkBitmap bitmap;
+ if (!bitmap.tryAllocPixels(bitmapInfo)) {
+ return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(),
+ bitmapInfo.width(), bitmapInfo.height());
+ }
+
+ size_t rowBytes = bitmap.rowBytes();
+ SkCodec::Result r = codec->getPixels(decodeInfo, bitmap.getPixels(), rowBytes);
+ if (SkCodec::kSuccess != r) {
+ return SkStringPrintf("Couldn't getPixels %s. Error code %d", fPath.c_str(), r);
}
switch (fMode) {
case kBaseline_Mode:
- canvas->drawBitmap(bitmap, 0, 0);
- break;
case kDst_sRGB_Mode:
- case kDst_HPZR30w_Mode: {
- sk_sp<SkColorSpace> srcSpace = sk_ref_sp(codec->getInfo().colorSpace());
- sk_sp<SkColorSpace> dstSpace = (kDst_sRGB_Mode == fMode) ?
- SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named) :
- SkColorSpace::NewICC(dstData->data(), dstData->size());
- SkASSERT(dstSpace);
-
- std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(srcSpace, dstSpace);
- if (!xform) {
- return "Unimplemented color conversion.";
- }
-
- if (kN32_SkColorType == fColorType) {
- uint32_t* srcRow = (uint32_t*) srcPixels;
- uint32_t* dstRow = (uint32_t*) bitmap.getPixels();
- for (int y = 0; y < info.height(); y++) {
- xform->applyTo8888(dstRow, srcRow, info.width());
- srcRow = SkTAddOffset<uint32_t>(srcRow, srcRowBytes);
- dstRow = SkTAddOffset<uint32_t>(dstRow, bitmap.rowBytes());
- }
- } else {
- SkASSERT(kRGBA_F16_SkColorType == fColorType);
-
- uint32_t* srcRow = (uint32_t*) srcPixels;
- uint64_t* dstRow = (uint64_t*) bitmap.getPixels();
- for (int y = 0; y < info.height(); y++) {
- xform->applyToF16(dstRow, srcRow, info.width());
- srcRow = SkTAddOffset<uint32_t>(srcRow, srcRowBytes);
- dstRow = SkTAddOffset<uint64_t>(dstRow, bitmap.rowBytes());
- }
- }
-
+ case kDst_HPZR30w_Mode:
canvas->drawBitmap(bitmap, 0, 0);
break;
- }
#if defined(SK_TEST_QCMS)
case kQCMS_HPZR30w_Mode: {
sk_sp<SkData> srcData = codec->getICCData();
@@ -967,12 +938,10 @@ Error ColorCodecSrc::draw(SkCanvas* canvas) const {
#endif
// Perform color correction.
- uint32_t* srcRow = (uint32_t*) srcPixels;
- uint32_t* dstRow = (uint32_t*) bitmap.getPixels();
- for (int y = 0; y < info.height(); y++) {
- qcms_transform_data_type(transform, srcRow, dstRow, info.width(), outType);
- srcRow = SkTAddOffset<uint32_t>(srcRow, srcRowBytes);
- dstRow = SkTAddOffset<uint32_t>(dstRow, bitmap.rowBytes());
+ uint32_t* row = (uint32_t*) bitmap.getPixels();
+ for (int y = 0; y < decodeInfo.height(); y++) {
+ qcms_transform_data_type(transform, row, row, decodeInfo.width(), outType);
+ row = SkTAddOffset<uint32_t>(row, rowBytes);
}
canvas->drawBitmap(bitmap, 0, 0);
diff --git a/include/codec/SkCodec.h b/include/codec/SkCodec.h
index 5c84e07c70..c5dc66a474 100644
--- a/include/codec/SkCodec.h
+++ b/include/codec/SkCodec.h
@@ -286,6 +286,12 @@ public:
* to scale. If the generator cannot perform this scale,
* it will return kInvalidScale.
*
+ * If the info contains a non-null SkColorSpace, the codec
+ * will perform the appropriate color space transformation.
+ * If the caller passes in the same color space that was
+ * reported by the codec, the color space transformation is
+ * a no-op.
+ *
* If info is kIndex8_SkColorType, then the caller must provide storage for up to 256
* SkPMColor values in ctable. On success the generator must copy N colors into that storage,
* (where N is the logical number of table entries) and set ctableCount to N.
diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp
index a81c759ff0..d158b4215a 100644
--- a/src/codec/SkJpegCodec.cpp
+++ b/src/codec/SkJpegCodec.cpp
@@ -196,7 +196,7 @@ bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
// libjpeg errors will be caught and reported here
if (setjmp(decoderMgr->getJmpBuf())) {
- return decoderMgr->returnFalse("setjmp");
+ return decoderMgr->returnFalse("ReadHeader");
}
// Initialize the decompress info and the source manager
@@ -212,7 +212,7 @@ bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
// Read the jpeg header
if (JPEG_HEADER_OK != jpeg_read_header(decoderMgr->dinfo(), true)) {
- return decoderMgr->returnFalse("read_header");
+ return decoderMgr->returnFalse("ReadHeader");
}
if (codecOut) {
@@ -268,7 +268,8 @@ SkJpegCodec::SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStr
: INHERITED(width, height, info, stream, std::move(colorSpace), origin)
, fDecoderMgr(decoderMgr)
, fReadyState(decoderMgr->dinfo()->global_state)
- , fSrcRow(nullptr)
+ , fSwizzleSrcRow(nullptr)
+ , fColorXformSrcRow(nullptr)
, fSwizzlerSubset(SkIRect::MakeEmpty())
, fICCData(std::move(iccData))
{}
@@ -341,14 +342,16 @@ SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const {
bool SkJpegCodec::onRewind() {
JpegDecoderMgr* decoderMgr = nullptr;
if (!ReadHeader(this->stream(), nullptr, &decoderMgr)) {
- return fDecoderMgr->returnFalse("could not rewind");
+ return fDecoderMgr->returnFalse("onRewind");
}
SkASSERT(nullptr != decoderMgr);
fDecoderMgr.reset(decoderMgr);
fSwizzler.reset(nullptr);
- fSrcRow = nullptr;
+ fSwizzleSrcRow = nullptr;
+ fColorXformSrcRow = nullptr;
fStorage.reset();
+ fColorXform.reset(nullptr);
return true;
}
@@ -358,22 +361,23 @@ bool SkJpegCodec::onRewind() {
* image has been implemented
* Sets the output color space
*/
-bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dst) {
- if (kUnknown_SkAlphaType == dst.alphaType()) {
+bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo, bool needsColorXform) {
+ if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
return false;
}
- if (kOpaque_SkAlphaType != dst.alphaType()) {
+ if (kOpaque_SkAlphaType != dstInfo.alphaType()) {
SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
"- it is being decoded as non-opaque, which will draw slower\n");
}
- // Check if we will decode to CMYK because a conversion to RGBA is not supported
- J_COLOR_SPACE colorSpace = fDecoderMgr->dinfo()->jpeg_color_space;
- bool isCMYK = JCS_CMYK == colorSpace || JCS_YCCK == colorSpace;
+ // Check if we will decode to CMYK. libjpeg-turbo does not convert CMYK to RGBA, so
+ // we must do it ourselves.
+ J_COLOR_SPACE encodedColorType = fDecoderMgr->dinfo()->jpeg_color_space;
+ bool isCMYK = (JCS_CMYK == encodedColorType || JCS_YCCK == encodedColorType);
// Check for valid color types and set the output color space
- switch (dst.colorType()) {
+ switch (dstInfo.colorType()) {
case kRGBA_8888_SkColorType:
if (isCMYK) {
fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
@@ -384,11 +388,19 @@ bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dst) {
case kBGRA_8888_SkColorType:
if (isCMYK) {
fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
+ } else if (needsColorXform) {
+ // Our color transformation code requires RGBA order inputs, but it'll swizzle
+ // to BGRA for us.
+ fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
} else {
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_BGRA;
}
return true;
case kRGB_565_SkColorType:
+ if (needsColorXform) {
+ return false;
+ }
+
if (isCMYK) {
fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
} else {
@@ -401,12 +413,19 @@ bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dst) {
}
return true;
case kGray_8_SkColorType:
- if (isCMYK) {
+ if (needsColorXform || JCS_GRAYSCALE != encodedColorType) {
return false;
+ }
+
+ fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
+ return true;
+ case kRGBA_F16_SkColorType:
+ SkASSERT(needsColorXform);
+
+ if (isCMYK) {
+ fDecoderMgr->dinfo()->out_color_space = JCS_CMYK;
} else {
- // We will enable decodes to gray even if the image is color because this is
- // much faster than decoding to color and then converting
- fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
+ fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
}
return true;
default:
@@ -420,7 +439,7 @@ bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dst) {
*/
bool SkJpegCodec::onDimensionsSupported(const SkISize& size) {
if (setjmp(fDecoderMgr->getJmpBuf())) {
- return fDecoderMgr->returnFalse("onDimensionsSupported/setjmp");
+ return fDecoderMgr->returnFalse("onDimensionsSupported");
}
const unsigned int dstWidth = size.width();
@@ -455,6 +474,84 @@ bool SkJpegCodec::onDimensionsSupported(const SkISize& size) {
return true;
}
+static bool needs_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
+ // FIXME (msarett):
+ // Do a better check for color space equality.
+ return (kRGBA_F16_SkColorType == dstInfo.colorType()) ||
+ (dstInfo.colorSpace() && (dstInfo.colorSpace() != srcInfo.colorSpace()));
+}
+
+int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count) {
+ // Set the jump location for libjpeg-turbo errors
+ if (setjmp(fDecoderMgr->getJmpBuf())) {
+ return 0;
+ }
+
+ // When fSwizzleSrcRow is non-null, it means that we need to swizzle. In this case,
+ // we will always decode into fSwizzlerSrcRow before swizzling into the next buffer.
+ // We can never swizzle "in place" because the swizzler may perform sampling and/or
+ // subsetting.
+ // When fColorXformSrcRow is non-null, it means that we need to color xform and that
+ // we cannot color xform "in place" (many times we can, but not when the dst is F16).
+ // In this case, we will color xform from fColorXformSrc into the dst.
+ JSAMPLE* decodeDst = (JSAMPLE*) dst;
+ uint32_t* swizzleDst = (uint32_t*) dst;
+ size_t decodeDstRowBytes = rowBytes;
+ size_t swizzleDstRowBytes = rowBytes;
+ if (fSwizzleSrcRow && fColorXformSrcRow) {
+ decodeDst = (JSAMPLE*) fSwizzleSrcRow;
+ swizzleDst = fColorXformSrcRow;
+ decodeDstRowBytes = 0;
+ swizzleDstRowBytes = 0;
+ } else if (fColorXformSrcRow) {
+ decodeDst = (JSAMPLE*) fColorXformSrcRow;
+ swizzleDst = fColorXformSrcRow;
+ decodeDstRowBytes = 0;
+ swizzleDstRowBytes = 0;
+ } else if (fSwizzleSrcRow) {
+ decodeDst = (JSAMPLE*) fSwizzleSrcRow;
+ decodeDstRowBytes = 0;
+ }
+
+ for (int y = 0; y < count; y++) {
+ uint32_t lines = jpeg_read_scanlines(fDecoderMgr->dinfo(), &decodeDst, 1);
+ size_t srcRowBytes = get_row_bytes(fDecoderMgr->dinfo());
+ sk_msan_mark_initialized(decodeDst, decodeDst + srcRowBytes, "skbug.com/4550");
+ if (0 == lines) {
+ return y;
+ }
+
+ if (fSwizzler) {
+ fSwizzler->swizzle(swizzleDst, decodeDst);
+ }
+
+ if (fColorXform) {
+ int width = dstInfo.width();
+ switch (dstInfo.colorType()) {
+ case kRGBA_8888_SkColorType:
+ fColorXform->applyToRGBA((uint32_t*) dst, swizzleDst, width);
+ break;
+ case kBGRA_8888_SkColorType:
+ fColorXform->applyToBGRA((uint32_t*) dst, swizzleDst, width);
+ break;
+ case kRGBA_F16_SkColorType:
+ fColorXform->applyToF16((uint64_t*) dst, swizzleDst, width);
+ break;
+ default:
+ SkASSERT(false);
+ break;
+ }
+
+ dst = SkTAddOffset<void>(dst, rowBytes);
+ }
+
+ decodeDst = SkTAddOffset<JSAMPLE>(decodeDst, decodeDstRowBytes);
+ swizzleDst = SkTAddOffset<uint32_t>(swizzleDst, swizzleDstRowBytes);
+ }
+
+ return count;
+}
+
/*
* Performs the jpeg decode
*/
@@ -476,11 +573,15 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
}
// Check if we can decode to the requested destination and set the output color space
- if (!this->setOutputColorSpace(dstInfo)) {
- return fDecoderMgr->returnFailure("conversion_possible", kInvalidConversion);
+ bool needsColorXform = needs_color_xform(dstInfo, this->getInfo());
+ if (!this->setOutputColorSpace(dstInfo, needsColorXform)) {
+ return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConversion);
+ }
+
+ if (!this->initializeColorXform(dstInfo, needsColorXform)) {
+ return fDecoderMgr->returnFailure("initializeColorXform", kInvalidParameters);
}
- // Now, given valid output dimensions, we can start the decompress
if (!jpeg_start_decompress(dinfo)) {
return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
}
@@ -494,39 +595,37 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
this->initializeSwizzler(dstInfo, options);
}
- // Perform the decode a single row at a time
- uint32_t dstHeight = dstInfo.height();
+ this->allocateStorage(dstInfo);
- JSAMPLE* dstRow;
- if (fSwizzler) {
- // write data to storage row, then sample using swizzler
- dstRow = fSrcRow;
- } else {
- // write data directly to dst
- dstRow = (JSAMPLE*) dst;
+ int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height());
+ if (rows < dstInfo.height()) {
+ *rowsDecoded = rows;
+ return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput);
}
- for (uint32_t y = 0; y < dstHeight; y++) {
- // Read rows of the image
- uint32_t lines = jpeg_read_scanlines(dinfo, &dstRow, 1);
- sk_msan_mark_initialized(dstRow, dstRow + dstRowBytes, "skbug.com/4550");
+ return kSuccess;
+}
- // If we cannot read enough rows, assume the input is incomplete
- if (lines != 1) {
- *rowsDecoded = y;
- return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput);
- }
+void SkJpegCodec::allocateStorage(const SkImageInfo& dstInfo) {
+ size_t swizzleBytes = 0;
+ if (fSwizzler) {
+ swizzleBytes = get_row_bytes(fDecoderMgr->dinfo());
+ SkASSERT(!fColorXform || SkIsAlign4(swizzleBytes));
+ }
- if (fSwizzler) {
- // use swizzler to sample row
- fSwizzler->swizzle(dst, dstRow);
- dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes);
- } else {
- dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes);
- }
+ size_t xformBytes = 0;
+ if (kRGBA_F16_SkColorType == dstInfo.colorType()) {
+ SkASSERT(fColorXform);
+ xformBytes = dstInfo.width() * sizeof(SkColorSpaceXform::RGBA32);
}
- return kSuccess;
+ size_t totalBytes = swizzleBytes + xformBytes;
+ if (totalBytes > 0) {
+ fStorage.reset(totalBytes);
+ fSwizzleSrcRow = (swizzleBytes > 0) ? fStorage.get() : nullptr;
+ fColorXformSrcRow = (xformBytes > 0) ?
+ SkTAddOffset<uint32_t>(fStorage.get(), swizzleBytes) : nullptr;
+ }
}
void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options) {
@@ -543,9 +642,9 @@ void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options&
break;
case JCS_CMYK:
preSwizzled = false;
- swizzlerInfo = SkEncodedInfo::Make(
- SkEncodedInfo::kInvertedCMYK_Color, swizzlerInfo.alpha(),
- swizzlerInfo.bitsPerComponent());
+ swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kInvertedCMYK_Color,
+ swizzlerInfo.alpha(),
+ swizzlerInfo.bitsPerComponent());
break;
default:
break;
@@ -563,17 +662,28 @@ void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options&
fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, nullptr, dstInfo, swizzlerOptions,
nullptr, preSwizzled));
SkASSERT(fSwizzler);
- fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
- fSrcRow = fStorage.get();
+}
+
+bool SkJpegCodec::initializeColorXform(const SkImageInfo& dstInfo, bool needsColorXform) {
+ if (needsColorXform) {
+ fColorXform = SkColorSpaceXform::New(sk_ref_sp(this->getInfo().colorSpace()),
+ sk_ref_sp(dstInfo.colorSpace()));
+ if (!fColorXform && kRGBA_F16_SkColorType == dstInfo.colorType()) {
+ return false;
+ }
+ }
+
+ return true;
}
SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) {
if (!createIfNecessary || fSwizzler) {
- SkASSERT(!fSwizzler || (fSrcRow && fStorage.get() == fSrcRow));
+ SkASSERT(!fSwizzler || (fSwizzleSrcRow && fStorage.get() == fSwizzleSrcRow));
return fSwizzler;
}
this->initializeSwizzler(this->dstInfo(), this->options());
+ this->allocateStorage(this->dstInfo());
return fSwizzler;
}
@@ -586,11 +696,15 @@ SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
}
// Check if we can decode to the requested destination and set the output color space
- if (!this->setOutputColorSpace(dstInfo)) {
+ bool needsColorXform = needs_color_xform(dstInfo, this->getInfo());
+ if (!this->setOutputColorSpace(dstInfo, needsColorXform)) {
return kInvalidConversion;
}
- // Now, given valid output dimensions, we can start the decompress
+ if (!this->initializeColorXform(dstInfo, needsColorXform)) {
+ return fDecoderMgr->returnFailure("initializeColorXform", kInvalidParameters);
+ }
+
if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
SkCodecPrintf("start decompress failed\n");
return kInvalidInput;
@@ -651,62 +765,37 @@ SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
}
#endif
+ this->allocateStorage(dstInfo);
+
return kSuccess;
}
int SkJpegCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
- // Set the jump location for libjpeg errors
- if (setjmp(fDecoderMgr->getJmpBuf())) {
- return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
- }
- // Read rows one at a time
- JSAMPLE* dstRow;
- size_t srcRowBytes = get_row_bytes(fDecoderMgr->dinfo());
- if (fSwizzler) {
- // write data to storage row, then sample using swizzler
- dstRow = fSrcRow;
- } else {
- // write data directly to dst
- SkASSERT(count == 1 || dstRowBytes >= srcRowBytes);
- dstRow = (JSAMPLE*) dst;
+ int rows = this->readRows(this->dstInfo(), dst, dstRowBytes, count);
+ if (rows < count) {
+ // This allows us to skip calling jpeg_finish_decompress().
+ fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height();
}
- for (int y = 0; y < count; y++) {
- // Read row of the image
- uint32_t rowsDecoded = jpeg_read_scanlines(fDecoderMgr->dinfo(), &dstRow, 1);
- sk_msan_mark_initialized(dstRow, dstRow + srcRowBytes, "skbug.com/4550");
- if (rowsDecoded != 1) {
- fDecoderMgr->dinfo()->output_scanline = this->dstInfo().height();
- return y;
- }
-
- if (fSwizzler) {
- // use swizzler to sample row
- fSwizzler->swizzle(dst, dstRow);
- dst = SkTAddOffset<JSAMPLE>(dst, dstRowBytes);
- } else {
- dstRow = SkTAddOffset<JSAMPLE>(dstRow, dstRowBytes);
- }
- }
- return count;
+ return rows;
}
bool SkJpegCodec::onSkipScanlines(int count) {
// Set the jump location for libjpeg errors
if (setjmp(fDecoderMgr->getJmpBuf())) {
- return fDecoderMgr->returnFalse("setjmp");
+ return fDecoderMgr->returnFalse("onSkipScanlines");
}
#ifdef TURBO_HAS_SKIP
return (uint32_t) count == jpeg_skip_scanlines(fDecoderMgr->dinfo(), count);
#else
- if (!fSrcRow) {
+ if (!fSwizzleSrcRow) {
fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
- fSrcRow = fStorage.get();
+ fSwizzleSrcRow = fStorage.get();
}
for (int y = 0; y < count; y++) {
- if (1 != jpeg_read_scanlines(fDecoderMgr->dinfo(), &fSrcRow, 1)) {
+ if (1 != jpeg_read_scanlines(fDecoderMgr->dinfo(), &fSwizzleSrcRow, 1)) {
return false;
}
}
diff --git a/src/codec/SkJpegCodec.h b/src/codec/SkJpegCodec.h
index 7aa275ce4e..7eb5100a8f 100644
--- a/src/codec/SkJpegCodec.h
+++ b/src/codec/SkJpegCodec.h
@@ -10,6 +10,7 @@
#include "SkCodec.h"
#include "SkColorSpace.h"
+#include "SkColorSpaceXform.h"
#include "SkImageInfo.h"
#include "SkSwizzler.h"
#include "SkStream.h"
@@ -99,34 +100,46 @@ private:
/*
* Checks if the conversion between the input image and the requested output
- * image has been implemented
- * Sets the output color space
+ * image has been implemented.
+ *
+ * Sets the output color space.
*/
- bool setOutputColorSpace(const SkImageInfo& dst);
+ bool setOutputColorSpace(const SkImageInfo& dst, bool needsColorXform);
- // scanline decoding
void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options);
+ bool initializeColorXform(const SkImageInfo& dstInfo, bool needsColorXform);
+ void allocateStorage(const SkImageInfo& dstInfo);
+ int readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count);
+
+ /*
+ * Scanline decoding.
+ */
SkSampler* getSampler(bool createIfNecessary) override;
Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options,
SkPMColor ctable[], int* ctableCount) override;
int onGetScanlines(void* dst, int count, size_t rowBytes) override;
bool onSkipScanlines(int count) override;
- SkAutoTDelete<JpegDecoderMgr> fDecoderMgr;
+ SkAutoTDelete<JpegDecoderMgr> fDecoderMgr;
+
// We will save the state of the decompress struct after reading the header.
// This allows us to safely call onGetScaledDimensions() at any time.
- const int fReadyState;
+ const int fReadyState;
+
+
+ SkAutoTMalloc<uint8_t> fStorage;
+ uint8_t* fSwizzleSrcRow;
+ uint32_t* fColorXformSrcRow;
- // scanline decoding
- SkAutoTMalloc<uint8_t> fStorage; // Only used if sampling is needed
- uint8_t* fSrcRow; // Only used if sampling is needed
// libjpeg-turbo provides some subsetting. In the case that libjpeg-turbo
// cannot take the exact the subset that we need, we will use the swizzler
// to further subset the output from libjpeg-turbo.
- SkIRect fSwizzlerSubset;
- SkAutoTDelete<SkSwizzler> fSwizzler;
+ SkIRect fSwizzlerSubset;
+
+ SkAutoTDelete<SkSwizzler> fSwizzler;
+ std::unique_ptr<SkColorSpaceXform> fColorXform;
- sk_sp<SkData> fICCData;
+ sk_sp<SkData> fICCData;
typedef SkCodec INHERITED;
};
diff --git a/src/core/SkColorSpaceXform.cpp b/src/core/SkColorSpaceXform.cpp
index 924f24f6fc..4fbfa6cd9e 100644
--- a/src/core/SkColorSpaceXform.cpp
+++ b/src/core/SkColorSpaceXform.cpp
@@ -629,7 +629,7 @@ SkColorSpaceXform_Base<Dst>::SkColorSpaceXform_Base(const sk_sp<SkColorSpace>& s
template <>
void SkColorSpaceXform_Base<SkColorSpace::kSRGB_GammaNamed>
-::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const
+::applyToRGBA(RGBA32* dst, const RGBA32* src, int len) const
{
if (fColorLUT) {
handle_color_lut(dst, src, len, fColorLUT.get());
@@ -641,7 +641,7 @@ void SkColorSpaceXform_Base<SkColorSpace::kSRGB_GammaNamed>
template <>
void SkColorSpaceXform_Base<SkColorSpace::k2Dot2Curve_GammaNamed>
-::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const
+::applyToRGBA(RGBA32* dst, const RGBA32* src, int len) const
{
if (fColorLUT) {
handle_color_lut(dst, src, len, fColorLUT.get());
@@ -653,7 +653,7 @@ void SkColorSpaceXform_Base<SkColorSpace::k2Dot2Curve_GammaNamed>
template <>
void SkColorSpaceXform_Base<SkColorSpace::kNonStandard_GammaNamed>
-::applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const
+::applyToRGBA(RGBA32* dst, const RGBA32* src, int len) const
{
if (fColorLUT) {
handle_color_lut(dst, src, len, fColorLUT.get());
@@ -663,6 +663,43 @@ void SkColorSpaceXform_Base<SkColorSpace::kNonStandard_GammaNamed>
SkOpts::color_xform_RGB1_to_table(dst, src, len, fSrcGammaTables, fSrcToDst, fDstGammaTables);
}
+template <>
+void SkColorSpaceXform_Base<SkColorSpace::kSRGB_GammaNamed>
+::applyToBGRA(BGRA32* dst, const RGBA32* src, int len) const
+{
+ if (fColorLUT) {
+ handle_color_lut(dst, src, len, fColorLUT.get());
+ src = dst;
+ }
+
+ SkOpts::color_xform_RGB1_to_srgb_swaprb(dst, src, len, fSrcGammaTables, fSrcToDst);
+}
+
+template <>
+void SkColorSpaceXform_Base<SkColorSpace::k2Dot2Curve_GammaNamed>
+::applyToBGRA(BGRA32* dst, const RGBA32* src, int len) const
+{
+ if (fColorLUT) {
+ handle_color_lut(dst, src, len, fColorLUT.get());
+ src = dst;
+ }
+
+ SkOpts::color_xform_RGB1_to_2dot2_swaprb(dst, src, len, fSrcGammaTables, fSrcToDst);
+}
+
+template <>
+void SkColorSpaceXform_Base<SkColorSpace::kNonStandard_GammaNamed>
+::applyToBGRA(BGRA32* dst, const RGBA32* src, int len) const
+{
+ if (fColorLUT) {
+ handle_color_lut(dst, src, len, fColorLUT.get());
+ src = dst;
+ }
+
+ SkOpts::color_xform_RGB1_to_table_swaprb(dst, src, len, fSrcGammaTables, fSrcToDst,
+ fDstGammaTables);
+}
+
template <SkColorSpace::GammaNamed T>
void SkColorSpaceXform_Base<T>
::applyToF16(RGBAF16* dst, const RGBA32* src, int len) const
diff --git a/src/core/SkColorSpaceXform.h b/src/core/SkColorSpaceXform.h
index 0a5b35c489..2696b8582a 100644
--- a/src/core/SkColorSpaceXform.h
+++ b/src/core/SkColorSpaceXform.h
@@ -15,6 +15,7 @@ class SkColorSpaceXform : SkNoncopyable {
public:
typedef uint32_t RGBA32;
+ typedef uint32_t BGRA32;
typedef uint64_t RGBAF16;
/**
@@ -32,7 +33,8 @@ public:
* The src is stored as RGBA (8888) and is treated as opaque.
* TODO (msarett): Support non-opaque srcs.
*/
- virtual void applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const = 0;
+ virtual void applyToRGBA(RGBA32* dst, const RGBA32* src, int len) const = 0;
+ virtual void applyToBGRA(BGRA32* dst, const RGBA32* src, int len) const = 0;
virtual void applyToF16(RGBAF16* dst, const RGBA32* src, int len) const = 0;
virtual ~SkColorSpaceXform() {}
@@ -42,7 +44,8 @@ template <SkColorSpace::GammaNamed Dst>
class SkColorSpaceXform_Base : public SkColorSpaceXform {
public:
- void applyTo8888(SkPMColor* dst, const RGBA32* src, int len) const override;
+ void applyToRGBA(RGBA32* dst, const RGBA32* src, int len) const override;
+ void applyToBGRA(BGRA32* dst, const RGBA32* src, int len) const override;
void applyToF16(RGBAF16* dst, const RGBA32* src, int len) const override;
static constexpr int kDstGammaTableSize = 1024;
diff --git a/src/core/SkOpts.cpp b/src/core/SkOpts.cpp
index c577bf9603..9ba7bc7178 100644
--- a/src/core/SkOpts.cpp
+++ b/src/core/SkOpts.cpp
@@ -76,6 +76,9 @@ namespace SkOpts {
DEFINE_DEFAULT(color_xform_RGB1_to_srgb);
DEFINE_DEFAULT(color_xform_RGB1_to_table);
DEFINE_DEFAULT(color_xform_RGB1_to_linear);
+ DEFINE_DEFAULT(color_xform_RGB1_to_2dot2_swaprb);
+ DEFINE_DEFAULT(color_xform_RGB1_to_srgb_swaprb);
+ DEFINE_DEFAULT(color_xform_RGB1_to_table_swaprb);
#undef DEFINE_DEFAULT
// Each Init_foo() is defined in src/opts/SkOpts_foo.cpp.
diff --git a/src/core/SkOpts.h b/src/core/SkOpts.h
index fc424e1473..87489ee94e 100644
--- a/src/core/SkOpts.h
+++ b/src/core/SkOpts.h
@@ -80,7 +80,16 @@ namespace SkOpts {
extern void (*color_xform_RGB1_to_linear)(uint64_t* dst, const uint32_t* src, int len,
const float* const srcTables[3],
const float srcToDstMatrix[16]);
-
+ extern void (*color_xform_RGB1_to_2dot2_swaprb) (uint32_t* dst, const uint32_t* src, int len,
+ const float* const srcTables[3],
+ const float srcToDstMatrix[16]);
+ extern void (*color_xform_RGB1_to_srgb_swaprb)(uint32_t* dst, const uint32_t* src, int len,
+ const float* const srcTables[3],
+ const float srcToDstMatrix[16]);
+ extern void (*color_xform_RGB1_to_table_swaprb)(uint32_t* dst, const uint32_t* src, int len,
+ const float* const srcTables[3],
+ const float srcToDstMatrix[16],
+ const uint8_t* const dstTables[3]);
}
#endif//SkOpts_DEFINED
diff --git a/src/opts/SkColorXform_opts.h b/src/opts/SkColorXform_opts.h
index b5b7f81bbf..b3da55c1fd 100644
--- a/src/opts/SkColorXform_opts.h
+++ b/src/opts/SkColorXform_opts.h
@@ -41,10 +41,19 @@ enum DstGamma {
kLinear_DstGamma,
};
-template <DstGamma kDstGamma>
+template <DstGamma kDstGamma, bool kSwapRB>
static void color_xform_RGB1(void* dst, const uint32_t* src, int len,
const float* const srcTables[3], const float matrix[16],
const uint8_t* const dstTables[3]) {
+ int kRShift = 0;
+ int kGShift = 8;
+ int kBShift = 16;
+ int kAShift = 24;
+ if (kSwapRB) {
+ kBShift = 0;
+ kRShift = 16;
+ }
+
Sk4f rXgXbX = Sk4f::Load(matrix + 0),
rYgYbY = Sk4f::Load(matrix + 4),
rZgZbZ = Sk4f::Load(matrix + 8),
@@ -77,7 +86,8 @@ static void color_xform_RGB1(void* dst, const uint32_t* src, int len,
dstBlues = rXgXbX[2]*reds + rYgYbY[2]*greens + rZgZbZ[2]*blues + rTgTbT[2];
};
- auto store_4 = [&dstReds, &dstGreens, &dstBlues, &dst, &dstTables] {
+ auto store_4 = [&dstReds, &dstGreens, &dstBlues, &dst, &dstTables, kRShift, kGShift,
+ kBShift, kAShift] {
if (kSRGB_DstGamma == kDstGamma || k2Dot2_DstGamma == kDstGamma) {
Sk4f (*linear_to_curve)(const Sk4f&) = (kSRGB_DstGamma == kDstGamma) ?
sk_linear_to_srgb_needs_trunc : linear_to_2dot2;
@@ -92,10 +102,10 @@ static void color_xform_RGB1(void* dst, const uint32_t* src, int len,
dstGreens = sk_clamp_0_255(dstGreens);
dstBlues = sk_clamp_0_255(dstBlues);
- auto rgba = (float_to_int(dstReds) << SK_R32_SHIFT)
- | (float_to_int(dstGreens) << SK_G32_SHIFT)
- | (float_to_int(dstBlues) << SK_B32_SHIFT)
- | (Sk4i{0xFF} << SK_A32_SHIFT);
+ auto rgba = (float_to_int(dstReds) << kRShift)
+ | (float_to_int(dstGreens) << kGShift)
+ | (float_to_int(dstBlues) << kBShift)
+ | (Sk4i{0xFF} << kAShift);
rgba.store((uint32_t*) dst);
dst = SkTAddOffset<void>(dst, 4 * sizeof(uint32_t));
@@ -109,22 +119,22 @@ static void color_xform_RGB1(void* dst, const uint32_t* src, int len,
Sk4i indicesBlues = Sk4f_round(scaledBlues);
uint32_t* dst32 = (uint32_t*) dst;
- dst32[0] = dstTables[0][indicesReds [0]] << SK_R32_SHIFT
- | dstTables[1][indicesGreens[0]] << SK_G32_SHIFT
- | dstTables[2][indicesBlues [0]] << SK_B32_SHIFT
- | 0xFF << SK_A32_SHIFT;
- dst32[1] = dstTables[0][indicesReds [1]] << SK_R32_SHIFT
- | dstTables[1][indicesGreens[1]] << SK_G32_SHIFT
- | dstTables[2][indicesBlues [1]] << SK_B32_SHIFT
- | 0xFF << SK_A32_SHIFT;
- dst32[2] = dstTables[0][indicesReds [2]] << SK_R32_SHIFT
- | dstTables[1][indicesGreens[2]] << SK_G32_SHIFT
- | dstTables[2][indicesBlues [2]] << SK_B32_SHIFT
- | 0xFF << SK_A32_SHIFT;
- dst32[3] = dstTables[0][indicesReds [3]] << SK_R32_SHIFT
- | dstTables[1][indicesGreens[3]] << SK_G32_SHIFT
- | dstTables[2][indicesBlues [3]] << SK_B32_SHIFT
- | 0xFF << SK_A32_SHIFT;
+ dst32[0] = dstTables[0][indicesReds [0]] << kRShift
+ | dstTables[1][indicesGreens[0]] << kGShift
+ | dstTables[2][indicesBlues [0]] << kBShift
+ | 0xFF << kAShift;
+ dst32[1] = dstTables[0][indicesReds [1]] << kRShift
+ | dstTables[1][indicesGreens[1]] << kGShift
+ | dstTables[2][indicesBlues [1]] << kBShift
+ | 0xFF << kAShift;
+ dst32[2] = dstTables[0][indicesReds [2]] << kRShift
+ | dstTables[1][indicesGreens[2]] << kGShift
+ | dstTables[2][indicesBlues [2]] << kBShift
+ | 0xFF << kAShift;
+ dst32[3] = dstTables[0][indicesReds [3]] << kRShift
+ | dstTables[1][indicesGreens[3]] << kGShift
+ | dstTables[2][indicesBlues [3]] << kBShift
+ | 0xFF << kAShift;
dst = SkTAddOffset<void>(dst, 4 * sizeof(uint32_t));
} else {
@@ -167,17 +177,21 @@ static void color_xform_RGB1(void* dst, const uint32_t* src, int len,
uint32_t rgba;
SkNx_cast<uint8_t>(float_to_int(dstPixel)).store(&rgba);
rgba |= 0xFF000000;
- *((uint32_t*) dst) = SkSwizzle_RGBA_to_PMColor(rgba);
+ if (kSwapRB) {
+ *((uint32_t*) dst) = SkSwizzle_RB(rgba);
+ } else {
+ *((uint32_t*) dst) = rgba;
+ }
dst = SkTAddOffset<void>(dst, sizeof(uint32_t));
} else if (kTable_DstGamma == kDstGamma) {
Sk4f scaledPixel = Sk4f::Min(Sk4f::Max(1023.0f * dstPixel, 0.0f), 1023.0f);
Sk4i indices = Sk4f_round(scaledPixel);
- *((uint32_t*) dst) = dstTables[0][indices[0]] << SK_R32_SHIFT
- | dstTables[1][indices[1]] << SK_G32_SHIFT
- | dstTables[2][indices[2]] << SK_B32_SHIFT
- | 0xFF << SK_A32_SHIFT;
+ *((uint32_t*) dst) = dstTables[0][indices[0]] << kRShift
+ | dstTables[1][indices[1]] << kGShift
+ | dstTables[2][indices[2]] << kBShift
+ | 0xFF << kAShift;
dst = SkTAddOffset<void>(dst, sizeof(uint32_t));
} else {
@@ -195,23 +209,42 @@ static void color_xform_RGB1(void* dst, const uint32_t* src, int len,
static void color_xform_RGB1_to_2dot2(uint32_t* dst, const uint32_t* src, int len,
const float* const srcTables[3], const float matrix[16]) {
- color_xform_RGB1<k2Dot2_DstGamma>(dst, src, len, srcTables, matrix, nullptr);
+ color_xform_RGB1<k2Dot2_DstGamma, false>(dst, src, len, srcTables, matrix, nullptr);
}
static void color_xform_RGB1_to_srgb(uint32_t* dst, const uint32_t* src, int len,
const float* const srcTables[3], const float matrix[16]) {
- color_xform_RGB1<kSRGB_DstGamma>(dst, src, len, srcTables, matrix, nullptr);
+ color_xform_RGB1<kSRGB_DstGamma, false>(dst, src, len, srcTables, matrix, nullptr);
}
static void color_xform_RGB1_to_table(uint32_t* dst, const uint32_t* src, int len,
const float* const srcTables[3], const float matrix[16],
const uint8_t* const dstTables[3]) {
- color_xform_RGB1<kTable_DstGamma>(dst, src, len, srcTables, matrix, dstTables);
+ color_xform_RGB1<kTable_DstGamma, false>(dst, src, len, srcTables, matrix, dstTables);
}
static void color_xform_RGB1_to_linear(uint64_t* dst, const uint32_t* src, int len,
const float* const srcTables[3], const float matrix[16]) {
- color_xform_RGB1<kLinear_DstGamma>(dst, src, len, srcTables, matrix, nullptr);
+ color_xform_RGB1<kLinear_DstGamma, false>(dst, src, len, srcTables, matrix, nullptr);
+}
+
+static void color_xform_RGB1_to_2dot2_swaprb(uint32_t* dst, const uint32_t* src, int len,
+ const float* const srcTables[3],
+ const float matrix[16]) {
+ color_xform_RGB1<k2Dot2_DstGamma, true>(dst, src, len, srcTables, matrix, nullptr);
+}
+
+static void color_xform_RGB1_to_srgb_swaprb(uint32_t* dst, const uint32_t* src, int len,
+ const float* const srcTables[3],
+ const float matrix[16]) {
+ color_xform_RGB1<kSRGB_DstGamma, true>(dst, src, len, srcTables, matrix, nullptr);
+}
+
+static void color_xform_RGB1_to_table_swaprb(uint32_t* dst, const uint32_t* src, int len,
+ const float* const srcTables[3],
+ const float matrix[16],
+ const uint8_t* const dstTables[3]) {
+ color_xform_RGB1<kTable_DstGamma, true>(dst, src, len, srcTables, matrix, dstTables);
}
} // namespace SK_OPTS_NS
diff --git a/src/opts/SkOpts_sse41.cpp b/src/opts/SkOpts_sse41.cpp
index e1e024d948..e70cedeb31 100644
--- a/src/opts/SkOpts_sse41.cpp
+++ b/src/opts/SkOpts_sse41.cpp
@@ -21,9 +21,12 @@ namespace SkOpts {
srcover_srgb_srgb = sse41::srcover_srgb_srgb;
blit_row_s32a_opaque = sse41::blit_row_s32a_opaque;
- color_xform_RGB1_to_2dot2 = sse41::color_xform_RGB1_to_2dot2;
- color_xform_RGB1_to_srgb = sse41::color_xform_RGB1_to_srgb;
- color_xform_RGB1_to_table = sse41::color_xform_RGB1_to_table;
- color_xform_RGB1_to_linear = sse41::color_xform_RGB1_to_linear;
+ color_xform_RGB1_to_2dot2 = sse41::color_xform_RGB1_to_2dot2;
+ color_xform_RGB1_to_srgb = sse41::color_xform_RGB1_to_srgb;
+ color_xform_RGB1_to_table = sse41::color_xform_RGB1_to_table;
+ color_xform_RGB1_to_linear = sse41::color_xform_RGB1_to_linear;
+ color_xform_RGB1_to_2dot2_swaprb = sse41::color_xform_RGB1_to_2dot2_swaprb;
+ color_xform_RGB1_to_srgb_swaprb = sse41::color_xform_RGB1_to_srgb_swaprb;
+ color_xform_RGB1_to_table_swaprb = sse41::color_xform_RGB1_to_table_swaprb;
}
}
diff --git a/tests/ColorSpaceXformTest.cpp b/tests/ColorSpaceXformTest.cpp
index 23b08ce8ae..1e75ee6853 100644
--- a/tests/ColorSpaceXformTest.cpp
+++ b/tests/ColorSpaceXformTest.cpp
@@ -37,19 +37,19 @@ static void test_identity_xform(skiatest::Reporter* r, const sk_sp<SkGammas>& ga
// Create and perform an identity xform.
std::unique_ptr<SkColorSpaceXform> xform = ColorSpaceXformTest::CreateIdentityXform(gammas);
- xform->applyTo8888(dstPixels, srcPixels, width);
+ xform->applyToRGBA(dstPixels, srcPixels, width);
// Since the src->dst matrix is the identity, and the gamma curves match,
// the pixels should be unchanged.
for (int i = 0; i < width; i++) {
REPORTER_ASSERT(r, almost_equal(((srcPixels[i] >> 0) & 0xFF),
- SkGetPackedR32(dstPixels[i])));
+ ((dstPixels[i] >> 0) & 0xFF)));
REPORTER_ASSERT(r, almost_equal(((srcPixels[i] >> 8) & 0xFF),
- SkGetPackedG32(dstPixels[i])));
+ ((dstPixels[i] >> 8) & 0xFF)));
REPORTER_ASSERT(r, almost_equal(((srcPixels[i] >> 16) & 0xFF),
- SkGetPackedB32(dstPixels[i])));
+ ((dstPixels[i] >> 16) & 0xFF)));
REPORTER_ASSERT(r, almost_equal(((srcPixels[i] >> 24) & 0xFF),
- SkGetPackedA32(dstPixels[i])));
+ ((dstPixels[i] >> 24) & 0xFF)));
}
}
diff --git a/tools/viewer/ImageSlide.cpp b/tools/viewer/ImageSlide.cpp
index b0471547bc..7dcee5d5ac 100644
--- a/tools/viewer/ImageSlide.cpp
+++ b/tools/viewer/ImageSlide.cpp
@@ -37,20 +37,18 @@ void ImageSlide::draw(SkCanvas* canvas) {
void ImageSlide::load(SkScalar, SkScalar) {
sk_sp<SkData> encoded = SkData::MakeFromFileName(fPath.c_str());
- fImage = SkImage::MakeFromEncoded(encoded);
- fImage->asLegacyBitmap(&fOriginalBitmap, SkImage::kRO_LegacyBitmapMode);
-
SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded.get()));
- sk_sp<SkColorSpace> srcSpace = sk_ref_sp(codec->getInfo().colorSpace());
- sk_sp<SkColorSpace> dstSpace = SkColorSpace::NewNamed(SkColorSpace::kAdobeRGB_Named);
- std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(srcSpace, dstSpace);
- fOriginalBitmap.deepCopyTo(&fXformedBitmap);
- uint32_t* row = (uint32_t*) fXformedBitmap.getPixels();
- for (int y = 0; y < fXformedBitmap.height(); y++) {
- xform->applyTo8888(row, row, fXformedBitmap.width());
- row = SkTAddOffset<uint32_t>(row, fXformedBitmap.rowBytes());
+ if (!codec) {
+ return;
}
- fXformedBitmap.notifyPixelsChanged(); // This is needed for the deepCopy
+
+ fOriginalBitmap.allocPixels(codec->getInfo());
+ codec->getPixels(codec->getInfo(), fOriginalBitmap.getPixels(), fOriginalBitmap.rowBytes());
+
+ SkImageInfo xformedInfo = codec->getInfo().makeColorSpace(
+ SkColorSpace::NewNamed(SkColorSpace::kAdobeRGB_Named));
+ fXformedBitmap.allocPixels(xformedInfo);
+ codec->getPixels(xformedInfo, fXformedBitmap.getPixels(), fXformedBitmap.rowBytes());
}
void ImageSlide::unload() {