Support sRGB 565.
It looks like I'm not going to be able to avoid supporting sRGB G8, I8, 565, 4444, 8888. (A8 and F16 will always be linear.) This fixes 565, and lays out the rest of the accum_*. I did a little reorganization to keep things in ascending bit depth, just for sanity. GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=5145 CQ_INCLUDE_TRYBOTS=master.client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot Change-Id: Ib0508e5a4ee1bab2044a76bcabc367841d634cd2 Reviewed-on: https://skia-review.googlesource.com/5145 Reviewed-by: Herb Derby <herb@google.com> Commit-Queue: Mike Klein <mtklein@chromium.org>
This commit is contained in:
parent
2cb6cb7218
commit
cb5338cadc
@ -79,7 +79,12 @@
|
||||
M(color_lookup_table) M(lab_to_xyz) M(swap_rb) \
|
||||
M(clamp_x) M(mirror_x) M(repeat_x) \
|
||||
M(clamp_y) M(mirror_y) M(repeat_y) \
|
||||
M(accum_565) M(accum_8888) M(accum_srgb) M(accum_f16) \
|
||||
M(accum_f16) M(accum_a8) \
|
||||
M(accum_g8) M(accum_g8_srgb) \
|
||||
M(accum_i8) M(accum_i8_srgb) \
|
||||
M(accum_565) M(accum_565_srgb) \
|
||||
M(accum_4444) M(accum_4444_srgb) \
|
||||
M(accum_8888) M(accum_8888_srgb) \
|
||||
M(top_left) M(top_right) M(bottom_left) M(bottom_right)
|
||||
|
||||
class SkRasterPipeline {
|
||||
|
@ -57,24 +57,36 @@ static inline SkNx<N,int> sk_linear_to_srgb(const SkNx<N,float>& x) {
|
||||
return SkNx_cast<int>(sk_clamp_0_255(f));
|
||||
}
|
||||
|
||||
// sRGB -> linear, using math instead of table lookups, scaling better to larger SIMD vectors.
|
||||
// sRGB -> linear, using math instead of table lookups.
|
||||
template <int N>
|
||||
static inline SkNx<N,float> sk_linear_from_srgb_math(const SkNx<N,float>& x) {
|
||||
// Non-linear segment of sRGB curve approximated by
|
||||
// l = 0.0025 + 0.6975x^2 + 0.3x^3
|
||||
const SkNx<N,float> k0 = 0.0025f,
|
||||
k2 = 0.6975f,
|
||||
k3 = 0.3000f;
|
||||
auto hi = SkNx_fma(x*x, SkNx_fma(x, k3, k2), k0);
|
||||
|
||||
// Linear segment of sRGB curve: the normal slope, extended a little further than normal.
|
||||
auto lo = x * (1/12.92f);
|
||||
|
||||
return (x < 0.055f).thenElse(lo, hi);
|
||||
}
|
||||
|
||||
// Same as above, starting from ints.
|
||||
template <int N>
|
||||
static inline SkNx<N,float> sk_linear_from_srgb_math(const SkNx<N,int>& s) {
|
||||
auto x = SkNx_cast<float>(s);
|
||||
|
||||
const float u = 1/255.0f; // x is [0,255], so x^n needs scaling by u^n.
|
||||
// Same math as above, but working with x in [0,255], so x^n needs scaling by u^n.
|
||||
const float u = 1/255.0f;
|
||||
|
||||
// Non-linear segment of sRGB curve approximated by
|
||||
// l = 0.0025 + 0.6975x^2 + 0.3x^3
|
||||
const SkNx<N,float> k0 = 0.0025f,
|
||||
k2 = 0.6975f * u*u,
|
||||
k3 = 0.3000f * u*u*u;
|
||||
auto hi = SkNx_fma(x*x, SkNx_fma(x, k3, k2), k0);
|
||||
|
||||
// Linear segment of sRGB curve: the normal slope, extended a little further than normal.
|
||||
auto lo = x * (u/12.92f);
|
||||
|
||||
return (x < 14.025f).thenElse(lo, hi);
|
||||
return (x < (0.055f/u)).thenElse(lo, hi);
|
||||
}
|
||||
|
||||
#endif//SkSRGB_DEFINED
|
||||
|
@ -345,21 +345,23 @@ bool SkImageShader::onAppendStages(SkRasterPipeline* p, SkColorSpace* dst, SkFal
|
||||
case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_y, &ctx->height); break;
|
||||
}
|
||||
|
||||
bool srgb = info.gammaCloseToSRGB() && dst != nullptr;
|
||||
|
||||
switch (info.colorType()) {
|
||||
case kRGB_565_SkColorType:
|
||||
p->append(srgb ? SkRasterPipeline::accum_565_srgb
|
||||
: SkRasterPipeline::accum_565, ctx);
|
||||
break;
|
||||
|
||||
case kRGBA_8888_SkColorType:
|
||||
case kBGRA_8888_SkColorType:
|
||||
if (info.gammaCloseToSRGB() && dst) {
|
||||
p->append(SkRasterPipeline::accum_srgb, ctx);
|
||||
} else {
|
||||
p->append(SkRasterPipeline::accum_8888, ctx);
|
||||
}
|
||||
p->append(srgb ? SkRasterPipeline::accum_8888_srgb
|
||||
: SkRasterPipeline::accum_8888, ctx);
|
||||
break;
|
||||
|
||||
case kRGBA_F16_SkColorType:
|
||||
p->append(SkRasterPipeline::accum_f16, ctx);
|
||||
break;
|
||||
case kRGB_565_SkColorType:
|
||||
p->append(SkRasterPipeline::accum_565, ctx);
|
||||
break;
|
||||
|
||||
default:
|
||||
SkASSERT(false);
|
||||
|
@ -777,6 +777,13 @@ SI SkNi offset_and_ptr(T** ptr, const void* ctx, const SkNf& x, const SkNf& y) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
STAGE(accum_a8, true) {} // TODO
|
||||
|
||||
STAGE(accum_g8, true) {} // TODO
|
||||
STAGE(accum_g8_srgb, true) {} // TODO
|
||||
STAGE(accum_i8, true) {} // TODO
|
||||
STAGE(accum_i8_srgb, true) {} // TODO
|
||||
|
||||
STAGE(accum_565, true) {
|
||||
const uint16_t* p;
|
||||
SkNi offset = offset_and_ptr(&p, ctx, r, g);
|
||||
@ -798,6 +805,77 @@ STAGE(accum_565, true) {
|
||||
db += scale * B;
|
||||
da += scale;
|
||||
}
|
||||
STAGE(accum_565_srgb, true) {
|
||||
const uint16_t* p;
|
||||
SkNi offset = offset_and_ptr(&p, ctx, r, g);
|
||||
|
||||
uint16_t px[N];
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
if (kIsTail && i >= tail) {
|
||||
px[i] = 0;
|
||||
continue;
|
||||
}
|
||||
px[i] = p[offset[i]];
|
||||
}
|
||||
SkNf R,G,B;
|
||||
from_565(SkNh::Load(px), &R, &G, &B);
|
||||
|
||||
SkNf scale = b;
|
||||
dr += scale * sk_linear_from_srgb_math(R);
|
||||
dg += scale * sk_linear_from_srgb_math(G);
|
||||
db += scale * sk_linear_from_srgb_math(B);
|
||||
da += scale;
|
||||
}
|
||||
|
||||
STAGE(accum_4444, true) {} // TODO
|
||||
STAGE(accum_4444_srgb, true) {} // TODO
|
||||
|
||||
STAGE(accum_8888, true) {
|
||||
const uint32_t* p;
|
||||
SkNi offset = offset_and_ptr(&p, ctx, r, g);
|
||||
|
||||
uint8_t R[N], G[N], B[N], A[N];
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
if (kIsTail && i >= tail) {
|
||||
R[i] = G[i] = B[i] = A[i] = 0;
|
||||
continue;
|
||||
}
|
||||
uint32_t rgba = p[offset[i]];
|
||||
R[i] = rgba >> 0;
|
||||
G[i] = rgba >> 8;
|
||||
B[i] = rgba >> 16;
|
||||
A[i] = rgba >> 24;
|
||||
}
|
||||
|
||||
SkNf scale = b;
|
||||
dr += scale * SkNx_cast<float>(SkNb::Load(R)) * (1/255.0f);
|
||||
dg += scale * SkNx_cast<float>(SkNb::Load(G)) * (1/255.0f);
|
||||
db += scale * SkNx_cast<float>(SkNb::Load(B)) * (1/255.0f);
|
||||
da += scale * SkNx_cast<float>(SkNb::Load(A)) * (1/255.0f);
|
||||
}
|
||||
STAGE(accum_8888_srgb, true) {
|
||||
const uint32_t* p;
|
||||
SkNi offset = offset_and_ptr(&p, ctx, r, g);
|
||||
|
||||
uint8_t R[N], G[N], B[N], A[N];
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
if (kIsTail && i >= tail) {
|
||||
R[i] = G[i] = B[i] = A[i] = 0;
|
||||
continue;
|
||||
}
|
||||
uint32_t rgba = p[offset[i]];
|
||||
R[i] = rgba >> 0;
|
||||
G[i] = rgba >> 8;
|
||||
B[i] = rgba >> 16;
|
||||
A[i] = rgba >> 24;
|
||||
}
|
||||
|
||||
SkNf scale = b;
|
||||
dr += scale * sk_linear_from_srgb_math(SkNx_cast<int>(SkNb::Load(R)));
|
||||
dg += scale * sk_linear_from_srgb_math(SkNx_cast<int>(SkNb::Load(G)));
|
||||
db += scale * sk_linear_from_srgb_math(SkNx_cast<int>(SkNb::Load(B)));
|
||||
da += scale * SkNx_cast<float>(SkNb::Load(A)) * (1/255.0f);
|
||||
}
|
||||
|
||||
STAGE(accum_f16, true) {
|
||||
const uint64_t* p;
|
||||
@ -822,53 +900,6 @@ STAGE(accum_f16, true) {
|
||||
da += scale * SkHalfToFloat_finite_ftz(SkNh::Load(A));
|
||||
}
|
||||
|
||||
STAGE(accum_8888, true) {
|
||||
const uint32_t* p;
|
||||
SkNi offset = offset_and_ptr(&p, ctx, r, g);
|
||||
|
||||
uint8_t R[N], G[N], B[N], A[N];
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
if (kIsTail && i >= tail) {
|
||||
R[i] = G[i] = B[i] = A[i] = 0;
|
||||
continue;
|
||||
}
|
||||
uint32_t rgba = p[offset[i]];
|
||||
R[i] = rgba >> 0;
|
||||
G[i] = rgba >> 8;
|
||||
B[i] = rgba >> 16;
|
||||
A[i] = rgba >> 24;
|
||||
}
|
||||
|
||||
SkNf scale = b;
|
||||
dr += scale * SkNx_cast<float>(SkNb::Load(R)) * (1/255.0f);
|
||||
dg += scale * SkNx_cast<float>(SkNb::Load(G)) * (1/255.0f);
|
||||
db += scale * SkNx_cast<float>(SkNb::Load(B)) * (1/255.0f);
|
||||
da += scale * SkNx_cast<float>(SkNb::Load(A)) * (1/255.0f);
|
||||
}
|
||||
|
||||
STAGE(accum_srgb, true) {
|
||||
const uint32_t* p;
|
||||
SkNi offset = offset_and_ptr(&p, ctx, r, g);
|
||||
|
||||
uint8_t R[N], G[N], B[N], A[N];
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
if (kIsTail && i >= tail) {
|
||||
R[i] = G[i] = B[i] = A[i] = 0;
|
||||
continue;
|
||||
}
|
||||
uint32_t rgba = p[offset[i]];
|
||||
R[i] = rgba >> 0;
|
||||
G[i] = rgba >> 8;
|
||||
B[i] = rgba >> 16;
|
||||
A[i] = rgba >> 24;
|
||||
}
|
||||
|
||||
SkNf scale = b;
|
||||
dr += scale * sk_linear_from_srgb_math(SkNx_cast<int>(SkNb::Load(R)));
|
||||
dg += scale * sk_linear_from_srgb_math(SkNx_cast<int>(SkNb::Load(G)));
|
||||
db += scale * sk_linear_from_srgb_math(SkNx_cast<int>(SkNb::Load(B)));
|
||||
da += scale * SkNx_cast<float>(SkNb::Load(A)) * (1/255.0f);
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
SI Fn enum_to_Fn(SkRasterPipeline::StockStage st) {
|
||||
|
Loading…
Reference in New Issue
Block a user