[glsl][ir] Emit struct types.
This CL adds emission of struct types to the GLSL IR backend.
Bug: 42251044
Change-Id: I7238aa554d3799646383af63d1bf9dd01348e94f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/204274
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/glsl/writer/printer/printer.cc b/src/tint/lang/glsl/writer/printer/printer.cc
index a499f72..ec54a22 100644
--- a/src/tint/lang/glsl/writer/printer/printer.cc
+++ b/src/tint/lang/glsl/writer/printer/printer.cc
@@ -28,6 +28,8 @@
#include "src/tint/lang/glsl/writer/printer/printer.h"
#include <string>
+#include <unordered_map>
+#include <unordered_set>
#include <utility>
#include "src/tint/lang/core/constant/splat.h"
@@ -61,9 +63,11 @@
#include "src/tint/lang/core/type/void.h"
#include "src/tint/lang/glsl/writer/common/printer_support.h"
#include "src/tint/lang/glsl/writer/common/version.h"
+#include "src/tint/utils/containers/map.h"
#include "src/tint/utils/generator/text_generator.h"
#include "src/tint/utils/macros/scoped_assignment.h"
#include "src/tint/utils/rtti/switch.h"
+#include "src/tint/utils/text/string.h"
using namespace tint::core::fluent_types; // NOLINT
@@ -126,6 +130,12 @@
/// A hashmap of value to name
Hashmap<const core::ir::Value*, std::string, 32> names_;
+ /// Map of builtin structure to unique generated name
+ std::unordered_map<const core::type::Struct*, std::string> builtin_struct_names_;
+
+ // The set of emitted structs
+ std::unordered_set<const core::type::Struct*> emitted_structs_;
+
/// @returns the name of the given value, creating a new unique name if the value is unnamed in
/// the module.
std::string NameOf(const core::ir::Value* value) {
@@ -142,6 +152,19 @@
return ir_.symbols.New(prefix).Name();
}
+ /// @param s the structure
+ /// @returns the name of the structure, taking special care of builtin structures that start
+ /// with double underscores. If the structure is a builtin, then the returned name will be a
+ /// unique name without the leading underscores.
+ std::string StructName(const core::type::Struct* s) {
+ auto name = s->Name().Name();
+ if (HasPrefix(name, "__")) {
+ name = tint::GetOrAdd(builtin_struct_names_, s,
+ [&] { return UniqueIdentifier(name.substr(2)); });
+ }
+ return name;
+ }
+
/// Emit the function
/// @param func the function to emit
void EmitFunction(const core::ir::Function* func) {
@@ -307,11 +330,42 @@
},
[&](const core::type::Vector* v) { EmitVectorType(out, v); },
[&](const core::type::Matrix* m) { EmitMatrixType(out, m); },
+ [&](const core::type::Struct* s) {
+ EmitStructType(s);
+ out << StructName(s);
+ },
// TODO(dsinclair): Handle remaining types
TINT_ICE_ON_NO_MATCH);
}
+ void EmitStructType(const core::type::Struct* str) {
+ auto it = emitted_structs_.emplace(str);
+ if (!it.second) {
+ return;
+ }
+
+ // This does not append directly to the preamble because a struct may require other
+ // structs to get emitted before it. So, the struct emits into a temporary text buffer, then
+ // anything it depends on will emit to the preamble first, and then it copies the text
+ // buffer into the preamble.
+ TextBuffer str_buf;
+ Line(&str_buf) << "\n" << "struct " << StructName(str) << " {";
+
+ str_buf.IncrementIndent();
+
+ for (auto* mem : str->Members()) {
+ auto out = Line(&str_buf);
+ EmitTypeAndName(out, mem->Type(), mem->Name().Name());
+ out << ";";
+ }
+
+ str_buf.DecrementIndent();
+ Line(&str_buf) << "};";
+
+ preamble_buffer_.Append(str_buf);
+ }
+
void EmitVectorType(StringStream& out, const core::type::Vector* v) {
tint::Switch(
v->Type(), //
@@ -450,11 +504,26 @@
[&](const core::type::F16*) { PrintF16(out, c->ValueAs<f16>()); },
[&](const core::type::Vector* v) { EmitConstantVector(out, v, c); },
[&](const core::type::Matrix* m) { EmitConstantMatrix(out, m, c); },
+ [&](const core::type::Struct* s) { EmitConstantStruct(out, s, c); },
// TODO(dsinclair): Emit remaining constant types
TINT_ICE_ON_NO_MATCH);
}
+ void EmitConstantStruct(StringStream& out,
+ const core::type::Struct* s,
+ const core::constant::Value* c) {
+ EmitType(out, s);
+ ScopedParen sp(out);
+
+ for (size_t i = 0; i < s->Members().Length(); ++i) {
+ if (i > 0) {
+ out << ", ";
+ }
+ EmitConstant(out, c->Index(i));
+ }
+ }
+
void EmitConstantVector(StringStream& out,
const core::type::Vector* v,
const core::constant::Value* c) {
diff --git a/src/tint/lang/glsl/writer/type_test.cc b/src/tint/lang/glsl/writer/type_test.cc
index 14a21a7..e717b37 100644
--- a/src/tint/lang/glsl/writer/type_test.cc
+++ b/src/tint/lang/glsl/writer/type_test.cc
@@ -366,8 +366,7 @@
)");
}
-// TODO(dsinclair): Add struct support
-TEST_F(GlslWriterTest, DISABLED_EmitType_Struct) {
+TEST_F(GlslWriterTest, EmitType_Struct) {
auto* s = ty.Struct(mod.symbols.New("S"), {
{mod.symbols.Register("a"), ty.i32()},
{mod.symbols.Register("b"), ty.f32()},
@@ -388,40 +387,12 @@
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void foo() {
- S a = {};
+ S a = S(0, 0.0f);
}
)");
}
-// TODO(dsinclair): Add struct support
-TEST_F(GlslWriterTest, DISABLED_EmitType_Struct_NameCollision) {
- auto* s = ty.Struct(mod.symbols.New("S"), {
- {mod.symbols.Register("double"), ty.i32()},
- {mod.symbols.Register("float"), ty.f32()},
- });
- auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kCompute);
- func->SetWorkgroupSize(1, 1, 1);
- b.Append(func->Block(), [&] {
- b.Var("a", ty.ptr(core::AddressSpace::kPrivate, s));
- b.Return(func);
- });
-
- ASSERT_TRUE(Generate()) << err_ << output_.glsl;
- EXPECT_EQ(output_.glsl, GlslHeader() + R"(
-struct S {
- int tint_symbol_1;
- float tint_symbol_2;
-};
-
-layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-void foo() {
- S a = {};
-}
-)");
-}
-
-// TODO(dsinclair): Add struct support
-TEST_F(GlslWriterTest, DISABLED_EmitType_Struct_Dedup) {
+TEST_F(GlslWriterTest, EmitType_Struct_Dedup) {
auto* s = ty.Struct(mod.symbols.New("S"), {
{mod.symbols.Register("a"), ty.i32()},
{mod.symbols.Register("b"), ty.f32()},
@@ -443,8 +414,45 @@
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void foo() {
- S a = {};
- S b = {};
+ S a = S(0, 0.0f);
+ S b = S(0, 0.0f);
+}
+)");
+}
+
+TEST_F(GlslWriterTest, EmitType_Struct_Nested) {
+ auto* inner =
+ ty.Struct(mod.symbols.New("Inner"), {
+ {mod.symbols.Register("x"), ty.u32()},
+ {mod.symbols.Register("y"), ty.vec4<f32>()},
+ });
+
+ auto* s = ty.Struct(mod.symbols.New("S"), {
+ {mod.symbols.Register("a"), ty.i32()},
+ {mod.symbols.Register("b"), inner},
+ });
+ auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kCompute);
+ func->SetWorkgroupSize(1, 1, 1);
+ b.Append(func->Block(), [&] {
+ b.Var("a", ty.ptr(core::AddressSpace::kPrivate, s));
+ b.Return(func);
+ });
+
+ ASSERT_TRUE(Generate()) << err_ << output_.glsl;
+ EXPECT_EQ(output_.glsl, GlslHeader() + R"(
+struct Inner {
+ uint x;
+ vec4 y;
+};
+
+struct S {
+ int a;
+ Inner b;
+};
+
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void foo() {
+ S a = S(0, Inner(0u, vec4(0.0f)));
}
)");
}