remove 'in uniform' support from GrSkSLFP, make rules more clear

Bug: skia:
Change-Id: Iaa4d33c1bfb295d87343411ba6aacc8fae68ef9c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/244300
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
Ethan Nicholas 2019-09-26 09:34:20 -04:00 committed by Skia Commit-Bot
parent 403f2955e7
commit ac18a5ca60
11 changed files with 68 additions and 37 deletions

View File

@ -26,7 +26,7 @@ class GrContext;
class GrRenderTargetContext;
const char* SKSL_TEST_SRC = R"(
layout(ctype=float) in uniform half b;
layout(ctype=float) uniform half b;
void main(inout half4 color) {
color.a = color.r*0.3 + color.g*0.6 + color.b*0.1;

View File

@ -23,7 +23,7 @@
#include <stddef.h>
static const char* RUNTIME_FUNCTIONS_SRC = R"(
layout(ctype=SkRect) in uniform half4 gColor;
layout(ctype=SkRect) uniform half4 gColor;
half scale(float x) {
return half(x) / 255;

View File

@ -23,7 +23,7 @@
#include <stddef.h>
const char* gProg = R"(
layout(ctype=SkRect) in uniform half4 gColor;
layout(ctype=SkRect) uniform half4 gColor;
void main(float x, float y, inout half4 color) {
color = half4(half(x)*(1.0/255), half(y)*(1.0/255), gColor.b, 1);

View File

@ -59,7 +59,7 @@ struct Effect {
uint flags;
};
in uniform float dt;
uniform float dt;
)";
static const char* kParticleHeader =
@ -77,7 +77,7 @@ struct Particle {
uint flags;
};
in uniform Effect effect;
uniform Effect effect;
)";
static const char* kDefaultEffectCode =

View File

@ -15,12 +15,12 @@
#include "src/gpu/effects/GrSkSLFP.h"
GR_FP_SRC_STRING SKSL_OVERDRAW_SRC = R"(
layout(ctype=SkPMColor) in uniform half4 color0;
layout(ctype=SkPMColor) in uniform half4 color1;
layout(ctype=SkPMColor) in uniform half4 color2;
layout(ctype=SkPMColor) in uniform half4 color3;
layout(ctype=SkPMColor) in uniform half4 color4;
layout(ctype=SkPMColor) in uniform half4 color5;
layout(ctype=SkPMColor) uniform half4 color0;
layout(ctype=SkPMColor) uniform half4 color1;
layout(ctype=SkPMColor) uniform half4 color2;
layout(ctype=SkPMColor) uniform half4 color3;
layout(ctype=SkPMColor) uniform half4 color4;
layout(ctype=SkPMColor) uniform half4 color5;
void main(inout half4 color) {
half alpha = 255.0 * color.a;

View File

@ -32,14 +32,14 @@
#include "src/gpu/glsl/GrGLSLUniformHandler.h"
GR_FP_SRC_STRING SKSL_ARITHMETIC_SRC = R"(
in uniform float4 k;
layout(key) const in bool enforcePMColor;
uniform float4 k;
in bool enforcePMColor;
in fragmentProcessor child;
void main(inout half4 color) {
half4 dst = sample(child);
color = saturate(half(k.x) * color * dst + half(k.y) * color + half(k.z) * dst + half(k.w));
if (enforcePMColor) {
@if (enforcePMColor) {
color.rgb = min(color.rgb, color.a);
}
}

View File

@ -46,7 +46,7 @@
GR_FP_SRC_STRING SKSL_DITHER_SRC = R"(
// This controls the range of values added to color channels
layout(key) in int rangeType;
in int rangeType;
void main(float x, float y, inout half4 color) {
half value;

View File

@ -34,9 +34,16 @@ GrSkSLFPFactory::GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCap
SkSL::VarDeclarations& v = (SkSL::VarDeclarations&) e;
for (const auto& varStatement : v.fVars) {
const SkSL::Variable& var = *((SkSL::VarDeclaration&) *varStatement).fVar;
if (var.fModifiers.fFlags & SkSL::Modifiers::kIn_Flag) {
fInputVars.push_back(&var);
if ((var.fModifiers.fFlags & SkSL::Modifiers::kIn_Flag) ||
(var.fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag)) {
fInAndUniformVars.push_back(&var);
}
// "in uniform" doesn't make sense outside of .fp files
SkASSERT((var.fModifiers.fFlags & SkSL::Modifiers::kIn_Flag) == 0 ||
(var.fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag) == 0);
// "layout(key)" doesn't make sense outside of .fp files; all 'in' variables are
// part of the key
SkASSERT(!var.fModifiers.fLayout.fKey);
}
}
}
@ -51,7 +58,7 @@ const SkSL::Program* GrSkSLFPFactory::getSpecialization(const SkSL::String& key,
std::unordered_map<SkSL::String, SkSL::Program::Settings::Value> inputMap;
size_t offset = 0;
for (const auto& v : fInputVars) {
for (const auto& v : fInAndUniformVars) {
SkSL::String name(v->fName);
if (&v->fType == fCompiler.context().fInt_Type.get() ||
&v->fType == fCompiler.context().fShort_Type.get()) {
@ -113,11 +120,12 @@ static SkSL::Layout::CType get_ctype(const SkSL::Context& context, const SkSL::V
class GrGLSLSkSLFP : public GrGLSLFragmentProcessor {
public:
GrGLSLSkSLFP(const SkSL::Context* context, const std::vector<const SkSL::Variable*>* inputVars,
GrGLSLSkSLFP(const SkSL::Context* context,
const std::vector<const SkSL::Variable*>* inAndUniformVars,
SkSL::String glsl, std::vector<SkSL::Compiler::FormatArg> formatArgs,
std::vector<SkSL::Compiler::GLSLFunction> functions)
: fContext(*context)
, fInputVars(*inputVars)
, fInAndUniformVars(*inAndUniformVars)
, fGLSL(glsl)
, fFormatArgs(std::move(formatArgs))
, fFunctions(std::move(functions)) {}
@ -149,7 +157,7 @@ public:
}
void emitCode(EmitArgs& args) override {
for (const auto& v : fInputVars) {
for (const auto& v : fInAndUniformVars) {
if (v->fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag && v->fType !=
*fContext.fFragmentProcessor_Type) {
fUniformHandles.push_back(args.fUniformHandler->addUniform(
@ -230,7 +238,7 @@ public:
size_t offset = 0;
const GrSkSLFP& outer = _proc.cast<GrSkSLFP>();
char* inputs = (char*) outer.fInputs.get();
for (const auto& v : outer.fFactory->fInputVars) {
for (const auto& v : outer.fFactory->fInAndUniformVars) {
switch (get_ctype(fContext, *v)) {
case SkSL::Layout::CType::kSkPMColor: {
float f1 = ((uint8_t*) inputs)[offset++] / 255.0;
@ -285,7 +293,7 @@ public:
}
const SkSL::Context& fContext;
const std::vector<const SkSL::Variable*>& fInputVars;
const std::vector<const SkSL::Variable*>& fInAndUniformVars;
// nearly-finished GLSL; still contains printf-style "%s" format tokens
const SkSL::String fGLSL;
std::vector<SkSL::Compiler::FormatArg> fFormatArgs;
@ -386,8 +394,8 @@ GrGLSLFragmentProcessor* GrSkSLFP::onCreateGLSLInstance() const {
printf("%s\n", fFactory->fCompiler.errorText().c_str());
SkASSERT(false);
}
return new GrGLSLSkSLFP(specialized->fContext.get(), &fFactory->fInputVars, glsl, formatArgs,
functions);
return new GrGLSLSkSLFP(specialized->fContext.get(), &fFactory->fInAndUniformVars, glsl,
formatArgs, functions);
}
void GrSkSLFP::onGetGLSLProcessorKey(const GrShaderCaps& caps,
@ -397,13 +405,13 @@ void GrSkSLFP::onGetGLSLProcessorKey(const GrShaderCaps& caps,
size_t offset = 0;
char* inputs = (char*) fInputs.get();
const SkSL::Context& context = fFactory->fCompiler.context();
for (const auto& v : fFactory->fInputVars) {
for (const auto& v : fFactory->fInAndUniformVars) {
if (&v->fType == context.fFragmentProcessor_Type.get()) {
continue;
}
switch (get_ctype(context, *v)) {
case SkSL::Layout::CType::kBool:
if (v->fModifiers.fLayout.fKey) {
if (v->fModifiers.fFlags & SkSL::Modifiers::kIn_Flag) {
fKey += inputs[offset];
b->add32(inputs[offset]);
}
@ -411,7 +419,7 @@ void GrSkSLFP::onGetGLSLProcessorKey(const GrShaderCaps& caps,
break;
case SkSL::Layout::CType::kInt32: {
offset = SkAlign4(offset);
if (v->fModifiers.fLayout.fKey) {
if (v->fModifiers.fFlags & SkSL::Modifiers::kIn_Flag) {
fKey += inputs[offset + 0];
fKey += inputs[offset + 1];
fKey += inputs[offset + 2];
@ -423,7 +431,7 @@ void GrSkSLFP::onGetGLSLProcessorKey(const GrShaderCaps& caps,
}
case SkSL::Layout::CType::kFloat: {
offset = SkAlign4(offset);
if (v->fModifiers.fLayout.fKey) {
if (v->fModifiers.fFlags & SkSL::Modifiers::kIn_Flag) {
fKey += inputs[offset + 0];
fKey += inputs[offset + 1];
fKey += inputs[offset + 2];
@ -436,7 +444,7 @@ void GrSkSLFP::onGetGLSLProcessorKey(const GrShaderCaps& caps,
case SkSL::Layout::CType::kSkPMColor:
case SkSL::Layout::CType::kSkPMColor4f:
case SkSL::Layout::CType::kSkRect:
if (v->fModifiers.fLayout.fKey) {
if (v->fModifiers.fFlags & SkSL::Modifiers::kIn_Flag) {
for (size_t i = 0; i < sizeof(float) * 4; ++i) {
fKey += inputs[offset + i];
}

View File

@ -40,12 +40,12 @@ public:
/**
* Creates a new fragment processor from an SkSL source string and a struct of inputs to the
* program. The input struct's type is derived from the 'in' variables in the SkSL source, so
* e.g. the shader:
* program. The input struct's type is derived from the 'in' and 'uniform' variables in the SkSL
* source, so e.g. the shader:
*
* in bool dither;
* in float x;
* in float y;
* uniform float x;
* uniform float y;
* ....
*
* would expect a pointer to a struct set up like:
@ -56,6 +56,24 @@ public:
* float y;
* };
*
* While both 'in' and 'uniform' variables go into this struct, the difference between them is
* that 'in' variables are statically "baked in" to the generated code, becoming literals,
* whereas uniform variables may be changed from invocation to invocation without having to
* recompile the shader.
*
* As the decision of whether to create a new shader or just upload new uniforms all happens
* behind the scenes, the difference between the two from an end-user perspective is primarily
* in performance: on the one hand, changing the value of an 'in' variable is very expensive
* (requiring the compiler to regenerate the code, upload a new shader to the GPU, and so
* forth), but on the other hand the compiler can optimize around its value because it is known
* at compile time. 'in' variables are therefore suitable for things like flags, where there are
* only a few possible values and a known-in-advance value can cause entire chunks of code to
* become dead (think static @ifs), while 'uniform's are used for continuous values like colors
* and coordinates, where it would be silly to create a separate shader for each possible set of
* values. Other than the (significant) performance implications, the only difference between
* the two is that 'in' variables can be used in static @if / @switch tests. When in doubt, use
* 'uniform'.
*
* As turning SkSL into GLSL / SPIR-V / etc. is fairly expensive, and the output may differ
* based on the inputs, internally the process is divided into two steps: we first parse and
* semantically analyze the SkSL into an internal representation, and then "specialize" this
@ -174,7 +192,7 @@ public:
std::shared_ptr<SkSL::Program> fBaseProgram;
std::vector<const SkSL::Variable*> fInputVars;
std::vector<const SkSL::Variable*> fInAndUniformVars;
std::unordered_map<SkSL::String, std::unique_ptr<const SkSL::Program>> fSpecializations;

View File

@ -66,7 +66,12 @@ bool ByteCodeGenerator::generateCode() {
if (declVar->fModifiers.fLayout.fBuiltin >= 0) {
continue;
}
if (declVar->fModifiers.fFlags & Modifiers::kIn_Flag) {
// if you trip this assert, it means the program has raw 'in' variables. You
// should either specialize the program (Compiler::specialize) to bake in the
// final values of the 'in' variables, or not use 'in' variables (maybe you
// meant to use 'uniform' instead?).
SkASSERT(!(declVar->fModifiers.fFlags & Modifiers::kIn_Flag));
if (declVar->fModifiers.fFlags & Modifiers::kUniform_Flag) {
for (int i = SlotCount(declVar->fType); i > 0; --i) {
fOutput->fInputSlots.push_back(fOutput->fGlobalCount++);
}

View File

@ -589,7 +589,7 @@ DEF_TEST(SkSLInterpreterCompound, r) {
"}\n"
// Uniforms, array-of-structs, dynamic indices
"in uniform Rect gRects[4];\n"
"uniform Rect gRects[4];\n"
"Rect get_rect(int i) { return gRects[i]; }\n"
// Kitchen sink (swizzles, inout, SoAoS)