diff --git a/src/dawn_native/Toggles.cpp b/src/dawn_native/Toggles.cpp index e7bae9ec44..e366cf14b0 100644 --- a/src/dawn_native/Toggles.cpp +++ b/src/dawn_native/Toggles.cpp @@ -138,7 +138,10 @@ namespace dawn_native { {"disallow_unsafe_apis", "Produces validation errors on API entry points or parameter combinations that " "aren't considered secure yet.", - "http://crbug.com/1138528"}} + "http://crbug.com/1138528"}}, + {Toggle::UseTintGenerator, + {"use_tint_generator", "Use Tint instead of SPRIV-cross to generate shaders.", + "https://crbug.com/dawn/548"}}, // Dummy comment to separate the }} so it is clearer what to copy-paste to add a toggle. }}; diff --git a/src/dawn_native/Toggles.h b/src/dawn_native/Toggles.h index c6380cf4d6..2e02f2cee5 100644 --- a/src/dawn_native/Toggles.h +++ b/src/dawn_native/Toggles.h @@ -44,6 +44,7 @@ namespace dawn_native { DisableRobustness, MetalEnableVertexPulling, DisallowUnsafeAPIs, + UseTintGenerator, EnumCount, InvalidEnum = EnumCount, diff --git a/src/dawn_native/d3d12/ComputePipelineD3D12.cpp b/src/dawn_native/d3d12/ComputePipelineD3D12.cpp index e74278442c..dacc87af6f 100644 --- a/src/dawn_native/d3d12/ComputePipelineD3D12.cpp +++ b/src/dawn_native/d3d12/ComputePipelineD3D12.cpp @@ -43,27 +43,37 @@ namespace dawn_native { namespace d3d12 { ShaderModule* module = ToBackend(descriptor->computeStage.module); - // Note that the HLSL will always use entryPoint "main". + const char* entryPoint = descriptor->computeStage.entryPoint; std::string hlslSource; - DAWN_TRY_ASSIGN(hlslSource, module->TranslateToHLSL(descriptor->computeStage.entryPoint, - SingleShaderStage::Compute, + if (device->IsToggleEnabled(Toggle::UseTintGenerator)) { + DAWN_TRY_ASSIGN(hlslSource, + module->TranslateToHLSLWithTint(entryPoint, SingleShaderStage::Compute, ToBackend(GetLayout()))); + } else { + DAWN_TRY_ASSIGN(hlslSource, + module->TranslateToHLSLWithSPIRVCross( + entryPoint, SingleShaderStage::Compute, ToBackend(GetLayout()))); + + // Note that the HLSL will always use entryPoint "main" under SPIRV-cross. + entryPoint = "main"; + } D3D12_COMPUTE_PIPELINE_STATE_DESC d3dDesc = {}; d3dDesc.pRootSignature = ToBackend(GetLayout())->GetRootSignature(); ComPtr compiledDXCShader; ComPtr compiledFXCShader; - if (device->IsToggleEnabled(Toggle::UseDXC)) { - DAWN_TRY_ASSIGN(compiledDXCShader, CompileShaderDXC(device, SingleShaderStage::Compute, - hlslSource, "main", compileFlags)); + DAWN_TRY_ASSIGN(compiledDXCShader, + CompileShaderDXC(device, SingleShaderStage::Compute, hlslSource, + entryPoint, compileFlags)); d3dDesc.CS.pShaderBytecode = compiledDXCShader->GetBufferPointer(); d3dDesc.CS.BytecodeLength = compiledDXCShader->GetBufferSize(); } else { - DAWN_TRY_ASSIGN(compiledFXCShader, CompileShaderFXC(device, SingleShaderStage::Compute, - hlslSource, "main", compileFlags)); + DAWN_TRY_ASSIGN(compiledFXCShader, + CompileShaderFXC(device, SingleShaderStage::Compute, hlslSource, + entryPoint, compileFlags)); d3dDesc.CS.pShaderBytecode = compiledFXCShader->GetBufferPointer(); d3dDesc.CS.BytecodeLength = compiledFXCShader->GetBufferSize(); } diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp index 949451e2d0..3b2689d01a 100644 --- a/src/dawn_native/d3d12/DeviceD3D12.cpp +++ b/src/dawn_native/d3d12/DeviceD3D12.cpp @@ -499,6 +499,7 @@ namespace dawn_native { namespace d3d12 { SetToggle(Toggle::UseD3D12RenderPass, GetDeviceInfo().supportsRenderPass); SetToggle(Toggle::UseD3D12ResidencyManagement, true); SetToggle(Toggle::UseDXC, false); + SetToggle(Toggle::UseTintGenerator, false); // By default use the maximum shader-visible heap size allowed. SetToggle(Toggle::UseD3D12SmallShaderVisibleHeapForTesting, false); diff --git a/src/dawn_native/d3d12/RenderPipelineD3D12.cpp b/src/dawn_native/d3d12/RenderPipelineD3D12.cpp index 4459345a03..158a000fb2 100644 --- a/src/dawn_native/d3d12/RenderPipelineD3D12.cpp +++ b/src/dawn_native/d3d12/RenderPipelineD3D12.cpp @@ -311,21 +311,32 @@ namespace dawn_native { namespace d3d12 { wgpu::ShaderStage renderStages = wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment; for (auto stage : IterateStages(renderStages)) { - // Note that the HLSL entryPoint will always be "main". std::string hlslSource; - DAWN_TRY_ASSIGN(hlslSource, - modules[stage]->TranslateToHLSL(GetStage(stage).entryPoint.c_str(), - stage, ToBackend(GetLayout()))); + const char* entryPoint = GetStage(stage).entryPoint.c_str(); + + if (device->IsToggleEnabled(Toggle::UseTintGenerator)) { + DAWN_TRY_ASSIGN(hlslSource, modules[stage]->TranslateToHLSLWithTint( + entryPoint, stage, ToBackend(GetLayout()))); + + } else { + DAWN_TRY_ASSIGN(hlslSource, modules[stage]->TranslateToHLSLWithSPIRVCross( + entryPoint, stage, ToBackend(GetLayout()))); + + // Note that the HLSL will always use entryPoint "main" under SPIRV-cross. + entryPoint = "main"; + } if (device->IsToggleEnabled(Toggle::UseDXC)) { - DAWN_TRY_ASSIGN(compiledDXCShader[stage], - CompileShaderDXC(device, stage, hlslSource, "main", compileFlags)); + DAWN_TRY_ASSIGN( + compiledDXCShader[stage], + CompileShaderDXC(device, stage, hlslSource, entryPoint, compileFlags)); shaders[stage]->pShaderBytecode = compiledDXCShader[stage]->GetBufferPointer(); shaders[stage]->BytecodeLength = compiledDXCShader[stage]->GetBufferSize(); } else { - DAWN_TRY_ASSIGN(compiledFXCShader[stage], - CompileShaderFXC(device, stage, hlslSource, "main", compileFlags)); + DAWN_TRY_ASSIGN( + compiledFXCShader[stage], + CompileShaderFXC(device, stage, hlslSource, entryPoint, compileFlags)); shaders[stage]->pShaderBytecode = compiledFXCShader[stage]->GetBufferPointer(); shaders[stage]->BytecodeLength = compiledFXCShader[stage]->GetBufferSize(); diff --git a/src/dawn_native/d3d12/ShaderModuleD3D12.cpp b/src/dawn_native/d3d12/ShaderModuleD3D12.cpp index 7dc7a29d83..36690887bc 100644 --- a/src/dawn_native/d3d12/ShaderModuleD3D12.cpp +++ b/src/dawn_native/d3d12/ShaderModuleD3D12.cpp @@ -29,6 +29,10 @@ #include +#ifdef DAWN_ENABLE_WGSL +# include +#endif // DAWN_ENABLE_WGSL + namespace dawn_native { namespace d3d12 { namespace { @@ -176,10 +180,68 @@ namespace dawn_native { namespace d3d12 { : ShaderModuleBase(device, descriptor) { } - ResultOrError ShaderModule::TranslateToHLSL(const char* entryPointName, - SingleShaderStage stage, - PipelineLayout* layout) const { + ResultOrError ShaderModule::TranslateToHLSLWithTint(const char* entryPointName, + SingleShaderStage stage, + PipelineLayout* layout) const { ASSERT(!IsError()); + +#ifdef DAWN_ENABLE_WGSL + std::ostringstream errorStream; + errorStream << "Tint HLSL failure:" << std::endl; + + // TODO: Remove redundant SPIRV step between WGSL and HLSL. + tint::Context context; + tint::reader::spirv::Parser parser(&context, GetSpirv()); + + if (!parser.Parse()) { + errorStream << "Parser: " << parser.error() << std::endl; + return DAWN_VALIDATION_ERROR(errorStream.str().c_str()); + } + + tint::ast::Module module = parser.module(); + if (!module.IsValid()) { + errorStream << "Invalid module generated..." << std::endl; + return DAWN_VALIDATION_ERROR(errorStream.str().c_str()); + } + + tint::TypeDeterminer typeDeterminer(&context, &module); + if (!typeDeterminer.Determine()) { + errorStream << "Type Determination: " << typeDeterminer.error(); + return DAWN_VALIDATION_ERROR(errorStream.str().c_str()); + } + + tint::Validator validator; + if (!validator.Validate(&module)) { + errorStream << "Validation: " << validator.error() << std::endl; + return DAWN_VALIDATION_ERROR(errorStream.str().c_str()); + } + + tint::transform::BoundArrayAccessorsTransform boundArrayTransformer(&context, &module); + if (!boundArrayTransformer.Run()) { + errorStream << "Bound Array Accessors Transform: " << boundArrayTransformer.error() + << std::endl; + return DAWN_VALIDATION_ERROR(errorStream.str().c_str()); + } + + tint::writer::hlsl::Generator generator(std::move(module)); + // TODO: Switch to GenerateEntryPoint once HLSL writer supports it. + if (!generator.Generate()) { + errorStream << "Generator: " << generator.error() << std::endl; + return DAWN_VALIDATION_ERROR(errorStream.str().c_str()); + } + + return generator.result(); +#else + return DAWN_VALIDATION_ERROR("Using Tint to generate HLSL is not supported."); +#endif // DAWN_ENABLE_WGSL + } + + ResultOrError ShaderModule::TranslateToHLSLWithSPIRVCross( + const char* entryPointName, + SingleShaderStage stage, + PipelineLayout* layout) const { + ASSERT(!IsError()); + // If these options are changed, the values in DawnSPIRVCrossHLSLFastFuzzer.cpp need to // be updated. spirv_cross::CompilerGLSL::Options options_glsl; diff --git a/src/dawn_native/d3d12/ShaderModuleD3D12.h b/src/dawn_native/d3d12/ShaderModuleD3D12.h index 554c36548c..dde759957d 100644 --- a/src/dawn_native/d3d12/ShaderModuleD3D12.h +++ b/src/dawn_native/d3d12/ShaderModuleD3D12.h @@ -40,9 +40,13 @@ namespace dawn_native { namespace d3d12 { static ResultOrError Create(Device* device, const ShaderModuleDescriptor* descriptor); - ResultOrError TranslateToHLSL(const char* entryPointName, - SingleShaderStage stage, - PipelineLayout* layout) const; + ResultOrError TranslateToHLSLWithTint(const char* entryPointName, + SingleShaderStage stage, + PipelineLayout* layout) const; + + ResultOrError TranslateToHLSLWithSPIRVCross(const char* entryPointName, + SingleShaderStage stage, + PipelineLayout* layout) const; private: ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor); diff --git a/src/tests/DawnTest.cpp b/src/tests/DawnTest.cpp index 7736429644..3040fa7e8f 100644 --- a/src/tests/DawnTest.cpp +++ b/src/tests/DawnTest.cpp @@ -637,6 +637,15 @@ bool DawnTestBase::IsAsan() const { #endif } +bool DawnTestBase::HasToggleEnabled(const char* toggle) const { + for (const char* toggleEnabled : mParam.forceEnabledWorkarounds) { + if (strcmp(toggle, toggleEnabled) == 0) { + return true; + } + } + return false; +} + bool DawnTestBase::HasVendorIdFilter() const { return gTestEnv->HasVendorIdFilter(); } diff --git a/src/tests/DawnTest.h b/src/tests/DawnTest.h index 68d7e867e7..031d11ace4 100644 --- a/src/tests/DawnTest.h +++ b/src/tests/DawnTest.h @@ -254,6 +254,8 @@ class DawnTestBase { bool IsAsan() const; + bool HasToggleEnabled(const char* workaround) const; + void StartExpectDeviceError(); bool EndExpectDeviceError(); diff --git a/src/tests/end2end/EntryPointTests.cpp b/src/tests/end2end/EntryPointTests.cpp index 0f27026dbe..7e3e071681 100644 --- a/src/tests/end2end/EntryPointTests.cpp +++ b/src/tests/end2end/EntryPointTests.cpp @@ -72,6 +72,10 @@ TEST_P(EntryPointTests, TwoComputeInModule) { // TODO: Reenable once Tint is able to produce Vulkan 1.0 / 1.1 SPIR-V. DAWN_SKIP_TEST_IF(IsVulkan()); + // TODO: Reenable once Tint's HLSL writer supports multiple entryPoints on a single stage. + // https://crbug.com/tint/297 + DAWN_SKIP_TEST_IF(IsD3D12() && HasToggleEnabled("use_tint_generator")); + wgpu::ShaderModule module = utils::CreateShaderModuleFromWGSL(device, R"( [[block]] struct Data { [[offset(0)]] data : u32; @@ -141,6 +145,7 @@ TEST_P(EntryPointTests, TwoComputeInModule) { DAWN_INSTANTIATE_TEST(EntryPointTests, D3D12Backend(), + D3D12Backend({"use_tint_generator"}), MetalBackend(), OpenGLBackend(), VulkanBackend());