Add storage and computation of SkColor4f version of gradient stops.
For now, we still only have the SkColor factory, but the Descriptor can now carry either an SkColor or SkColor4f specified gradient. Base class constructor automatically populates both forms of color, so that legacy raster backend will continue to work, and new backend work can operate directly from the float4 version. On the GPU side, we have similar logic, but GrGradientEffect only keeps one version of colors around: SkColor if the destination is legacy, and SkColor4f (with an optional gamut xform) if the destination is gamma correct. The 4f colors are already linear, and we gamut xform them in setData, so gradients are now fully color-correct in sRGB and F16 modes... ... unless there are more than three stops. Then we use a texture, and that code path isn't handled yet. We have a few choices here (do we use an 8-bit sRGB atlas, or just always use F16 linear atlas so we can share it among both sRGB and wide-gamut rendering). In any case, I'd like to defer that to a second CL. This change does fix the non-texture gradients in the gamut GM. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2337313002 Review-Url: https://codereview.chromium.org/2337313002
This commit is contained in:
parent
1949386ae0
commit
b9c5137a1c
@ -23,7 +23,7 @@ public:
|
||||
|
||||
static sk_sp<GrColorSpaceXform> Make(SkColorSpace* src, SkColorSpace* dst);
|
||||
|
||||
const SkMatrix44& srcToDst() { return fSrcToDst; }
|
||||
const SkMatrix44& srcToDst() const { return fSrcToDst; }
|
||||
|
||||
/**
|
||||
* GrGLSLFragmentProcessor::GenKey() must call this and include the returned value in its
|
||||
@ -34,6 +34,8 @@ public:
|
||||
return SkToBool(xform) ? 1 : 0;
|
||||
}
|
||||
|
||||
static bool Equals(const GrColorSpaceXform* a, const GrColorSpaceXform* b);
|
||||
|
||||
GrColor4f apply(const GrColor4f& srcColor);
|
||||
|
||||
private:
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
void SkGradientShaderBase::Descriptor::flatten(SkWriteBuffer& buffer) const {
|
||||
buffer.writeColorArray(fColors, fCount);
|
||||
// TODO: Flatten fColors4f and fColorSpace
|
||||
if (fPos) {
|
||||
buffer.writeBool(true);
|
||||
buffer.writeScalarArray(fPos, fCount);
|
||||
@ -31,6 +32,7 @@ void SkGradientShaderBase::Descriptor::flatten(SkWriteBuffer& buffer) const {
|
||||
}
|
||||
|
||||
bool SkGradientShaderBase::DescriptorScope::unflatten(SkReadBuffer& buffer) {
|
||||
// TODO: Unflatten fColors4f and fColorSpace
|
||||
fCount = buffer.getArrayCount();
|
||||
if (fCount > kStorageCount) {
|
||||
size_t allocSize = (sizeof(SkColor) + sizeof(SkScalar)) * fCount;
|
||||
@ -103,7 +105,7 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatri
|
||||
}
|
||||
|
||||
if (fColorCount > kColorStorageCount) {
|
||||
size_t size = sizeof(SkColor) + sizeof(Rec);
|
||||
size_t size = sizeof(SkColor) + sizeof(SkColor4f) + sizeof(Rec);
|
||||
if (desc.fPos) {
|
||||
size += sizeof(SkScalar);
|
||||
}
|
||||
@ -114,8 +116,14 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatri
|
||||
fOrigColors = fStorage;
|
||||
}
|
||||
|
||||
// Now copy over the colors, adding the dummies as needed
|
||||
{
|
||||
fOrigColors4f = (SkColor4f*)(fOrigColors + fColorCount);
|
||||
|
||||
// We should have been supplied with either fColors *or* (fColors4f and fColorSpace)
|
||||
if (desc.fColors) {
|
||||
// TODO: Should we support alternate gamma-encoded colorspaces with SkColor inputs?
|
||||
SkASSERT(!desc.fColors4f && !desc.fColorSpace);
|
||||
|
||||
// Now copy over the colors, adding the dummies as needed
|
||||
SkColor* origColors = fOrigColors;
|
||||
if (dummyFirst) {
|
||||
*origColors++ = desc.fColors[0];
|
||||
@ -125,14 +133,44 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatri
|
||||
origColors += desc.fCount;
|
||||
*origColors = desc.fColors[desc.fCount - 1];
|
||||
}
|
||||
|
||||
// Convert our SkColor colors to SkColor4f as well
|
||||
for (int i = 0; i < fColorCount; ++i) {
|
||||
fOrigColors4f[i] = SkColor4f::FromColor(fOrigColors[i]);
|
||||
}
|
||||
|
||||
// Color space refers to fColors4f, so it's always linear gamma
|
||||
fColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)->makeLinearGamma();
|
||||
} else {
|
||||
SkASSERT(desc.fColors4f && desc.fColorSpace && desc.fColorSpace->gammaIsLinear());
|
||||
|
||||
// Now copy over the colors, adding the dummies as needed
|
||||
SkColor4f* origColors = fOrigColors4f;
|
||||
if (dummyFirst) {
|
||||
*origColors++ = desc.fColors4f[0];
|
||||
}
|
||||
memcpy(origColors, desc.fColors4f, desc.fCount * sizeof(SkColor4f));
|
||||
if (dummyLast) {
|
||||
origColors += desc.fCount;
|
||||
*origColors = desc.fColors4f[desc.fCount - 1];
|
||||
}
|
||||
|
||||
// Convert our SkColor4f colors to SkColor as well. Note that this is incorrect if the
|
||||
// source colors are not in sRGB gamut. We would need to do a gamut transformation, but
|
||||
// SkColorSpaceXform can't do that (yet). GrColorSpaceXform can, but we may not have GPU
|
||||
// support compiled in here.
|
||||
for (int i = 0; i < fColorCount; ++i) {
|
||||
fOrigColors[i] = fOrigColors4f[i].toSkColor();
|
||||
}
|
||||
fColorSpace = desc.fColorSpace;
|
||||
}
|
||||
|
||||
if (desc.fPos && fColorCount) {
|
||||
fOrigPos = (SkScalar*)(fOrigColors + fColorCount);
|
||||
fOrigPos = (SkScalar*)(fOrigColors4f + fColorCount);
|
||||
fRecs = (Rec*)(fOrigPos + fColorCount);
|
||||
} else {
|
||||
fOrigPos = nullptr;
|
||||
fRecs = (Rec*)(fOrigColors + fColorCount);
|
||||
fRecs = (Rec*)(fOrigColors4f + fColorCount);
|
||||
}
|
||||
|
||||
if (fColorCount > 2) {
|
||||
@ -218,6 +256,8 @@ void SkGradientShaderBase::initCommon() {
|
||||
void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const {
|
||||
Descriptor desc;
|
||||
desc.fColors = fOrigColors;
|
||||
desc.fColors4f = fOrigColors4f;
|
||||
desc.fColorSpace = fColorSpace;
|
||||
desc.fPos = fOrigPos;
|
||||
desc.fCount = fColorCount;
|
||||
desc.fTileMode = fTileMode;
|
||||
@ -661,6 +701,8 @@ static void desc_init(SkGradientShaderBase::Descriptor* desc,
|
||||
SkASSERT(colorCount > 1);
|
||||
|
||||
desc->fColors = colors;
|
||||
desc->fColors4f = nullptr;
|
||||
desc->fColorSpace = nullptr; // SkColor is always sRGB
|
||||
desc->fPos = pos;
|
||||
desc->fCount = colorCount;
|
||||
desc->fTileMode = mode;
|
||||
@ -945,6 +987,52 @@ void GrGradientEffect::GLSLProcessor::emitUniforms(GrGLSLUniformHandler* uniform
|
||||
}
|
||||
}
|
||||
|
||||
static inline void set_after_interp_color_uni_array(
|
||||
const GrGLSLProgramDataManager& pdman,
|
||||
const GrGLSLProgramDataManager::UniformHandle uni,
|
||||
const SkTDArray<SkColor4f>& colors,
|
||||
const GrColorSpaceXform* colorSpaceXform) {
|
||||
int count = colors.count();
|
||||
if (colorSpaceXform) {
|
||||
constexpr int kSmallCount = 10;
|
||||
SkAutoSTArray<4 * kSmallCount, float> vals(4 * count);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
colorSpaceXform->srcToDst().mapScalars(colors[i].vec(), &vals[4 * i]);
|
||||
}
|
||||
|
||||
pdman.set4fv(uni, count, vals.get());
|
||||
} else {
|
||||
pdman.set4fv(uni, count, (float*)&colors[0]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void set_before_interp_color_uni_array(
|
||||
const GrGLSLProgramDataManager& pdman,
|
||||
const GrGLSLProgramDataManager::UniformHandle uni,
|
||||
const SkTDArray<SkColor4f>& colors,
|
||||
const GrColorSpaceXform* colorSpaceXform) {
|
||||
int count = colors.count();
|
||||
constexpr int kSmallCount = 10;
|
||||
SkAutoSTArray<4 * kSmallCount, float> vals(4 * count);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
float a = colors[i].fA;
|
||||
vals[4 * i + 0] = colors[i].fR * a;
|
||||
vals[4 * i + 1] = colors[i].fG * a;
|
||||
vals[4 * i + 2] = colors[i].fB * a;
|
||||
vals[4 * i + 3] = a;
|
||||
}
|
||||
|
||||
if (colorSpaceXform) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
colorSpaceXform->srcToDst().mapScalars(&vals[4 * i]);
|
||||
}
|
||||
}
|
||||
|
||||
pdman.set4fv(uni, count, vals.get());
|
||||
}
|
||||
|
||||
static inline void set_after_interp_color_uni_array(const GrGLSLProgramDataManager& pdman,
|
||||
const GrGLSLProgramDataManager::UniformHandle uni,
|
||||
const SkTDArray<SkColor>& colors) {
|
||||
@ -998,10 +1086,22 @@ void GrGradientEffect::GLSLProcessor::onSetData(const GrGLSLProgramDataManager&
|
||||
#endif
|
||||
case GrGradientEffect::kTwo_ColorType:
|
||||
case GrGradientEffect::kThree_ColorType: {
|
||||
if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
|
||||
set_before_interp_color_uni_array(pdman, fColorsUni, e.fColors);
|
||||
if (e.fColors4f.count() > 0) {
|
||||
// Gamma-correct / color-space aware
|
||||
if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
|
||||
set_before_interp_color_uni_array(pdman, fColorsUni, e.fColors4f,
|
||||
e.fColorSpaceXform.get());
|
||||
} else {
|
||||
set_after_interp_color_uni_array(pdman, fColorsUni, e.fColors4f,
|
||||
e.fColorSpaceXform.get());
|
||||
}
|
||||
} else {
|
||||
set_after_interp_color_uni_array(pdman, fColorsUni, e.fColors);
|
||||
// Legacy mode. Would be nice if we had converted the 8-bit colors to float earlier
|
||||
if (GrGradientEffect::kBeforeInterp_PremulType == e.getPremulType()) {
|
||||
set_before_interp_color_uni_array(pdman, fColorsUni, e.fColors);
|
||||
} else {
|
||||
set_after_interp_color_uni_array(pdman, fColorsUni, e.fColors);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@ -1253,7 +1353,11 @@ GrGradientEffect::GrGradientEffect(const CreateArgs& args) {
|
||||
fColorType = this->determineColorType(shader);
|
||||
|
||||
if (kTexture_ColorType != fColorType) {
|
||||
if (shader.fOrigColors) {
|
||||
SkASSERT(shader.fOrigColors && shader.fOrigColors4f);
|
||||
if (args.fGammaCorrect) {
|
||||
fColors4f = SkTDArray<SkColor4f>(shader.fOrigColors4f, shader.fColorCount);
|
||||
fColorSpaceXform = std::move(args.fColorSpaceXform);
|
||||
} else {
|
||||
fColors = SkTDArray<SkColor>(shader.fOrigColors, shader.fColorCount);
|
||||
}
|
||||
|
||||
@ -1353,7 +1457,8 @@ bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const {
|
||||
}
|
||||
} else {
|
||||
if (this->getPremulType() != ge.getPremulType() ||
|
||||
this->fColors.count() != ge.fColors.count()) {
|
||||
this->fColors.count() != ge.fColors.count() ||
|
||||
this->fColors4f.count() != ge.fColors4f.count()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1362,10 +1467,16 @@ bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < this->fColors4f.count(); i++) {
|
||||
if (*this->getColors4f(i) != *ge.getColors4f(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SkASSERT(this->useAtlas() == ge.useAtlas());
|
||||
return true;
|
||||
return GrColorSpaceXform::Equals(this->fColorSpaceXform.get(), ge.fColorSpaceXform.get());
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "SkGradientShader.h"
|
||||
#include "SkClampRange.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkColorSpace.h"
|
||||
#include "SkReadBuffer.h"
|
||||
#include "SkWriteBuffer.h"
|
||||
#include "SkMallocPixelRef.h"
|
||||
@ -84,6 +85,8 @@ public:
|
||||
|
||||
const SkMatrix* fLocalMatrix;
|
||||
const SkColor* fColors;
|
||||
const SkColor4f* fColors4f;
|
||||
sk_sp<SkColorSpace> fColorSpace;
|
||||
const SkScalar* fPos;
|
||||
int fCount;
|
||||
SkShader::TileMode fTileMode;
|
||||
@ -226,13 +229,16 @@ private:
|
||||
enum {
|
||||
kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
|
||||
|
||||
kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(SkScalar) + sizeof(Rec))
|
||||
kStorageSize = kColorStorageCount *
|
||||
(sizeof(SkColor) + sizeof(SkScalar) + sizeof(Rec) + sizeof(SkColor4f))
|
||||
};
|
||||
SkColor fStorage[(kStorageSize + 3) >> 2];
|
||||
SkColor fStorage[(kStorageSize + 3) >> 2];
|
||||
public:
|
||||
SkColor* fOrigColors; // original colors, before modulation by paint in context.
|
||||
SkScalar* fOrigPos; // original positions
|
||||
int fColorCount;
|
||||
SkColor* fOrigColors; // original colors, before modulation by paint in context.
|
||||
SkColor4f* fOrigColors4f; // original colors, as linear floats
|
||||
SkScalar* fOrigPos; // original positions
|
||||
int fColorCount;
|
||||
sk_sp<SkColorSpace> fColorSpace; // color space of gradient stops
|
||||
|
||||
bool colorsAreOpaque() const { return fColorsAreOpaque; }
|
||||
|
||||
@ -240,7 +246,7 @@ public:
|
||||
Rec* getRecs() const { return fRecs; }
|
||||
|
||||
private:
|
||||
bool fColorsAreOpaque;
|
||||
bool fColorsAreOpaque;
|
||||
|
||||
GradientShaderCache* refCache(U8CPU alpha, bool dither) const;
|
||||
mutable SkMutex fCacheMutex;
|
||||
@ -265,6 +271,7 @@ static inline int next_dither_toggle(int toggle) {
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
#include "GrColorSpaceXform.h"
|
||||
#include "GrCoordTransform.h"
|
||||
#include "GrFragmentProcessor.h"
|
||||
#include "glsl/GrGLSLFragmentProcessor.h"
|
||||
@ -304,16 +311,22 @@ public:
|
||||
CreateArgs(GrContext* context,
|
||||
const SkGradientShaderBase* shader,
|
||||
const SkMatrix* matrix,
|
||||
SkShader::TileMode tileMode)
|
||||
SkShader::TileMode tileMode,
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform,
|
||||
bool gammaCorrect)
|
||||
: fContext(context)
|
||||
, fShader(shader)
|
||||
, fMatrix(matrix)
|
||||
, fTileMode(tileMode) {}
|
||||
, fTileMode(tileMode)
|
||||
, fColorSpaceXform(std::move(colorSpaceXform))
|
||||
, fGammaCorrect(gammaCorrect) {}
|
||||
|
||||
GrContext* fContext;
|
||||
const SkGradientShaderBase* fShader;
|
||||
const SkMatrix* fMatrix;
|
||||
SkShader::TileMode fTileMode;
|
||||
sk_sp<GrColorSpaceXform> fColorSpaceXform;
|
||||
bool fGammaCorrect;
|
||||
};
|
||||
|
||||
class GLSLProcessor;
|
||||
@ -361,6 +374,12 @@ public:
|
||||
return &fColors[pos];
|
||||
}
|
||||
|
||||
const SkColor4f* getColors4f(int pos) const {
|
||||
SkASSERT(fColorType != kTexture_ColorType);
|
||||
SkASSERT(pos < fColors4f.count());
|
||||
return &fColors4f[pos];
|
||||
}
|
||||
|
||||
protected:
|
||||
/** Populates a pair of arrays with colors and stop info to construct a random gradient.
|
||||
The function decides whether stop values should be used or not. The return value indicates
|
||||
@ -384,9 +403,15 @@ protected:
|
||||
private:
|
||||
static const GrCoordSet kCoordSet = kLocal_GrCoordSet;
|
||||
|
||||
SkTDArray<SkColor> fColors;
|
||||
SkTDArray<SkScalar> fPositions;
|
||||
SkShader::TileMode fTileMode;
|
||||
// If we're in legacy mode, then fColors will be populated. If we're gamma-correct, then
|
||||
// fColors4f and fColorSpaceXform will be populated.
|
||||
SkTDArray<SkColor> fColors;
|
||||
|
||||
SkTDArray<SkColor4f> fColors4f;
|
||||
sk_sp<GrColorSpaceXform> fColorSpaceXform;
|
||||
|
||||
SkTDArray<SkScalar> fPositions;
|
||||
SkShader::TileMode fTileMode;
|
||||
|
||||
GrCoordTransform fCoordTransform;
|
||||
GrTextureAccess fTextureAccess;
|
||||
|
@ -341,6 +341,7 @@ SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const {
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
#include "GrColorSpaceXform.h"
|
||||
#include "glsl/GrGLSLCaps.h"
|
||||
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
||||
#include "SkGr.h"
|
||||
@ -461,8 +462,11 @@ sk_sp<GrFragmentProcessor> SkLinearGradient::asFragmentProcessor(const AsFPArgs&
|
||||
}
|
||||
matrix.postConcat(fPtsToUnit);
|
||||
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
|
||||
args.fDstColorSpace);
|
||||
sk_sp<GrFragmentProcessor> inner(GrLinearGradient::Make(
|
||||
GrGradientEffect::CreateArgs(args.fContext, this, &matrix, fTileMode)));
|
||||
GrGradientEffect::CreateArgs(args.fContext, this, &matrix, fTileMode,
|
||||
std::move(colorSpaceXform), SkToBool(args.fDstColorSpace))));
|
||||
return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
|
||||
}
|
||||
|
||||
|
@ -355,8 +355,11 @@ sk_sp<GrFragmentProcessor> SkRadialGradient::asFragmentProcessor(const AsFPArgs&
|
||||
matrix.postConcat(inv);
|
||||
}
|
||||
matrix.postConcat(fPtsToUnit);
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
|
||||
args.fDstColorSpace);
|
||||
sk_sp<GrFragmentProcessor> inner(GrRadialGradient::Make(
|
||||
GrGradientEffect::CreateArgs(args.fContext, this, &matrix, fTileMode)));
|
||||
GrGradientEffect::CreateArgs(args.fContext, this, &matrix, fTileMode,
|
||||
std::move(colorSpaceXform), SkToBool(args.fDstColorSpace))));
|
||||
return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
|
||||
}
|
||||
|
||||
|
@ -247,8 +247,11 @@ sk_sp<GrFragmentProcessor> SkSweepGradient::asFragmentProcessor(const AsFPArgs&
|
||||
}
|
||||
matrix.postConcat(fPtsToUnit);
|
||||
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
|
||||
args.fDstColorSpace);
|
||||
sk_sp<GrFragmentProcessor> inner(GrSweepGradient::Make(
|
||||
GrGradientEffect::CreateArgs(args.fContext, this, &matrix, SkShader::kClamp_TileMode)));
|
||||
GrGradientEffect::CreateArgs(args.fContext, this, &matrix, SkShader::kClamp_TileMode,
|
||||
std::move(colorSpaceXform), SkToBool(args.fDstColorSpace))));
|
||||
return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
|
||||
}
|
||||
|
||||
|
@ -360,8 +360,11 @@ sk_sp<GrFragmentProcessor> SkTwoPointConicalGradient::asFragmentProcessor(
|
||||
const AsFPArgs& args) const {
|
||||
SkASSERT(args.fContext);
|
||||
SkASSERT(fPtsToUnit.isIdentity());
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(fColorSpace.get(),
|
||||
args.fDstColorSpace);
|
||||
sk_sp<GrFragmentProcessor> inner(Gr2PtConicalGradientEffect::Make(
|
||||
GrGradientEffect::CreateArgs(args.fContext, this, args.fLocalMatrix, fTileMode)));
|
||||
GrGradientEffect::CreateArgs(args.fContext, this, args.fLocalMatrix, fTileMode,
|
||||
std::move(colorSpaceXform), SkToBool(args.fDstColorSpace))));
|
||||
return GrFragmentProcessor::MulOutputByInputAlpha(std::move(inner));
|
||||
}
|
||||
|
||||
|
@ -1306,7 +1306,8 @@ sk_sp<GrFragmentProcessor> Gr2PtConicalGradientEffect::Make(
|
||||
matrix.postConcat(inv);
|
||||
}
|
||||
|
||||
GrGradientEffect::CreateArgs newArgs(args.fContext, args.fShader, &matrix, args.fTileMode);
|
||||
GrGradientEffect::CreateArgs newArgs(args.fContext, args.fShader, &matrix, args.fTileMode,
|
||||
std::move(args.fColorSpaceXform), args.fGammaCorrect);
|
||||
|
||||
if (shader.getStartRadius() < kErrorTol) {
|
||||
SkScalar focalX;
|
||||
|
@ -59,6 +59,18 @@ sk_sp<GrColorSpaceXform> GrColorSpaceXform::Make(SkColorSpace* src, SkColorSpace
|
||||
return sk_make_sp<GrColorSpaceXform>(srcToDst);
|
||||
}
|
||||
|
||||
bool GrColorSpaceXform::Equals(const GrColorSpaceXform* a, const GrColorSpaceXform* b) {
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!a || !b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return a->fSrcToDst == b->fSrcToDst;
|
||||
}
|
||||
|
||||
GrColor4f GrColorSpaceXform::apply(const GrColor4f& srcColor) {
|
||||
GrColor4f result;
|
||||
fSrcToDst.mapScalars(srcColor.fRGBA, result.fRGBA);
|
||||
|
Loading…
Reference in New Issue
Block a user