Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(178)

Unified Diff: src/effects/gradients/SkGradientShader.cpp

Issue 2337313002: (Some) gradients are gamma and gamut correct on GPU (Closed)
Patch Set: Rebase Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/effects/gradients/SkGradientShader.cpp
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 14e67842b337b3addb15f45e51630fae65541c52..60767f876d2ea4b69f396ad3bd08531ea2ed9488 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -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;
@@ -748,6 +788,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;
@@ -1032,6 +1074,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) {
@@ -1085,10 +1173,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;
@@ -1340,7 +1440,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);
}
@@ -1440,7 +1544,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;
}
@@ -1449,10 +1554,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;

Powered by Google App Engine
This is Rietveld 408576698