Added SkSL unpremul intrinsic

Change-Id: I5303f6f5210628a0a5d941b2f4a6376b5e158b60
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/289577
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
Brian Osman 2020-05-13 17:06:46 -04:00 committed by Skia Commit-Bot
parent 568f35f8d9
commit 08f986dde7
15 changed files with 35 additions and 41 deletions

View File

@ -138,8 +138,7 @@ const char RuntimeColorMatrix_GPU_SRC[] = R"(
m10, m11, m12, m13, m14,
m15, m16, m17, m18, m19;
void main(inout half4 c) {
half nonZeroAlpha = max(c.a, 0.0001);
c = half4(c.rgb / nonZeroAlpha, nonZeroAlpha);
c = unpremul(c);
half4x4 m = half4x4(m0, m5, m10, m15,
m1, m6, m11, m16,

View File

@ -305,9 +305,8 @@ void GLHighContrastFilterEffect::emitCode(EmitArgs& args) {
fragBuilder->codeAppendf("half4 color = %s;", args.fInputColor);
// Unpremultiply. The max() is to guard against 0 / 0.
fragBuilder->codeAppendf("half nonZeroAlpha = max(color.a, 0.0001);");
fragBuilder->codeAppendf("color = half4(color.rgb / nonZeroAlpha, nonZeroAlpha);");
// Unpremultiply.
fragBuilder->codeAppendf("color = unpremul(color);");
if (hcfe.linearize()) {
fragBuilder->codeAppend("color.rgb = color.rgb * color.rgb;");

View File

@ -329,17 +329,11 @@ void GLColorTableEffect::emitCode(EmitArgs& args) {
if (nullptr == args.fInputColor) {
// the input color is solid white (all ones).
static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
fragBuilder->codeAppendf("\t\thalf4 coord = half4(%f, %f, %f, %f);\n",
kMaxValue, kMaxValue, kMaxValue, kMaxValue);
fragBuilder->codeAppendf("\t\thalf4 coord = half4(%f);\n", kMaxValue);
} else {
fragBuilder->codeAppendf("\t\thalf nonZeroAlpha = max(%s.a, .0001);\n", args.fInputColor);
fragBuilder->codeAppendf("\t\thalf4 coord = half4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n",
args.fInputColor);
fragBuilder->codeAppendf("\t\tcoord = coord * %f + half4(%f, %f, %f, %f);\n",
kColorScaleFactor,
kColorOffsetFactor, kColorOffsetFactor,
kColorOffsetFactor, kColorOffsetFactor);
fragBuilder->codeAppendf("\t\thalf4 coord = unpremul(%s);\n", args.fInputColor);
fragBuilder->codeAppendf("\t\tcoord = coord * %f + %f;\n",
kColorScaleFactor, kColorOffsetFactor);
}
SkString coord;

View File

@ -18,10 +18,7 @@ layout(key) in bool premulOutput;
void main() {
half4 inputColor = sk_InColor;
@if (unpremulInput) {
// The max() is to guard against 0 / 0 during unpremul when the incoming color is
// transparent black.
half nonZeroAlpha = max(inputColor.a, 0.0001);
inputColor = half4(inputColor.rgb / nonZeroAlpha, inputColor.a);
inputColor = unpremul(inputColor);
}
sk_OutColor = m * inputColor + v;
@if (clampRGBOutput) {

View File

@ -191,7 +191,7 @@ void GrGLMatrixConvolutionEffect::emitKernelBlock(EmitArgs& args, SkIPoint loc)
auto sample = this->invokeChild(0, args, "coord + sourceOffset");
fragBuilder->codeAppendf("half4 c = %s;", sample.c_str());
if (!mce.convolveAlpha()) {
fragBuilder->codeAppend("c.rgb /= max(c.a, 0.0001);");
fragBuilder->codeAppend("c = unpremul(c);");
fragBuilder->codeAppend("c.rgb = saturate(c.rgb);");
}
fragBuilder->codeAppend("sum += c * k;");

View File

@ -39,11 +39,9 @@ public:
vVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, kHalf4_GrSLType,
"v");
fragBuilder->codeAppendf(
"half4 inputColor = %s;\n@if (%s) {\n half nonZeroAlpha = max(inputColor.w, "
"9.9999997473787516e-05);\n inputColor = half4(inputColor.xyz / nonZeroAlpha, "
"inputColor.w);\n}\n%s = %s * inputColor + %s;\n@if (%s) {\n %s = clamp(%s, "
"0.0, 1.0);\n} else {\n %s.w = clamp(%s.w, 0.0, 1.0);\n}\n@if (%s) {\n "
"%s.xyz *= %s.w;\n}\n",
"half4 inputColor = %s;\n@if (%s) {\n inputColor = unpremul(inputColor);\n}\n%s "
"= %s * inputColor + %s;\n@if (%s) {\n %s = clamp(%s, 0.0, 1.0);\n} else {\n "
"%s.w = clamp(%s.w, 0.0, 1.0);\n}\n@if (%s) {\n %s.xyz *= %s.w;\n}\n",
args.fInputColor, (_outer.unpremulInput ? "true" : "false"), args.fOutputColor,
args.fUniformHandler->getUniformCStr(mVar),
args.fUniformHandler->getUniformCStr(vVar),

View File

@ -198,9 +198,7 @@ void GrGLSLShaderBuilder::appendColorGamutXform(SkString* out,
GrShaderVar("color", useFloat ? kFloat4_GrSLType : kHalf4_GrSLType)};
SkString body;
if (colorXformHelper->applyUnpremul()) {
body.appendf("%s nonZeroAlpha = max(color.a, 0.0001);", useFloat ? "float" : "half");
body.appendf("color = %s(color.rgb / nonZeroAlpha, nonZeroAlpha);",
useFloat ? "float4" : "half4");
body.appendf("color = unpremul%s(color);", useFloat ? "_float" : "");
}
if (colorXformHelper->applySrcTF()) {
body.appendf("color.r = %s(half(color.r));", srcTFFuncName.c_str());

View File

@ -557,6 +557,9 @@ static const char* glsltype_string(const Context& context, const Type& type) {
void CPPCodeGenerator::writeFunction(const FunctionDefinition& f) {
const FunctionDeclaration& decl = f.fDeclaration;
if (decl.fBuiltin) {
return;
}
fFunctionHeader = "";
OutputStream* oldOut = fOut;
StringStream buffer;

View File

@ -78,14 +78,17 @@ static const char* SKSL_PIPELINE_INCLUDE =
namespace SkSL {
static void grab_intrinsics(std::vector<std::unique_ptr<ProgramElement>>* src,
std::map<StringFragment, std::pair<std::unique_ptr<ProgramElement>, bool>>* target) {
for (auto& element : *src) {
std::map<String, std::pair<std::unique_ptr<ProgramElement>, bool>>* target) {
for (auto iter = src->begin(); iter != src->end(); ) {
std::unique_ptr<ProgramElement>& element = *iter;
switch (element->fKind) {
case ProgramElement::kFunction_Kind: {
FunctionDefinition& f = (FunctionDefinition&) *element;
StringFragment name = f.fDeclaration.fName;
SkASSERT(target->find(name) == target->end());
(*target)[name] = std::make_pair(std::move(element), false);
SkASSERT(f.fDeclaration.fBuiltin);
String key = f.fDeclaration.declaration();
SkASSERT(target->find(key) == target->end());
(*target)[key] = std::make_pair(std::move(element), false);
iter = src->erase(iter);
break;
}
case ProgramElement::kEnum_Kind: {
@ -93,6 +96,7 @@ static void grab_intrinsics(std::vector<std::unique_ptr<ProgramElement>>* src,
StringFragment name = e.fTypeName;
SkASSERT(target->find(name) == target->end());
(*target)[name] = std::make_pair(std::move(element), false);
iter = src->erase(iter);
break;
}
default:

View File

@ -215,8 +215,8 @@ private:
Position position(int offset);
std::map<StringFragment, std::pair<std::unique_ptr<ProgramElement>, bool>> fGPUIntrinsics;
std::map<StringFragment, std::pair<std::unique_ptr<ProgramElement>, bool>> fInterpreterIntrinsics;
std::map<String, std::pair<std::unique_ptr<ProgramElement>, bool>> fGPUIntrinsics;
std::map<String, std::pair<std::unique_ptr<ProgramElement>, bool>> fInterpreterIntrinsics;
std::unique_ptr<ASTFile> fGpuIncludeSource;
std::shared_ptr<SymbolTable> fGpuSymbolTable;
std::vector<std::unique_ptr<ProgramElement>> fVertexInclude;

View File

@ -1815,7 +1815,7 @@ std::unique_ptr<Expression> IRGenerator::call(int offset,
const FunctionDeclaration& function,
std::vector<std::unique_ptr<Expression>> arguments) {
if (function.fBuiltin) {
auto found = fIntrinsics->find(function.fName);
auto found = fIntrinsics->find(function.declaration());
if (found != fIntrinsics->end() && !found->second.second) {
found->second.second = true;
const FunctionDeclaration* old = fCurrentFunction;

View File

@ -158,7 +158,7 @@ private:
std::shared_ptr<SymbolTable> fSymbolTable;
// Symbols which have definitions in the include files. The bool tells us whether this
// intrinsic has been included already.
std::map<StringFragment, std::pair<std::unique_ptr<ProgramElement>, bool>>* fIntrinsics = nullptr;
std::map<String, std::pair<std::unique_ptr<ProgramElement>, bool>>* fIntrinsics = nullptr;
int fLoopLevel;
int fSwitchLevel;
ErrorReporter& fErrors;

View File

@ -36,7 +36,7 @@ struct FunctionDeclaration : public Symbol {
for (auto p : fParameters) {
result += separator;
separator = ", ";
result += p->fName;
result += p->fType.displayName();
}
result += ")";
return result;

View File

@ -114,9 +114,7 @@ void SymbolTable::markAllFunctionsBuiltin() {
break;
case Symbol::kUnresolvedFunction_Kind:
for (auto& f : ((UnresolvedFunction&) *pair.second).fFunctions) {
if (!((FunctionDeclaration*)f)->fDefined) {
((FunctionDeclaration*)f)->fBuiltin = true;
}
((FunctionDeclaration*)f)->fBuiltin = true;
}
break;
default:

View File

@ -298,4 +298,8 @@ half4 blend(SkBlendMode mode, half4 src, half4 dst) {
}
return half4(0); // Avoids "'blend' can exit without returning a value."
}
// The max() guards against division by zero when the incoming color is transparent black
half4 unpremul(half4 color) { return half4(color.rgb / max(color.a, 0.0001), color.a); }
float4 unpremul_float(float4 color) { return float4(color.rgb / max(color.a, 0.0001), color.a); }
)SKSL"