[hlsl-writer] Emit uniform variables.

This CL adds emission of uniform storage class variables to the HLSL
backend. If the variable is a base type (float, int, etc) it is emitted
as a `cbuffer`. If the variable is a struct it will emit as a
`ConstantBuffer`.

Bug: tint:7
Change-Id: I9932d30df24c023c58d3a2ba4167bcb7ccb85dae
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/26920
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
dan sinclair 2020-08-19 18:57:09 +00:00 committed by Commit Bot service account
parent 7df4a845d9
commit bfaa6f8e57
3 changed files with 137 additions and 2 deletions

View File

@ -787,6 +787,50 @@ bool GeneratorImpl::EmitEntryPointData(ast::EntryPoint* ep) {
}
}
bool emitted_uniform = false;
for (auto data : func->referenced_uniform_variables()) {
auto* var = data.first;
// 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
auto* binding = data.second.binding;
if (binding == nullptr) {
error_ = "unable to find binding information for uniform: " + var->name();
return false;
}
// auto* set = data.second.set;
auto* type = var->type()->UnwrapAliasesIfNeeded();
if (type->IsStruct()) {
auto* strct = type->AsStruct();
out_ << "ConstantBuffer<" << strct->name() << "> " << var->name()
<< " : register(b" << binding->value() << ");" << std::endl;
} else {
// TODO(dsinclair): There is outstanding spec work to require all uniform
// buffers to be [[block]] decorated, which means structs. This is
// currently not the case, so this code handles the cases where the data
// is not a block.
// Relevant: https://github.com/gpuweb/gpuweb/issues/1004
// https://github.com/gpuweb/gpuweb/issues/1008
out_ << "cbuffer : register(b" << binding->value() << ") {" << std::endl;
increment_indent();
make_indent();
if (!EmitType(type, "")) {
return false;
}
out_ << " " << var->name() << ";" << std::endl;
decrement_indent();
out_ << "};" << std::endl;
}
emitted_uniform = true;
}
if (emitted_uniform) {
out_ << std::endl;
}
auto ep_name = ep->name();
if (ep_name.empty()) {
ep_name = ep->function_name();

View File

@ -29,9 +29,12 @@
#include "src/ast/scalar_constructor_expression.h"
#include "src/ast/set_decoration.h"
#include "src/ast/sint_literal.h"
#include "src/ast/struct.h"
#include "src/ast/type/alias_type.h"
#include "src/ast/type/array_type.h"
#include "src/ast/type/f32_type.h"
#include "src/ast/type/i32_type.h"
#include "src/ast/type/struct_type.h"
#include "src/ast/type/vector_type.h"
#include "src/ast/type/void_type.h"
#include "src/ast/variable.h"
@ -280,7 +283,7 @@ frag_main_out frag_main(frag_main_in tint_in) {
)");
}
TEST_F(HlslGeneratorImplTest, DISABLED_Emit_Function_EntryPoint_With_Uniform) {
TEST_F(HlslGeneratorImplTest, Emit_Function_EntryPoint_With_Uniform) {
ast::type::VoidType void_type;
ast::type::F32Type f32;
ast::type::VectorType vec4(&f32, 4);
@ -326,7 +329,91 @@ TEST_F(HlslGeneratorImplTest, DISABLED_Emit_Function_EntryPoint_With_Uniform) {
GeneratorImpl g(&mod);
ASSERT_TRUE(g.Generate()) << g.error();
EXPECT_EQ(g.result(), R"( ... )");
EXPECT_EQ(g.result(), R"(cbuffer : register(b0) {
vector<float, 4> coord;
};
void frag_main() {
float v = coord.x;
return;
}
)");
}
TEST_F(HlslGeneratorImplTest, Emit_Function_EntryPoint_With_UniformStruct) {
ast::type::VoidType void_type;
ast::type::F32Type f32;
ast::type::VectorType vec4(&f32, 4);
ast::StructMemberList members;
members.push_back(std::make_unique<ast::StructMember>(
"coord", &vec4, ast::StructMemberDecorationList{}));
auto str = std::make_unique<ast::Struct>();
str->set_members(std::move(members));
ast::type::StructType s(std::move(str));
s.set_name("Uniforms");
auto alias = std::make_unique<ast::type::AliasType>("Uniforms", &s);
Context ctx;
ast::Module mod;
TypeDeterminer td(&ctx, &mod);
auto coord_var =
std::make_unique<ast::DecoratedVariable>(std::make_unique<ast::Variable>(
"uniforms", ast::StorageClass::kUniform, alias.get()));
mod.AddAliasType(alias.get());
ast::VariableDecorationList decos;
decos.push_back(std::make_unique<ast::BindingDecoration>(0));
decos.push_back(std::make_unique<ast::SetDecoration>(1));
coord_var->set_decorations(std::move(decos));
td.RegisterVariableForTesting(coord_var.get());
mod.AddGlobalVariable(std::move(coord_var));
ast::VariableList params;
auto func = std::make_unique<ast::Function>("frag_main", std::move(params),
&void_type);
auto var =
std::make_unique<ast::Variable>("v", ast::StorageClass::kFunction, &f32);
var->set_constructor(std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::MemberAccessorExpression>(
std::make_unique<ast::IdentifierExpression>("uniforms"),
std::make_unique<ast::IdentifierExpression>("coord")),
std::make_unique<ast::IdentifierExpression>("x")));
auto body = std::make_unique<ast::BlockStatement>();
body->append(std::make_unique<ast::VariableDeclStatement>(std::move(var)));
body->append(std::make_unique<ast::ReturnStatement>());
func->set_body(std::move(body));
mod.AddFunction(std::move(func));
auto ep = std::make_unique<ast::EntryPoint>(ast::PipelineStage::kFragment, "",
"frag_main");
mod.AddEntryPoint(std::move(ep));
ASSERT_TRUE(td.Determine()) << td.error();
GeneratorImpl g(&mod);
ASSERT_TRUE(g.Generate()) << g.error();
EXPECT_EQ(g.result(), R"(typedef struct {
vector<float, 4> coord;
} Uniforms;
ConstantBuffer<Uniforms> uniforms : register(b0);
void frag_main() {
float v = uniforms.coord.x;
return;
}
)");
}
TEST_F(HlslGeneratorImplTest,

View File

@ -1347,6 +1347,10 @@ bool GeneratorImpl::EmitEntryPointFunction(ast::EntryPoint* ep) {
// we should instead be using a provided mapping that uses both buffer and
// set. https://bugs.chromium.org/p/tint/issues/detail?id=104
auto* binding = data.second.binding;
if (binding == nullptr) {
error_ = "unable to find binding information for uniform: " + var->name();
return false;
}
// auto* set = data.second.set;
out_ << "constant ";