Work toward removing SkPM4f

Added SkColor4f premul/unpremul that just return SkColor4f.
Renamed existing premul to toPM4f. For many uses of SkPM4f,
conversion to pure SkColor4f code was simple. In all other
cases, continue to use SkPM4f for now.

Also convert usage of one-off SkRGBAf class in SkPatchUtils,
and delete that class, along with some truly tautological
unit tests that were the only thing keeping some PM4f API
around.

Bug: skia:
Change-Id: I344c3290ee7af6bbe86c3ff74a2df2f5e87afa38
Reviewed-on: https://skia-review.googlesource.com/156005
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
Brian Osman 2018-09-21 11:09:15 -04:00 committed by Skia Commit-Bot
parent 5717e82cf4
commit 81cbd03a24
22 changed files with 90 additions and 256 deletions

View File

@ -307,11 +307,28 @@ struct SK_API SkColor4f {
return Pin(fR, fG, fB, fA);
}
/** Returns SkColor4f with all components premultiplied by alpha.
@return premultiplied color
*/
SkColor4f premul() const {
return { fR * fA, fG * fA, fB * fA, fA };
}
SkColor4f unpremul() const {
if (fA == 0.0f) {
return { 0, 0, 0, 0 };
} else {
float invAlpha = 1 / fA;
return { fR * invAlpha, fG * invAlpha, fB * invAlpha, fA };
}
}
/** Internal use only.
@return premultiplied color
*/
SkPM4f premul() const;
SkPM4f toPM4f() const;
};
#endif

View File

@ -10,7 +10,6 @@
//
#include "SkDevice_Compute.h"
#include "SkPM4f.h"
//
//
@ -276,9 +275,9 @@ void SkDevice_Compute::path_rasterize_and_place(const SkPaint& paint,
cmds[SK_ARRAY_COUNT(cmds)-1] = SKC_STYLING_CMD_OP_BLEND_OVER | SKC_STYLING_CMD_OP_IS_FINAL;
{
SkPM4f rgba = SkColor4f::FromColor(paint.getColor()).premul();
SkColor4f rgba = paint.getColor4f().premul();
skc_styling_layer_fill_solid_encoder(cmds+1, rgba.fVec);
skc_styling_layer_fill_solid_encoder(cmds+1, rgba.vec());
skc_styling_group_layer(fStyling, fGroupID, fGroupLayerID, SKC_STYLING_CMDS(cmds));
}

View File

@ -121,20 +121,22 @@ void SkBlendMode_AppendStages(SkBlendMode mode, SkRasterPipeline* p) {
p->append(stage);
}
SkPM4f SkBlendMode_Apply(SkBlendMode mode, const SkPM4f& src, const SkPM4f& dst) {
SkColor4f SkBlendMode_Apply(SkBlendMode mode, const SkColor4f& src, const SkColor4f& dst) {
// special-case simple/common modes...
switch (mode) {
case SkBlendMode::kClear: return {{ 0, 0, 0, 0 }};
case SkBlendMode::kClear: return { 0, 0, 0, 0 };
case SkBlendMode::kSrc: return src;
case SkBlendMode::kDst: return dst;
case SkBlendMode::kSrcOver:
return SkPM4f::From4f(src.to4f() + dst.to4f() * Sk4f(1 - src.a()));
case SkBlendMode::kSrcOver: {
Sk4f r = Sk4f::Load(src.vec()) + Sk4f::Load(dst.vec()) * Sk4f(1 - src.fA);
return { r[0], r[1], r[2], r[3] };
}
default:
break;
}
SkRasterPipeline_<256> p;
SkPM4f src_storage = src,
SkColor4f src_storage = src,
dst_storage = dst,
res_storage;
SkJumper_MemoryCtx src_ctx = { &src_storage, 0 },

View File

@ -9,9 +9,9 @@
#define SkBlendModePriv_DEFINED
#include "SkBlendMode.h"
#include "SkPM4f.h"
class SkRasterPipeline;
struct SkColor4f;
bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode);
@ -39,7 +39,7 @@ enum class SkBlendModeCoeff {
bool SkBlendMode_AsCoeff(SkBlendMode mode, SkBlendModeCoeff* src, SkBlendModeCoeff* dst);
SkPM4f SkBlendMode_Apply(SkBlendMode, const SkPM4f& src, const SkPM4f& dst);
SkColor4f SkBlendMode_Apply(SkBlendMode, const SkColor4f& src, const SkColor4f& dst);
#if SK_SUPPORT_GPU
#include "GrXferProcessor.h"

View File

@ -133,22 +133,6 @@ uint64_t SkPM4f::toF16() const {
return value;
}
SkPM4f SkPM4f::FromF16(const uint16_t half[4]) {
return {{
SkHalfToFloat(half[0]),
SkHalfToFloat(half[1]),
SkHalfToFloat(half[2]),
SkHalfToFloat(half[3])
}};
}
#ifdef SK_DEBUG
void SkPM4f::assertIsUnit() const {
auto c4 = Sk4f::Load(fVec);
SkASSERT((c4 >= Sk4f(0)).allTrue() && (c4 <= Sk4f(1)).allTrue());
}
#endif
///////////////////////////////////////////////////////////////////////////////////////////////////
SkColor4f SkColor4f::FromColor(SkColor bgra) {
@ -167,7 +151,7 @@ SkColor4f SkColor4f::Pin(float r, float g, float b, float a) {
return c4;
}
SkPM4f SkColor4f::premul() const {
SkPM4f SkColor4f::toPM4f() const {
auto rgba = Sk4f::Load(this->vec());
return SkPM4f::From4f(rgba * Sk4f(rgba[3], rgba[3], rgba[3], 1));
}

View File

@ -9,7 +9,6 @@
#include "SkColorFilter.h"
#include "SkColorSpaceXformer.h"
#include "SkNx.h"
#include "SkPM4f.h"
#include "SkRasterPipeline.h"
#include "SkReadBuffer.h"
#include "SkRefCnt.h"
@ -65,7 +64,7 @@ SkColor SkColorFilter::filterColor(SkColor c) const {
#include "SkRasterPipeline.h"
SkColor4f SkColorFilter::filterColor4f(const SkColor4f& c, SkColorSpace* colorSpace) const {
SkPM4f dst, src = c.premul();
SkColor4f dst, src = c.premul();
SkSTArenaAlloc<128> alloc;
SkRasterPipeline pipeline(&alloc);

View File

@ -10,7 +10,6 @@
#include "SkComposeShader.h"
#include "SkDraw.h"
#include "SkNx.h"
#include "SkPM4fPriv.h"
#include "SkRasterClip.h"
#include "SkScan.h"
#include "SkShaderBase.h"
@ -98,7 +97,7 @@ private:
};
static bool SK_WARN_UNUSED_RESULT
update_tricolor_matrix(const SkMatrix& ctmInv, const SkPoint pts[], const SkPM4f colors[],
update_tricolor_matrix(const SkMatrix& ctmInv, const SkPoint pts[], const SkColor4f colors[],
int index0, int index1, int index2, Matrix43* result) {
SkMatrix m, im;
m.reset();
@ -115,9 +114,9 @@ update_tricolor_matrix(const SkMatrix& ctmInv, const SkPoint pts[], const SkPM4f
SkMatrix dstToUnit;
dstToUnit.setConcat(im, ctmInv);
Sk4f c0 = colors[index0].to4f(),
c1 = colors[index1].to4f(),
c2 = colors[index2].to4f();
Sk4f c0 = Sk4f::Load(colors[index0].vec()),
c1 = Sk4f::Load(colors[index1].vec()),
c2 = Sk4f::Load(colors[index2].vec());
Matrix43 colorm;
(c1 - c0).store(&colorm.fMat[0]);
@ -136,14 +135,12 @@ update_tricolor_matrix(const SkMatrix& ctmInv, const SkPoint pts[], const SkPM4f
// - convert colors into dst colorspace before interpolation (matches gradients)
// - apply per-color alpha before interpolation (matches old version of vertices)
//
static SkPM4f* convert_colors(const SkColor src[], int count, SkColorSpace* deviceCS,
SkArenaAlloc* alloc) {
SkPM4f* dst = alloc->makeArray<SkPM4f>(count);
static SkColor4f* convert_colors(const SkColor src[], int count, SkColorSpace* deviceCS,
SkArenaAlloc* alloc) {
SkColor4f* dst = alloc->makeArray<SkColor4f>(count);
if (!deviceCS) {
for (int i = 0; i < count; ++i) {
SkColor4f color4f;
swizzle_rb(Sk4f_fromL32(src[i])).store(&color4f);
dst[i] = color4f.premul();
dst[i] = SkColor4f::FromColor(src[i]).premul();
}
} else {
auto srcCS = SkColorSpace::MakeSRGB();
@ -210,7 +207,7 @@ void SkDraw::drawVertices(SkVertices::VertexMode vmode, int vertexCount,
constexpr size_t kDefVertexCount = 16;
constexpr size_t kOuterSize = sizeof(SkTriColorShader) +
sizeof(SkComposeShader) +
(2 * sizeof(SkPoint) + sizeof(SkPM4f)) * kDefVertexCount;
(2 * sizeof(SkPoint) + sizeof(SkColor4f)) * kDefVertexCount;
SkSTArenaAlloc<kOuterSize> outerAlloc;
// deform vertices using the skeleton if it is passed in
@ -271,7 +268,7 @@ void SkDraw::drawVertices(SkVertices::VertexMode vmode, int vertexCount,
VertState::Proc vertProc = state.chooseProc(vmode);
if (colors || textures) {
SkPM4f* dstColors = nullptr;
SkColor4f* dstColors = nullptr;
Matrix43* matrix43 = nullptr;
if (colors) {

View File

@ -58,42 +58,20 @@ struct SK_API SkPM4f {
float b() const { return fVec[B]; }
float a() const { return fVec[A]; }
static SkPM4f FromPremulRGBA(float r, float g, float b, float a) {
SkPM4f p;
p.fVec[R] = r;
p.fVec[G] = g;
p.fVec[B] = b;
p.fVec[A] = a;
return p;
}
static SkPM4f From4f(const Sk4f& x) {
SkPM4f pm;
x.store(pm.fVec);
return pm;
}
static SkPM4f FromF16(const uint16_t[4]);
static SkPM4f FromPMColor(SkPMColor);
Sk4f to4f() const { return Sk4f::Load(fVec); }
Sk4f to4f_rgba() const { return this->to4f(); }
Sk4f to4f_bgra() const { return swizzle_rb(this->to4f()); }
Sk4f to4f_pmorder() const { return swizzle_rb_if_bgra(this->to4f()); }
SkPMColor toPMColor() const {
return Sk4f_toL32(swizzle_rb_if_bgra(this->to4f()));
}
void toF16(uint16_t[4]) const;
uint64_t toF16() const; // 4 float16 values packed into uint64_t
SkColor4f unpremul() const;
#ifdef SK_DEBUG
void assertIsUnit() const;
#else
void assertIsUnit() const {}
#endif
};
#endif

View File

@ -14,26 +14,19 @@
// This file is mostly helper routines for doing color space management.
// It probably wants a new name, and they likely don't need to be inline.
//
// There are two generations of routines in here, the old ones that assumed linear blending,
// and the new ones assuming as-encoded blending. We're trying to move to the new as-encoded
// ones and will hopefully eventually remove all the linear routines.
//
// We'll start with the new as-encoded routines first,
// and shove all the old broken routines towards the bottom.
static inline SkPM4f premul_in_dst_colorspace(SkColor4f color4f,
SkColorSpace* srcCS, SkColorSpace* dstCS) {
static inline SkColor4f premul_in_dst_colorspace(SkColor4f color4f,
SkColorSpace* srcCS, SkColorSpace* dstCS) {
// TODO: In the very common case of srcCS being sRGB,
// can we precompute an sRGB -> dstCS SkColorSpaceXformSteps for each device and use it here?
SkColorSpaceXformSteps(srcCS, kUnpremul_SkAlphaType,
dstCS, kPremul_SkAlphaType)
.apply(color4f.vec());
return {{color4f.fR, color4f.fG, color4f.fB, color4f.fA}};
return color4f;
}
static inline SkPM4f premul_in_dst_colorspace(SkColor c, SkColorSpace* dstCS) {
static inline SkColor4f premul_in_dst_colorspace(SkColor c, SkColorSpace* dstCS) {
SkColor4f color4f;
swizzle_rb(Sk4f_fromL32(c)).store(color4f.vec());

View File

@ -17,7 +17,6 @@
#include "SkImageShader.h"
#include "SkMask.h"
#include "SkNx.h"
#include "SkPM4f.h"
#include "SkPixmapPriv.h"
#include "SkReadPixelsRec.h"
#include "SkSurface.h"
@ -255,7 +254,8 @@ bool SkPixmap::erase(const SkColor4f& origColor, const SkIRect* subset) const {
const SkColor4f color = origColor.pin();
if (pm.colorType() == kRGBA_F16_SkColorType) {
const uint64_t half4 = color.premul().toF16();
uint64_t half4;
SkFloatToHalf_finite_ftz(Sk4f::Load(color.premul().vec())).store(&half4);
for (int y = 0; y < pm.height(); ++y) {
sk_memset64(pm.writable_addr64(0, y), half4, pm.width());
}
@ -263,14 +263,14 @@ bool SkPixmap::erase(const SkColor4f& origColor, const SkIRect* subset) const {
}
if (pm.colorType() == kRGBA_F32_SkColorType) {
const SkPM4f rgba = color.premul();
const SkColor4f rgba = color.premul();
for (int y = 0; y < pm.height(); ++y) {
auto row = (float*)pm.writable_addr(0, y);
for (int x = 0; x < pm.width(); ++x) {
row[4*x+0] = rgba.r();
row[4*x+1] = rgba.g();
row[4*x+2] = rgba.b();
row[4*x+3] = rgba.a();
row[4*x+0] = rgba.fR;
row[4*x+1] = rgba.fG;
row[4*x+2] = rgba.fB;
row[4*x+3] = rgba.fA;
}
}
return true;

View File

@ -9,9 +9,9 @@
#define SkRasterPipeline_DEFINED
#include "SkArenaAlloc.h"
#include "SkColor.h"
#include "SkImageInfo.h"
#include "SkNx.h"
#include "SkPM4f.h"
#include "SkTArray.h"
#include "SkTypes.h"
#include <functional>
@ -141,9 +141,6 @@ public:
// Tries to optimize the stage based on the color.
void append_constant_color(SkArenaAlloc*, const float rgba[4]);
void append_constant_color(SkArenaAlloc* alloc, const SkPM4f& color) {
this->append_constant_color(alloc, color.fVec);
}
void append_constant_color(SkArenaAlloc* alloc, const SkColor4f& color) {
this->append_constant_color(alloc, color.vec());
}

View File

@ -113,7 +113,7 @@ SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
#else
SkColorSpace* dstCS = dst.colorSpace();
#endif
SkPM4f paintColor = premul_in_dst_colorspace(paint.getColor4f(), sk_srgb_singleton(), dstCS);
SkColor4f paintColor = premul_in_dst_colorspace(paint.getColor4f(), sk_srgb_singleton(), dstCS);
auto shader = as_SB(paint.getShader());
@ -121,14 +121,14 @@ SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
if (!shader) {
// Having no shader makes things nice and easy... just use the paint color.
shaderPipeline.append_constant_color(alloc, paintColor);
bool is_opaque = paintColor.a() == 1.0f,
bool is_opaque = paintColor.fA == 1.0f,
is_constant = true;
return SkRasterPipelineBlitter::Create(dst, paint, alloc,
shaderPipeline, nullptr,
is_opaque, is_constant);
}
bool is_opaque = shader->isOpaque() && paintColor.a() == 1.0f;
bool is_opaque = shader->isOpaque() && paintColor.fA == 1.0f;
bool is_constant = shader->isConstant();
// Check whether the shader prefers to run in burst mode.
@ -140,9 +140,9 @@ SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst,
}
if (shader->appendStages({&shaderPipeline, alloc, dstCS, paint, nullptr, ctm})) {
if (paintColor.a() != 1.0f) {
if (paintColor.fA != 1.0f) {
shaderPipeline.append(SkRasterPipeline::scale_1_float,
alloc->make<float>(paintColor.a()));
alloc->make<float>(paintColor.fA));
}
return SkRasterPipelineBlitter::Create(dst, paint, alloc, shaderPipeline, nullptr,
is_opaque, is_constant);
@ -216,14 +216,14 @@ SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst,
// A pipeline that's still constant here can collapse back into a constant color.
if (is_constant) {
SkPM4f constantColor;
SkColor4f constantColor;
SkJumper_MemoryCtx constantColorPtr = { &constantColor, 0 };
colorPipeline->append(SkRasterPipeline::store_f32, &constantColorPtr);
colorPipeline->run(0,0,1,1);
colorPipeline->reset();
colorPipeline->append_constant_color(alloc, constantColor);
is_opaque = constantColor.a() == 1.0f;
is_opaque = constantColor.fA == 1.0f;
}
// We can strength-reduce SrcOver into Src when opaque.

View File

@ -7,6 +7,7 @@
#include "SkHighContrastFilter.h"
#include "SkArenaAlloc.h"
#include "SkColorData.h"
#include "SkRasterPipeline.h"
#include "SkReadBuffer.h"
#include "SkString.h"

View File

@ -55,8 +55,8 @@ static SkColor4f xferColor(const SkColor4f& src, const SkColor4f& dst, SkBlendMo
case SkBlendMode::kDst:
return dst;
default: {
SkPM4f pmS = src.premul();
SkPM4f pmD = dst.premul();
SkColor4f pmS = src.premul();
SkColor4f pmD = dst.premul();
return SkBlendMode_Apply(mode, pmS, pmD).unpremul();
}
}

View File

@ -19,7 +19,6 @@
#include "SkFilterQuality.h"
#include "SkImageInfo.h"
#include "SkMatrix.h"
#include "SkPM4f.h"
#include "SkVertices.h"
class GrCaps;
@ -64,21 +63,6 @@ GrColor4f SkColorToPremulGrColor4f(SkColor, const GrColorSpaceInfo&);
GrColor4f SkColor4fToPremulGrColor4fLegacy(SkColor4f);
GrColor4f SkColor4fToUnpremulGrColor4f(SkColor4f, const GrColorSpaceInfo&);
//////////////////////////////////////////////////////////////////////////////
static inline SkPM4f GrColor4fToSkPM4f(const GrColor4f& c) {
SkPM4f pm4f;
pm4f.fVec[SkPM4f::R] = c.fRGBA[0];
pm4f.fVec[SkPM4f::G] = c.fRGBA[1];
pm4f.fVec[SkPM4f::B] = c.fRGBA[2];
pm4f.fVec[SkPM4f::A] = c.fRGBA[3];
return pm4f;
}
static inline GrColor4f SkPM4fToGrColor4f(const SkPM4f& c) {
return GrColor4f{c.r(), c.g(), c.b(), c.a()};
}
////////////////////////////////////////////////////////////////////////////////
// Paint conversion

View File

@ -151,10 +151,10 @@ private:
input = input.opaque();
GrColor4f srcColor = ConstantOutputForConstantInput(this->childProcessor(0), input);
GrColor4f dstColor = ConstantOutputForConstantInput(this->childProcessor(1), input);
SkPM4f src = GrColor4fToSkPM4f(srcColor);
SkPM4f dst = GrColor4fToSkPM4f(dstColor);
SkPM4f res = SkBlendMode_Apply(fMode, src, dst);
return SkPM4fToGrColor4f(res).mulByScalar(alpha);
SkColor4f src = srcColor.toSkColor4f();
SkColor4f dst = dstColor.toSkColor4f();
SkColor4f res = SkBlendMode_Apply(fMode, src, dst);
return GrColor4f::FromSkColor4f(res).mulByScalar(alpha);
}
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
@ -406,16 +406,16 @@ private:
GrColor4f constantOutputForConstantInput(GrColor4f inputColor) const override {
GrColor4f childColor =
ConstantOutputForConstantInput(this->childProcessor(0), GrColor4f::OpaqueWhite());
SkPM4f src, dst;
SkColor4f src, dst;
if (kSrc_Child == fChild) {
src = GrColor4fToSkPM4f(childColor);
dst = GrColor4fToSkPM4f(inputColor);
src = childColor.toSkColor4f();
dst = inputColor.toSkColor4f();
} else {
src = GrColor4fToSkPM4f(inputColor);
dst = GrColor4fToSkPM4f(childColor);
src = inputColor.toSkColor4f();
dst = childColor.toSkColor4f();
}
SkPM4f res = SkBlendMode_Apply(fMode, src, dst);
return SkPM4fToGrColor4f(res);
SkColor4f res = SkBlendMode_Apply(fMode, src, dst);
return GrColor4f::FromSkColor4f(res);
}
private:

View File

@ -56,7 +56,7 @@ SkColorShader::ColorShaderContext::ColorShaderContext(const SkColorShader& shade
SkColor4f c4 = SkColor4f::FromColor(shader.fColor);
c4.fA *= rec.fPaint->getAlpha() / 255.0f;
fPM4f = c4.premul();
fPM4f = c4.toPM4f();
fFlags = kConstInY32_Flag;
if (255 == a) {
@ -171,7 +171,7 @@ SkColor4Shader::Color4Context::Color4Context(const SkColor4Shader& shader,
SkColor4f c4 = shader.fColor4;
c4.fA *= rec.fPaint->getAlpha() * (1 / 255.0f);
fPM4f = c4.premul();
fPM4f = c4.toPM4f();
fFlags = kConstInY32_Flag;
if (255 == a) {

View File

@ -13,7 +13,7 @@ namespace {
Sk4f pack_color(const SkColor4f& c4f, bool premul, const Sk4f& component_scale) {
Sk4f pm4f = premul
? c4f.premul().to4f()
? c4f.toPM4f().to4f()
: Sk4f{c4f.fR, c4f.fG, c4f.fB, c4f.fA};
if (premul) {

View File

@ -229,7 +229,7 @@ static void add_stop_color(SkJumper_GradientCtx* ctx, size_t stop, SkPM4f Fs, Sk
}
static void add_const_color(SkJumper_GradientCtx* ctx, size_t stop, SkPM4f color) {
add_stop_color(ctx, stop, SkPM4f::FromPremulRGBA(0,0,0,0), color);
add_stop_color(ctx, stop, {{ 0, 0, 0, 0 }}, color);
}
// Calculate a factor F and a bias B so that color = F*t + B when t is in range of
@ -317,7 +317,7 @@ bool SkGradientShaderBase::onAppendStages(const StageRec& rec) const {
auto prepareColor = [premulGrad, &xformedColors](int i) {
SkColor4f c = xformedColors.fColors[i];
return premulGrad ? c.premul()
return premulGrad ? c.toPM4f()
: SkPM4f::From4f(Sk4f::Load(&c));
};

View File

@ -215,45 +215,9 @@ void SkPatchUtils::GetRightCubic(const SkPoint cubics[12], SkPoint points[4]) {
points[3] = cubics[kRightP3_CubicCtrlPts];
}
#include "SkPM4fPriv.h"
#include "SkColorSpaceXform.h"
struct SkRGBAf {
float fVec[4];
static SkRGBAf From4f(const Sk4f& x) {
SkRGBAf c;
x.store(c.fVec);
return c;
}
static SkRGBAf FromBGRA32(SkColor c) {
return From4f(swizzle_rb(SkNx_cast<float>(Sk4b::Load(&c)) * (1/255.0f)));
}
Sk4f to4f() const {
return Sk4f::Load(fVec);
}
SkColor toBGRA32() const {
SkColor color;
SkNx_cast<uint8_t>(swizzle_rb(this->to4f()) * Sk4f(255) + Sk4f(0.5f)).store(&color);
return color;
}
SkRGBAf premul() const {
float a = fVec[3];
return From4f(this->to4f() * Sk4f(a, a, a, 1));
}
SkRGBAf unpremul() const {
float a = fVec[3];
float inv = a ? 1/a : 0;
return From4f(this->to4f() * Sk4f(inv, inv, inv, 1));
}
};
static void skcolor_to_float(SkRGBAf dst[], const SkColor src[], int count, SkColorSpace* dstCS,
static void skcolor_to_float(SkColor4f dst[], const SkColor src[], int count, SkColorSpace* dstCS,
bool doPremul) {
// Source is always sRGB SkColor.
auto srcCS = sk_srgb_singleton();
@ -264,7 +228,7 @@ static void skcolor_to_float(SkRGBAf dst[], const SkColor src[], int count, SkCo
count, op));
}
static void float_to_skcolor(SkColor dst[], const SkRGBAf src[], int count, SkColorSpace* srcCS) {
static void float_to_skcolor(SkColor dst[], const SkColor4f src[], int count, SkColorSpace* srcCS) {
// Destination is always sRGB SkColor.
auto dstCS = sk_srgb_singleton();
SkAssertResult(SkColorSpaceXform::Apply(dstCS, SkColorSpaceXform::kBGRA_8888_ColorFormat, dst,
@ -272,7 +236,7 @@ static void float_to_skcolor(SkColor dst[], const SkRGBAf src[], int count, SkCo
count, SkColorSpaceXform::kPreserve_AlphaOp));
}
static void unpremul(SkRGBAf array[], int count) {
static void unpremul(SkColor4f array[], int count) {
for (int i = 0; i < count; ++i) {
array[i] = array[i].unpremul();
}
@ -322,8 +286,8 @@ sk_sp<SkVertices> SkPatchUtils::MakeVertices(const SkPoint cubics[12], const SkC
}
SkSTArenaAlloc<2048> alloc;
SkRGBAf* cornerColors = srcColors ? alloc.makeArray<SkRGBAf>(4) : nullptr;
SkRGBAf* tmpColors = srcColors ? alloc.makeArray<SkRGBAf>(vertexCount) : nullptr;
SkColor4f* cornerColors = srcColors ? alloc.makeArray<SkColor4f>(4) : nullptr;
SkColor4f* tmpColors = srcColors ? alloc.makeArray<SkColor4f>(vertexCount) : nullptr;
SkVertices::Builder builder(SkVertices::kTriangles_VertexMode, vertexCount, indexCount, flags);
SkPoint* pos = builder.positions();
@ -391,12 +355,13 @@ sk_sp<SkVertices> SkPatchUtils::MakeVertices(const SkPoint cubics[12], const SkC
pos[dataIndex] = s0 + s1 - s2;
if (cornerColors) {
bilerp(u, v, cornerColors[kTopLeft_Corner].to4f(),
cornerColors[kTopRight_Corner].to4f(),
cornerColors[kBottomLeft_Corner].to4f(),
cornerColors[kBottomRight_Corner].to4f()).store(tmpColors[dataIndex].fVec);
bilerp(u, v, Sk4f::Load(cornerColors[kTopLeft_Corner].vec()),
Sk4f::Load(cornerColors[kTopRight_Corner].vec()),
Sk4f::Load(cornerColors[kBottomLeft_Corner].vec()),
Sk4f::Load(cornerColors[kBottomRight_Corner].vec()))
.store(tmpColors[dataIndex].vec());
if (is_opaque) {
tmpColors[dataIndex].fVec[3] = 1;
tmpColors[dataIndex].fA = 1;
}
}

View File

@ -9,7 +9,6 @@
#include "SkColor.h"
#include "SkHalf.h"
#include "SkOpts.h"
#include "SkPM4f.h"
#include "SkPixmap.h"
#include "SkRandom.h"
#include "SkTo.h"
@ -17,47 +16,6 @@
#include <cmath>
static bool eq_within_half_float(float a, float b) {
const float kTolerance = 1.0f / (1 << (8 + 10));
SkHalf ha = SkFloatToHalf(a);
SkHalf hb = SkFloatToHalf(b);
float a2 = SkHalfToFloat(ha);
float b2 = SkHalfToFloat(hb);
return fabsf(a2 - b2) <= kTolerance;
}
static bool eq_within_half_float(const SkPM4f& a, const SkPM4f& b) {
for (int i = 0; i < 4; ++i) {
if (!eq_within_half_float(a.fVec[i], b.fVec[i])) {
return false;
}
}
return true;
}
DEF_TEST(color_half_float, reporter) {
const int w = 100;
const int h = 100;
SkImageInfo info = SkImageInfo::Make(w, h, kRGBA_F16_SkColorType, kPremul_SkAlphaType);
SkAutoPixmapStorage pm;
pm.alloc(info);
REPORTER_ASSERT(reporter, pm.computeByteSize() == SkToSizeT(w * h * sizeof(uint64_t)));
SkColor4f c4 { 1, 0.5f, 0.25f, 0.5f };
pm.erase(c4);
SkPM4f origpm4 = c4.premul();
for (int y = 0; y < pm.height(); ++y) {
for (int x = 0; x < pm.width(); ++x) {
SkPM4f pm4 = SkPM4f::FromF16(pm.addrF16(x, y));
REPORTER_ASSERT(reporter, eq_within_half_float(origpm4, pm4));
}
}
}
static bool is_denorm(uint16_t h) {
return (h & 0x7fff) < 0x0400;
}

View File

@ -5,23 +5,8 @@
* found in the LICENSE file.
*/
#include "SkBitmapProcShader.h"
#include "SkColor.h"
#include "SkColorMatrixFilter.h"
#include "SkGradientShader.h"
#include "SkImage.h"
#include "SkPM4f.h"
#include "SkShader.h"
#include "Test.h"
#include "SkRandom.h"
const float kTolerance = 1.0f / (1 << 20);
static bool nearly_equal(float a, float b, float tol = kTolerance) {
SkASSERT(tol >= 0);
return fabsf(a - b) <= tol;
}
DEF_TEST(SkColor4f_FromColor, reporter) {
const struct {
@ -41,28 +26,3 @@ DEF_TEST(SkColor4f_FromColor, reporter) {
REPORTER_ASSERT(reporter, c4 == r.fC4);
}
}
DEF_TEST(Color4f_premul, reporter) {
SkRandom rand;
for (int i = 0; i < 1000000; ++i) {
// First just test opaque colors, so that the premul should be exact
SkColor4f c4 {
rand.nextUScalar1(), rand.nextUScalar1(), rand.nextUScalar1(), 1
};
SkPM4f pm4 = c4.premul();
REPORTER_ASSERT(reporter, pm4.a() == c4.fA);
REPORTER_ASSERT(reporter, pm4.r() == c4.fA * c4.fR);
REPORTER_ASSERT(reporter, pm4.g() == c4.fA * c4.fG);
REPORTER_ASSERT(reporter, pm4.b() == c4.fA * c4.fB);
// We compare with a tolerance, in case our premul multiply is implemented at slightly
// different precision than the test code.
c4.fA = rand.nextUScalar1();
pm4 = c4.premul();
REPORTER_ASSERT(reporter, pm4.fVec[SK_A_INDEX] == c4.fA);
REPORTER_ASSERT(reporter, nearly_equal(pm4.r(), c4.fA * c4.fR));
REPORTER_ASSERT(reporter, nearly_equal(pm4.g(), c4.fA * c4.fG));
REPORTER_ASSERT(reporter, nearly_equal(pm4.b(), c4.fA * c4.fB));
}
}