Reland "Add sRGB 8888 colortype"

This is a reland of 0f7c10ef56

Original change's description:
> Add sRGB 8888 colortype
>
> A color type that linearizes just after loading, and re-encodes to sRGB
> just before storing, mimicking the GPU formats that work the same way.
>
> Notes:
>   - No mipmap support
>   - No SkPngEncoder support (HashAndEncode's .pngs are ok, though?)
>   - Needs better testing
>
> This is a re-creation of reviews.skia.org/392990
>
> Change-Id: I4739c2280211e7176aae98ba0a8476a7fe5efa72
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/438219
> Commit-Queue: Brian Osman <brianosman@google.com>
> Reviewed-by: Brian Salomon <bsalomon@google.com>

Change-Id: I5b6bb28c4c1faa6c97fcad7552d12c331535714d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/441402
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2021-08-10 14:39:18 -04:00 committed by SkCQ
parent 3a15110898
commit 9f1e06aef9
32 changed files with 251 additions and 104 deletions

View File

@ -530,12 +530,13 @@ static skstd::optional<Config> create_config(const SkCommandLineConfig* config)
CPU_CONFIG("nonrendering", kNonRendering_Backend, kUnknown_SkColorType, kUnpremul_SkAlphaType)
CPU_CONFIG("a8", kRaster_Backend, kAlpha_8_SkColorType, kPremul_SkAlphaType)
CPU_CONFIG("565", kRaster_Backend, kRGB_565_SkColorType, kOpaque_SkAlphaType)
CPU_CONFIG("8888", kRaster_Backend, kN32_SkColorType, kPremul_SkAlphaType)
CPU_CONFIG("rgba", kRaster_Backend, kRGBA_8888_SkColorType, kPremul_SkAlphaType)
CPU_CONFIG("bgra", kRaster_Backend, kBGRA_8888_SkColorType, kPremul_SkAlphaType)
CPU_CONFIG("f16", kRaster_Backend, kRGBA_F16_SkColorType, kPremul_SkAlphaType)
CPU_CONFIG("a8", kRaster_Backend, kAlpha_8_SkColorType, kPremul_SkAlphaType)
CPU_CONFIG("565", kRaster_Backend, kRGB_565_SkColorType, kOpaque_SkAlphaType)
CPU_CONFIG("8888", kRaster_Backend, kN32_SkColorType, kPremul_SkAlphaType)
CPU_CONFIG("rgba", kRaster_Backend, kRGBA_8888_SkColorType, kPremul_SkAlphaType)
CPU_CONFIG("bgra", kRaster_Backend, kBGRA_8888_SkColorType, kPremul_SkAlphaType)
CPU_CONFIG("f16", kRaster_Backend, kRGBA_F16_SkColorType, kPremul_SkAlphaType)
CPU_CONFIG("srgba", kRaster_Backend, kSRGBA_8888_SkColorType, kPremul_SkAlphaType)
#undef CPU_CONFIG

View File

@ -982,6 +982,7 @@ static Sink* create_sink(const GrContextOptions& grCtxOptions, const SkCommandLi
SINK("f16", RasterSink, kRGBA_F16_SkColorType);
SINK("f16norm", RasterSink, kRGBA_F16Norm_SkColorType);
SINK("f32", RasterSink, kRGBA_F32_SkColorType);
SINK("srgba", RasterSink, kSRGBA_8888_SkColorType);
SINK("pdf", PDFSink, false, SK_ScalarDefaultRasterDPI);
SINK("skp", SKPSink);

View File

@ -21,6 +21,7 @@ static const char* colortype_name(SkColorType ct) {
case kRGB_565_SkColorType: return "RGB_565";
case kARGB_4444_SkColorType: return "ARGB_4444";
case kRGBA_8888_SkColorType: return "RGBA_8888";
case kSRGBA_8888_SkColorType: return "SRGBA_8888";
case kRGB_888x_SkColorType: return "RGB_888x";
case kBGRA_8888_SkColorType: return "BGRA_8888";
case kRGBA_1010102_SkColorType: return "RGBA_1010102";

View File

@ -48,6 +48,7 @@ static const char* color_type_name(SkColorType colorType) {
case kA16_float_SkColorType: return "A16_float";
case kR16G16_float_SkColorType: return "R16G16_float";
case kR16G16B16A16_unorm_SkColorType: return "R16G16B16A16_unorm";
case kSRGBA_8888_SkColorType: return "SRGBA_8888";
}
return "";
}

View File

@ -16,6 +16,9 @@
#include "include/private/SkTFitsIn.h"
#include "include/private/SkTo.h"
// Temporary guard for Chromium
#define SK_HAS_SRGBA_COLOR_TYPE
class SkReadBuffer;
class SkWriteBuffer;
@ -91,7 +94,9 @@ enum SkColorType : int {
kR16G16B16A16_unorm_SkColorType, //!< pixel with a little endian uint16_t for red, green, blue
// and alpha
kLastEnum_SkColorType = kR16G16B16A16_unorm_SkColorType, //!< last valid value
kSRGBA_8888_SkColorType,
kLastEnum_SkColorType = kSRGBA_8888_SkColorType, //!< last valid value
#if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
kN32_SkColorType = kBGRA_8888_SkColorType,//!< native 32-bit BGRA encoding

View File

@ -940,8 +940,7 @@ static constexpr SkColorType GrColorTypeToSkColorType(GrColorType ct) {
case GrColorType::kBGR_565: return kRGB_565_SkColorType;
case GrColorType::kABGR_4444: return kARGB_4444_SkColorType;
case GrColorType::kRGBA_8888: return kRGBA_8888_SkColorType;
// Once we add kRGBA_8888_SRGB_SkColorType we should return that here.
case GrColorType::kRGBA_8888_SRGB: return kRGBA_8888_SkColorType;
case GrColorType::kRGBA_8888_SRGB: return kSRGBA_8888_SkColorType;
case GrColorType::kRGB_888x: return kRGB_888x_SkColorType;
case GrColorType::kRG_88: return kR8G8_unorm_SkColorType;
case GrColorType::kBGRA_8888: return kBGRA_8888_SkColorType;
@ -978,6 +977,7 @@ static constexpr GrColorType SkColorTypeToGrColorType(SkColorType ct) {
case kRGB_565_SkColorType: return GrColorType::kBGR_565;
case kARGB_4444_SkColorType: return GrColorType::kABGR_4444;
case kRGBA_8888_SkColorType: return GrColorType::kRGBA_8888;
case kSRGBA_8888_SkColorType: return GrColorType::kRGBA_8888_SRGB;
case kRGB_888x_SkColorType: return GrColorType::kRGB_888x;
case kBGRA_8888_SkColorType: return GrColorType::kBGRA_8888;
case kGray_8_SkColorType: return GrColorType::kGray_8;
@ -998,12 +998,6 @@ static constexpr GrColorType SkColorTypeToGrColorType(SkColorType ct) {
SkUNREACHABLE;
}
// This is a temporary means of mapping an SkColorType and format to a
// GrColorType::kRGBA_8888_SRGB. Once we have an SRGB SkColorType this can go away.
GrColorType SkColorTypeAndFormatToGrColorType(const GrCaps* caps,
SkColorType skCT,
const GrBackendFormat& format);
static constexpr uint32_t GrColorTypeChannelFlags(GrColorType ct) {
switch (ct) {
case GrColorType::kUnknown: return 0;

View File

@ -34,6 +34,7 @@ static inline uint32_t SkColorTypeChannelFlags(SkColorType ct) {
case kA16_float_SkColorType: return kAlpha_SkColorChannelFlag;
case kR16G16_float_SkColorType: return kRG_SkColorChannelFlags;
case kR16G16B16A16_unorm_SkColorType: return kRGBA_SkColorChannelFlags;
case kSRGBA_8888_SkColorType: return kRGBA_SkColorChannelFlags;
}
SkUNREACHABLE;
}
@ -69,6 +70,7 @@ static int SkColorTypeShiftPerPixel(SkColorType ct) {
case kA16_float_SkColorType: return 1;
case kR16G16_float_SkColorType: return 2;
case kR16G16B16A16_unorm_SkColorType: return 3;
case kSRGBA_8888_SkColorType: return 2;
}
SkUNREACHABLE;
}
@ -107,7 +109,8 @@ static inline bool SkColorTypeIsNormalized(SkColorType ct) {
case kA16_unorm_SkColorType:
case kA16_float_SkColorType: /*subtle... alpha is always [0,1]*/
case kR16G16_unorm_SkColorType:
case kR16G16B16A16_unorm_SkColorType: return true;
case kR16G16B16A16_unorm_SkColorType:
case kSRGBA_8888_SkColorType: return true;
case kRGBA_F16_SkColorType:
case kRGBA_F32_SkColorType:
@ -133,6 +136,7 @@ static inline int SkColorTypeMaxBitsPerChannel(SkColorType ct) {
case kBGRA_8888_SkColorType:
case kGray_8_SkColorType:
case kR8G8_unorm_SkColorType:
case kSRGBA_8888_SkColorType:
return 8;
case kRGBA_1010102_SkColorType:

View File

@ -101,6 +101,10 @@ static inline bool is_almost_linear(const skcms_TransferFunction& coeffs) {
return linearExp || linearFn;
}
skvm::F32 sk_program_transfer_fn(
skvm::F32 v, TFKind,
skvm::F32 G, skvm::F32 A, skvm::F32 B, skvm::F32 C, skvm::F32 D, skvm::F32 E, skvm::F32 F);
skvm::Color sk_program_transfer_fn(skvm::Builder*, skvm::Uniforms*,
const skcms_TransferFunction&, skvm::Color);

View File

@ -137,6 +137,47 @@ void SkColorSpaceXformSteps::apply(SkRasterPipeline* p) const {
if (flags.premul) { p->append(SkRasterPipeline::premul); }
}
skvm::F32 sk_program_transfer_fn(
skvm::F32 v, TFKind tf_kind,
skvm::F32 G, skvm::F32 A, skvm::F32 B, skvm::F32 C, skvm::F32 D, skvm::F32 E, skvm::F32 F)
{
// Strip off the sign bit and save it for later.
skvm::I32 bits = pun_to_I32(v),
sign = bits & 0x80000000;
v = pun_to_F32(bits ^ sign);
switch (tf_kind) {
case Bad_TF: SkASSERT(false); break;
case sRGBish_TF: {
v = select(v <= D, C*v + F
, approx_powf(A*v + B, G) + E);
} break;
case PQish_TF: {
skvm::F32 vC = approx_powf(v, C);
v = approx_powf(max(B * vC + A, 0.0f) / (E * vC + D), F);
} break;
case HLGish_TF: {
skvm::F32 vA = v*A,
K = F + 1.0f;
v = K*select(vA <= 1.0f, approx_powf(vA, B)
, approx_exp((v-E) * C + D));
} break;
case HLGinvish_TF: {
skvm::F32 K = F + 1.0f;
v /= K;
v = select(v <= 1.0f, A * approx_powf(v, B)
, C * approx_log(v-D) + E);
} break;
}
// Re-apply the original sign bit on our way out the door.
return pun_to_F32(sign | pun_to_I32(v));
}
skvm::Color sk_program_transfer_fn(skvm::Builder* p, skvm::Uniforms* uniforms,
const skcms_TransferFunction& tf, skvm::Color c) {
skvm::F32 G = p->uniformF(uniforms->pushF(tf.g)),
@ -146,46 +187,13 @@ skvm::Color sk_program_transfer_fn(skvm::Builder* p, skvm::Uniforms* uniforms,
D = p->uniformF(uniforms->pushF(tf.d)),
E = p->uniformF(uniforms->pushF(tf.e)),
F = p->uniformF(uniforms->pushF(tf.f));
auto apply = [&](skvm::F32 v) -> skvm::F32 {
// Strip off the sign bit and save it for later.
skvm::I32 bits = pun_to_I32(v),
sign = bits & 0x80000000;
v = pun_to_F32(bits ^ sign);
switch (classify_transfer_fn(tf)) {
case Bad_TF: SkASSERT(false); break;
case sRGBish_TF:
v = select(v <= D, C*v + F
, approx_powf(A*v + B, G) + E);
break;
case PQish_TF: {
skvm::F32 vC = approx_powf(v, C);
v = approx_powf(max(B * vC + A, 0.0f) / (E * vC + D), F);
} break;
case HLGish_TF: {
skvm::F32 vA = v*A,
K = F + 1.0f;
v = K*select(vA <= 1.0f, approx_powf(vA, B)
, approx_exp((v-E) * C + D));
} break;
case HLGinvish_TF:
skvm::F32 K = F + 1.0f;
v /= K;
v = select(v <= 1.0f, A * approx_powf(v, B)
, C * approx_log(v-D) + E);
break;
}
// Re-apply the original sign bit on our way out the door.
return pun_to_F32(sign | pun_to_I32(v));
TFKind tf_kind = classify_transfer_fn(tf);
return {
sk_program_transfer_fn(c.r, tf_kind, G,A,B,C,D,E,F),
sk_program_transfer_fn(c.g, tf_kind, G,A,B,C,D,E,F),
sk_program_transfer_fn(c.b, tf_kind, G,A,B,C,D,E,F),
c.a,
};
return {apply(c.r), apply(c.g), apply(c.b), c.a};
}
skvm::Color SkColorSpaceXformSteps::program(skvm::Builder* p, skvm::Uniforms* uniforms,

View File

@ -124,7 +124,8 @@ static bool convert_to_alpha8(const SkImageInfo& dstInfo, void* vdst, size
}
case kBGRA_8888_SkColorType:
case kRGBA_8888_SkColorType: {
case kRGBA_8888_SkColorType:
case kSRGBA_8888_SkColorType: {
auto src32 = (const uint32_t*) src;
for (int y = 0; y < srcInfo.height(); y++) {
for (int x = 0; x < srcInfo.width(); x++) {

View File

@ -33,6 +33,7 @@ int SkColorTypeBytesPerPixel(SkColorType ct) {
case kA16_float_SkColorType: return 2;
case kR16G16_float_SkColorType: return 4;
case kR16G16B16A16_unorm_SkColorType: return 8;
case kSRGBA_8888_SkColorType: return 4;
}
SkUNREACHABLE;
}
@ -93,6 +94,7 @@ bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType,
[[fallthrough]];
case kARGB_4444_SkColorType:
case kRGBA_8888_SkColorType:
case kSRGBA_8888_SkColorType:
case kBGRA_8888_SkColorType:
case kRGBA_1010102_SkColorType:
case kBGRA_1010102_SkColorType:

View File

@ -543,6 +543,9 @@ SkMipmap* SkMipmap::Build(const SkPixmap& src, SkDiscardableFactoryProc fact,
case kBGR_101010x_SkColorType: // TODO: use 1010102?
case kRGBA_F32_SkColorType:
return nullptr;
case kSRGBA_8888_SkColorType: // TODO: needs careful handling
return nullptr;
}
if (src.width() <= 1 && src.height() <= 1) {

View File

@ -128,6 +128,7 @@ float SkPixmap::getAlphaf(int x, int y) const {
}
case kRGBA_8888_SkColorType:
case kBGRA_8888_SkColorType:
case kSRGBA_8888_SkColorType:
value = static_cast<const uint8_t*>(srcPtr)[3] * (1.0f/255);
break;
case kRGBA_1010102_SkColorType:
@ -326,6 +327,30 @@ SkColor SkPixmap::getColor(int x, int y) const {
SkPMColor c = SkSwizzle_RGBA_to_PMColor(value);
return toColor(c);
}
case kSRGBA_8888_SkColorType: {
auto srgb_to_linear = [](float x) {
return (x <= 0.04045f) ? x * (1 / 12.92f)
: sk_float_pow(x * (1 / 1.055f) + (0.055f / 1.055f), 2.4f);
};
uint32_t value = *this->addr32(x, y);
float r = ((value >> 0) & 0xff) * (1/255.0f),
g = ((value >> 8) & 0xff) * (1/255.0f),
b = ((value >> 16) & 0xff) * (1/255.0f),
a = ((value >> 24) & 0xff) * (1/255.0f);
r = srgb_to_linear(r);
g = srgb_to_linear(g);
b = srgb_to_linear(b);
if (a != 0 && needsUnpremul) {
r = SkTPin(r/a, 0.0f, 1.0f);
g = SkTPin(g/a, 0.0f, 1.0f);
b = SkTPin(b/a, 0.0f, 1.0f);
}
return (uint32_t)( r * 255.0f ) << 16
| (uint32_t)( g * 255.0f ) << 8
| (uint32_t)( b * 255.0f ) << 0
| (uint32_t)( a * 255.0f ) << 24;
}
case kRGB_101010x_SkColorType: {
uint32_t value = *this->addr32(x, y);
// Convert 10-bit rgb to 8-bit bgr, and mask in 0xff alpha at the top.
@ -481,7 +506,8 @@ bool SkPixmap::computeIsOpaque() const {
return true;
}
case kBGRA_8888_SkColorType:
case kRGBA_8888_SkColorType: {
case kRGBA_8888_SkColorType:
case kSRGBA_8888_SkColorType: {
SkPMColor c = (SkPMColor)~0;
for (int y = 0; y < height; ++y) {
const SkPMColor* row = this->addr32(0, y);

View File

@ -210,6 +210,11 @@ void SkRasterPipeline::append_load(SkColorType ct, const SkRasterPipeline_Memory
case kBGRA_8888_SkColorType: this->append(load_8888, ctx);
this->append(swap_rb);
break;
case kSRGBA_8888_SkColorType:
this->append(load_8888, ctx);
this->append_transfer_function(*skcms_sRGB_TransferFunction());
break;
}
}
@ -256,6 +261,14 @@ void SkRasterPipeline::append_load_dst(SkColorType ct, const SkRasterPipeline_Me
case kBGRA_8888_SkColorType: this->append(load_8888_dst, ctx);
this->append(swap_rb_dst);
break;
case kSRGBA_8888_SkColorType:
// TODO: We could remove the double-swap if we had _dst versions of all the TF stages
this->append(load_8888_dst, ctx);
this->append(swap_src_dst);
this->append_transfer_function(*skcms_sRGB_TransferFunction());
this->append(swap_src_dst);
break;
}
}
@ -302,6 +315,11 @@ void SkRasterPipeline::append_store(SkColorType ct, const SkRasterPipeline_Memor
case kBGRA_8888_SkColorType: this->append(swap_rb);
this->append(store_8888, ctx);
break;
case kSRGBA_8888_SkColorType:
this->append_transfer_function(*skcms_sRGB_Inverse_TransferFunction());
this->append(store_8888, ctx);
break;
}
}

View File

@ -38,7 +38,7 @@ class SkData;
#define SK_RASTER_PIPELINE_STAGES(M) \
M(callback) \
M(move_src_dst) M(move_dst_src) \
M(move_src_dst) M(move_dst_src) M(swap_src_dst) \
M(clamp_0) M(clamp_1) M(clamp_a) M(clamp_gamut) \
M(unpremul) M(premul) M(premul_dst) \
M(force_opaque) M(force_opaque_dst) \

View File

@ -208,7 +208,8 @@ SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst,
case kGray_8_SkColorType:
case kRGB_888x_SkColorType:
case kRGBA_8888_SkColorType:
case kBGRA_8888_SkColorType: blitter->fDitherRate = 1/255.0f; break;
case kBGRA_8888_SkColorType:
case kSRGBA_8888_SkColorType: blitter->fDitherRate = 1/255.0f; break;
case kRGB_101010x_SkColorType:
case kRGBA_1010102_SkColorType:
case kBGR_101010x_SkColorType:

View File

@ -13,6 +13,7 @@
#include "include/private/SkTFitsIn.h"
#include "include/private/SkThreadID.h"
#include "include/private/SkVx.h"
#include "src/core/SkColorSpacePriv.h"
#include "src/core/SkColorSpaceXformSteps.h"
#include "src/core/SkCpu.h"
#include "src/core/SkEnumerate.h"
@ -112,7 +113,20 @@ bool gSkVMJITViaDylib{false};
#endif
#endif
#if defined(SKSL_STANDALONE)
// skslc needs to link against this module (for the VM code generator). This module pulls in
// color-space code, but attempting to add those transitive dependencies to skslc gets out of
// hand. So we terminate the chain here with stub functions. Note that skslc's usage of SkVM
// never cares about color management.
skvm::F32 sk_program_transfer_fn(
skvm::F32 v, TFKind tf_kind,
skvm::F32 G, skvm::F32 A, skvm::F32 B, skvm::F32 C, skvm::F32 D, skvm::F32 E, skvm::F32 F) {
return v;
}
const skcms_TransferFunction* skcms_sRGB_TransferFunction() { return nullptr; }
const skcms_TransferFunction* skcms_sRGB_Inverse_TransferFunction() { return nullptr; }
#endif
namespace skvm {
@ -1043,6 +1057,7 @@ namespace skvm {
PixelFormat SkColorType_to_PixelFormat(SkColorType ct) {
auto UNORM = PixelFormat::UNORM,
SRGB = PixelFormat::SRGB,
FLOAT = PixelFormat::FLOAT;
switch (ct) {
case kUnknown_SkColorType: break;
@ -1065,6 +1080,7 @@ namespace skvm {
case kRGBA_8888_SkColorType: return {UNORM, 8,8,8,8, 0,8,16,24};
case kRGB_888x_SkColorType: return {UNORM, 8,8,8,0, 0,8,16,32}; // 32-bit
case kBGRA_8888_SkColorType: return {UNORM, 8,8,8,8, 16,8, 0,24};
case kSRGBA_8888_SkColorType: return { SRGB, 8,8,8,8, 0,8,16,24};
case kRGBA_1010102_SkColorType: return {UNORM, 10,10,10,2, 0,10,20,30};
case kBGRA_1010102_SkColorType: return {UNORM, 10,10,10,2, 20,10, 0,30};
@ -1091,19 +1107,43 @@ namespace skvm {
static Color unpack(PixelFormat f, I32 x) {
SkASSERT(byte_size(f) <= 4);
auto unpack_channel = [=](int bits, int shift) {
auto from_srgb = [](int bits, I32 channel) -> F32 {
const skcms_TransferFunction* tf = skcms_sRGB_TransferFunction();
F32 v = from_unorm(bits, channel);
return sk_program_transfer_fn(v, sRGBish_TF,
v->splat(tf->g),
v->splat(tf->a),
v->splat(tf->b),
v->splat(tf->c),
v->splat(tf->d),
v->splat(tf->e),
v->splat(tf->f));
};
auto unpack_rgb = [=](int bits, int shift) -> F32 {
I32 channel = extract(x, shift, (1<<bits)-1);
switch (f.encoding) {
case PixelFormat::UNORM: return from_unorm(bits, channel);
case PixelFormat:: SRGB: return from_srgb (bits, channel);
case PixelFormat::FLOAT: return from_fp16 ( channel);
}
SkUNREACHABLE;
};
auto unpack_alpha = [=](int bits, int shift) -> F32 {
I32 channel = extract(x, shift, (1<<bits)-1);
switch (f.encoding) {
case PixelFormat::UNORM:
case PixelFormat:: SRGB: return from_unorm(bits, channel);
case PixelFormat::FLOAT: return from_fp16 ( channel);
}
SkUNREACHABLE;
};
return {
f.r_bits ? unpack_channel(f.r_bits, f.r_shift) : x->splat(0.0f),
f.g_bits ? unpack_channel(f.g_bits, f.g_shift) : x->splat(0.0f),
f.b_bits ? unpack_channel(f.b_bits, f.b_shift) : x->splat(0.0f),
f.a_bits ? unpack_channel(f.a_bits, f.a_shift) : x->splat(1.0f),
f.r_bits ? unpack_rgb (f.r_bits, f.r_shift) : x->splat(0.0f),
f.g_bits ? unpack_rgb (f.g_bits, f.g_shift) : x->splat(0.0f),
f.b_bits ? unpack_rgb (f.b_bits, f.b_shift) : x->splat(0.0f),
f.a_bits ? unpack_alpha(f.a_bits, f.a_shift) : x->splat(1.0f),
};
}
@ -1211,19 +1251,42 @@ namespace skvm {
static I32 pack32(PixelFormat f, Color c) {
SkASSERT(byte_size(f) <= 4);
auto to_srgb = [](int bits, F32 v) {
const skcms_TransferFunction* tf = skcms_sRGB_Inverse_TransferFunction();
return to_unorm(bits, sk_program_transfer_fn(v, sRGBish_TF,
v->splat(tf->g),
v->splat(tf->a),
v->splat(tf->b),
v->splat(tf->c),
v->splat(tf->d),
v->splat(tf->e),
v->splat(tf->f)));
};
I32 packed = c->splat(0);
auto pack_channel = [&](F32 channel, int bits, int shift) {
auto pack_rgb = [&](F32 channel, int bits, int shift) {
I32 encoded;
switch (f.encoding) {
case PixelFormat::UNORM: encoded = to_unorm(bits, channel); break;
case PixelFormat:: SRGB: encoded = to_srgb (bits, channel); break;
case PixelFormat::FLOAT: encoded = to_fp16 ( channel); break;
}
packed = pack(packed, encoded, shift);
};
if (f.r_bits) { pack_channel(c.r, f.r_bits, f.r_shift); }
if (f.g_bits) { pack_channel(c.g, f.g_bits, f.g_shift); }
if (f.b_bits) { pack_channel(c.b, f.b_bits, f.b_shift); }
if (f.a_bits) { pack_channel(c.a, f.a_bits, f.a_shift); }
auto pack_alpha = [&](F32 channel, int bits, int shift) {
I32 encoded;
switch (f.encoding) {
case PixelFormat::UNORM:
case PixelFormat:: SRGB: encoded = to_unorm(bits, channel); break;
case PixelFormat::FLOAT: encoded = to_fp16 ( channel); break;
}
packed = pack(packed, encoded, shift);
};
if (f.r_bits) { pack_rgb (c.r, f.r_bits, f.r_shift); }
if (f.g_bits) { pack_rgb (c.g, f.g_bits, f.g_shift); }
if (f.b_bits) { pack_rgb (c.b, f.b_bits, f.b_shift); }
if (f.a_bits) { pack_alpha(c.a, f.a_bits, f.a_shift); }
return packed;
}

View File

@ -560,7 +560,7 @@ namespace skvm {
};
struct PixelFormat {
enum { UNORM, FLOAT} encoding;
enum { UNORM, SRGB, FLOAT} encoding;
int r_bits, g_bits, b_bits, a_bits,
r_shift, g_shift, b_shift, a_shift;
};

View File

@ -114,7 +114,8 @@ namespace {
case kGray_8_SkColorType:
case kRGB_888x_SkColorType:
case kRGBA_8888_SkColorType:
case kBGRA_8888_SkColorType: rate = 1/255.0f; break;
case kBGRA_8888_SkColorType:
case kSRGBA_8888_SkColorType: rate = 1/255.0f; break;
case kRGB_101010x_SkColorType:
case kRGBA_1010102_SkColorType:
case kBGR_101010x_SkColorType:

View File

@ -747,18 +747,3 @@ bool GrClearImage(const GrImageInfo& dstInfo, void* dst, size_t dstRB, std::arra
return true;
}
GrColorType SkColorTypeAndFormatToGrColorType(const GrCaps* caps,
SkColorType skCT,
const GrBackendFormat& format) {
GrColorType grCT = SkColorTypeToGrColorType(skCT);
// Until we support SRGB in the SkColorType we have to do this manual check here to make sure
// we use the correct GrColorType.
if (caps->isFormatSRGB(format)) {
if (grCT != GrColorType::kRGBA_8888) {
return GrColorType::kUnknown;
}
grCT = GrColorType::kRGBA_8888_SRGB;
}
return grCT;
}

View File

@ -683,7 +683,7 @@ bool GrDirectContext::updateBackendTexture(const GrBackendTexture& backendTextur
}
GrBackendFormat format = backendTexture.getBackendFormat();
GrColorType grColorType = SkColorTypeAndFormatToGrColorType(this->caps(), skColorType, format);
GrColorType grColorType = SkColorTypeToGrColorType(skColorType);
if (!this->caps()->areColorTypeAndFormatCompatible(grColorType, format)) {
return false;

View File

@ -154,7 +154,7 @@ SkImage_Gpu::SkImage_Gpu(sk_sp<GrImageContext> context,
#ifdef SK_DEBUG
const GrBackendFormat& format = fChooser.backendFormat();
const GrCaps* caps = this->context()->priv().caps();
GrColorType grCT = SkColorTypeAndFormatToGrColorType(caps, this->colorType(), format);
GrColorType grCT = SkColorTypeToGrColorType(this->colorType());
SkASSERT(caps->isFormatCompressed(format) ||
caps->areColorTypeAndFormatCompatible(grCT, format));
#endif
@ -179,7 +179,7 @@ SkImage_Gpu::SkImage_Gpu(sk_sp<GrDirectContext> dContext,
#ifdef SK_DEBUG
const GrBackendFormat& format = fChooser.backendFormat();
const GrCaps* caps = this->context()->priv().caps();
GrColorType grCT = SkColorTypeAndFormatToGrColorType(caps, this->colorType(), format);
GrColorType grCT = SkColorTypeToGrColorType(this->colorType());
SkASSERT(caps->isFormatCompressed(format) ||
caps->areColorTypeAndFormatCompatible(grCT, format));
#endif
@ -457,7 +457,7 @@ sk_sp<SkImage> SkImage::MakeFromTexture(GrRecordingContext* rContext,
const GrCaps* caps = rContext->priv().caps();
GrColorType grColorType = SkColorTypeAndFormatToGrColorType(caps, ct, tex.getBackendFormat());
GrColorType grColorType = SkColorTypeToGrColorType(ct);
if (GrColorType::kUnknown == grColorType) {
return nullptr;
}
@ -482,7 +482,7 @@ sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrRecordingContext* rContext,
const GrCaps* caps = dContext->priv().caps();
GrColorType grColorType = SkColorTypeAndFormatToGrColorType(caps, ct, tex.getBackendFormat());
GrColorType grColorType = SkColorTypeToGrColorType(ct);
if (GrColorType::kUnknown == grColorType) {
return nullptr;
}
@ -595,9 +595,7 @@ sk_sp<SkImage> SkImage::MakePromiseTexture(sk_sp<GrContextThreadSafeProxy> threa
return nullptr;
}
GrColorType grColorType = SkColorTypeAndFormatToGrColorType(threadSafeProxy->priv().caps(),
colorType,
backendFormat);
GrColorType grColorType = SkColorTypeToGrColorType(colorType);
if (GrColorType::kUnknown == grColorType) {
return nullptr;
}
@ -834,9 +832,7 @@ std::tuple<GrSurfaceProxyView, GrColorType> SkImage_Gpu::onAsView(
SkColorTypeToGrColorType(this->colorType())};
}
GrSurfaceProxyView view = this->makeView(recordingContext);
GrColorType ct = SkColorTypeAndFormatToGrColorType(recordingContext->priv().caps(),
this->colorType(),
view.proxy()->backendFormat());
GrColorType ct = SkColorTypeToGrColorType(this->colorType());
if (mipmapped == GrMipmapped::kYes) {
view = FindOrMakeCachedMipmappedView(recordingContext, std::move(view), this->uniqueID());
}

View File

@ -489,8 +489,7 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrRecordingContext* rContext,
}
sampleCnt = std::max(1, sampleCnt);
GrColorType grColorType = SkColorTypeAndFormatToGrColorType(rContext->priv().caps(), colorType,
tex.getBackendFormat());
GrColorType grColorType = SkColorTypeToGrColorType(colorType);
if (grColorType == GrColorType::kUnknown) {
return nullptr;
}
@ -607,8 +606,7 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrRecordingContext* rCon
return nullptr;
}
GrColorType grColorType = SkColorTypeAndFormatToGrColorType(rContext->priv().caps(), colorType,
rt.getBackendFormat());
GrColorType grColorType = SkColorTypeToGrColorType(colorType);
if (grColorType == GrColorType::kUnknown) {
return nullptr;
}

View File

@ -237,6 +237,11 @@ static transform_scanline_proc choose_proc(const SkImageInfo& info) {
case kUnknown_SkColorType:
break;
// TODO: I don't think this can just use kRGBA's procs.
// kPremul is especially tricky here, since it's presumably TF⁻¹(rgb * a),
// so to get at unpremul rgb we'd need to undo the transfer function first.
case kSRGBA_8888_SkColorType: return nullptr;
case kRGBA_8888_SkColorType:
switch (info.alphaType()) {
case kOpaque_SkAlphaType:

View File

@ -1644,6 +1644,12 @@ STAGE(move_dst_src, Ctx::None) {
b = db;
a = da;
}
STAGE(swap_src_dst, Ctx::None) {
std::swap(r, dr);
std::swap(g, dg);
std::swap(b, db);
std::swap(a, da);
}
STAGE(premul, Ctx::None) {
r = r * a;
@ -3288,6 +3294,13 @@ STAGE_PP(move_dst_src, Ctx::None) {
a = da;
}
STAGE_PP(swap_src_dst, Ctx::None) {
std::swap(r, dr);
std::swap(g, dg);
std::swap(b, db);
std::swap(a, da);
}
// ~~~~~~ Blend modes ~~~~~~ //
// The same logic applied to all 4 channels.

View File

@ -539,6 +539,11 @@ bool SkImageShader::doStages(const SkStageRec& rec, SkImageStageUpdater* updater
case kBGRA_8888_SkColorType: p->append(SkRasterPipeline::gather_8888, ctx);
p->append(SkRasterPipeline::swap_rb ); break;
case kSRGBA_8888_SkColorType:
p->append(SkRasterPipeline::gather_8888, ctx);
p->append_transfer_function(*skcms_sRGB_TransferFunction());
break;
case kUnknown_SkColorType: SkASSERT(false);
}
if (decal_ctx) {

View File

@ -573,6 +573,7 @@ void color_type_backend_allocation_test(const sk_gpu_test::ContextInfo& ctxInfo,
{ kRGB_565_SkColorType, SkColors::kRed },
{ kARGB_4444_SkColorType, SkColors::kGreen },
{ kRGBA_8888_SkColorType, SkColors::kBlue },
{ kSRGBA_8888_SkColorType, { 0.25f, 0.5f, 0.75f, 1.0f}},
{ kRGB_888x_SkColorType, SkColors::kCyan },
// TODO: readback is busted when alpha = 0.5f (perhaps premul vs. unpremul)
{ kBGRA_8888_SkColorType, { 1, 0, 0, 1.0f } },

View File

@ -39,6 +39,7 @@ static constexpr int min_rgb_channel_bits(SkColorType ct) {
case kR16G16_unorm_SkColorType: return 16;
case kR16G16_float_SkColorType: return 16;
case kRGBA_8888_SkColorType: return 8;
case kSRGBA_8888_SkColorType: return 8;
case kRGB_888x_SkColorType: return 8;
case kBGRA_8888_SkColorType: return 8;
case kRGBA_1010102_SkColorType: return 10;
@ -66,6 +67,7 @@ static constexpr int alpha_channel_bits(SkColorType ct) {
case kR16G16_unorm_SkColorType: return 0;
case kR16G16_float_SkColorType: return 0;
case kRGBA_8888_SkColorType: return 8;
case kSRGBA_8888_SkColorType: return 8;
case kRGB_888x_SkColorType: return 0;
case kBGRA_8888_SkColorType: return 8;
case kRGBA_1010102_SkColorType: return 2;

View File

@ -29,6 +29,7 @@ HashAndEncode::HashAndEncode(const SkBitmap& bitmap) : fSize(bitmap.info().dimen
case kARGB_4444_SkColorType: srcFmt = skcms_PixelFormat_ABGR_4444; break;
case kRGBA_8888_SkColorType: srcFmt = skcms_PixelFormat_RGBA_8888; break;
case kBGRA_8888_SkColorType: srcFmt = skcms_PixelFormat_BGRA_8888; break;
case kSRGBA_8888_SkColorType: srcFmt = skcms_PixelFormat_RGBA_8888_sRGB; break;
case kRGBA_1010102_SkColorType: srcFmt = skcms_PixelFormat_RGBA_1010102; break;
case kBGRA_1010102_SkColorType: srcFmt = skcms_PixelFormat_BGRA_1010102; break;
case kGray_8_SkColorType: srcFmt = skcms_PixelFormat_G_8; break;

View File

@ -55,6 +55,7 @@ const char* colortype_name(SkColorType ct) {
case kRGB_565_SkColorType: return "RGB_565";
case kARGB_4444_SkColorType: return "ARGB_4444";
case kRGBA_8888_SkColorType: return "RGBA_8888";
case kSRGBA_8888_SkColorType: return "SRGBA_8888";
case kRGB_888x_SkColorType: return "RGB_888x";
case kBGRA_8888_SkColorType: return "BGRA_8888";
case kRGBA_1010102_SkColorType: return "RGBA_1010102";
@ -83,6 +84,7 @@ const char* colortype_depth(SkColorType ct) {
case kRGB_565_SkColorType: return "565";
case kARGB_4444_SkColorType: return "4444";
case kRGBA_8888_SkColorType: return "8888";
case kSRGBA_8888_SkColorType: return "8888";
case kRGB_888x_SkColorType: return "888";
case kBGRA_8888_SkColorType: return "8888";
case kRGBA_1010102_SkColorType: return "1010102";

View File

@ -61,7 +61,9 @@ static const struct {
{ "gles1010102", "gpu", "api=gles,color=1010102" },
{ "glf16", "gpu", "api=gl,color=f16" },
{ "glf16norm", "gpu", "api=gl,color=f16norm" },
{ "glsrgba", "gpu", "api=gl,color=srgba" },
{ "glesf16", "gpu", "api=gles,color=f16" },
{ "glessrgba", "gpu", "api=gles,color=srgba" },
{ "glnostencils", "gpu", "api=gl,stencils=false" },
{ "gldft", "gpu", "api=gl,dit=true" },
{ "glesdft", "gpu", "api=gles,dit=true" },
@ -339,9 +341,9 @@ static bool parse_option_gpu_api(const SkString& value,
return false;
}
static bool parse_option_gpu_color(const SkString& value,
SkColorType* outColorType,
SkAlphaType* alphaType) {
static bool parse_option_gpu_color(const SkString& value,
SkColorType* outColorType,
SkAlphaType* alphaType) {
// We always use premul unless the color type is 565.
*alphaType = kPremul_SkAlphaType;
@ -362,6 +364,8 @@ static bool parse_option_gpu_color(const SkString& value,
*outColorType = kRGBA_F16_SkColorType;
} else if (value.equals("f16norm")) {
*outColorType = kRGBA_F16Norm_SkColorType;
} else if (value.equals("srgba")) {
*outColorType = kSRGBA_8888_SkColorType;
} else {
return false;
}

View File

@ -520,6 +520,7 @@ int main(int argc, char** argv) {
{ "f32", kRGBA_F32_SkColorType },
{ "rgba", kRGBA_8888_SkColorType },
{ "bgra", kBGRA_8888_SkColorType },
{ "srgba", kSRGBA_8888_SkColorType },
{ "16161616", kR16G16B16A16_unorm_SkColorType },
};
const FlagOption<SkAlphaType> kAlphaTypes[] = {