Skip to content

Commit 866cbe4

Browse files
rphilliSkCQ
authored andcommitted
[graphite] Implement RuntimeEffect toLinearSrgb/fromLinearSrgb handling
In Graphite, for any RuntimeEffect that uses the intrinsics, we always upload the colorSpace uniforms and generate the colorSpace conversion code. If the dest ColorSpace is nullptr or is already LinearSRGB the color space conversion just becomes a noop. Bug: b/40044496 (aka skia:13508) Bug: b/331445583 Change-Id: I455b95ad3150a28ec92c9a9d236890f15782ba3d Reviewed-on: https://skia-review.googlesource.com/c/skia/+/833428 Commit-Queue: Robert Phillips <[email protected]> Reviewed-by: John Stiles <[email protected]>
1 parent 1d8b300 commit 866cbe4

File tree

3 files changed

+130
-12
lines changed

3 files changed

+130
-12
lines changed

src/core/SkRuntimeEffectPriv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ class SkRuntimeEffectPriv {
132132
skia_private::TArray<SkRuntimeEffect::ChildPtr>* children);
133133
static void WriteChildEffects(SkWriteBuffer& buffer,
134134
SkSpan<const SkRuntimeEffect::ChildPtr> children);
135+
136+
static bool UsesColorTransform(const SkRuntimeEffect* effect) {
137+
return effect->usesColorTransform();
138+
}
135139
};
136140

137141
// These internal APIs for creating runtime effects vary from the public API in two ways:

src/gpu/graphite/KeyHelpers.cpp

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -949,13 +949,20 @@ bool RuntimeEffectBlock::ShaderData::operator==(const ShaderData& rhs) const {
949949
return fEffect == rhs.fEffect && skdata_matches(fUniforms.get(), rhs.fUniforms.get());
950950
}
951951

952-
static void gather_runtime_effect_uniforms(SkSpan<const SkRuntimeEffect::Uniform> rtsUniforms,
952+
static void gather_runtime_effect_uniforms(const KeyContext& keyContext,
953+
const SkRuntimeEffect* effect,
953954
SkSpan<const Uniform> graphiteUniforms,
954955
const SkData* uniformData,
955956
PipelineDataGatherer* gatherer) {
956-
if (!rtsUniforms.empty() && uniformData) {
957-
SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, graphiteUniforms);)
957+
if (!uniformData) {
958+
return; // precompiling
959+
}
960+
961+
SkDEBUGCODE(UniformExpectationsValidator uev(gatherer, graphiteUniforms);)
958962

963+
SkSpan<const SkRuntimeEffect::Uniform> rtsUniforms = effect->uniforms();
964+
965+
if (!rtsUniforms.empty() && uniformData) {
959966
// Collect all the other uniforms from the provided SkData.
960967
const uint8_t* uniformBase = uniformData->bytes();
961968
for (size_t index = 0; index < rtsUniforms.size(); ++index) {
@@ -966,6 +973,27 @@ static void gather_runtime_effect_uniforms(SkSpan<const SkRuntimeEffect::Uniform
966973
gatherer->write(uniform, uniformPtr);
967974
}
968975
}
976+
977+
if (SkRuntimeEffectPriv::UsesColorTransform(effect)) {
978+
SkColorSpace* dstCS = keyContext.dstColorInfo().colorSpace();
979+
if (!dstCS) {
980+
dstCS = sk_srgb_linear_singleton(); // turn colorspace conversion into a noop
981+
}
982+
983+
// TODO(b/332565302): If the runtime shader only uses one of these
984+
// transforms, we could upload only one set of uniforms.
985+
ColorSpaceTransformBlock::ColorSpaceTransformData dstToLinear(dstCS,
986+
kUnpremul_SkAlphaType,
987+
sk_srgb_linear_singleton(),
988+
kUnpremul_SkAlphaType);
989+
ColorSpaceTransformBlock::ColorSpaceTransformData linearToDst(sk_srgb_linear_singleton(),
990+
kUnpremul_SkAlphaType,
991+
dstCS,
992+
kUnpremul_SkAlphaType);
993+
994+
add_color_space_uniforms(dstToLinear.fSteps, ReadSwizzle::kRGBA, gatherer);
995+
add_color_space_uniforms(linearToDst.fSteps, ReadSwizzle::kRGBA, gatherer);
996+
}
969997
}
970998

971999
void RuntimeEffectBlock::BeginBlock(const KeyContext& keyContext,
@@ -982,7 +1010,8 @@ void RuntimeEffectBlock::BeginBlock(const KeyContext& keyContext,
9821010
const ShaderSnippet* entry = dict->getEntry(codeSnippetID);
9831011
SkASSERT(entry);
9841012

985-
gather_runtime_effect_uniforms(shaderData.fEffect->uniforms(),
1013+
gather_runtime_effect_uniforms(keyContext,
1014+
shaderData.fEffect.get(),
9861015
entry->fUniforms,
9871016
shaderData.fUniforms.get(),
9881017
gatherer);

src/gpu/graphite/ShaderCodeDictionary.cpp

Lines changed: 93 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,25 @@ static constexpr char kRuntimeShaderName[] = "RuntimeEffect";
3939

4040
static_assert(static_cast<int>(BuiltInCodeSnippetID::kLast) < kSkiaBuiltInReservedCnt);
4141

42+
// The toLinearSrgb and fromLinearSrgb RuntimeEffect intrinsics need to be able to map to and
43+
// from the dst color space and linearSRGB. These are the 10 uniforms needed to allow that.
44+
// These boil down to two copies of the kColorSpaceTransformUniforms uniforms. The first set
45+
// for mapping to LinearSRGB and the second set for mapping from LinearSRGB.
46+
static constexpr Uniform kRuntimeEffectColorSpaceTransformUniforms[] = {
47+
// to LinearSRGB
48+
{ "flags_toLinear", SkSLType::kInt },
49+
{ "srcKind_toLinear", SkSLType::kInt },
50+
{ "gamutTransform_toLinear", SkSLType::kHalf3x3 },
51+
{ "dstKind_toLinear", SkSLType::kInt },
52+
{ "csXformCoeffs_toLinear", SkSLType::kHalf4x4 },
53+
// from LinearSRGB
54+
{ "flags_fromLinear", SkSLType::kInt },
55+
{ "srcKind_fromLinear", SkSLType::kInt },
56+
{ "gamutTransform_fromLinear", SkSLType::kHalf3x3 },
57+
{ "dstKind_fromLinear", SkSLType::kInt },
58+
{ "csXformCoeffs_fromLinear", SkSLType::kHalf4x4 },
59+
};
60+
4261
namespace {
4362

4463
std::string get_mangled_name(const std::string& baseName, int manglingSuffix) {
@@ -1151,10 +1170,12 @@ class GraphitePipelineCallbacks : public SkSL::PipelineStage::Callbacks {
11511170
public:
11521171
GraphitePipelineCallbacks(const ShaderInfo& shaderInfo,
11531172
const ShaderNode* node,
1154-
std::string* preamble)
1173+
std::string* preamble,
1174+
const SkRuntimeEffect* effect)
11551175
: fShaderInfo(shaderInfo)
11561176
, fNode(node)
1157-
, fPreamble(preamble) {}
1177+
, fPreamble(preamble)
1178+
, fEffect(effect) {}
11581179

11591180
std::string declareUniform(const SkSL::VarDeclaration* decl) override {
11601181
std::string result = get_mangled_name(std::string(decl->var()->name()), fNode->keyIndex());
@@ -1206,12 +1227,30 @@ class GraphitePipelineCallbacks : public SkSL::PipelineStage::Callbacks {
12061227
}
12071228

12081229
std::string toLinearSrgb(std::string color) override {
1209-
// TODO(skia:13508): implement to-linear-SRGB child effect
1210-
return color;
1230+
if (!SkRuntimeEffectPriv::UsesColorTransform(fEffect)) {
1231+
return color;
1232+
}
1233+
1234+
color = SkSL::String::printf("(%s).rgb1", color.c_str());
1235+
std::string helper = get_mangled_name("toLinearSRGB", fNode->keyIndex());
1236+
std::string xformedColor = SkSL::String::printf("%s(%s)",
1237+
helper.c_str(),
1238+
color.c_str());
1239+
return SkSL::String::printf("(%s).rgb", xformedColor.c_str());
12111240
}
1241+
1242+
12121243
std::string fromLinearSrgb(std::string color) override {
1213-
// TODO(skia:13508): implement from-linear-SRGB child effect
1214-
return color;
1244+
if (!SkRuntimeEffectPriv::UsesColorTransform(fEffect)) {
1245+
return color;
1246+
}
1247+
1248+
color = SkSL::String::printf("(%s).rgb1", color.c_str());
1249+
std::string helper = get_mangled_name("fromLinearSRGB", fNode->keyIndex());
1250+
std::string xformedColor = SkSL::String::printf("%s(%s)",
1251+
helper.c_str(),
1252+
color.c_str());
1253+
return SkSL::String::printf("(%s).rgb", xformedColor.c_str());
12151254
}
12161255

12171256
std::string getMangledName(const char* name) override {
@@ -1222,6 +1261,7 @@ class GraphitePipelineCallbacks : public SkSL::PipelineStage::Callbacks {
12221261
const ShaderInfo& fShaderInfo;
12231262
const ShaderNode* fNode;
12241263
std::string* fPreamble;
1264+
const SkRuntimeEffect* fEffect;
12251265
};
12261266

12271267
std::string GenerateRuntimeShaderPreamble(const ShaderInfo& shaderInfo,
@@ -1240,7 +1280,42 @@ std::string GenerateRuntimeShaderPreamble(const ShaderInfo& shaderInfo,
12401280
const SkSL::Program& program = SkRuntimeEffectPriv::Program(*effect);
12411281

12421282
std::string preamble;
1243-
GraphitePipelineCallbacks callbacks{shaderInfo, node, &preamble};
1283+
if (SkRuntimeEffectPriv::UsesColorTransform(effect)) {
1284+
SkSL::String::appendf(
1285+
&preamble,
1286+
"half4 %s(half4 inColor) {"
1287+
"return sk_color_space_transform(inColor, %s, %s, %s, %s, %s);"
1288+
"}",
1289+
get_mangled_name("toLinearSRGB", node->keyIndex()).c_str(),
1290+
get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[0],
1291+
node->keyIndex()).c_str(),
1292+
get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[1],
1293+
node->keyIndex()).c_str(),
1294+
get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[2],
1295+
node->keyIndex()).c_str(),
1296+
get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[3],
1297+
node->keyIndex()).c_str(),
1298+
get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[4],
1299+
node->keyIndex()).c_str());
1300+
SkSL::String::appendf(
1301+
&preamble,
1302+
"half4 %s(half4 inColor) {"
1303+
"return sk_color_space_transform(inColor, %s, %s, %s, %s, %s);"
1304+
"}",
1305+
get_mangled_name("fromLinearSRGB", node->keyIndex()).c_str(),
1306+
get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[5],
1307+
node->keyIndex()).c_str(),
1308+
get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[6],
1309+
node->keyIndex()).c_str(),
1310+
get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[7],
1311+
node->keyIndex()).c_str(),
1312+
get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[8],
1313+
node->keyIndex()).c_str(),
1314+
get_mangled_uniform_name(shaderInfo, kRuntimeEffectColorSpaceTransformUniforms[9],
1315+
node->keyIndex()).c_str());
1316+
}
1317+
1318+
GraphitePipelineCallbacks callbacks{shaderInfo, node, &preamble, effect};
12441319
SkSL::PipelineStage::ConvertProgram(program, "coords", "inColor", "destColor", &callbacks);
12451320
return preamble;
12461321
}
@@ -1449,9 +1524,19 @@ SkSpan<const Uniform> ShaderCodeDictionary::convertUniforms(const SkRuntimeEffec
14491524
using rteUniform = SkRuntimeEffect::Uniform;
14501525
SkSpan<const rteUniform> uniforms = effect->uniforms();
14511526

1527+
int numBaseUniforms = uniforms.size();
1528+
int xtraUniforms = 0;
1529+
if (SkRuntimeEffectPriv::UsesColorTransform(effect)) {
1530+
xtraUniforms += std::size(kRuntimeEffectColorSpaceTransformUniforms);
1531+
}
1532+
14521533
// Convert the SkRuntimeEffect::Uniform array into its Uniform equivalent.
1453-
int numUniforms = uniforms.size();
1534+
int numUniforms = numBaseUniforms + xtraUniforms;
14541535
Uniform* uniformArray = fArena.makeInitializedArray<Uniform>(numUniforms, [&](int index) {
1536+
if (index >= numBaseUniforms) {
1537+
return kRuntimeEffectColorSpaceTransformUniforms[index - numBaseUniforms];
1538+
}
1539+
14551540
const rteUniform* u;
14561541
u = &uniforms[index];
14571542

0 commit comments

Comments
 (0)