Avoid multiplication by alpha in fragment shader when known to be 1.

Implemented for image shaders, image draws, and gradient shaders.

Reimplement GrFragmentProcessor::OverrideInput as GrOverrideInputFragmentProcessor.fp.
It allows specification of whether the replacement input color should be
a literal in the shader code or a uniform. For above use case use with literal white.

Make key in variables in fp files work for 4f colors.

Fix issue in CPP code gen from .fp where when + key vars that pushed multiple values
into the shader key only skipped the first key value when the when condition is not
true.

Bug: skia:7722

Change-Id: Id7c865132d620e8cdea8b00f2a627103eef171ac
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/201985
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
Brian Salomon 2019-04-10 15:02:11 -04:00 committed by Skia Commit-Bot
parent 6c431d5202
commit c0d79e525f
17 changed files with 286 additions and 145 deletions

View File

@ -372,6 +372,8 @@ skia_gpu_sources = [
"$_src/gpu/effects/generated/GrMagnifierEffect.h",
"$_src/gpu/effects/generated/GrMixerEffect.cpp",
"$_src/gpu/effects/generated/GrMixerEffect.h",
"$_src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp",
"$_src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h",
"$_src/gpu/effects/generated/GrPremulInputFragmentProcessor.cpp",
"$_src/gpu/effects/generated/GrPremulInputFragmentProcessor.h",
"$_src/gpu/effects/generated/GrRectBlurEffect.cpp",

View File

@ -45,6 +45,7 @@ skia_gpu_processor_sources = [
"$_src/gpu/effects/GrLumaColorFilterEffect.fp",
"$_src/gpu/effects/GrMagnifierEffect.fp",
"$_src/gpu/effects/GrMixerEffect.fp",
"$_src/gpu/effects/GrOverrideInputFragmentProcessor.fp",
"$_src/gpu/effects/GrPremulInputFragmentProcessor.fp",
"$_src/gpu/effects/GrRectBlurEffect.fp",
"$_src/gpu/effects/GrRRectBlurEffect.fp",

View File

@ -42,6 +42,9 @@ struct GrFPArgs {
const SkMatrix* fPreLocalMatrix = nullptr;
const SkMatrix* fPostLocalMatrix = nullptr;
// Make this SkAlphaType?
bool fInputColorIsOpaque = false;
SkFilterQuality fFilterQuality;
const GrColorSpaceInfo* fDstColorSpaceInfo;
};

View File

@ -9,9 +9,10 @@
#include "GrCoordTransform.h"
#include "GrPipeline.h"
#include "GrProcessorAnalysis.h"
#include "effects/generated/GrConstColorProcessor.h"
#include "effects/generated/GrPremulInputFragmentProcessor.h"
#include "effects/GrXfermodeFragmentProcessor.h"
#include "effects/generated/GrConstColorProcessor.h"
#include "effects/generated/GrOverrideInputFragmentProcessor.h"
#include "effects/generated/GrPremulInputFragmentProcessor.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLProgramDataManager.h"
@ -282,93 +283,11 @@ std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MakeInputPremulAndMulB
//////////////////////////////////////////////////////////////////////////////
std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::OverrideInput(
std::unique_ptr<GrFragmentProcessor> fp, const SkPMColor4f& color) {
class ReplaceInputFragmentProcessor : public GrFragmentProcessor {
public:
static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child,
const SkPMColor4f& color) {
return std::unique_ptr<GrFragmentProcessor>(
new ReplaceInputFragmentProcessor(std::move(child), color));
}
const char* name() const override { return "Replace Color"; }
std::unique_ptr<GrFragmentProcessor> clone() const override {
return Make(this->childProcessor(0).clone(), fColor);
}
private:
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
class GLFP : public GrGLSLFragmentProcessor {
public:
GLFP() : fHaveSetColor(false) {}
void emitCode(EmitArgs& args) override {
const char* colorName;
fColorUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
kHalf4_GrSLType,
"Color", &colorName);
this->emitChild(0, colorName, args);
}
private:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& fp) override {
SkPMColor4f color = fp.cast<ReplaceInputFragmentProcessor>().fColor;
if (!fHaveSetColor || color != fPreviousColor) {
pdman.set4fv(fColorUni, 1, color.vec());
fPreviousColor = color;
fHaveSetColor = true;
}
}
GrGLSLProgramDataManager::UniformHandle fColorUni;
bool fHaveSetColor;
SkPMColor4f fPreviousColor;
};
return new GLFP;
}
ReplaceInputFragmentProcessor(std::unique_ptr<GrFragmentProcessor> child,
const SkPMColor4f& color)
: INHERITED(kReplaceInputFragmentProcessor_ClassID, OptFlags(child.get(), color))
, fColor(color) {
this->registerChildProcessor(std::move(child));
}
static OptimizationFlags OptFlags(const GrFragmentProcessor* child,
const SkPMColor4f& color) {
OptimizationFlags childFlags = child->optimizationFlags();
OptimizationFlags flags = kNone_OptimizationFlags;
if (childFlags & kConstantOutputForConstantInput_OptimizationFlag) {
flags |= kConstantOutputForConstantInput_OptimizationFlag;
}
if ((childFlags & kPreservesOpaqueInput_OptimizationFlag) && color.isOpaque()) {
flags |= kPreservesOpaqueInput_OptimizationFlag;
}
return flags;
}
void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override
{}
bool onIsEqual(const GrFragmentProcessor& that) const override {
return fColor == that.cast<ReplaceInputFragmentProcessor>().fColor;
}
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f&) const override {
return ConstantOutputForConstantInput(this->childProcessor(0), fColor);
}
SkPMColor4f fColor;
typedef GrFragmentProcessor INHERITED;
};
std::unique_ptr<GrFragmentProcessor> fp, const SkPMColor4f& color, bool useUniform) {
if (!fp) {
return nullptr;
}
return ReplaceInputFragmentProcessor::Make(std::move(fp), color);
return GrOverrideInputFragmentProcessor::Make(std::move(fp), color, useUniform);
}
std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::RunInSeries(

View File

@ -63,7 +63,8 @@ public:
* child.
*/
static std::unique_ptr<GrFragmentProcessor> OverrideInput(std::unique_ptr<GrFragmentProcessor>,
const SkPMColor4f&);
const SkPMColor4f&,
bool useUniform = true);
/**
* Returns a fragment processor that premuls the input before calling the passed in fragment
@ -293,6 +294,11 @@ protected:
return static_cast<OptimizationFlags>(kAll_OptimizationFlags & fFlags);
}
/** Useful when you can't call fp->optimizationFlags() on a base class object from a subclass.*/
static OptimizationFlags ProcessorOptimizationFlags(const GrFragmentProcessor* fp) {
return fp->optimizationFlags();
}
/**
* This allows one subclass to access another subclass's implementation of
* constantOutputForConstantInput. It must only be called when

View File

@ -124,6 +124,7 @@ public:
kGrMorphologyEffect_ClassID,
kGrMixerEffect_ClassID,
kGrOverdrawFragmentProcessor_ClassID,
kGrOverrideInputFragmentProcessor_ClassID,
kGrPathProcessor_ClassID,
kGrPerlinNoise2Effect_ClassID,
kGrPipelineDynamicStateTestProcessor_ClassID,

View File

@ -1061,7 +1061,11 @@ void SkGpuDevice::drawSpecial(SkSpecialImage* special, int left, int top, const
if (GrPixelConfigIsAlphaOnly(config)) {
fp = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp));
} else {
fp = GrFragmentProcessor::MulChildByInputAlpha(std::move(fp));
if (paint.getColor4f().isOpaque()) {
fp = GrFragmentProcessor::OverrideInput(std::move(fp), SK_PMColor4fWHITE, false);
} else {
fp = GrFragmentProcessor::MulChildByInputAlpha(std::move(fp));
}
}
GrPaint grPaint;

View File

@ -355,12 +355,13 @@ static inline bool skpaint_to_grpaint_impl(GrRecordingContext* context,
// Convert SkPaint color to 4f format in the destination color space
SkColor4f origColor = SkColor4fPrepForDst(skPaint.getColor4f(), colorSpaceInfo);
const GrFPArgs fpArgs(context, &viewM, skPaint.getFilterQuality(), &colorSpaceInfo);
GrFPArgs fpArgs(context, &viewM, skPaint.getFilterQuality(), &colorSpaceInfo);
// Setup the initial color considering the shader, the SkPaint color, and the presence or not
// of per-vertex colors.
std::unique_ptr<GrFragmentProcessor> shaderFP;
if (!primColorMode || blend_requires_shader(*primColorMode)) {
fpArgs.fInputColorIsOpaque = origColor.isOpaque();
if (shaderProcessor) {
shaderFP = std::move(*shaderProcessor);
} else if (const auto* shader = as_SB(skPaint.getShader())) {
@ -457,6 +458,8 @@ static inline bool skpaint_to_grpaint_impl(GrRecordingContext* context,
SkMaskFilterBase* maskFilter = as_MFB(skPaint.getMaskFilter());
if (maskFilter) {
// We may have set this before passing to the SkShader.
fpArgs.fInputColorIsOpaque = false;
if (auto mfFP = maskFilter->asFragmentProcessor(fpArgs)) {
grPaint->addCoverageFragmentProcessor(std::move(mfFP));
}
@ -551,7 +554,11 @@ bool SkPaintToGrPaintWithTexture(GrRecordingContext* context,
shaderFP = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp));
}
} else {
shaderFP = GrFragmentProcessor::MulChildByInputAlpha(std::move(fp));
if (paint.getColor4f().isOpaque()) {
shaderFP = GrFragmentProcessor::OverrideInput(std::move(fp), SK_PMColor4fWHITE, false);
} else {
shaderFP = GrFragmentProcessor::MulChildByInputAlpha(std::move(fp));
}
}
return SkPaintToGrPaintReplaceShader(context, colorSpaceInfo, paint, std::move(shaderFP),

View File

@ -15,27 +15,11 @@ in uniform half weight;
static OptimizationFlags OptFlags(const std::unique_ptr<GrFragmentProcessor>& fp0,
const std::unique_ptr<GrFragmentProcessor>& fp1) {
auto get_flags = [](const std::unique_ptr<GrFragmentProcessor>& fp) {
auto flags = kNone_OptimizationFlags;
if (fp->compatibleWithCoverageAsAlpha()) {
flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag;
}
if (fp->preservesOpaqueInput()) {
flags |= kPreservesOpaqueInput_OptimizationFlag;
}
if (fp->hasConstantOutputForConstantInput()) {
flags |= kConstantOutputForConstantInput_OptimizationFlag;
}
return flags;
};
const auto fp0_flags = get_flags(fp0);
return fp1 ? (fp0_flags & get_flags(fp1)) : fp0_flags;
auto flags = ProcessorOptimizationFlags(fp0.get());
if (fp1) {
flags &= ProcessorOptimizationFlags(fp1.get());
}
return flags;
}
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {

View File

@ -0,0 +1,55 @@
/*
* Copyright 2019 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
// Ignores its own input color and invokes 'fp' with a constant color
// The constant color can either be specified as a literal or as a
// uniform, controlled by useUniform.
in fragmentProcessor fp;
layout(key) in bool useUniform;
layout(when=useUniform, ctype=SkPMColor4f) in uniform half4 uniformColor;
layout(when=!useUniform, key, ctype=SkPMColor4f) in half4 literalColor;
@make {
static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
const SkPMColor4f& color,
bool useUniform = true) {
return std::unique_ptr<GrFragmentProcessor>(
new GrOverrideInputFragmentProcessor(std::move(fp), useUniform, color, color));
}
}
@class {
static OptimizationFlags OptFlags(const std::unique_ptr<GrFragmentProcessor>& fp,
const SkPMColor4f& color) {
auto childFlags = ProcessorOptimizationFlags(fp.get());
auto flags = kNone_OptimizationFlags;
if (childFlags & kConstantOutputForConstantInput_OptimizationFlag) {
flags |= kConstantOutputForConstantInput_OptimizationFlag;
}
if ((childFlags & kPreservesOpaqueInput_OptimizationFlag) && color.isOpaque()) {
flags |= kPreservesOpaqueInput_OptimizationFlag;
}
return flags;
}
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
return ConstantOutputForConstantInput(this->childProcessor(0), uniformColor);
}
}
@optimizationFlags { OptFlags(fp, useUniform ? uniformColor : literalColor) }
void main() {
half4 constColor;
@if(useUniform) {
constColor = uniformColor;
} else {
constColor = literalColor;
}
sk_OutColor = process(fp, constColor);
}

View File

@ -326,17 +326,8 @@ private:
case SkBlendMode::kSrcIn:
case SkBlendMode::kDstIn:
case SkBlendMode::kModulate:
if (fp->compatibleWithCoverageAsAlpha()) {
if (fp->preservesOpaqueInput()) {
flags = kPreservesOpaqueInput_OptimizationFlag |
kCompatibleWithCoverageAsAlpha_OptimizationFlag;
} else {
flags = kCompatibleWithCoverageAsAlpha_OptimizationFlag;
}
} else {
flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
: kNone_OptimizationFlags;
}
flags = ProcessorOptimizationFlags(fp) &
~kConstantOutputForConstantInput_OptimizationFlag;
break;
// Produces zero when both are opaque, indeterminate if one is opaque.

View File

@ -17,27 +17,11 @@ class GrMixerEffect : public GrFragmentProcessor {
public:
static OptimizationFlags OptFlags(const std::unique_ptr<GrFragmentProcessor>& fp0,
const std::unique_ptr<GrFragmentProcessor>& fp1) {
auto get_flags = [](const std::unique_ptr<GrFragmentProcessor>& fp) {
auto flags = kNone_OptimizationFlags;
if (fp->compatibleWithCoverageAsAlpha()) {
flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag;
}
if (fp->preservesOpaqueInput()) {
flags |= kPreservesOpaqueInput_OptimizationFlag;
}
if (fp->hasConstantOutputForConstantInput()) {
flags |= kConstantOutputForConstantInput_OptimizationFlag;
}
return flags;
};
const auto fp0_flags = get_flags(fp0);
return fp1 ? (fp0_flags & get_flags(fp1)) : fp0_flags;
auto flags = ProcessorOptimizationFlags(fp0.get());
if (fp1) {
flags &= ProcessorOptimizationFlags(fp1.get());
}
return flags;
}
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {

View File

@ -0,0 +1,97 @@
/*
* Copyright 2019 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/**************************************************************************************************
*** This file was autogenerated from GrOverrideInputFragmentProcessor.fp; do not modify.
**************************************************************************************************/
#include "GrOverrideInputFragmentProcessor.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLProgramBuilder.h"
#include "GrTexture.h"
#include "SkSLCPP.h"
#include "SkSLUtil.h"
class GrGLSLOverrideInputFragmentProcessor : public GrGLSLFragmentProcessor {
public:
GrGLSLOverrideInputFragmentProcessor() {}
void emitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
const GrOverrideInputFragmentProcessor& _outer =
args.fFp.cast<GrOverrideInputFragmentProcessor>();
(void)_outer;
auto useUniform = _outer.useUniform;
(void)useUniform;
auto uniformColor = _outer.uniformColor;
(void)uniformColor;
auto literalColor = _outer.literalColor;
(void)literalColor;
if (useUniform) {
uniformColorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
kHalf4_GrSLType, "uniformColor");
}
fragBuilder->codeAppendf(
"half4 constColor;\n@if (%s) {\n constColor = %s;\n} else {\n constColor = "
"half4(%f, %f, %f, %f);\n}",
(_outer.useUniform ? "true" : "false"),
uniformColorVar.isValid() ? args.fUniformHandler->getUniformCStr(uniformColorVar)
: "half4(0)",
_outer.literalColor.fR, _outer.literalColor.fG, _outer.literalColor.fB,
_outer.literalColor.fA);
SkString _input0("constColor");
SkString _child0("_child0");
this->emitChild(_outer.fp_index, _input0.c_str(), &_child0, args);
fragBuilder->codeAppendf("\n%s = %s;\n", args.fOutputColor, _child0.c_str());
}
private:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& _proc) override {
const GrOverrideInputFragmentProcessor& _outer =
_proc.cast<GrOverrideInputFragmentProcessor>();
{
if (uniformColorVar.isValid()) {
pdman.set4fv(uniformColorVar, 1, (_outer.uniformColor).vec());
}
}
}
UniformHandle uniformColorVar;
};
GrGLSLFragmentProcessor* GrOverrideInputFragmentProcessor::onCreateGLSLInstance() const {
return new GrGLSLOverrideInputFragmentProcessor();
}
void GrOverrideInputFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {
b->add32((int32_t)useUniform);
if (!useUniform) {
uint16_t red = SkFloatToHalf(literalColor.fR);
uint16_t green = SkFloatToHalf(literalColor.fG);
uint16_t blue = SkFloatToHalf(literalColor.fB);
uint16_t alpha = SkFloatToHalf(literalColor.fA);
b->add32(((uint32_t)red << 16) | green);
b->add32(((uint32_t)blue << 16) | alpha);
}
}
bool GrOverrideInputFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) const {
const GrOverrideInputFragmentProcessor& that = other.cast<GrOverrideInputFragmentProcessor>();
(void)that;
if (useUniform != that.useUniform) return false;
if (uniformColor != that.uniformColor) return false;
if (literalColor != that.literalColor) return false;
return true;
}
GrOverrideInputFragmentProcessor::GrOverrideInputFragmentProcessor(
const GrOverrideInputFragmentProcessor& src)
: INHERITED(kGrOverrideInputFragmentProcessor_ClassID, src.optimizationFlags())
, fp_index(src.fp_index)
, useUniform(src.useUniform)
, uniformColor(src.uniformColor)
, literalColor(src.literalColor) {
this->registerChildProcessor(src.childProcessor(fp_index).clone());
}
std::unique_ptr<GrFragmentProcessor> GrOverrideInputFragmentProcessor::clone() const {
return std::unique_ptr<GrFragmentProcessor>(new GrOverrideInputFragmentProcessor(*this));
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 2019 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/**************************************************************************************************
*** This file was autogenerated from GrOverrideInputFragmentProcessor.fp; do not modify.
**************************************************************************************************/
#ifndef GrOverrideInputFragmentProcessor_DEFINED
#define GrOverrideInputFragmentProcessor_DEFINED
#include "SkTypes.h"
#include "GrFragmentProcessor.h"
#include "GrCoordTransform.h"
class GrOverrideInputFragmentProcessor : public GrFragmentProcessor {
public:
static OptimizationFlags OptFlags(const std::unique_ptr<GrFragmentProcessor>& fp,
const SkPMColor4f& color) {
auto childFlags = ProcessorOptimizationFlags(fp.get());
auto flags = kNone_OptimizationFlags;
if (childFlags & kConstantOutputForConstantInput_OptimizationFlag) {
flags |= kConstantOutputForConstantInput_OptimizationFlag;
}
if ((childFlags & kPreservesOpaqueInput_OptimizationFlag) && color.isOpaque()) {
flags |= kPreservesOpaqueInput_OptimizationFlag;
}
return flags;
}
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
return ConstantOutputForConstantInput(this->childProcessor(0), uniformColor);
}
static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
const SkPMColor4f& color,
bool useUniform = true) {
return std::unique_ptr<GrFragmentProcessor>(
new GrOverrideInputFragmentProcessor(std::move(fp), useUniform, color, color));
}
GrOverrideInputFragmentProcessor(const GrOverrideInputFragmentProcessor& src);
std::unique_ptr<GrFragmentProcessor> clone() const override;
const char* name() const override { return "OverrideInputFragmentProcessor"; }
int fp_index = -1;
bool useUniform;
SkPMColor4f uniformColor;
SkPMColor4f literalColor;
private:
GrOverrideInputFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp,
bool useUniform,
SkPMColor4f uniformColor,
SkPMColor4f literalColor)
: INHERITED(kGrOverrideInputFragmentProcessor_ClassID,
(OptimizationFlags)OptFlags(fp, useUniform ? uniformColor : literalColor))
, useUniform(useUniform)
, uniformColor(uniformColor)
, literalColor(literalColor) {
SkASSERT(fp);
fp_index = this->numChildProcessors();
this->registerChildProcessor(std::move(fp));
}
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
bool onIsEqual(const GrFragmentProcessor&) const override;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
typedef GrFragmentProcessor INHERITED;
};
#endif

View File

@ -236,7 +236,9 @@ static std::unique_ptr<GrFragmentProcessor> make_gradient(const SkGradientShader
// Unexpected tile mode
return nullptr;
}
if (args.fInputColorIsOpaque) {
return GrFragmentProcessor::OverrideInput(std::move(master), SK_PMColor4fWHITE, false);
}
return GrFragmentProcessor::MulChildByInputAlpha(std::move(master));
}

View File

@ -257,6 +257,8 @@ std::unique_ptr<GrFragmentProcessor> SkImageShader::asFragmentProcessor(
args.fDstColorSpaceInfo->colorSpace());
if (isAlphaOnly) {
return inner;
} else if (args.fInputColorIsOpaque) {
return GrFragmentProcessor::OverrideInput(std::move(inner), SK_PMColor4fWHITE, false);
}
return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
}

View File

@ -1106,7 +1106,7 @@ void CPPCodeGenerator::writeGetKey() {
switch (param->fModifiers.fLayout.fKey) {
case Layout::kKey_Key:
if (param->fModifiers.fLayout.fWhen.size()) {
this->writef("if (%s) ", param->fModifiers.fLayout.fWhen.c_str());
this->writef("if (%s) {", param->fModifiers.fLayout.fWhen.c_str());
}
if (param->fType == *fContext.fFloat4x4_Type) {
ABORT("no automatic key handling for float4x4\n");
@ -1124,10 +1124,24 @@ void CPPCodeGenerator::writeGetKey() {
HCodeGenerator::FieldName(name).c_str());
this->writef(" b->add32(%s.height());\n",
HCodeGenerator::FieldName(name).c_str());
} else if (param->fType == *fContext.fHalf4_Type) {
this->writef(" uint16_t red = SkFloatToHalf(%s.fR);\n",
HCodeGenerator::FieldName(name).c_str());
this->writef(" uint16_t green = SkFloatToHalf(%s.fG);\n",
HCodeGenerator::FieldName(name).c_str());
this->writef(" uint16_t blue = SkFloatToHalf(%s.fB);\n",
HCodeGenerator::FieldName(name).c_str());
this->writef(" uint16_t alpha = SkFloatToHalf(%s.fA);\n",
HCodeGenerator::FieldName(name).c_str());
this->write(" b->add32(((uint32_t)red << 16) | green);\n");
this->write(" b->add32(((uint32_t)blue << 16) | alpha);\n");
} else {
this->writef(" b->add32((int32_t) %s);\n",
HCodeGenerator::FieldName(name).c_str());
}
if (param->fModifiers.fLayout.fWhen.size()) {
this->write("}");
}
break;
case Layout::kIdentity_Key:
if (param->fType.kind() != Type::kMatrix_Kind) {