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:
parent
568f35f8d9
commit
08f986dde7
@ -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,
|
||||
|
@ -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;");
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;");
|
||||
|
@ -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),
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user