hlsl/writer: Fix output for texture intrinsics and types
Fixed: tint:146
Change-Id: Icf356faf7bee364a0783c717ee76ea98056b4401
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/42022
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index 9a60d21..4a7d5f4 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -58,7 +58,9 @@
#include "src/type/f32_type.h"
#include "src/type/i32_type.h"
#include "src/type/matrix_type.h"
+#include "src/type/multisampled_texture_type.h"
#include "src/type/pointer_type.h"
+#include "src/type/sampled_texture_type.h"
#include "src/type/sampler_type.h"
#include "src/type/storage_texture_type.h"
#include "src/type/struct_type.h"
@@ -161,7 +163,10 @@
}
}
+ // emitted_globals is a set used to ensure that globals are emitted once even
+ // if they are used by multiple entry points.
std::unordered_set<Symbol> emitted_globals;
+
// Make sure all entry point data is emitted before the entry point functions
for (auto* func : builder_.AST().Functions()) {
if (!func->IsEntryPoint()) {
@@ -791,9 +796,9 @@
case semantic::IntrinsicType::kTextureNumLevels:
case semantic::IntrinsicType::kTextureNumSamples: {
// All of these intrinsics use the GetDimensions() method on the texture
+ bool is_ms = texture_type->Is<type::MultisampledTexture>();
int num_dimensions = 0;
- const char* swizzle = "";
- bool add_mip_level_in = false;
+ std::string swizzle;
switch (intrinsic->Type()) {
case semantic::IntrinsicType::kTextureDimensions:
@@ -809,10 +814,11 @@
swizzle = ".x";
break;
case type::TextureDimension::k2d:
- num_dimensions = 2;
+ num_dimensions = is_ms ? 3 : 2;
+ swizzle = is_ms ? ".xy" : "";
break;
case type::TextureDimension::k2dArray:
- num_dimensions = 3;
+ num_dimensions = is_ms ? 4 : 3;
swizzle = ".xy";
break;
case type::TextureDimension::k3d:
@@ -838,10 +844,13 @@
TINT_ICE(diagnostics_) << "texture dimension is not arrayed";
return false;
case type::TextureDimension::k1dArray:
- num_dimensions = 2;
+ num_dimensions = is_ms ? 3 : 2;
swizzle = ".y";
break;
case type::TextureDimension::k2dArray:
+ num_dimensions = is_ms ? 4 : 3;
+ swizzle = ".z";
+ break;
case type::TextureDimension::kCubeArray:
num_dimensions = 3;
swizzle = ".z";
@@ -849,7 +858,6 @@
}
break;
case semantic::IntrinsicType::kTextureNumLevels:
- add_mip_level_in = true;
switch (texture_type->dim()) {
default:
TINT_ICE(diagnostics_)
@@ -889,34 +897,63 @@
return false;
}
+ auto* level_arg = arg(Usage::kLevel);
+
+ if (level_arg) {
+ // `NumberOfLevels` is a non-optional argument if `MipLevel` was passed.
+ // Increment the number of dimensions for the temporary vector to
+ // accommodate this.
+ num_dimensions++;
+
+ // If the swizzle was empty, the expression will evaluate to the whole
+ // vector. As we've grown the vector by one element, we now need to
+ // swizzle to keep the result expression equivalent.
+ if (swizzle.empty()) {
+ static constexpr const char* swizzles[] = {"", ".x", ".xy", ".xyz"};
+ swizzle = swizzles[num_dimensions - 1];
+ }
+ }
+
+ if (num_dimensions > 4) {
+ TINT_ICE(diagnostics_)
+ << "Texture query intrinsic temporary vector has " << num_dimensions
+ << " dimensions";
+ return false;
+ }
+
// Declare a variable to hold the queried texture info
auto dims = generate_name(kTempNamePrefix);
if (num_dimensions == 1) {
- pre << "int " << dims << ";\n";
+ pre << "int " << dims << ";";
} else {
- pre << "int" << num_dimensions << " " << dims << ";\n";
+ pre << "int" << num_dimensions << " " << dims << ";";
}
+ pre << std::endl;
+ make_indent(pre);
+
if (!EmitExpression(pre, pre, texture)) {
return false;
}
pre << ".GetDimensions(";
- if (auto* level = arg(Usage::kLevel)) {
- if (!EmitExpression(pre, pre, level)) {
+
+ if (level_arg) {
+ if (!EmitExpression(pre, pre, level_arg)) {
return false;
}
pre << ", ";
- } else if (add_mip_level_in) {
+ } else if (intrinsic->Type() ==
+ semantic::IntrinsicType::kTextureNumLevels) {
pre << "0, ";
}
if (num_dimensions == 1) {
pre << dims;
} else {
+ static constexpr char xyzw[] = {'x', 'y', 'z', 'w'};
assert(num_dimensions > 0);
assert(num_dimensions <= 4);
- static constexpr char xyzw[] = {'x', 'y', 'z', 'w'};
for (int i = 0; i < num_dimensions; i++) {
if (i > 0) {
pre << ", ";
@@ -924,7 +961,9 @@
pre << dims << "." << xyzw[i];
}
}
- pre << ");";
+
+ pre << ");" << std::endl;
+ make_indent(pre);
// The out parameters of the GetDimensions() call is now in temporary
// `dims` variable. This may be packed with other data, so the final
@@ -1578,6 +1617,11 @@
for (auto data : func_sem->ReferencedUniformVariables()) {
auto* var = data.first;
auto* decl = var->Declaration();
+
+ if (!emitted_globals.emplace(decl->symbol()).second) {
+ continue; // Global already emitted
+ }
+
// TODO(dsinclair): We're using the binding to make up the buffer number but
// we should instead be using a provided mapping that uses both buffer and
// set. https://bugs.chromium.org/p/tint/issues/detail?id=104
@@ -1590,13 +1634,6 @@
}
// auto* set = data.second.set;
- // If the global has already been emitted we skip it, it's been emitted by
- // a previous entry point.
- if (emitted_globals.count(decl->symbol()) != 0) {
- continue;
- }
- emitted_globals.insert(decl->symbol());
-
auto* type = decl->type()->UnwrapIfNeeded();
if (auto* strct = type->As<type::Struct>()) {
out << "ConstantBuffer<" << builder_.Symbols().NameFor(strct->symbol())
@@ -1634,15 +1671,12 @@
for (auto data : func_sem->ReferencedStorageBufferVariables()) {
auto* var = data.first;
auto* decl = var->Declaration();
- auto* binding = data.second.binding;
- // If the global has already been emitted we skip it, it's been emitted by
- // a previous entry point.
- if (emitted_globals.count(decl->symbol()) != 0) {
- continue;
+ if (!emitted_globals.emplace(decl->symbol()).second) {
+ continue; // Global already emitted
}
- emitted_globals.insert(decl->symbol());
+ auto* binding = data.second.binding;
auto* ac = decl->type()->As<type::AccessControl>();
if (ac == nullptr) {
diagnostics_.add_error("access control type required for storage buffer");
@@ -1762,6 +1796,34 @@
out << "};" << std::endl << std::endl;
}
+ {
+ bool add_newline = false;
+ for (auto* var : func_sem->ReferencedModuleVariables()) {
+ auto* decl = var->Declaration();
+
+ auto* unwrapped_type = decl->type()->UnwrapAll();
+ if (!unwrapped_type->Is<type::Texture>() &&
+ !unwrapped_type->Is<type::Sampler>()) {
+ continue; // Not interested in this type
+ }
+
+ if (!emitted_globals.emplace(decl->symbol()).second) {
+ continue; // Global already emitted
+ }
+
+ if (!EmitType(out, decl->type(), "")) {
+ return false;
+ }
+ out << " " << namer_.NameFor(builder_.Symbols().NameFor(decl->symbol()))
+ << ";" << std::endl;
+
+ add_newline = true;
+ }
+ if (add_newline) {
+ out << std::endl;
+ }
+ }
+
return true;
}
@@ -2314,6 +2376,9 @@
return false;
}
out << pre.str();
+ if (!TypeOf(c->expr())->Is<type::Void>()) {
+ out << "(void) ";
+ }
out << call_out.str() << ";" << std::endl;
return true;
}
@@ -2439,6 +2504,8 @@
}
out << "Texture";
+ auto* ms = tex->As<type::MultisampledTexture>();
+
switch (tex->dim()) {
case type::TextureDimension::k1d:
out << "1D";
@@ -2447,10 +2514,10 @@
out << "1DArray";
break;
case type::TextureDimension::k2d:
- out << "2D";
+ out << (ms ? "2DMS" : "2D");
break;
case type::TextureDimension::k2dArray:
- out << "2DArray";
+ out << (ms ? "2DMSArray" : "2DArray");
break;
case type::TextureDimension::k3d:
out << "3D";
@@ -2462,11 +2529,31 @@
out << "CubeArray";
break;
default:
- diagnostics_.add_error("Invalid texture dimensions");
+ TINT_UNREACHABLE(diagnostics_)
+ << "unexpected TextureDimension " << tex->dim();
return false;
}
- if (auto* st = tex->As<type::StorageTexture>()) {
+ if (ms) {
+ out << "<";
+ if (ms->type()->Is<type::F32>()) {
+ out << "float4";
+ } else if (ms->type()->Is<type::I32>()) {
+ out << "int4";
+ } else if (ms->type()->Is<type::U32>()) {
+ out << "uint4";
+ } else {
+ TINT_ICE(diagnostics_) << "Unsupported multisampled texture type";
+ return false;
+ }
+
+ // TODO(ben-clayton): The HLSL docs claim that the MS texture type should
+ // also contain the number of samples, which is not part of the WGSL type.
+ // However, DXC seems to consider this optional.
+ // See: https://github.com/gpuweb/gpuweb/issues/1445
+
+ out << ">";
+ } else if (auto* st = tex->As<type::StorageTexture>()) {
auto* component = image_format_to_rwtexture_type(st->image_format());
if (component == nullptr) {
TINT_ICE(diagnostics_) << "Unsupported StorageTexture ImageFormat: "
diff --git a/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc b/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc
index ce84d3c..b9ddb0f 100644
--- a/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc
+++ b/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc
@@ -44,127 +44,153 @@
case ValidTextureOverload::kDimensionsStorageRO1d:
case ValidTextureOverload::kDimensionsStorageWO1d:
return {
- "int _tint_tmp;\n"
- "texture_tint_0.GetDimensions(_tint_tmp);",
+ R"(int _tint_tmp;
+texture_tint_0.GetDimensions(_tint_tmp);
+)",
"_tint_tmp",
};
case ValidTextureOverload::kDimensions1dArray:
case ValidTextureOverload::kDimensionsStorageRO1dArray:
case ValidTextureOverload::kDimensionsStorageWO1dArray:
return {
- "int2 _tint_tmp;\n"
- "texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y);",
+ R"(int2 _tint_tmp;
+texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y);
+)",
"_tint_tmp.x",
};
case ValidTextureOverload::kDimensions2d:
- case ValidTextureOverload::kDimensionsMultisampled2d:
case ValidTextureOverload::kDimensionsDepth2d:
case ValidTextureOverload::kDimensionsStorageRO2d:
case ValidTextureOverload::kDimensionsStorageWO2d:
return {
- "int2 _tint_tmp;\n"
- "texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y);",
+ R"(int2 _tint_tmp;
+texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y);
+)",
"_tint_tmp",
};
+ case ValidTextureOverload::kDimensionsMultisampled2d:
+ return {
+ R"(int3 _tint_tmp;
+texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z);
+)",
+ "_tint_tmp.xy",
+ };
+
case ValidTextureOverload::kDimensions2dArray:
- case ValidTextureOverload::kDimensionsMultisampled2dArray:
case ValidTextureOverload::kDimensionsDepth2dArray:
case ValidTextureOverload::kDimensionsStorageRO2dArray:
case ValidTextureOverload::kDimensionsStorageWO2dArray:
return {
- "int3 _tint_tmp;\n"
- "texture_tint_0."
- "GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z);",
+ R"(int3 _tint_tmp;
+texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z);
+)",
+ "_tint_tmp.xy",
+ };
+ case ValidTextureOverload::kDimensionsMultisampled2dArray:
+ return {
+ R"(int4 _tint_tmp;
+texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z, _tint_tmp.w);
+)",
"_tint_tmp.xy",
};
case ValidTextureOverload::kDimensions3d:
case ValidTextureOverload::kDimensionsStorageRO3d:
case ValidTextureOverload::kDimensionsStorageWO3d:
return {
- "int3 _tint_tmp;\n"
- "texture_tint_0."
- "GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z);",
+ R"(int3 _tint_tmp;
+texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z);
+)",
"_tint_tmp",
};
case ValidTextureOverload::kDimensionsCube:
case ValidTextureOverload::kDimensionsDepthCube:
return {
"int2 _tint_tmp;\n"
- "texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y);",
+ "texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y);\n",
"_tint_tmp.xyy",
};
case ValidTextureOverload::kDimensionsCubeArray:
case ValidTextureOverload::kDimensionsDepthCubeArray:
return {
- "int3 _tint_tmp;\n"
- "texture_tint_0."
- "GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z);",
+ R"(int3 _tint_tmp;
+texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z);
+)",
"_tint_tmp.xyy",
};
case ValidTextureOverload::kDimensions2dLevel:
case ValidTextureOverload::kDimensionsDepth2dLevel:
return {
- "int2 _tint_tmp;\n"
- "texture_tint_0.GetDimensions(1, _tint_tmp.x, _tint_tmp.y);",
- "_tint_tmp",
+ R"(int3 _tint_tmp;
+texture_tint_0.GetDimensions(1, _tint_tmp.x, _tint_tmp.y, _tint_tmp.z);
+)",
+ "_tint_tmp.xy",
};
case ValidTextureOverload::kDimensions2dArrayLevel:
case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
return {
- "int3 _tint_tmp;\n"
- "texture_tint_0."
- "GetDimensions(1, _tint_tmp.x, _tint_tmp.y, _tint_tmp.z);",
+ R"(int4 _tint_tmp;
+texture_tint_0.GetDimensions(1, _tint_tmp.x, _tint_tmp.y, _tint_tmp.z, _tint_tmp.w);
+)",
"_tint_tmp.xy",
};
case ValidTextureOverload::kDimensions3dLevel:
return {
- "int3 _tint_tmp;\n"
- "texture_tint_0."
- "GetDimensions(1, _tint_tmp.x, _tint_tmp.y, _tint_tmp.z);",
- "_tint_tmp",
+ R"(int4 _tint_tmp;
+texture_tint_0.GetDimensions(1, _tint_tmp.x, _tint_tmp.y, _tint_tmp.z, _tint_tmp.w);
+)",
+ "_tint_tmp.xyz",
};
case ValidTextureOverload::kDimensionsCubeLevel:
case ValidTextureOverload::kDimensionsDepthCubeLevel:
return {
- "int2 _tint_tmp;\n"
- "texture_tint_0.GetDimensions(1, _tint_tmp.x, _tint_tmp.y);",
+ R"(int3 _tint_tmp;
+texture_tint_0.GetDimensions(1, _tint_tmp.x, _tint_tmp.y, _tint_tmp.z);
+)",
"_tint_tmp.xyy",
};
case ValidTextureOverload::kDimensionsCubeArrayLevel:
case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
return {
- "int3 _tint_tmp;\n"
- "texture_tint_0."
- "GetDimensions(1, _tint_tmp.x, _tint_tmp.y, _tint_tmp.z);",
+ R"(int4 _tint_tmp;
+texture_tint_0.GetDimensions(1, _tint_tmp.x, _tint_tmp.y, _tint_tmp.z, _tint_tmp.w);
+)",
"_tint_tmp.xyy",
};
case ValidTextureOverload::kNumLayers1dArray:
case ValidTextureOverload::kNumLayersStorageWO1dArray:
return {
- "int2 _tint_tmp;\n"
- "texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y);",
+ R"(int2 _tint_tmp;
+texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y);
+)",
"_tint_tmp.y",
};
case ValidTextureOverload::kNumLayers2dArray:
- case ValidTextureOverload::kNumLayersMultisampled2dArray:
case ValidTextureOverload::kNumLayersDepth2dArray:
case ValidTextureOverload::kNumLayersCubeArray:
case ValidTextureOverload::kNumLayersDepthCubeArray:
case ValidTextureOverload::kNumLayersStorageWO2dArray:
return {
- "int3 _tint_tmp;\n"
- "texture_tint_0."
- "GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z);",
+ R"(int3 _tint_tmp;
+texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z);
+)",
"_tint_tmp.z",
};
+ case ValidTextureOverload::kNumLayersMultisampled2dArray:
+ return {
+ R"(int4 _tint_tmp;
+texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z, _tint_tmp.w);
+)",
+ "_tint_tmp.z",
+ };
+
case ValidTextureOverload::kNumLevels2d:
case ValidTextureOverload::kNumLevelsCube:
case ValidTextureOverload::kNumLevelsDepth2d:
case ValidTextureOverload::kNumLevelsDepthCube:
return {
- "int3 _tint_tmp;\n"
- "texture_tint_0."
- "GetDimensions(0, _tint_tmp.x, _tint_tmp.y, _tint_tmp.z);",
+ R"(int3 _tint_tmp;
+texture_tint_0.GetDimensions(0, _tint_tmp.x, _tint_tmp.y, _tint_tmp.z);
+)",
"_tint_tmp.z",
};
case ValidTextureOverload::kNumLevels2dArray:
@@ -173,23 +199,23 @@
case ValidTextureOverload::kNumLevelsDepth2dArray:
case ValidTextureOverload::kNumLevelsDepthCubeArray:
return {
- "int4 _tint_tmp;\n"
- "texture_tint_0.GetDimensions(0, "
- "_tint_tmp.x, _tint_tmp.y, _tint_tmp.z, _tint_tmp.w);",
+ R"(int4 _tint_tmp;
+texture_tint_0.GetDimensions(0, _tint_tmp.x, _tint_tmp.y, _tint_tmp.z, _tint_tmp.w);
+)",
"_tint_tmp.w",
};
case ValidTextureOverload::kNumSamplesMultisampled2d:
return {
- "int3 _tint_tmp;\n"
- "texture_tint_0."
- "GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z);",
+ R"(int3 _tint_tmp;
+texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z);
+)",
"_tint_tmp.z",
};
case ValidTextureOverload::kNumSamplesMultisampled2dArray:
return {
- "int4 _tint_tmp;\n"
- "texture_tint_0."
- "GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z, _tint_tmp.w);",
+ R"(int4 _tint_tmp;
+texture_tint_0.GetDimensions(_tint_tmp.x, _tint_tmp.y, _tint_tmp.z, _tint_tmp.w);
+)",
"_tint_tmp.w",
};
case ValidTextureOverload::kSample1dF32:
diff --git a/src/writer/hlsl/generator_impl_type_test.cc b/src/writer/hlsl/generator_impl_type_test.cc
index 6f29eed..c75a5e2 100644
--- a/src/writer/hlsl/generator_impl_type_test.cc
+++ b/src/writer/hlsl/generator_impl_type_test.cc
@@ -389,7 +389,7 @@
GeneratorImpl& gen = Build();
ASSERT_TRUE(gen.EmitType(out, &s, "")) << gen.error();
- EXPECT_EQ(result(), "Texture2D");
+ EXPECT_EQ(result(), "Texture2DMS<float4>");
}
struct HlslStorageTextureData {