Add color gamut xform helpers to GrGLSLShaderBuilder
New helper functions inject the necessary shader function. Texture lookup functions can now insert the gamut xform at the appropriate place, too. As written, could be used to transform non-texture colors (e.g. vertex colors) as well. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2180803005 Review-Url: https://codereview.chromium.org/2180803005
This commit is contained in:
parent
d2e39dbc6a
commit
77320dbabc
@ -8,6 +8,7 @@
|
||||
#ifndef GrColorSpaceXform_DEFINED
|
||||
#define GrColorSpaceXform_DEFINED
|
||||
|
||||
#include "SkImageInfo.h"
|
||||
#include "SkRefCnt.h"
|
||||
|
||||
class SkColorSpace;
|
||||
@ -18,15 +19,32 @@ class SkMatrix44;
|
||||
*/
|
||||
class GrColorSpaceXform : public SkRefCnt {
|
||||
public:
|
||||
GrColorSpaceXform(const SkMatrix44& srcToDst);
|
||||
GrColorSpaceXform(const SkMatrix44& srcToDst, SkAlphaType srcAlphaType);
|
||||
|
||||
static sk_sp<GrColorSpaceXform> Make(SkColorSpace* src, SkColorSpace* dst);
|
||||
static sk_sp<GrColorSpaceXform> Make(SkColorSpace* src, SkColorSpace* dst,
|
||||
SkAlphaType srcAlphaType);
|
||||
|
||||
const float* srcToDst() { return fSrcToDst; }
|
||||
SkAlphaType alphaType() const { return fSrcAlphaType; }
|
||||
|
||||
/**
|
||||
* GrGLSLFragmentProcessor::GenKey() must call this and include the returned value in its
|
||||
* computed key.
|
||||
*/
|
||||
static uint32_t XformKey(GrColorSpaceXform* xform) {
|
||||
if (!xform) {
|
||||
return 0;
|
||||
}
|
||||
// Code generation just depends on whether the alpha type is premul or not
|
||||
return kPremul_SkAlphaType == xform->fSrcAlphaType ? 1 : 2;
|
||||
}
|
||||
|
||||
private:
|
||||
// We store the column-major form of the srcToDst matrix, for easy uploading to uniforms
|
||||
float fSrcToDst[16];
|
||||
|
||||
// Alpha type of the source. If it's premul, we need special handling
|
||||
SkAlphaType fSrcAlphaType;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -34,11 +34,13 @@ static inline bool matrix_is_almost_identity(const SkMatrix44& m,
|
||||
sk_float_almost_equals(m.getFloat(3, 3), 1.0f, tol);
|
||||
}
|
||||
|
||||
GrColorSpaceXform::GrColorSpaceXform(const SkMatrix44& srcToDst) {
|
||||
GrColorSpaceXform::GrColorSpaceXform(const SkMatrix44& srcToDst, SkAlphaType srcAlphaType)
|
||||
: fSrcAlphaType(srcAlphaType) {
|
||||
srcToDst.asColMajorf(fSrcToDst);
|
||||
}
|
||||
|
||||
sk_sp<GrColorSpaceXform> GrColorSpaceXform::Make(SkColorSpace* src, SkColorSpace* dst) {
|
||||
sk_sp<GrColorSpaceXform> GrColorSpaceXform::Make(SkColorSpace* src, SkColorSpace* dst,
|
||||
SkAlphaType srcAlphaType) {
|
||||
if (!src || !dst) {
|
||||
// Invalid
|
||||
return nullptr;
|
||||
@ -59,5 +61,5 @@ sk_sp<GrColorSpaceXform> GrColorSpaceXform::Make(SkColorSpace* src, SkColorSpace
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return sk_make_sp<GrColorSpaceXform>(srcToDst);
|
||||
return sk_make_sp<GrColorSpaceXform>(srcToDst, srcAlphaType);
|
||||
}
|
||||
|
@ -424,7 +424,8 @@ sk_sp<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor(
|
||||
(domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom));
|
||||
textureMatrix.postIDiv(texture->width(), texture->height());
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(this->getColorSpace(),
|
||||
dstColorSpace);
|
||||
dstColorSpace,
|
||||
this->alphaType());
|
||||
return create_fp_for_domain_and_filter(texture, std::move(colorSpaceXform), textureMatrix,
|
||||
domainMode, domain, filterOrNullForBicubic);
|
||||
}
|
||||
@ -506,7 +507,8 @@ sk_sp<GrFragmentProcessor> GrTextureMaker::createFragmentProcessor(
|
||||
SkMatrix normalizedTextureMatrix = textureMatrix;
|
||||
normalizedTextureMatrix.postIDiv(texture->width(), texture->height());
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(this->getColorSpace(),
|
||||
dstColorSpace);
|
||||
dstColorSpace,
|
||||
this->alphaType());
|
||||
return create_fp_for_domain_and_filter(texture, std::move(colorSpaceXform),
|
||||
normalizedTextureMatrix, domainMode, domain,
|
||||
filterOrNullForBicubic);
|
||||
|
@ -1010,7 +1010,8 @@ void SkGpuDevice::drawBitmapTile(const SkBitmap& bitmap,
|
||||
}
|
||||
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform =
|
||||
GrColorSpaceXform::Make(bitmap.colorSpace(), fDrawContext->getColorSpace());
|
||||
GrColorSpaceXform::Make(bitmap.colorSpace(), fDrawContext->getColorSpace(),
|
||||
bitmap.alphaType());
|
||||
|
||||
SkScalar iw = 1.f / texture->width();
|
||||
SkScalar ih = 1.f / texture->height();
|
||||
@ -1134,8 +1135,12 @@ void SkGpuDevice::drawSpecial(const SkDraw& draw,
|
||||
SkPaint tmpUnfiltered(paint);
|
||||
tmpUnfiltered.setImageFilter(nullptr);
|
||||
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform =
|
||||
GrColorSpaceXform::Make(result->getColorSpace(), fDrawContext->getColorSpace(),
|
||||
result->alphaType());
|
||||
GrPaint grPaint;
|
||||
sk_sp<GrFragmentProcessor> fp(GrSimpleTextureEffect::Make(texture.get(), nullptr,
|
||||
sk_sp<GrFragmentProcessor> fp(GrSimpleTextureEffect::Make(texture.get(),
|
||||
std::move(colorSpaceXform),
|
||||
SkMatrix::I()));
|
||||
if (GrPixelConfigIsAlphaOnly(texture->config())) {
|
||||
fp = GrFragmentProcessor::MulOutputByInputUnpremulColor(std::move(fp));
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
GrProcessorKeyBuilder* b) {
|
||||
const GrBicubicEffect& bicubicEffect = effect.cast<GrBicubicEffect>();
|
||||
b->add32(GrTextureDomain::GLDomain::DomainKey(bicubicEffect.domain()));
|
||||
b->add32(SkToInt(SkToBool(bicubicEffect.colorSpaceXform())));
|
||||
b->add32(GrColorSpaceXform::XformKey(bicubicEffect.colorSpaceXform()));
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -114,7 +114,9 @@ void GrGLBicubicEffect::emitCode(EmitArgs& args) {
|
||||
SkString bicubicColor;
|
||||
bicubicColor.printf("%s(%s, f.y, s0, s1, s2, s3)", cubicBlendName.c_str(), coeff);
|
||||
if (colorSpaceHelper.getXformMatrix()) {
|
||||
bicubicColor.appendf(" * %s", colorSpaceHelper.getXformMatrix());
|
||||
SkString xformedColor;
|
||||
fragBuilder->appendColorGamutXform(&xformedColor, bicubicColor.c_str(), &colorSpaceHelper);
|
||||
bicubicColor.swap(xformedColor);
|
||||
}
|
||||
fragBuilder->codeAppendf("\t%s = %s;\n",
|
||||
args.fOutputColor, (GrGLSLExpr4(bicubicColor.c_str()) *
|
||||
|
@ -8,23 +8,46 @@
|
||||
#include "GrSimpleTextureEffect.h"
|
||||
#include "GrInvariantOutput.h"
|
||||
#include "GrTexture.h"
|
||||
#include "glsl/GrGLSLColorSpaceXformHelper.h"
|
||||
#include "glsl/GrGLSLFragmentProcessor.h"
|
||||
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
||||
|
||||
class GrGLSimpleTextureEffect : public GrGLSLFragmentProcessor {
|
||||
public:
|
||||
void emitCode(EmitArgs& args) override {
|
||||
const GrSimpleTextureEffect& textureEffect = args.fFp.cast<GrSimpleTextureEffect>();
|
||||
GrGLSLColorSpaceXformHelper colorSpaceHelper(args.fUniformHandler,
|
||||
textureEffect.colorSpaceXform(),
|
||||
&fColorSpaceXformUni);
|
||||
|
||||
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
|
||||
fragBuilder->codeAppendf("%s = ", args.fOutputColor);
|
||||
fragBuilder->appendTextureLookupAndModulate(args.fInputColor,
|
||||
args.fTexSamplers[0],
|
||||
args.fCoords[0].c_str(),
|
||||
args.fCoords[0].getType());
|
||||
args.fTexSamplers[0],
|
||||
args.fCoords[0].c_str(),
|
||||
args.fCoords[0].getType(),
|
||||
&colorSpaceHelper);
|
||||
fragBuilder->codeAppend(";");
|
||||
}
|
||||
|
||||
static inline void GenKey(const GrProcessor& effect, const GrGLSLCaps&,
|
||||
GrProcessorKeyBuilder* b) {
|
||||
const GrSimpleTextureEffect& textureEffect = effect.cast<GrSimpleTextureEffect>();
|
||||
b->add32(GrColorSpaceXform::XformKey(textureEffect.colorSpaceXform()));
|
||||
}
|
||||
|
||||
protected:
|
||||
void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& processor) override {
|
||||
const GrSimpleTextureEffect& textureEffect = processor.cast<GrSimpleTextureEffect>();
|
||||
if (SkToBool(textureEffect.colorSpaceXform())) {
|
||||
pdman.setMatrix4f(fColorSpaceXformUni, textureEffect.colorSpaceXform()->srcToDst());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef GrGLSLFragmentProcessor INHERITED;
|
||||
|
||||
UniformHandle fColorSpaceXformUni;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -30,6 +30,8 @@ public:
|
||||
return str;
|
||||
}
|
||||
|
||||
GrColorSpaceXform* colorSpaceXform() const { return fColorSpaceXform.get(); }
|
||||
|
||||
protected:
|
||||
/** unfiltered, clamp mode */
|
||||
GrSingleTextureEffect(GrTexture*, sk_sp<GrColorSpaceXform>, const SkMatrix&,
|
||||
|
@ -8,12 +8,13 @@
|
||||
#ifndef GrGLSLColorSpaceXformHelper_DEFINED
|
||||
#define GrGLSLColorSpaceXformHelper_DEFINED
|
||||
|
||||
#include "GrColorSpaceXform.h"
|
||||
#include "GrGLSLUniformHandler.h"
|
||||
|
||||
class GrColorSpaceXform;
|
||||
|
||||
/**
|
||||
* Stack helper class to assist with using GrColorSpaceXform within an FP's emitCode function.
|
||||
* This injects the uniform declaration, and stores the information needed to generate correct
|
||||
* gamut-transformation shader code.
|
||||
*/
|
||||
class GrGLSLColorSpaceXformHelper : public SkNoncopyable {
|
||||
public:
|
||||
@ -25,15 +26,18 @@ public:
|
||||
*handle = uniformHandler->addUniform(kFragment_GrShaderFlag, kMat44f_GrSLType,
|
||||
kDefault_GrSLPrecision, "ColorXform",
|
||||
&fXformMatrix);
|
||||
fAlphaType = colorSpaceXform->alphaType();
|
||||
} else {
|
||||
fXformMatrix = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const char* getXformMatrix() const { return fXformMatrix; }
|
||||
SkAlphaType alphaType() const { return fAlphaType; }
|
||||
|
||||
private:
|
||||
const char* fXformMatrix;
|
||||
SkAlphaType fAlphaType;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "GrSwizzle.h"
|
||||
#include "glsl/GrGLSLShaderBuilder.h"
|
||||
#include "glsl/GrGLSLCaps.h"
|
||||
#include "glsl/GrGLSLColorSpaceXformHelper.h"
|
||||
#include "glsl/GrGLSLShaderVar.h"
|
||||
#include "glsl/GrGLSLSampler.h"
|
||||
#include "glsl/GrGLSLProgramBuilder.h"
|
||||
@ -98,17 +99,79 @@ void GrGLSLShaderBuilder::appendTextureLookup(SkString* out,
|
||||
|
||||
void GrGLSLShaderBuilder::appendTextureLookup(SamplerHandle samplerHandle,
|
||||
const char* coordName,
|
||||
GrSLType varyingType) {
|
||||
this->appendTextureLookup(&this->code(), samplerHandle, coordName, varyingType);
|
||||
GrSLType varyingType,
|
||||
GrGLSLColorSpaceXformHelper* colorXformHelper) {
|
||||
if (colorXformHelper && colorXformHelper->getXformMatrix()) {
|
||||
// With a color gamut transform, we need to wrap the lookup in another function call
|
||||
SkString lookup;
|
||||
this->appendTextureLookup(&lookup, samplerHandle, coordName, varyingType);
|
||||
this->appendColorGamutXform(lookup.c_str(), colorXformHelper);
|
||||
} else {
|
||||
this->appendTextureLookup(&this->code(), samplerHandle, coordName, varyingType);
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLSLShaderBuilder::appendTextureLookupAndModulate(const char* modulation,
|
||||
SamplerHandle samplerHandle,
|
||||
const char* coordName,
|
||||
GrSLType varyingType) {
|
||||
void GrGLSLShaderBuilder::appendTextureLookupAndModulate(
|
||||
const char* modulation,
|
||||
SamplerHandle samplerHandle,
|
||||
const char* coordName,
|
||||
GrSLType varyingType,
|
||||
GrGLSLColorSpaceXformHelper* colorXformHelper) {
|
||||
SkString lookup;
|
||||
this->appendTextureLookup(&lookup, samplerHandle, coordName, varyingType);
|
||||
this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(lookup)).c_str());
|
||||
if (colorXformHelper && colorXformHelper->getXformMatrix()) {
|
||||
SkString xform;
|
||||
this->appendColorGamutXform(&xform, lookup.c_str(), colorXformHelper);
|
||||
this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(xform)).c_str());
|
||||
} else {
|
||||
this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(lookup)).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void GrGLSLShaderBuilder::appendColorGamutXform(SkString* out,
|
||||
const char* srcColor,
|
||||
GrGLSLColorSpaceXformHelper* colorXformHelper) {
|
||||
// Our color is (r, g, b, a), but we want to multiply (r, g, b, 1) by our matrix, then
|
||||
// re-insert the original alpha. The supplied srcColor is likely to be of the form
|
||||
// "texture(...)", and we don't want to evaluate that twice.
|
||||
//
|
||||
// Worse: We can't do the transformation on premultiplied colors, so if the source is premul,
|
||||
// we need to unpremul, transform, then multiply again. Anyways, we wrap all of the work in a
|
||||
// function.
|
||||
static const GrGLSLShaderVar gColorGamutXformArgs[] = {
|
||||
GrGLSLShaderVar("color", kVec4f_GrSLType),
|
||||
GrGLSLShaderVar("xform", kMat44f_GrSLType),
|
||||
};
|
||||
SkString functionBody;
|
||||
if (kPremul_SkAlphaType == colorXformHelper->alphaType()) {
|
||||
// Unpremultiply
|
||||
functionBody.append("\tfloat nonZeroAlpha = max(color.a, 0.00001);\n"
|
||||
"\tcolor.rgb = color.rgb / nonZeroAlpha;\n");
|
||||
}
|
||||
// Gamut xform, clamp to destination gamut
|
||||
functionBody.append("\tcolor.rgb = clamp((vec4(color.rgb, 1.0) * xform).rgb, 0.0, 1.0);\n");
|
||||
if (kPremul_SkAlphaType == colorXformHelper->alphaType()) {
|
||||
// Re-multiply by alpha
|
||||
functionBody.append("\tcolor.rgb = color.rgb * nonZeroAlpha;\n");
|
||||
}
|
||||
functionBody.append("\treturn color;");
|
||||
SkString colorGamutXformFuncName;
|
||||
this->emitFunction(kVec4f_GrSLType,
|
||||
"colorGamutXform",
|
||||
SK_ARRAY_COUNT(gColorGamutXformArgs),
|
||||
gColorGamutXformArgs,
|
||||
functionBody.c_str(),
|
||||
&colorGamutXformFuncName);
|
||||
|
||||
out->appendf("%s(%s, %s)", colorGamutXformFuncName.c_str(), srcColor,
|
||||
colorXformHelper->getXformMatrix());
|
||||
}
|
||||
|
||||
void GrGLSLShaderBuilder::appendColorGamutXform(const char* srcColor,
|
||||
GrGLSLColorSpaceXformHelper* colorXformHelper) {
|
||||
SkString xform;
|
||||
this->appendColorGamutXform(&xform, srcColor, colorXformHelper);
|
||||
this->codeAppend(xform.c_str());
|
||||
}
|
||||
|
||||
void GrGLSLShaderBuilder::appendTexelFetch(SkString* out,
|
||||
|
@ -15,6 +15,8 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
class GrGLSLColorSpaceXformHelper;
|
||||
|
||||
/**
|
||||
base class for all shaders builders
|
||||
*/
|
||||
@ -37,7 +39,8 @@ public:
|
||||
/** Version of above that appends the result to the shader code instead.*/
|
||||
void appendTextureLookup(SamplerHandle,
|
||||
const char* coordName,
|
||||
GrSLType coordType = kVec2f_GrSLType);
|
||||
GrSLType coordType = kVec2f_GrSLType,
|
||||
GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
|
||||
|
||||
|
||||
/** Does the work of appendTextureLookup and modulates the result by modulation. The result is
|
||||
@ -47,7 +50,18 @@ public:
|
||||
void appendTextureLookupAndModulate(const char* modulation,
|
||||
SamplerHandle,
|
||||
const char* coordName,
|
||||
GrSLType coordType = kVec2f_GrSLType);
|
||||
GrSLType coordType = kVec2f_GrSLType,
|
||||
GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
|
||||
|
||||
/** Adds a helper function to facilitate color gamut transformation, and produces code that
|
||||
returns the srcColor transformed into a new gamut (via multiplication by the xform from
|
||||
colorXformHelper). Premultiplied sources are also handled correctly (colorXformHelper
|
||||
determines if the source is premultipled or not). */
|
||||
void appendColorGamutXform(SkString* out, const char* srcColor,
|
||||
GrGLSLColorSpaceXformHelper* colorXformHelper);
|
||||
|
||||
/** Version of above that appends the result to the shader code instead. */
|
||||
void appendColorGamutXform(const char* srcColor, GrGLSLColorSpaceXformHelper* colorXformHelper);
|
||||
|
||||
/** Fetches an unfiltered texel from a sampler at integer coordinates. coordExpr must match the
|
||||
dimensionality of the sampler and must be within the sampler's range. coordExpr is emitted
|
||||
|
@ -214,11 +214,15 @@ sk_sp<GrFragmentProcessor> SkImageShader::asFragmentProcessor(const AsFPArgs& ar
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkImageInfo info = as_IB(fImage)->onImageInfo();
|
||||
sk_sp<GrColorSpaceXform> colorSpaceXform = GrColorSpaceXform::Make(info.colorSpace(),
|
||||
args.fDstColorSpace,
|
||||
info.alphaType());
|
||||
sk_sp<GrFragmentProcessor> inner;
|
||||
if (doBicubic) {
|
||||
inner = GrBicubicEffect::Make(texture, nullptr, matrix, tm);
|
||||
inner = GrBicubicEffect::Make(texture, std::move(colorSpaceXform), matrix, tm);
|
||||
} else {
|
||||
inner = GrSimpleTextureEffect::Make(texture, nullptr, matrix, params);
|
||||
inner = GrSimpleTextureEffect::Make(texture, std::move(colorSpaceXform), matrix, params);
|
||||
}
|
||||
|
||||
if (GrPixelConfigIsAlphaOnly(texture->config())) {
|
||||
|
Loading…
Reference in New Issue
Block a user