aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Matt Sarett <msarett@google.com>2017-03-27 15:07:35 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-03-28 16:07:04 +0000
commitd2adc66efec8a172b71bf5572fbedde064025825 (patch)
tree12a61a477bfc82b769912951e920eb787a42eb60
parent20ece3a966708bf2886034cda15aea7f4946f4b1 (diff)
Use SkTransferFunctionBehavior for raster pixel conversions
Fixes some gbr-8888 behaviors. BUG=skia: Change-Id: I1351b043129f7ed0e125bfdb626a0ecaf64c15cc Reviewed-on: https://skia-review.googlesource.com/10169 Reviewed-by: Mike Klein <mtklein@chromium.org> Commit-Queue: Matt Sarett <msarett@google.com>
-rw-r--r--include/core/SkBitmap.h7
-rw-r--r--src/core/SkBitmap.cpp8
-rw-r--r--src/core/SkConvertPixels.cpp79
-rw-r--r--src/core/SkConvertPixels.h2
-rw-r--r--src/core/SkPixmap.cpp2
-rw-r--r--src/image/SkImage_Raster.cpp4
6 files changed, 70 insertions, 32 deletions
diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h
index 700dbc2cb4..fd25a23cdd 100644
--- a/include/core/SkBitmap.h
+++ b/include/core/SkBitmap.h
@@ -657,7 +657,9 @@ public:
* This is logically the same as creating a bitmap around src, and calling readPixels on it
* with this bitmap as the dst.
*/
- bool writePixels(const SkPixmap& src, int dstX, int dstY);
+ bool writePixels(const SkPixmap& src, int dstX, int dstY) {
+ return this->writePixels(src, dstX, dstY, SkTransferFunctionBehavior::kRespect);
+ }
bool writePixels(const SkPixmap& src) {
return this->writePixels(src, 0, 0);
}
@@ -777,6 +779,8 @@ private:
uint32_t fRowBytes;
uint8_t fFlags;
+ bool writePixels(const SkPixmap& src, int x, int y, SkTransferFunctionBehavior behavior);
+
/* Unreference any pixelrefs or colortables
*/
void freePixels();
@@ -785,6 +789,7 @@ private:
static void WriteRawPixels(SkWriteBuffer*, const SkBitmap&);
static bool ReadRawPixels(SkReadBuffer*, SkBitmap*);
+ friend class SkImage_Raster;
friend class SkReadBuffer; // unflatten, rawpixels
friend class SkBinaryWriteBuffer; // rawpixels
friend struct SkBitmapProcState;
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp
index 4a55e1a7f3..0a999cee42 100644
--- a/src/core/SkBitmap.cpp
+++ b/src/core/SkBitmap.cpp
@@ -709,7 +709,8 @@ bool SkBitmap::readPixels(const SkPixmap& dst, int srcX, int srcY) const {
return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
}
-bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY) {
+bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY,
+ SkTransferFunctionBehavior behavior) {
SkAutoPixmapUnlock dst;
if (!this->requestLock(&dst)) {
return false;
@@ -727,7 +728,7 @@ bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY) {
void* dstPixels = this->getAddr(rec.fX, rec.fY);
const SkImageInfo dstInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels, rec.fRowBytes,
- src.ctable());
+ src.ctable(), behavior);
return true;
}
@@ -848,7 +849,8 @@ static bool GetBitmapAlpha(const SkBitmap& src, uint8_t* SK_RESTRICT alpha, int
}
const SkPixmap& pmap = apl.pixmap();
SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes,
- pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable());
+ pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable(),
+ SkTransferFunctionBehavior::kRespect);
return true;
}
diff --git a/src/core/SkConvertPixels.cpp b/src/core/SkConvertPixels.cpp
index 787acb97f2..b919f5dbe8 100644
--- a/src/core/SkConvertPixels.cpp
+++ b/src/core/SkConvertPixels.cpp
@@ -5,7 +5,7 @@
* found in the LICENSE file.
*/
-#include "SkColorSpaceXform.h"
+#include "SkColorSpaceXform_Base.h"
#include "SkColorSpaceXformPriv.h"
#include "SkColorTable.h"
#include "SkConvertPixels.h"
@@ -87,9 +87,13 @@ void swizzle_and_multiply(const SkImageInfo& dstInfo, void* dstPixels, size_t ds
}
// Fast Path 3: Color space xform.
-static inline bool optimized_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
- if (kUnpremul_SkAlphaType == dstInfo.alphaType() && kPremul_SkAlphaType == srcInfo.alphaType())
- {
+static inline bool optimized_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo,
+ SkTransferFunctionBehavior behavior) {
+ // Unpremultiplication is unsupported by SkColorSpaceXform. Note that if |src| is non-linearly
+ // premultiplied, we're always going to have to unpremultiply before doing anything.
+ if (kPremul_SkAlphaType == srcInfo.alphaType() &&
+ (kUnpremul_SkAlphaType == dstInfo.alphaType() ||
+ SkTransferFunctionBehavior::kIgnore == behavior)) {
return false;
}
@@ -115,7 +119,7 @@ static inline bool optimized_color_xform(const SkImageInfo& dstInfo, const SkIma
static inline void apply_color_xform(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
const SkImageInfo& srcInfo, const void* srcPixels,
- size_t srcRB) {
+ size_t srcRB, SkTransferFunctionBehavior behavior) {
SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType());
SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(srcInfo.colorType());
SkAlphaType xformAlpha;
@@ -142,8 +146,8 @@ static inline void apply_color_xform(const SkImageInfo& dstInfo, void* dstPixels
break;
}
- std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(srcInfo.colorSpace(),
- dstInfo.colorSpace());
+ std::unique_ptr<SkColorSpaceXform> xform =
+ SkColorSpaceXform_Base::New(srcInfo.colorSpace(), dstInfo.colorSpace(), behavior);
SkASSERT(xform);
for (int y = 0; y < dstInfo.height(); y++) {
@@ -158,14 +162,14 @@ static inline void apply_color_xform(const SkImageInfo& dstInfo, void* dstPixels
template <typename T>
void do_index8(const SkImageInfo& dstInfo, T* dstPixels, size_t dstRB,
const SkImageInfo& srcInfo, const uint8_t* srcPixels, size_t srcRB,
- SkColorTable* ctable) {
+ SkColorTable* ctable, SkTransferFunctionBehavior behavior) {
T dstCTable[256];
int count = ctable->count();
SkImageInfo srcInfo8888 = srcInfo.makeColorType(kN32_SkColorType).makeWH(count, 1);
SkImageInfo dstInfoCT = dstInfo.makeWH(count, 1);
size_t rowBytes = count * sizeof(T);
SkConvertPixels(dstInfoCT, dstCTable, rowBytes, srcInfo8888, ctable->readColors(), rowBytes,
- nullptr);
+ nullptr, behavior);
for (int y = 0; y < dstInfo.height(); y++) {
for (int x = 0; x < dstInfo.width(); x++) {
@@ -178,21 +182,25 @@ void do_index8(const SkImageInfo& dstInfo, T* dstPixels, size_t dstRB,
void convert_from_index8(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
const SkImageInfo& srcInfo, const uint8_t* srcPixels, size_t srcRB,
- SkColorTable* ctable) {
+ SkColorTable* ctable, SkTransferFunctionBehavior behavior) {
switch (dstInfo.colorType()) {
case kAlpha_8_SkColorType:
- do_index8(dstInfo, (uint8_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable);
+ do_index8(dstInfo, (uint8_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable,
+ behavior);
break;
case kRGB_565_SkColorType:
case kARGB_4444_SkColorType:
- do_index8(dstInfo, (uint16_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable);
+ do_index8(dstInfo, (uint16_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable,
+ behavior);
break;
case kRGBA_8888_SkColorType:
case kBGRA_8888_SkColorType:
- do_index8(dstInfo, (uint32_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable);
+ do_index8(dstInfo, (uint32_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable,
+ behavior);
break;
case kRGBA_F16_SkColorType:
- do_index8(dstInfo, (uint64_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable);
+ do_index8(dstInfo, (uint64_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable,
+ behavior);
break;
default:
SkASSERT(false);
@@ -267,7 +275,7 @@ static void convert_to_alpha8(uint8_t* dst, size_t dstRB, const SkImageInfo& src
// Default: Use the pipeline.
static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB,
const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB,
- bool isColorAware) {
+ bool isColorAware, SkTransferFunctionBehavior behavior) {
SkRasterPipeline pipeline;
switch (srcInfo.colorType()) {
case kRGBA_8888_SkColorType:
@@ -294,6 +302,12 @@ static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size
break;
}
+ SkAlphaType premulState = srcInfo.alphaType();
+ if (kPremul_SkAlphaType == premulState && SkTransferFunctionBehavior::kIgnore == behavior) {
+ pipeline.append(SkRasterPipeline::unpremul);
+ premulState = kUnpremul_SkAlphaType;
+ }
+
if (isColorAware && srcInfo.gammaCloseToSRGB()) {
pipeline.append_from_srgb(srcInfo.alphaType());
}
@@ -304,18 +318,32 @@ static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size
dstInfo.colorSpace()));
}
- SkAlphaType sat = srcInfo.alphaType();
SkAlphaType dat = dstInfo.alphaType();
- if (sat == kPremul_SkAlphaType && dat == kUnpremul_SkAlphaType) {
- pipeline.append(SkRasterPipeline::unpremul);
- } else if (sat == kUnpremul_SkAlphaType && dat == kPremul_SkAlphaType) {
- pipeline.append(SkRasterPipeline::premul);
+ if (SkTransferFunctionBehavior::kRespect == behavior) {
+ if (kPremul_SkAlphaType == premulState && kUnpremul_SkAlphaType == dat) {
+ pipeline.append(SkRasterPipeline::unpremul);
+ premulState = kUnpremul_SkAlphaType;
+ } else if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat) {
+ pipeline.append(SkRasterPipeline::premul);
+ premulState = kPremul_SkAlphaType;
+ }
}
if (isColorAware && dstInfo.gammaCloseToSRGB()) {
pipeline.append(SkRasterPipeline::to_srgb);
}
+ if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat &&
+ SkTransferFunctionBehavior::kIgnore == behavior)
+ {
+ pipeline.append(SkRasterPipeline::premul);
+ premulState = kPremul_SkAlphaType;
+ }
+
+ // The final premul state must equal the dst alpha type. Note that if we are "converting"
+ // opaque to another alpha type, there's no need to worry about multiplication.
+ SkASSERT(premulState == dat || kOpaque_SkAlphaType == srcInfo.alphaType());
+
switch (dstInfo.colorType()) {
case kRGBA_8888_SkColorType:
pipeline.append(SkRasterPipeline::store_8888, &dstRow);
@@ -349,7 +377,7 @@ static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size
void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB,
- SkColorTable* ctable) {
+ SkColorTable* ctable, SkTransferFunctionBehavior behavior) {
SkASSERT(dstInfo.dimensions() == srcInfo.dimensions());
SkASSERT(SkImageInfoValidConversion(dstInfo, srcInfo));
@@ -369,8 +397,8 @@ void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
}
// Fast Path 3: Color space xform.
- if (isColorAware && optimized_color_xform(dstInfo, srcInfo)) {
- apply_color_xform(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB);
+ if (isColorAware && optimized_color_xform(dstInfo, srcInfo, behavior)) {
+ apply_color_xform(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, behavior);
return;
}
@@ -378,7 +406,7 @@ void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
if (kIndex_8_SkColorType == srcInfo.colorType()) {
SkASSERT(ctable);
convert_from_index8(dstInfo, dstPixels, dstRB, srcInfo, (const uint8_t*) srcPixels, srcRB,
- ctable);
+ ctable, behavior);
return;
}
@@ -389,5 +417,6 @@ void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
}
// Default: Use the pipeline.
- convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, isColorAware);
+ convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, isColorAware,
+ behavior);
}
diff --git a/src/core/SkConvertPixels.h b/src/core/SkConvertPixels.h
index aa641e552d..c825d84aa1 100644
--- a/src/core/SkConvertPixels.h
+++ b/src/core/SkConvertPixels.h
@@ -15,7 +15,7 @@ class SkColorTable;
void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRowBytes,
- SkColorTable* srcCTable = nullptr);
+ SkColorTable* srcCTable, SkTransferFunctionBehavior behavior);
static inline void SkRectMemcpy(void* dst, size_t dstRB, const void* src, size_t srcRB,
size_t bytesPerRow, int rowCount) {
diff --git a/src/core/SkPixmap.cpp b/src/core/SkPixmap.cpp
index 62dda1696c..7eac6c4ed5 100644
--- a/src/core/SkPixmap.cpp
+++ b/src/core/SkPixmap.cpp
@@ -98,7 +98,7 @@ const {
const void* srcPixels = this->addr(rec.fX, rec.fY);
const SkImageInfo srcInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
SkConvertPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, srcInfo, srcPixels, this->rowBytes(),
- this->ctable());
+ this->ctable(), SkTransferFunctionBehavior::kRespect);
return true;
}
diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp
index 30262ddbc3..547bdbf5ad 100644
--- a/src/image/SkImage_Raster.cpp
+++ b/src/image/SkImage_Raster.cpp
@@ -374,7 +374,9 @@ sk_sp<SkImage> SkImage_Raster::onMakeColorSpace(sk_sp<SkColorSpace> target) cons
src.setColorSpace(SkColorSpace::MakeSRGB());
}
- SkAssertResult(dst.writePixels(src));
+ // Use kIgnore for transfer function behavior. This is used by the SkColorSpaceXformCanvas,
+ // which wants to pre-xform the inputs but ignore the transfer function on blends.
+ SkAssertResult(dst.writePixels(src, 0, 0, SkTransferFunctionBehavior::kIgnore));
dst.setImmutable();
return SkImage::MakeFromBitmap(dst);
}