writer/hlsl: Move the coord/arrayidx packing to utility function
So we can also use this for the `spirv` backend
Bug: tint:146
Change-Id: I26f70125a5015946d2428a6e669da32bdea23bcd
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/33780
Reviewed-by: David Neto <dneto@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 5199a59..bf1d393 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -426,6 +426,8 @@
"src/validator/validator_test_helper.h",
"src/writer/float_to_string.cc",
"src/writer/float_to_string.h",
+ "src/writer/pack_coord_arrayidx.cc",
+ "src/writer/pack_coord_arrayidx.h",
"src/writer/text.cc",
"src/writer/text.h",
"src/writer/text_generator.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0ff1ee2..e41d3b7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -247,6 +247,8 @@
validator/validator_test_helper.h
writer/float_to_string.cc
writer/float_to_string.h
+ writer/pack_coord_arrayidx.cc
+ writer/pack_coord_arrayidx.h
writer/text.cc
writer/text.h
writer/text_generator.cc
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index 5eb1a3b..86edcf7 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -52,6 +52,7 @@
#include "src/ast/unary_op_expression.h"
#include "src/ast/variable_decl_statement.h"
#include "src/writer/float_to_string.h"
+#include "src/writer/pack_coord_arrayidx.h"
namespace tint {
namespace writer {
@@ -103,20 +104,6 @@
return 0;
}
-ast::TypeConstructorExpression* AsVectorConstructor(ast::Expression* expr) {
- if (!expr->IsConstructor())
- return nullptr;
- auto* constructor = expr->AsConstructor();
- if (!constructor->IsTypeConstructor()) {
- return nullptr;
- }
- auto* type_constructor = constructor->AsTypeConstructor();
- if (!type_constructor->type()->IsVector()) {
- return nullptr;
- }
- return type_constructor;
-}
-
} // namespace
GeneratorImpl::GeneratorImpl(Context* ctx, ast::Module* module)
@@ -775,41 +762,12 @@
// Array index needs to be appended to the coordinates.
auto* param_coords = params[pidx.coords];
auto* param_array_index = params[pidx.array_index];
-
- uint32_t packed_coords_size;
- ast::type::Type* packed_coords_el_ty; // Currenly must be f32.
- if (param_coords->result_type()->IsVector()) {
- auto* vec = param_coords->result_type()->AsVector();
- packed_coords_size = vec->size() + 1;
- packed_coords_el_ty = vec->type();
- } else {
- packed_coords_size = 2;
- packed_coords_el_ty = param_coords->result_type();
- }
-
- // Cast param_array_index to the vector element type
- ast::TypeConstructorExpression array_index_cast(packed_coords_el_ty,
- {param_array_index});
- array_index_cast.set_result_type(packed_coords_el_ty);
-
- ast::type::VectorType packed_coords_ty(packed_coords_el_ty,
- packed_coords_size);
-
- ast::ExpressionList coords;
- // If the coordinates are already passed in a vector constructor, extract
- // the elements into the new vector instead of nesting a vector-in-vector.
- if (auto* vc = AsVectorConstructor(param_coords)) {
- coords = vc->values();
- } else {
- coords.emplace_back(param_coords);
- }
- coords.emplace_back(&array_index_cast);
-
- ast::TypeConstructorExpression constructor{&packed_coords_ty,
- std::move(coords)};
-
- if (!EmitExpression(pre, out, &constructor))
+ if (!PackCoordAndArrayIndex(param_coords, param_array_index,
+ [&](ast::TypeConstructorExpression* packed) {
+ return EmitExpression(pre, out, packed);
+ })) {
return false;
+ }
} else {
if (!EmitExpression(pre, out, params[pidx.coords]))
diff --git a/src/writer/pack_coord_arrayidx.cc b/src/writer/pack_coord_arrayidx.cc
new file mode 100644
index 0000000..3384ee6
--- /dev/null
+++ b/src/writer/pack_coord_arrayidx.cc
@@ -0,0 +1,85 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/writer/pack_coord_arrayidx.h"
+
+#include <utility>
+
+#include "src/ast/expression.h"
+#include "src/ast/type/vector_type.h"
+#include "src/ast/type_constructor_expression.h"
+
+namespace tint {
+namespace writer {
+
+namespace {
+
+ast::TypeConstructorExpression* AsVectorConstructor(ast::Expression* expr) {
+ if (!expr->IsConstructor())
+ return nullptr;
+ auto* constructor = expr->AsConstructor();
+ if (!constructor->IsTypeConstructor()) {
+ return nullptr;
+ }
+ auto* type_constructor = constructor->AsTypeConstructor();
+ if (!type_constructor->type()->IsVector()) {
+ return nullptr;
+ }
+ return type_constructor;
+}
+
+} // namespace
+
+bool PackCoordAndArrayIndex(
+ ast::Expression* coords,
+ ast::Expression* array_idx,
+ std::function<bool(ast::TypeConstructorExpression*)> callback) {
+ uint32_t packed_size;
+ ast::type::Type* packed_el_ty; // Currenly must be f32.
+ if (coords->result_type()->IsVector()) {
+ auto* vec = coords->result_type()->AsVector();
+ packed_size = vec->size() + 1;
+ packed_el_ty = vec->type();
+ } else {
+ packed_size = 2;
+ packed_el_ty = coords->result_type();
+ }
+
+ if (!packed_el_ty) {
+ return false; // missing type info
+ }
+
+ // Cast array_idx to the vector element type
+ ast::TypeConstructorExpression array_index_cast(packed_el_ty, {array_idx});
+ array_index_cast.set_result_type(packed_el_ty);
+
+ ast::type::VectorType packed_ty(packed_el_ty, packed_size);
+
+ // If the coordinates are already passed in a vector constructor, extract
+ // the elements into the new vector instead of nesting a vector-in-vector.
+ ast::ExpressionList packed;
+ if (auto* vc = AsVectorConstructor(coords)) {
+ packed = vc->values();
+ } else {
+ packed.emplace_back(coords);
+ }
+ packed.emplace_back(&array_index_cast);
+
+ ast::TypeConstructorExpression constructor{&packed_ty, std::move(packed)};
+
+ return callback(&constructor);
+}
+
+} // namespace writer
+} // namespace tint
diff --git a/src/writer/pack_coord_arrayidx.h b/src/writer/pack_coord_arrayidx.h
new file mode 100644
index 0000000..d31728a
--- /dev/null
+++ b/src/writer/pack_coord_arrayidx.h
@@ -0,0 +1,52 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_WRITER_PACK_COORD_ARRAYIDX_H_
+#define SRC_WRITER_PACK_COORD_ARRAYIDX_H_
+
+#include <functional>
+
+#include "src/source.h"
+
+namespace tint {
+
+namespace ast {
+class Expression;
+class TypeConstructorExpression;
+} // namespace ast
+
+namespace writer {
+
+/// A helper function use to generate texture intrinsic function calls for
+/// backends that expect the texture coordinate and array index to be packed
+/// together into a single 'coordinate' parameter.
+/// PackCoordAndArrayIndex() calls the @p callback function with a vector
+/// expression containing the elements of @p coords followed by the single
+/// element of @p array_idx cast to the @p coords element type.
+/// All types must have been assigned to the expressions and their child nodes
+/// before calling.
+/// @param coords the texture coordinates. May be a scalar, `vec2` or `vec3`.
+/// @param array_idx the texture array index. Must be a scalar.
+/// @param callback the function called with the packed result. Note that the
+/// pointer argument is only valid for the duration of the call.
+/// @returns the value returned by `callback` to indicate success
+bool PackCoordAndArrayIndex(
+ ast::Expression* coords,
+ ast::Expression* array_idx,
+ std::function<bool(ast::TypeConstructorExpression*)> callback);
+
+} // namespace writer
+} // namespace tint
+
+#endif // SRC_WRITER_PACK_COORD_ARRAYIDX_H_