Support structs in runtime effects
Uses the pipeline-stage callback mechanism. It mangles the type name
(with a test to verify that this works), and then calls defineStruct
with the entire SkSL struct definition string.
Bug: skia:10939
Change-Id: If14cf1b11faaa80ad8d4086cdacf68532bac43fc
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/368809
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
diff --git a/fuzz/oss_fuzz/FuzzSKSL2Pipeline.cpp b/fuzz/oss_fuzz/FuzzSKSL2Pipeline.cpp
index f2fdd35..79897e3 100644
--- a/fuzz/oss_fuzz/FuzzSKSL2Pipeline.cpp
+++ b/fuzz/oss_fuzz/FuzzSKSL2Pipeline.cpp
@@ -34,6 +34,7 @@
}
void defineFunction(const char* /*decl*/, const char* /*body*/, bool /*isMain*/) override {}
+ void defineStruct(const char* /*definition*/) override {}
String sampleChild(int index, String coords) override {
return SkSL::String::printf("sample(%d%s%s)", index, coords.empty() ? "" : ", ",
diff --git a/resources/sksl/shared/Assignment.sksl b/resources/sksl/shared/Assignment.sksl
index 16afcec..710e9a3 100644
--- a/resources/sksl/shared/Assignment.sksl
+++ b/resources/sksl/shared/Assignment.sksl
@@ -1,12 +1,11 @@
uniform half4 colorGreen;
-// TODO(skia:10939): Structs not working in Runtime Effects yet
-//struct S {
-// float f;
-// float af[5];
-// half4 h4;
-// half4 ah4[5];
-//};
+struct S {
+ float f;
+ float af[5];
+ half4 h4;
+ half4 ah4[5];
+};
half4 main() {
/* assign to scalar */ int i; i = 0;
@@ -18,11 +17,10 @@
/* assign to array of matrix */ half3x3 ah2x4[1]; ah2x4[0] = half3x3(1,2,3,4,5,6,7,8,9);
/* assign to array swizzle */ float4 af4[1]; af4[0].x = 0; af4[0].ywxz = float4(1);
-// TODO(skia:10939): Structs not working in Runtime Effects yet
-// /* assign to struct variable */ S s; s.f = 0;
-// /* assign to struct array */ s.af[1] = 0;
-// /* assign to struct swizzle */ s.h4.zxy = half3(9);
-// /* assign to struct array swizzle */ s.ah4[2].yw = half2(5);
+ /* assign to struct variable */ S s; s.f = 0;
+ /* assign to struct array */ s.af[1] = 0;
+ /* assign to struct swizzle */ s.h4.zxy = half3(9);
+ /* assign to struct array swizzle */ s.ah4[2].yw = half2(5);
// Not allowed in ES2
// /* assign to array idx by lookup */ ai[0] = 0; ai[ai[0]] = 0;
@@ -30,14 +28,14 @@
// Not allowed natively in GLSL, but SkSL will turn these into valid GLSL expressions.
/* assign to folded ternary */ half l, r; (true ? l : r) = 0;
/* assign to unary plus */ +ai[0] += +ai4[0][0];
-// TODO(skia:10939): Structs not working in Runtime Effects yet
-// /* assign to struct unary plus */ +s.f = 1; +s.af[0] = 2;
-// +s.h4 = half4(1); +s.ah4[0] = half4(2);
+ /* assign to struct unary plus */ +s.f = 1; +s.af[0] = 2;
+ +s.h4 = half4(1); +s.ah4[0] = half4(2);
// Keep these variables alive
af4[0] *= float(ah2x4[0][0][0]);
i4.y *= i;
x.y *= l;
+ s.f *= l;
return colorGreen;
}
diff --git a/src/gpu/effects/GrSkSLFP.cpp b/src/gpu/effects/GrSkSLFP.cpp
index c370a5f..e2316e5 100644
--- a/src/gpu/effects/GrSkSLFP.cpp
+++ b/src/gpu/effects/GrSkSLFP.cpp
@@ -83,6 +83,10 @@
}
}
+ void defineStruct(const char* definition) override {
+ fArgs.fFragBuilder->definitionAppend(definition);
+ }
+
String sampleChild(int index, String coords) override {
return String(fSelf->invokeChild(index, fArgs, coords).c_str());
}
diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.h b/src/gpu/glsl/GrGLSLShaderBuilder.h
index 21c8b2f..5182795 100644
--- a/src/gpu/glsl/GrGLSLShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLShaderBuilder.h
@@ -92,6 +92,8 @@
this->definitions().append(";\n");
}
+ void definitionAppend(const char* str) { this->definitions().append(str); }
+
void declareGlobal(const GrShaderVar&);
// Generates a unique variable name for holding the result of a temporary expression when it's
diff --git a/src/sksl/SkSLGLSLCodeGenerator.cpp b/src/sksl/SkSLGLSLCodeGenerator.cpp
index 3e38ea2..2b290c7 100644
--- a/src/sksl/SkSLGLSLCodeGenerator.cpp
+++ b/src/sksl/SkSLGLSLCodeGenerator.cpp
@@ -82,7 +82,7 @@
return fProgram.fCaps->usesPrecisionModifiers();
}
-// Returns the name of the type with array dimensions, e.g. `float[2][4]`.
+// Returns the name of the type with array dimensions, e.g. `float[2]`.
String GLSLCodeGenerator::getTypeName(const Type& type) {
switch (type.typeKind()) {
case Type::TypeKind::kVector: {
@@ -165,10 +165,13 @@
for (const auto& f : type.fields()) {
this->writeModifiers(f.fModifiers, false);
this->writeTypePrecision(*f.fType);
- // sizes (which must be static in structs) are part of the type name here
- this->writeType(*f.fType);
+ const Type& baseType = f.fType->isArray() ? f.fType->componentType() : *f.fType;
+ this->writeType(baseType);
this->write(" ");
this->write(f.fName);
+ if (f.fType->isArray()) {
+ this->write("[" + to_string(f.fType->columns()) + "]");
+ }
this->writeLine(";");
}
fIndentation--;
@@ -1188,6 +1191,7 @@
return "";
case Type::TypeKind::kVector: // fall through
case Type::TypeKind::kMatrix:
+ case Type::TypeKind::kArray:
return this->getTypePrecision(type.componentType());
default:
break;
diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp
index 46c1c00..4064c08 100644
--- a/src/sksl/SkSLIRGenerator.cpp
+++ b/src/sksl/SkSLIRGenerator.cpp
@@ -1117,16 +1117,7 @@
if (returnType == nullptr) {
return;
}
- auto typeIsAllowed = [&](const Type* t) {
-#if defined(SKSL_STANDALONE)
- return true;
-#else
- GrSLType unusedSLType;
- return fKind != Program::kRuntimeEffect_Kind ||
- type_to_grsltype(fContext, *t, &unusedSLType);
-#endif
- };
- if (returnType->isArray() || !typeIsAllowed(returnType)) {
+ if (returnType->isArray()) {
this->errorReporter().error(
f.fOffset, "functions may not return type '" + returnType->displayName() + "'");
return;
@@ -1163,8 +1154,7 @@
// Only the (builtin) declarations of 'sample' are allowed to have FP parameters.
// (You can pass other opaque types to functions safely; this restriction is
// fragment-processor specific.)
- if ((*type == *fContext.fTypes.fFragmentProcessor && !fIsBuiltinCode) ||
- !typeIsAllowed(type)) {
+ if (*type == *fContext.fTypes.fFragmentProcessor && !fIsBuiltinCode) {
this->errorReporter().error(
param.fOffset, "parameters of type '" + type->displayName() + "' not allowed");
return;
diff --git a/src/sksl/SkSLMain.cpp b/src/sksl/SkSLMain.cpp
index 7bfac72..e688ed8 100644
--- a/src/sksl/SkSLMain.cpp
+++ b/src/sksl/SkSLMain.cpp
@@ -420,6 +420,10 @@
fOutput += String(decl) + "{" + body + "}";
}
+ void defineStruct(const char* definition) override {
+ fOutput += definition;
+ }
+
String sampleChild(int index, String coords) override {
return String::printf("sample(%s%s%s)", fChildNames[index].c_str(),
coords.empty() ? "" : ", ", coords.c_str());
diff --git a/src/sksl/SkSLPipelineStageCodeGenerator.cpp b/src/sksl/SkSLPipelineStageCodeGenerator.cpp
index ef76b88..804ecd3 100644
--- a/src/sksl/SkSLPipelineStageCodeGenerator.cpp
+++ b/src/sksl/SkSLPipelineStageCodeGenerator.cpp
@@ -25,6 +25,7 @@
#include "src/sksl/ir/SkSLProgramElement.h"
#include "src/sksl/ir/SkSLReturnStatement.h"
#include "src/sksl/ir/SkSLStatement.h"
+#include "src/sksl/ir/SkSLStructDefinition.h"
#include "src/sksl/ir/SkSLSwizzle.h"
#include "src/sksl/ir/SkSLTernaryExpression.h"
#include "src/sksl/ir/SkSLVarDeclarations.h"
@@ -63,8 +64,12 @@
void writeModifiers(const Modifiers& modifiers);
+ // Handles arrays correctly, eg: `float x[2]`
+ String typedVariable(const Type& type, StringFragment name);
+
void writeVarDeclaration(const VarDeclaration& var);
void writeGlobalVarDeclaration(const GlobalVarDeclaration& g);
+ void writeStructDefinition(const StructDefinition& s);
void writeExpression(const Expression& expr, Precedence parentPrecedence);
void writeFunctionCall(const FunctionCall& c);
@@ -107,6 +112,7 @@
std::unordered_map<const Variable*, String> fUniformNames;
std::unordered_map<const FunctionDeclaration*, String> fFunctionNames;
+ std::unordered_map<const Type*, String> fStructNames;
StringStream* fBuffer = nullptr;
bool fCastReturnsToHalf = false;
@@ -333,6 +339,18 @@
}
}
+void PipelineStageCodeGenerator::writeStructDefinition(const StructDefinition& s) {
+ const Type& type = s.type();
+ String mangledName = fCallbacks->getMangledName(String(type.name()).c_str());
+ String definition = "struct " + mangledName + " {\n";
+ for (const auto& f : type.fields()) {
+ definition += this->typedVariable(*f.fType, f.fName) + ";\n";
+ }
+ definition += "};\n";
+ fStructNames.insert({&type, std::move(mangledName)});
+ fCallbacks->defineStruct(definition.c_str());
+}
+
void PipelineStageCodeGenerator::writeProgramElement(const ProgramElement& e) {
switch (e.kind()) {
case ProgramElement::Kind::kGlobalVar:
@@ -345,10 +363,12 @@
// Runtime effects don't allow calls to undefined functions, so prototypes are never
// necessary. If we do support them, they should emit calls to emitFunctionPrototype.
break;
- // Custom types (enums and structs) are ignored (so they don't yet work in runtime effects).
+ case ProgramElement::Kind::kStructDefinition:
+ this->writeStructDefinition(e.as<StructDefinition>());
+ break;
+ // Enums are ignored (so they don't yet work in runtime effects).
// We need to emit their declarations (via callback), with name mangling support.
case ProgramElement::Kind::kEnum: // skbug.com/11296
- case ProgramElement::Kind::kStructDefinition: // skbug.com/10939
case ProgramElement::Kind::kExtension:
case ProgramElement::Kind::kInterfaceBlock:
@@ -361,7 +381,8 @@
}
String PipelineStageCodeGenerator::typeName(const Type& type) {
- return type.name();
+ auto it = fStructNames.find(&type);
+ return it != fStructNames.end() ? it->second : type.name();
}
void PipelineStageCodeGenerator::writeType(const Type& type) {
@@ -524,16 +545,19 @@
}
}
+String PipelineStageCodeGenerator::typedVariable(const Type& type, StringFragment name) {
+ const Type& baseType = type.isArray() ? type.componentType() : type;
+
+ String decl = this->typeName(baseType) + " " + name;
+ if (type.isArray()) {
+ decl += "[" + to_string(type.columns()) + "]";
+ }
+ return decl;
+}
+
void PipelineStageCodeGenerator::writeVarDeclaration(const VarDeclaration& var) {
this->writeModifiers(var.var().modifiers());
- this->writeType(var.baseType());
- this->write(" ");
- this->write(var.var().name());
- if (var.arraySize() > 0) {
- this->write("[");
- this->write(to_string(var.arraySize()));
- this->write("]");
- }
+ this->write(this->typedVariable(var.var().type(), var.var().name()));
if (var.value()) {
this->write(" = ");
this->writeExpression(*var.value(), Precedence::kTopLevel);
diff --git a/src/sksl/SkSLPipelineStageCodeGenerator.h b/src/sksl/SkSLPipelineStageCodeGenerator.h
index c022ada..8f5aa5d 100644
--- a/src/sksl/SkSLPipelineStageCodeGenerator.h
+++ b/src/sksl/SkSLPipelineStageCodeGenerator.h
@@ -24,6 +24,7 @@
virtual String getMangledName(const char* name) { return name; }
virtual void defineFunction(const char* declaration, const char* body, bool isMain) = 0;
+ virtual void defineStruct(const char* definition) = 0;
virtual String declareUniform(const VarDeclaration*) = 0;
virtual String sampleChild(int index, String coords) = 0;
diff --git a/tests/SkRuntimeEffectTest.cpp b/tests/SkRuntimeEffectTest.cpp
index a36f03f..f364c53 100644
--- a/tests/SkRuntimeEffectTest.cpp
+++ b/tests/SkRuntimeEffectTest.cpp
@@ -401,3 +401,44 @@
REPORTER_ASSERT(r, c.fB == 0.5625f);
REPORTER_ASSERT(r, c.fA == 1.0f);
}
+
+static void test_RuntimeEffectStructNameReuse(skiatest::Reporter* r, GrRecordingContext* rContext) {
+ // Test that two different runtime effects can reuse struct names in a single paint operation
+ auto [childEffect, err] = SkRuntimeEffect::Make(SkString(
+ "uniform shader paint;"
+ "struct S { half4 rgba; };"
+ "void process(inout S s) { s.rgba.rgb *= 0.5; }"
+ "half4 main() { S s; s.rgba = sample(paint); process(s); return s.rgba; }"
+ ));
+ REPORTER_ASSERT(r, childEffect, "%s\n", err.c_str());
+ sk_sp<SkShader> nullChild = nullptr;
+ sk_sp<SkShader> child = childEffect->makeShader(/*uniforms=*/nullptr, &nullChild,
+ /*childCount=*/1, /*localMatrix=*/nullptr,
+ /*isOpaque=*/false);
+
+ SkImageInfo info = SkImageInfo::Make(2, 2, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+ sk_sp<SkSurface> surface = rContext
+ ? SkSurface::MakeRenderTarget(rContext, SkBudgeted::kNo, info)
+ : SkSurface::MakeRaster(info);
+ REPORTER_ASSERT(r, surface);
+
+ TestEffect effect(r, surface);
+ effect.build(
+ "uniform shader child;"
+ "struct S { float2 coord; };"
+ "void process(inout S s) { s.coord = s.coord.yx; }"
+ "half4 main(float2 p) { S s; s.coord = p; process(s); return sample(child, s.coord); "
+ "}");
+ effect.child("child") = child;
+ effect.test(0xFF00407F, [](SkCanvas*, SkPaint* paint) {
+ paint->setColor4f({0.99608f, 0.50196f, 0.0f, 1.0f});
+ });
+}
+
+DEF_TEST(SkRuntimeStructNameReuse, r) {
+ test_RuntimeEffectStructNameReuse(r, nullptr);
+}
+
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkRuntimeStructNameReuse_GPU, r, ctxInfo) {
+ test_RuntimeEffectStructNameReuse(r, ctxInfo.directContext());
+}
diff --git a/tests/SkSLTest.cpp b/tests/SkSLTest.cpp
index 214d52e..dcce46e 100644
--- a/tests/SkSLTest.cpp
+++ b/tests/SkSLTest.cpp
@@ -130,7 +130,7 @@
SKSL_TEST(SkSLIntFoldingES2, "folding/IntFoldingES2.sksl")
SKSL_TEST(SkSLFloatFolding, "folding/FloatFolding.sksl")
SKSL_TEST(SkSLMatrixFoldingES2, "folding/MatrixFoldingES2.sksl")
-SKSL_TEST_CPU(SkSLSelfAssignment, "folding/SelfAssignment.sksl")
+SKSL_TEST(SkSLSelfAssignment, "folding/SelfAssignment.sksl")
SKSL_TEST(SkSLShortCircuitBoolFolding, "folding/ShortCircuitBoolFolding.sksl")
SKSL_TEST(SkSLVectorScalarFolding, "folding/VectorScalarFolding.sksl")
SKSL_TEST(SkSLVectorVectorFolding, "folding/VectorVectorFolding.sksl")
@@ -173,6 +173,7 @@
SKSL_TEST(SkSLScalarConversionConstructorsES2, "shared/ScalarConversionConstructorsES2.sksl")
SKSL_TEST(SkSLStackingVectorCasts, "shared/StackingVectorCasts.sksl")
SKSL_TEST(SkSLStaticIf, "shared/StaticIf.sksl")
+SKSL_TEST(SkSLStructsInFunctions, "shared/StructsInFunctions.sksl")
SKSL_TEST(SkSLSwizzleBoolConstants, "shared/SwizzleBoolConstants.sksl")
SKSL_TEST(SkSLSwizzleByConstantIndex, "shared/SwizzleByConstantIndex.sksl")
SKSL_TEST(SkSLSwizzleConstants, "shared/SwizzleConstants.sksl")
@@ -192,12 +193,6 @@
*/
/*
-TODO(skia:10939): enable this test when Runtime Effects supports structs in function signatures
-SKSL_TEST(SkSLSelfAssignment, "folding/SelfAssignment.sksl")
-SKSL_TEST(SkSLStructsInFunctions, "shared/StructsInFunctions.sksl")
-*/
-
-/*
TODO(skia:11209): enable these tests when Runtime Effects have support for ES3
SKSL_TEST(SkSLIntFoldingES3, "folding/IntFoldingES3.sksl")
diff --git a/tests/sksl/inliner/TrivialArgumentsInlineDirectly.glsl b/tests/sksl/inliner/TrivialArgumentsInlineDirectly.glsl
index 96832b7..96479ba 100644
--- a/tests/sksl/inliner/TrivialArgumentsInlineDirectly.glsl
+++ b/tests/sksl/inliner/TrivialArgumentsInlineDirectly.glsl
@@ -5,8 +5,8 @@
uniform vec4 uh4;
uniform bool b;
struct S {
- vec4[1] ah4;
- float[1] ah;
+ vec4 ah4[1];
+ float ah[1];
vec4 h4;
float h;
};
diff --git a/tests/sksl/shared/Assignment.asm.frag b/tests/sksl/shared/Assignment.asm.frag
index f66558b..5c9be9d 100644
--- a/tests/sksl/shared/Assignment.asm.frag
+++ b/tests/sksl/shared/Assignment.asm.frag
@@ -15,6 +15,12 @@
OpName %ai4 "ai4"
OpName %ah2x4 "ah2x4"
OpName %af4 "af4"
+OpName %S "S"
+OpMemberName %S 0 "f"
+OpMemberName %S 1 "af"
+OpMemberName %S 2 "h4"
+OpMemberName %S 3 "ah4"
+OpName %s "s"
OpDecorate %sk_FragColor RelaxedPrecision
OpDecorate %sk_FragColor Location 0
OpDecorate %sk_FragColor Index 0
@@ -34,10 +40,20 @@
OpDecorate %65 RelaxedPrecision
OpDecorate %62 RelaxedPrecision
OpDecorate %_arr_v4float_int_1 ArrayStride 16
-OpDecorate %87 RelaxedPrecision
-OpDecorate %94 RelaxedPrecision
-OpDecorate %95 RelaxedPrecision
-OpDecorate %98 RelaxedPrecision
+OpDecorate %_arr_float_int_5 ArrayStride 16
+OpDecorate %_arr_v4float_int_5 ArrayStride 16
+OpMemberDecorate %S 0 Offset 0
+OpMemberDecorate %S 1 Offset 16
+OpMemberDecorate %S 2 Offset 96
+OpMemberDecorate %S 2 RelaxedPrecision
+OpMemberDecorate %S 3 Offset 112
+OpMemberDecorate %S 3 RelaxedPrecision
+OpDecorate %88 RelaxedPrecision
+OpDecorate %92 RelaxedPrecision
+OpDecorate %108 RelaxedPrecision
+OpDecorate %115 RelaxedPrecision
+OpDecorate %116 RelaxedPrecision
+OpDecorate %122 RelaxedPrecision
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
@@ -87,6 +103,14 @@
%_arr_v4float_int_1 = OpTypeArray %v4float %int_1
%_ptr_Function__arr_v4float_int_1 = OpTypePointer Function %_arr_v4float_int_1
%73 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
+%int_5 = OpConstant %int 5
+%_arr_float_int_5 = OpTypeArray %float %int_5
+%_arr_v4float_int_5 = OpTypeArray %v4float %int_5
+%S = OpTypeStruct %float %_arr_float_int_5 %v4float %_arr_v4float_int_5
+%_ptr_Function_S = OpTypePointer Function %S
+%85 = OpConstantComposite %v3float %float_9 %float_9 %float_9
+%89 = OpConstantComposite %v2float %float_5 %float_5
+%102 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
%_ptr_Function_v3float = OpTypePointer Function %v3float
%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
%_entrypoint = OpFunction %void None %15
@@ -103,6 +127,7 @@
%ai4 = OpVariable %_ptr_Function__arr_v4int_int_1 Function
%ah2x4 = OpVariable %_ptr_Function__arr_mat3v3float_int_1 Function
%af4 = OpVariable %_ptr_Function__arr_v4float_int_1 Function
+%s = OpVariable %_ptr_Function_S Function
OpStore %i4 %28
%32 = OpAccessChain %_ptr_Function_float %x %int_3
OpStore %32 %float_0
@@ -126,29 +151,53 @@
%75 = OpLoad %v4float %74
%76 = OpVectorShuffle %v4float %75 %73 6 4 7 5
OpStore %74 %76
-%77 = OpAccessChain %_ptr_Function_int %ai %int_0
-%78 = OpLoad %int %77
-%79 = OpAccessChain %_ptr_Function_v4int %ai4 %int_0
-%80 = OpLoad %v4int %79
-%81 = OpCompositeExtract %int %80 0
-%82 = OpIAdd %int %78 %81
-OpStore %77 %82
-%83 = OpAccessChain %_ptr_Function_v4float %af4 %int_0
-%84 = OpLoad %v4float %83
-%85 = OpAccessChain %_ptr_Function_v3float %ah2x4 %int_0 %int_0
-%87 = OpLoad %v3float %85
-%88 = OpCompositeExtract %float %87 0
-%89 = OpVectorTimesScalar %v4float %84 %88
-OpStore %83 %89
-%90 = OpAccessChain %_ptr_Function_int %i4 %int_1
-%91 = OpLoad %int %90
-%92 = OpIMul %int %91 %int_0
+%83 = OpAccessChain %_ptr_Function_float %s %int_0
+OpStore %83 %float_0
+%84 = OpAccessChain %_ptr_Function_float %s %int_1 %int_1
+OpStore %84 %float_0
+%86 = OpAccessChain %_ptr_Function_v4float %s %int_2
+%87 = OpLoad %v4float %86
+%88 = OpVectorShuffle %v4float %87 %85 5 6 4 3
+OpStore %86 %88
+%90 = OpAccessChain %_ptr_Function_v4float %s %int_3 %int_2
+%91 = OpLoad %v4float %90
+%92 = OpVectorShuffle %v4float %91 %89 0 4 2 5
OpStore %90 %92
-%93 = OpAccessChain %_ptr_Function_float %x %int_1
-%94 = OpLoad %float %93
-%95 = OpFMul %float %94 %float_0
-OpStore %93 %95
-%96 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
-%98 = OpLoad %v4float %96
-OpReturnValue %98
+%93 = OpAccessChain %_ptr_Function_int %ai %int_0
+%94 = OpLoad %int %93
+%95 = OpAccessChain %_ptr_Function_v4int %ai4 %int_0
+%96 = OpLoad %v4int %95
+%97 = OpCompositeExtract %int %96 0
+%98 = OpIAdd %int %94 %97
+OpStore %93 %98
+%99 = OpAccessChain %_ptr_Function_float %s %int_0
+OpStore %99 %float_1
+%100 = OpAccessChain %_ptr_Function_float %s %int_1 %int_0
+OpStore %100 %float_2
+%101 = OpAccessChain %_ptr_Function_v4float %s %int_2
+OpStore %101 %73
+%103 = OpAccessChain %_ptr_Function_v4float %s %int_3 %int_0
+OpStore %103 %102
+%104 = OpAccessChain %_ptr_Function_v4float %af4 %int_0
+%105 = OpLoad %v4float %104
+%106 = OpAccessChain %_ptr_Function_v3float %ah2x4 %int_0 %int_0
+%108 = OpLoad %v3float %106
+%109 = OpCompositeExtract %float %108 0
+%110 = OpVectorTimesScalar %v4float %105 %109
+OpStore %104 %110
+%111 = OpAccessChain %_ptr_Function_int %i4 %int_1
+%112 = OpLoad %int %111
+%113 = OpIMul %int %112 %int_0
+OpStore %111 %113
+%114 = OpAccessChain %_ptr_Function_float %x %int_1
+%115 = OpLoad %float %114
+%116 = OpFMul %float %115 %float_0
+OpStore %114 %116
+%117 = OpAccessChain %_ptr_Function_float %s %int_0
+%118 = OpLoad %float %117
+%119 = OpFMul %float %118 %float_0
+OpStore %117 %119
+%120 = OpAccessChain %_ptr_Uniform_v4float %10 %int_0
+%122 = OpLoad %v4float %120
+OpReturnValue %122
OpFunctionEnd
diff --git a/tests/sksl/shared/Assignment.glsl b/tests/sksl/shared/Assignment.glsl
index fe884e6..5f2fb97 100644
--- a/tests/sksl/shared/Assignment.glsl
+++ b/tests/sksl/shared/Assignment.glsl
@@ -1,6 +1,12 @@
out vec4 sk_FragColor;
uniform vec4 colorGreen;
+struct S {
+ float f;
+ float af[5];
+ vec4 h4;
+ vec4 ah4[5];
+};
vec4 main() {
ivec4 i4;
i4 = ivec4(1, 2, 3, 4);
@@ -16,9 +22,19 @@
vec4 af4[1];
af4[0].x = 0.0;
af4[0].ywxz = vec4(1.0);
+ S s;
+ s.f = 0.0;
+ s.af[1] = 0.0;
+ s.h4.zxy = vec3(9.0);
+ s.ah4[2].yw = vec2(5.0);
ai[0] += ai4[0].x;
+ s.f = 1.0;
+ s.af[0] = 2.0;
+ s.h4 = vec4(1.0);
+ s.ah4[0] = vec4(2.0);
af4[0] *= ah2x4[0][0].x;
i4.y *= 0;
x.y *= 0.0;
+ s.f *= 0.0;
return colorGreen;
}
diff --git a/tests/sksl/shared/Assignment.metal b/tests/sksl/shared/Assignment.metal
index e28e820..7a8d59a 100644
--- a/tests/sksl/shared/Assignment.metal
+++ b/tests/sksl/shared/Assignment.metal
@@ -1,6 +1,12 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
+struct S {
+ float f;
+ array<float, 5> af;
+ float4 h4;
+ array<float4, 5> ah4;
+};
struct Uniforms {
float4 colorGreen;
};
@@ -27,10 +33,20 @@
array<float4, 1> af4;
af4[0].x = 0.0;
af4[0].ywxz = float4(1.0);
+ S s;
+ s.f = 0.0;
+ s.af[1] = 0.0;
+ s.h4.zxy = float3(9.0);
+ s.ah4[2].yw = float2(5.0);
ai[0] += ai4[0].x;
+ s.f = 1.0;
+ s.af[0] = 2.0;
+ s.h4 = float4(1.0);
+ s.ah4[0] = float4(2.0);
af4[0] *= ah2x4[0][0].x;
i4.y = i4.y * 0;
x.y = x.y * 0.0;
+ s.f *= 0.0;
_out.sk_FragColor = _uniforms.colorGreen;
return _out;
}
diff --git a/tests/sksl/shared/StructMaxDepth.glsl b/tests/sksl/shared/StructMaxDepth.glsl
index 0b3f753..d6ab111 100644
--- a/tests/sksl/shared/StructMaxDepth.glsl
+++ b/tests/sksl/shared/StructMaxDepth.glsl
@@ -25,27 +25,27 @@
};
in S8 s8;
struct SA1 {
- int[8] x;
+ int x[8];
};
struct SA2 {
- SA1[7] x;
+ SA1 x[7];
};
struct SA3 {
- SA2[6] x;
+ SA2 x[6];
};
struct SA4 {
- SA3[5] x;
+ SA3 x[5];
};
struct SA5 {
- SA4[4] x;
+ SA4 x[4];
};
struct SA6 {
- SA5[3] x;
+ SA5 x[3];
};
struct SA7 {
- SA6[2] x;
+ SA6 x[2];
};
struct SA8 {
- SA7[1] x;
+ SA7 x[1];
};
in SA8 sa8[9];
diff --git a/tests/sksl/shared/Structs.glsl b/tests/sksl/shared/Structs.glsl
index 71b7630..07d907c 100644
--- a/tests/sksl/shared/Structs.glsl
+++ b/tests/sksl/shared/Structs.glsl
@@ -7,7 +7,7 @@
A a1;
struct B {
float x;
- float[2] y;
+ float y[2];
layout (binding = 1) A z;
};
B b1;