diff --git a/src/dawn/native/d3d/ShaderUtils.cpp b/src/dawn/native/d3d/ShaderUtils.cpp index bf9225438e..3dafb08712 100644 --- a/src/dawn/native/d3d/ShaderUtils.cpp +++ b/src/dawn/native/d3d/ShaderUtils.cpp @@ -208,9 +208,6 @@ ResultOrError> CompileShaderFXC(const d3d::D3DBytecodeCompilati MaybeError TranslateToHLSL(d3d::HlslCompilationRequest r, CacheKey::UnsafeUnkeyedValue tracePlatform, CompiledShader* compiledShader) { - std::ostringstream errorStream; - errorStream << "Tint HLSL failure:\n"; - tint::ast::transform::Manager transformManager; tint::ast::transform::DataMap transformInputs; @@ -232,7 +229,7 @@ MaybeError TranslateToHLSL(d3d::HlslCompilationRequest r, std::move(requestedNames)); } - if (r.stage == SingleShaderStage::Vertex) { + if (!r.useTintIR && r.stage == SingleShaderStage::Vertex) { transformManager.Add(); transformInputs.Add( r.firstIndexOffsetShaderRegister, r.firstIndexOffsetRegisterSpace); @@ -257,7 +254,7 @@ MaybeError TranslateToHLSL(d3d::HlslCompilationRequest r, bool usesVertexIndex = false; bool usesInstanceIndex = false; - if (r.stage == SingleShaderStage::Vertex) { + if (!r.useTintIR && r.stage == SingleShaderStage::Vertex) { if (auto* data = transformOutputs.Get()) { usesVertexIndex = data->has_vertex_index; usesInstanceIndex = data->has_instance_index; @@ -301,6 +298,11 @@ MaybeError TranslateToHLSL(d3d::HlslCompilationRequest r, DAWN_INVALID_IF(result != tint::Success, "An error occurred while generating HLSL:\n%s", result.Failure().reason.Str()); + if (r.useTintIR && r.stage == SingleShaderStage::Vertex) { + usesVertexIndex = result->has_vertex_index; + usesInstanceIndex = result->has_instance_index; + } + compiledShader->usesVertexIndex = usesVertexIndex; compiledShader->usesInstanceIndex = usesInstanceIndex; compiledShader->hlslSource = std::move(result->hlsl); diff --git a/src/dawn/native/d3d11/ShaderModuleD3D11.cpp b/src/dawn/native/d3d11/ShaderModuleD3D11.cpp index 038982af79..d8cb75c25a 100644 --- a/src/dawn/native/d3d11/ShaderModuleD3D11.cpp +++ b/src/dawn/native/d3d11/ShaderModuleD3D11.cpp @@ -88,13 +88,14 @@ ResultOrError ShaderModule::Compile( ScopedTintICEHandler scopedICEHandler(device); const EntryPointMetadata& entryPoint = GetEntryPoint(programmableStage.entryPoint); + const bool useTintIR = device->IsToggleEnabled(Toggle::UseTintIR); d3d::D3DCompilationRequest req = {}; req.tracePlatform = UnsafeUnkeyedValue(device->GetPlatform()); req.hlsl.shaderModel = 50; req.hlsl.disableSymbolRenaming = device->IsToggleEnabled(Toggle::DisableSymbolRenaming); req.hlsl.dumpShaders = device->IsToggleEnabled(Toggle::DumpShaders); - req.hlsl.useTintIR = device->IsToggleEnabled(Toggle::UseTintIR); + req.hlsl.useTintIR = useTintIR; req.bytecode.hasShaderF16Feature = false; req.bytecode.compileFlags = compileFlags; @@ -195,19 +196,22 @@ ResultOrError ShaderModule::Compile( req.hlsl.stage = stage; // Put the firstIndex into the internally reserved group and binding to avoid conflicting with // any existing bindings. - req.hlsl.firstIndexOffsetRegisterSpace = PipelineLayout::kReservedConstantsBindGroupIndex; - req.hlsl.firstIndexOffsetShaderRegister = PipelineLayout::kFirstIndexOffsetBindingNumber; - // Remap to the desired space and binding, [0, kFirstIndexOffsetConstantBufferSlot]. - { - tint::BindingPoint srcBindingPoint{req.hlsl.firstIndexOffsetRegisterSpace, - req.hlsl.firstIndexOffsetShaderRegister}; - // D3D11 (HLSL SM5.0) doesn't support spaces, so we have to put the firstIndex in the - // default space(0) - tint::BindingPoint dstBindingPoint{0u, PipelineLayout::kFirstIndexOffsetConstantBufferSlot}; - - bindings.uniform.emplace( - srcBindingPoint, - tint::hlsl::writer::binding::Uniform{dstBindingPoint.group, dstBindingPoint.binding}); + if (!useTintIR) { + req.hlsl.firstIndexOffsetRegisterSpace = PipelineLayout::kReservedConstantsBindGroupIndex; + req.hlsl.firstIndexOffsetShaderRegister = PipelineLayout::kFirstIndexOffsetBindingNumber; + // Remap to the desired space and binding, [0, kFirstIndexOffsetConstantBufferSlot]. + { + tint::BindingPoint srcBindingPoint{req.hlsl.firstIndexOffsetRegisterSpace, + req.hlsl.firstIndexOffsetShaderRegister}; + // D3D11 (HLSL SM5.0) doesn't support spaces, so we have to put the firstIndex in the + // default space(0) + tint::BindingPoint dstBindingPoint{0u, + PipelineLayout::kFirstIndexOffsetConstantBufferSlot}; + + bindings.uniform.emplace(srcBindingPoint, + tint::hlsl::writer::binding::Uniform{dstBindingPoint.group, + dstBindingPoint.binding}); + } } req.hlsl.substituteOverrideConfig = std::move(substituteOverrideConfig); @@ -222,10 +226,13 @@ ResultOrError ShaderModule::Compile( req.hlsl.tintOptions.bindings = std::move(bindings); if (entryPoint.usesNumWorkgroups) { - // D3D11 (HLSL SM5.0) doesn't support spaces, so we have to put the numWorkgroups in the - // default space(0) + DAWN_ASSERT(stage == SingleShaderStage::Compute); req.hlsl.tintOptions.root_constant_binding_point = tint::BindingPoint{0, PipelineLayout::kNumWorkgroupsConstantBufferSlot}; + } else if (useTintIR && stage == SingleShaderStage::Vertex) { + // For vertex shaders, use root constant to add FirstIndexOffset, if needed + req.hlsl.tintOptions.root_constant_binding_point = + tint::BindingPoint{0, PipelineLayout::kFirstIndexOffsetConstantBufferSlot}; } if (stage == SingleShaderStage::Vertex) { diff --git a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp index c4629bc708..309bf74ae9 100644 --- a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp +++ b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp @@ -133,6 +133,7 @@ ResultOrError ShaderModule::Compile( ScopedTintICEHandler scopedICEHandler(device); const EntryPointMetadata& entryPoint = GetEntryPoint(programmableStage.entryPoint); + const bool useTintIR = device->IsToggleEnabled(Toggle::UseTintIR); d3d::D3DCompilationRequest req = {}; req.tracePlatform = UnsafeUnkeyedValue(device->GetPlatform()); @@ -140,7 +141,7 @@ ResultOrError ShaderModule::Compile( ->GetAppliedShaderModelUnderToggles(device->GetTogglesState()); req.hlsl.disableSymbolRenaming = device->IsToggleEnabled(Toggle::DisableSymbolRenaming); req.hlsl.dumpShaders = device->IsToggleEnabled(Toggle::DumpShaders); - req.hlsl.useTintIR = device->IsToggleEnabled(Toggle::UseTintIR); + req.hlsl.useTintIR = useTintIR; req.bytecode.hasShaderF16Feature = device->HasFeature(Feature::ShaderF16); req.bytecode.compileFlags = compileFlags; @@ -327,8 +328,10 @@ ResultOrError ShaderModule::Compile( req.hlsl.inputProgram = &(tintProgram->program); req.hlsl.entryPointName = programmableStage.entryPoint.c_str(); req.hlsl.stage = stage; - req.hlsl.firstIndexOffsetShaderRegister = layout->GetFirstIndexOffsetShaderRegister(); - req.hlsl.firstIndexOffsetRegisterSpace = layout->GetFirstIndexOffsetRegisterSpace(); + if (!useTintIR) { + req.hlsl.firstIndexOffsetRegisterSpace = layout->GetFirstIndexOffsetRegisterSpace(); + req.hlsl.firstIndexOffsetShaderRegister = layout->GetFirstIndexOffsetShaderRegister(); + } req.hlsl.substituteOverrideConfig = std::move(substituteOverrideConfig); req.hlsl.tintOptions.disable_robustness = !device->IsRobustnessEnabled(); @@ -341,8 +344,14 @@ ResultOrError ShaderModule::Compile( : tint::hlsl::writer::Options::Compiler::kDXC; if (entryPoint.usesNumWorkgroups) { + DAWN_ASSERT(stage == SingleShaderStage::Compute); req.hlsl.tintOptions.root_constant_binding_point = tint::BindingPoint{ layout->GetNumWorkgroupsRegisterSpace(), layout->GetNumWorkgroupsShaderRegister()}; + } else if (useTintIR && stage == SingleShaderStage::Vertex) { + // For vertex shaders, use root constant to add FirstIndexOffset, if needed + req.hlsl.tintOptions.root_constant_binding_point = + tint::BindingPoint{layout->GetFirstIndexOffsetRegisterSpace(), + layout->GetFirstIndexOffsetShaderRegister()}; } // TODO(dawn:549): HLSL generation outputs the indices into the diff --git a/src/tint/lang/hlsl/writer/common/output.h b/src/tint/lang/hlsl/writer/common/output.h index ad55e6e224..56547d776d 100644 --- a/src/tint/lang/hlsl/writer/common/output.h +++ b/src/tint/lang/hlsl/writer/common/output.h @@ -76,6 +76,12 @@ struct Output { /// The workgroup size information, if the entry point was a compute shader WorkgroupInfo workgroup_info{}; + + /// True if the shader uses vertex_index + bool has_vertex_index = false; + + /// True if the shader uses instance_index + bool has_instance_index = false; }; } // namespace tint::hlsl::writer diff --git a/src/tint/lang/hlsl/writer/printer/printer.cc b/src/tint/lang/hlsl/writer/printer/printer.cc index eacd1031ff..4ca7bca1a8 100644 --- a/src/tint/lang/hlsl/writer/printer/printer.cc +++ b/src/tint/lang/hlsl/writer/printer/printer.cc @@ -1569,6 +1569,17 @@ class Printer : public tint::TextGenerator { ++which_clip_distance; } else { name = builtin_to_attribute(builtin.value()); + + switch (builtin.value()) { + case core::BuiltinValue::kVertexIndex: + result_.has_vertex_index = true; + break; + case core::BuiltinValue::kInstanceIndex: + result_.has_instance_index = true; + break; + default: + break; + } } TINT_ASSERT(!name.empty()); diff --git a/src/tint/lang/hlsl/writer/raise/raise.cc b/src/tint/lang/hlsl/writer/raise/raise.cc index 7e9c1033ed..2dbf82cd35 100644 --- a/src/tint/lang/hlsl/writer/raise/raise.cc +++ b/src/tint/lang/hlsl/writer/raise/raise.cc @@ -173,6 +173,7 @@ Result Raise(core::ir::Module& module, const Options& options) { { raise::ShaderIOConfig config; config.num_workgroups_binding = options.root_constant_binding_point; + config.first_index_offset_binding = options.root_constant_binding_point; config.add_input_position_member = pixel_local_enabled; config.truncate_interstage_variables = options.truncate_interstage_variables; config.interstage_locations = std::move(options.interstage_locations); diff --git a/src/tint/lang/hlsl/writer/raise/shader_io.cc b/src/tint/lang/hlsl/writer/raise/shader_io.cc index 5bc92304f4..82ba776769 100644 --- a/src/tint/lang/hlsl/writer/raise/shader_io.cc +++ b/src/tint/lang/hlsl/writer/raise/shader_io.cc @@ -73,6 +73,10 @@ struct StateImpl : core::ir::transform::ShaderIOBackendState { std::optional second_clip_distance_index; Hashset truncated_indices; + // If set, points to a var of type struct with fields for offsets to apply to vertex_index and + // instance_index + core::ir::Var* tint_first_index_offset = nullptr; + /// Constructor StateImpl(core::ir::Module& mod, core::ir::Function* f, const ShaderIOConfig& c) : ShaderIOBackendState(mod, f), config(c) {} @@ -199,6 +203,7 @@ struct StateImpl : core::ir::transform::ShaderIOBackendState { } Vector input_data; + bool has_vertex_or_instance_index = false; for (uint32_t i = 0; i < inputs.Length(); ++i) { // Save the index of certain builtins for GetIndex. Although struct members will not be // added for these inputs, we still add entries to input_data so that other inputs with @@ -210,6 +215,10 @@ struct StateImpl : core::ir::transform::ShaderIOBackendState { subgroup_size_index = i; } else if (*builtin == core::BuiltinValue::kNumWorkgroups) { num_workgroups_index = i; + } else if (*builtin == core::BuiltinValue::kVertexIndex) { + has_vertex_or_instance_index = true; + } else if (*builtin == core::BuiltinValue::kInstanceIndex) { + has_vertex_or_instance_index = true; } } @@ -218,6 +227,22 @@ struct StateImpl : core::ir::transform::ShaderIOBackendState { input_indices.Resize(input_data.Length()); + if (config.first_index_offset_binding.has_value() && has_vertex_or_instance_index) { + // Create a FirstIndexOffset uniform buffer. GetInput will use this to offset the + // vertex/instance index. + TINT_ASSERT(func->IsVertex()); + tint::Vector members; + auto* str = ty.Struct(ir.symbols.New("tint_first_index_offset_struct"), + { + {ir.symbols.New("vertex_index"), ty.u32(), {}}, + {ir.symbols.New("instance_index"), ty.u32(), {}}, + }); + tint_first_index_offset = b.Var("tint_first_index_offset", uniform, str); + tint_first_index_offset->SetBindingPoint(config.first_index_offset_binding->group, + config.first_index_offset_binding->binding); + ir.root_block->Append(tint_first_index_offset); + } + // Sort the struct members to satisfy HLSL interfacing matching rules. // We use stable_sort so that two members with the same attributes maintain their relative // ordering (e.g. kClipDistance). @@ -406,12 +431,27 @@ struct StateImpl : core::ir::transform::ShaderIOBackendState { core::ir::Value* v = builder.Access(inputs[idx].type, input_param, u32(index))->Result(0); - // If this is an input position builtin we need to invert the 'w' component of the vector. if (inputs[idx].attributes.builtin == core::BuiltinValue::kPosition) { + // If this is an input position builtin we need to invert the 'w' component of the + // vector. auto* w = builder.Access(ty.f32(), v, 3_u); auto* div = builder.Divide(ty.f32(), 1.0_f, w); auto* swizzle = builder.Swizzle(ty.vec3(), v, {0, 1, 2}); - v = builder.Construct(ty.vec4(), swizzle, div)->Results()[0]; + v = builder.Construct(ty.vec4(), swizzle, div)->Result(0); + } else if (config.first_index_offset_binding.has_value() && + inputs[idx].attributes.builtin == core::BuiltinValue::kVertexIndex) { + // Apply vertex_index offset + TINT_ASSERT(tint_first_index_offset); + auto* vertex_index_offset = + builder.Access(ty.ptr(), tint_first_index_offset, 0_u); + v = builder.Add(v, builder.Load(vertex_index_offset))->Result(0); + } else if (config.first_index_offset_binding.has_value() && + inputs[idx].attributes.builtin == core::BuiltinValue::kInstanceIndex) { + // Apply instance_index offset + TINT_ASSERT(tint_first_index_offset); + auto* instance_index_offset = + builder.Access(ty.ptr(), tint_first_index_offset, 1_u); + v = builder.Add(v, builder.Load(instance_index_offset))->Result(0); } return v; diff --git a/src/tint/lang/hlsl/writer/raise/shader_io.h b/src/tint/lang/hlsl/writer/raise/shader_io.h index 339446a33e..90533778ad 100644 --- a/src/tint/lang/hlsl/writer/raise/shader_io.h +++ b/src/tint/lang/hlsl/writer/raise/shader_io.h @@ -47,6 +47,12 @@ struct ShaderIOConfig { /// group plus 1 is used if at least one resource is bound, otherwise group 0 binding 0 is used. std::optional num_workgroups_binding; + /// The binding point to use for the first_index_offset uniform buffer. If set, and if a vertex + /// entry point contains a vertex_index or instance_index input parameter (or both), this + /// transform will add a uniform buffer with both indices, and will add the offsets to the input + /// variables, respectively. + std::optional first_index_offset_binding; + /// If one doesn't exist, adds a @position member to the input struct as the last member. /// This is used for PixelLocal, for which Dawn requires such a member in the final HLSL shader. bool add_input_position_member = false; diff --git a/src/tint/lang/hlsl/writer/raise/shader_io_test.cc b/src/tint/lang/hlsl/writer/raise/shader_io_test.cc index fca4349f6d..99fd4bd692 100644 --- a/src/tint/lang/hlsl/writer/raise/shader_io_test.cc +++ b/src/tint/lang/hlsl/writer/raise/shader_io_test.cc @@ -3522,5 +3522,297 @@ foo2_outputs = struct @align(16) { EXPECT_EQ(expect, str()); } +TEST_F(HlslWriterTransformTest, ShaderIOParameters_FirstIndexOffset_VertexIndex) { + auto* vert_idx = b.FunctionParam("vert_idx", ty.u32()); + vert_idx->SetBuiltin(core::BuiltinValue::kVertexIndex); + + auto* ep = b.Function("foo", ty.vec4(), core::ir::Function::PipelineStage::kVertex); + ep->SetParams({vert_idx}); + ep->SetReturnBuiltin(core::BuiltinValue::kPosition); + + b.Append(ep->Block(), [&] { + b.Add(ty.u32(), vert_idx, vert_idx); + b.Return(ep, b.Construct(ty.vec4(), 0.5_f)); + }); + + auto* src = R"( +%foo = @vertex func(%vert_idx:u32 [@vertex_index]):vec4 [@position] { + $B1: { + %3:u32 = add %vert_idx, %vert_idx + %4:vec4 = construct 0.5f + ret %4 + } +} +)"; + EXPECT_EQ(src, str()); + + auto* expect = R"( +tint_first_index_offset_struct = struct @align(4) { + vertex_index:u32 @offset(0) + instance_index:u32 @offset(4) +} + +foo_inputs = struct @align(4) { + vert_idx:u32 @offset(0), @builtin(vertex_index) +} + +foo_outputs = struct @align(16) { + tint_symbol:vec4 @offset(0), @builtin(position) +} + +$B1: { # root + %tint_first_index_offset:ptr = var @binding_point(12, 34) +} + +%foo_inner = func(%vert_idx:u32):vec4 { + $B2: { + %4:u32 = add %vert_idx, %vert_idx + %5:vec4 = construct 0.5f + ret %5 + } +} +%foo = @vertex func(%inputs:foo_inputs):foo_outputs { + $B3: { + %8:u32 = access %inputs, 0u + %9:ptr = access %tint_first_index_offset, 0u + %10:u32 = load %9 + %11:u32 = add %8, %10 + %12:vec4 = call %foo_inner, %11 + %13:foo_outputs = construct %12 + ret %13 + } +} +)"; + + ShaderIOConfig config; + config.first_index_offset_binding = {12, 34}; + Run(ShaderIO, config); + + EXPECT_EQ(expect, str()); +} + +TEST_F(HlslWriterTransformTest, ShaderIOParameters_FirstIndexOffset_InstanceIndex) { + auto* inst_idx = b.FunctionParam("inst_idx", ty.u32()); + inst_idx->SetBuiltin(core::BuiltinValue::kInstanceIndex); + + auto* ep = b.Function("foo", ty.vec4(), core::ir::Function::PipelineStage::kVertex); + ep->SetParams({inst_idx}); + ep->SetReturnBuiltin(core::BuiltinValue::kPosition); + + b.Append(ep->Block(), [&] { + b.Add(ty.u32(), inst_idx, inst_idx); + b.Return(ep, b.Construct(ty.vec4(), 0.5_f)); + }); + + auto* src = R"( +%foo = @vertex func(%inst_idx:u32 [@instance_index]):vec4 [@position] { + $B1: { + %3:u32 = add %inst_idx, %inst_idx + %4:vec4 = construct 0.5f + ret %4 + } +} +)"; + EXPECT_EQ(src, str()); + + auto* expect = R"( +tint_first_index_offset_struct = struct @align(4) { + vertex_index:u32 @offset(0) + instance_index:u32 @offset(4) +} + +foo_inputs = struct @align(4) { + inst_idx:u32 @offset(0), @builtin(instance_index) +} + +foo_outputs = struct @align(16) { + tint_symbol:vec4 @offset(0), @builtin(position) +} + +$B1: { # root + %tint_first_index_offset:ptr = var @binding_point(12, 34) +} + +%foo_inner = func(%inst_idx:u32):vec4 { + $B2: { + %4:u32 = add %inst_idx, %inst_idx + %5:vec4 = construct 0.5f + ret %5 + } +} +%foo = @vertex func(%inputs:foo_inputs):foo_outputs { + $B3: { + %8:u32 = access %inputs, 0u + %9:ptr = access %tint_first_index_offset, 1u + %10:u32 = load %9 + %11:u32 = add %8, %10 + %12:vec4 = call %foo_inner, %11 + %13:foo_outputs = construct %12 + ret %13 + } +} +)"; + + ShaderIOConfig config; + config.first_index_offset_binding = {12, 34}; + Run(ShaderIO, config); + + EXPECT_EQ(expect, str()); +} + +TEST_F(HlslWriterTransformTest, ShaderIOParameters_FirstIndexOffset_Both) { + auto* vert_idx = b.FunctionParam("vert_idx", ty.u32()); + vert_idx->SetBuiltin(core::BuiltinValue::kVertexIndex); + + auto* inst_idx = b.FunctionParam("inst_idx", ty.u32()); + inst_idx->SetBuiltin(core::BuiltinValue::kInstanceIndex); + + auto* ep = b.Function("foo", ty.vec4(), core::ir::Function::PipelineStage::kVertex); + ep->SetParams({vert_idx, inst_idx}); + ep->SetReturnBuiltin(core::BuiltinValue::kPosition); + + b.Append(ep->Block(), [&] { + b.Add(ty.u32(), vert_idx, inst_idx); + b.Return(ep, b.Construct(ty.vec4(), 0.5_f)); + }); + + auto* src = R"( +%foo = @vertex func(%vert_idx:u32 [@vertex_index], %inst_idx:u32 [@instance_index]):vec4 [@position] { + $B1: { + %4:u32 = add %vert_idx, %inst_idx + %5:vec4 = construct 0.5f + ret %5 + } +} +)"; + EXPECT_EQ(src, str()); + + auto* expect = R"( +tint_first_index_offset_struct = struct @align(4) { + vertex_index:u32 @offset(0) + instance_index:u32 @offset(4) +} + +foo_inputs = struct @align(4) { + vert_idx:u32 @offset(0), @builtin(vertex_index) + inst_idx:u32 @offset(4), @builtin(instance_index) +} + +foo_outputs = struct @align(16) { + tint_symbol:vec4 @offset(0), @builtin(position) +} + +$B1: { # root + %tint_first_index_offset:ptr = var @binding_point(12, 34) +} + +%foo_inner = func(%vert_idx:u32, %inst_idx:u32):vec4 { + $B2: { + %5:u32 = add %vert_idx, %inst_idx + %6:vec4 = construct 0.5f + ret %6 + } +} +%foo = @vertex func(%inputs:foo_inputs):foo_outputs { + $B3: { + %9:u32 = access %inputs, 0u + %10:ptr = access %tint_first_index_offset, 0u + %11:u32 = load %10 + %12:u32 = add %9, %11 + %13:u32 = access %inputs, 1u + %14:ptr = access %tint_first_index_offset, 1u + %15:u32 = load %14 + %16:u32 = add %13, %15 + %17:vec4 = call %foo_inner, %12, %16 + %18:foo_outputs = construct %17 + ret %18 + } +} +)"; + + ShaderIOConfig config; + config.first_index_offset_binding = {12, 34}; + Run(ShaderIO, config); + + EXPECT_EQ(expect, str()); +} + +TEST_F(HlslWriterTransformTest, ShaderIOParameters_FirstIndexOffset_BothReorder) { + auto* inst_idx = b.FunctionParam("inst_idx", ty.u32()); + inst_idx->SetBuiltin(core::BuiltinValue::kInstanceIndex); + + auto* vert_idx = b.FunctionParam("vert_idx", ty.u32()); + vert_idx->SetBuiltin(core::BuiltinValue::kVertexIndex); + + auto* ep = b.Function("foo", ty.vec4(), core::ir::Function::PipelineStage::kVertex); + ep->SetParams({inst_idx, vert_idx}); + ep->SetReturnBuiltin(core::BuiltinValue::kPosition); + + b.Append(ep->Block(), [&] { + b.Add(ty.u32(), vert_idx, inst_idx); + b.Return(ep, b.Construct(ty.vec4(), 0.5_f)); + }); + + auto* src = R"( +%foo = @vertex func(%inst_idx:u32 [@instance_index], %vert_idx:u32 [@vertex_index]):vec4 [@position] { + $B1: { + %4:u32 = add %vert_idx, %inst_idx + %5:vec4 = construct 0.5f + ret %5 + } +} +)"; + EXPECT_EQ(src, str()); + + auto* expect = R"( +tint_first_index_offset_struct = struct @align(4) { + vertex_index:u32 @offset(0) + instance_index:u32 @offset(4) +} + +foo_inputs = struct @align(4) { + vert_idx:u32 @offset(0), @builtin(vertex_index) + inst_idx:u32 @offset(4), @builtin(instance_index) +} + +foo_outputs = struct @align(16) { + tint_symbol:vec4 @offset(0), @builtin(position) +} + +$B1: { # root + %tint_first_index_offset:ptr = var @binding_point(12, 34) +} + +%foo_inner = func(%inst_idx:u32, %vert_idx:u32):vec4 { + $B2: { + %5:u32 = add %vert_idx, %inst_idx + %6:vec4 = construct 0.5f + ret %6 + } +} +%foo = @vertex func(%inputs:foo_inputs):foo_outputs { + $B3: { + %9:u32 = access %inputs, 1u + %10:ptr = access %tint_first_index_offset, 1u + %11:u32 = load %10 + %12:u32 = add %9, %11 + %13:u32 = access %inputs, 0u + %14:ptr = access %tint_first_index_offset, 0u + %15:u32 = load %14 + %16:u32 = add %13, %15 + %17:vec4 = call %foo_inner, %12, %16 + %18:foo_outputs = construct %17 + ret %18 + } +} +)"; + + ShaderIOConfig config; + config.first_index_offset_binding = {12, 34}; + Run(ShaderIO, config); + + EXPECT_EQ(expect, str()); +} + } // namespace } // namespace tint::hlsl::writer::raise diff --git a/src/tint/lang/hlsl/writer/writer.cc b/src/tint/lang/hlsl/writer/writer.cc index 2af07c536e..a73bac30e1 100644 --- a/src/tint/lang/hlsl/writer/writer.cc +++ b/src/tint/lang/hlsl/writer/writer.cc @@ -41,8 +41,6 @@ namespace tint::hlsl::writer { Result Generate(core::ir::Module& ir, const Options& options) { - Output output; - // Raise the core-dialect to HLSL-dialect auto res = Raise(ir, options); if (res != Success) {