[d3d] Move shader translation and compile code to d3d So it can be shared between d3d11 and d3d12 backends Bug: dawn:1705 Change-Id: Iffabe8d77a0ac3713da985c0cac5839299dc2a47 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/124883 Reviewed-by: Austin Eng <enga@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Peng Huang <penghuang@chromium.org>
diff --git a/src/dawn/native/BUILD.gn b/src/dawn/native/BUILD.gn index 1ca341d..ff21df0 100644 --- a/src/dawn/native/BUILD.gn +++ b/src/dawn/native/BUILD.gn
@@ -409,6 +409,8 @@ "d3d/Forward.h", "d3d/PlatformFunctions.cpp", "d3d/PlatformFunctions.h", + "d3d/ShaderUtils.cpp", + "d3d/ShaderUtils.h", "d3d/UtilsD3D.cpp", "d3d/UtilsD3D.h", "d3d/d3d_platform.h",
diff --git a/src/dawn/native/CMakeLists.txt b/src/dawn/native/CMakeLists.txt index d1625a1..3ad2292 100644 --- a/src/dawn/native/CMakeLists.txt +++ b/src/dawn/native/CMakeLists.txt
@@ -267,6 +267,8 @@ "d3d/Forward.h" "d3d/PlatformFunctions.cpp" "d3d/PlatformFunctions.h" + "d3d/ShaderUtils.cpp" + "d3d/ShaderUtils.h" "d3d/UtilsD3D.cpp" "d3d/UtilsD3D.h" "d3d/d3d_platform.h"
diff --git a/src/dawn/native/d3d/ShaderUtils.cpp b/src/dawn/native/d3d/ShaderUtils.cpp new file mode 100644 index 0000000..ca39e92 --- /dev/null +++ b/src/dawn/native/d3d/ShaderUtils.cpp
@@ -0,0 +1,280 @@ +// Copyright 2023 The Dawn 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 "dawn/native/d3d/ShaderUtils.h" + +#include <string> +#include <utility> +#include <vector> + +#include "dawn/native/d3d/BlobD3D.h" +#include "dawn/native/d3d/D3DCompilationRequest.h" +#include "dawn/native/d3d/D3DError.h" +#include "dawn/native/d3d/UtilsD3D.h" +#include "dawn/platform/DawnPlatform.h" +#include "dawn/platform/tracing/TraceEvent.h" + +#include "tint/tint.h" + +namespace dawn::native::d3d { + +namespace { + +std::vector<const wchar_t*> GetDXCArguments(uint32_t compileFlags, bool enable16BitTypes) { + std::vector<const wchar_t*> arguments; + if (compileFlags & D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY) { + arguments.push_back(L"/Gec"); + } + if (compileFlags & D3DCOMPILE_IEEE_STRICTNESS) { + arguments.push_back(L"/Gis"); + } + constexpr uint32_t d3dCompileFlagsBits = D3DCOMPILE_OPTIMIZATION_LEVEL2; + if (compileFlags & d3dCompileFlagsBits) { + switch (compileFlags & D3DCOMPILE_OPTIMIZATION_LEVEL2) { + case D3DCOMPILE_OPTIMIZATION_LEVEL0: + arguments.push_back(L"/O0"); + break; + case D3DCOMPILE_OPTIMIZATION_LEVEL2: + arguments.push_back(L"/O2"); + break; + case D3DCOMPILE_OPTIMIZATION_LEVEL3: + arguments.push_back(L"/O3"); + break; + } + } + if (compileFlags & D3DCOMPILE_DEBUG) { + arguments.push_back(L"/Zi"); + } + if (compileFlags & D3DCOMPILE_PACK_MATRIX_ROW_MAJOR) { + arguments.push_back(L"/Zpr"); + } + if (compileFlags & D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR) { + arguments.push_back(L"/Zpc"); + } + if (compileFlags & D3DCOMPILE_AVOID_FLOW_CONTROL) { + arguments.push_back(L"/Gfa"); + } + if (compileFlags & D3DCOMPILE_PREFER_FLOW_CONTROL) { + arguments.push_back(L"/Gfp"); + } + if (compileFlags & D3DCOMPILE_RESOURCES_MAY_ALIAS) { + arguments.push_back(L"/res_may_alias"); + } + + if (enable16BitTypes) { + // enable-16bit-types are only allowed in -HV 2018 (default) + arguments.push_back(L"/enable-16bit-types"); + } + + arguments.push_back(L"-HV"); + arguments.push_back(L"2018"); + + return arguments; +} + +ResultOrError<ComPtr<IDxcBlob>> CompileShaderDXC(const d3d::D3DBytecodeCompilationRequest& r, + const std::string& entryPointName, + const std::string& hlslSource) { + ComPtr<IDxcBlobEncoding> sourceBlob; + DAWN_TRY(CheckHRESULT(r.dxcLibrary->CreateBlobWithEncodingFromPinned( + hlslSource.c_str(), hlslSource.length(), CP_UTF8, &sourceBlob), + "DXC create blob")); + + std::wstring entryPointW; + DAWN_TRY_ASSIGN(entryPointW, d3d::ConvertStringToWstring(entryPointName)); + + std::vector<const wchar_t*> arguments = GetDXCArguments(r.compileFlags, r.hasShaderF16Feature); + + ComPtr<IDxcOperationResult> result; + DAWN_TRY(CheckHRESULT(r.dxcCompiler->Compile(sourceBlob.Get(), nullptr, entryPointW.c_str(), + r.dxcShaderProfile.data(), arguments.data(), + arguments.size(), nullptr, 0, nullptr, &result), + "DXC compile")); + + HRESULT hr; + DAWN_TRY(CheckHRESULT(result->GetStatus(&hr), "DXC get status")); + + if (FAILED(hr)) { + ComPtr<IDxcBlobEncoding> errors; + DAWN_TRY(CheckHRESULT(result->GetErrorBuffer(&errors), "DXC get error buffer")); + + return DAWN_VALIDATION_ERROR("DXC compile failed with: %s", + static_cast<char*>(errors->GetBufferPointer())); + } + + ComPtr<IDxcBlob> compiledShader; + DAWN_TRY(CheckHRESULT(result->GetResult(&compiledShader), "DXC get result")); + return std::move(compiledShader); +} + +ResultOrError<ComPtr<ID3DBlob>> CompileShaderFXC(const d3d::D3DBytecodeCompilationRequest& r, + const std::string& entryPointName, + const std::string& hlslSource) { + ComPtr<ID3DBlob> compiledShader; + ComPtr<ID3DBlob> errors; + + DAWN_INVALID_IF(FAILED(r.d3dCompile(hlslSource.c_str(), hlslSource.length(), nullptr, nullptr, + nullptr, entryPointName.c_str(), r.fxcShaderProfile.data(), + r.compileFlags, 0, &compiledShader, &errors)), + "D3D compile failed with: %s", static_cast<char*>(errors->GetBufferPointer())); + + return std::move(compiledShader); +} + +ResultOrError<std::string> TranslateToHLSL( + d3d::HlslCompilationRequest r, + CacheKey::UnsafeUnkeyedValue<dawn::platform::Platform*> tracePlatform, + std::string* remappedEntryPointName, + bool* usesVertexOrInstanceIndex) { + std::ostringstream errorStream; + errorStream << "Tint HLSL failure:" << std::endl; + + tint::transform::Manager transformManager; + tint::transform::DataMap transformInputs; + + // Run before the renamer so that the entry point name matches `entryPointName` still. + transformManager.Add<tint::transform::SingleEntryPoint>(); + transformInputs.Add<tint::transform::SingleEntryPoint::Config>(r.entryPointName.data()); + + // Needs to run before all other transforms so that they can use builtin names safely. + transformManager.Add<tint::transform::Renamer>(); + if (r.disableSymbolRenaming) { + // We still need to rename HLSL reserved keywords + transformInputs.Add<tint::transform::Renamer::Config>( + tint::transform::Renamer::Target::kHlslKeywords); + } + + if (r.stage == SingleShaderStage::Vertex) { + transformManager.Add<tint::transform::FirstIndexOffset>(); + transformInputs.Add<tint::transform::FirstIndexOffset::BindingPoint>( + r.firstIndexOffsetShaderRegister, r.firstIndexOffsetRegisterSpace); + } + + if (r.substituteOverrideConfig) { + // This needs to run after SingleEntryPoint transform which removes unused overrides for + // current entry point. + transformManager.Add<tint::transform::SubstituteOverride>(); + transformInputs.Add<tint::transform::SubstituteOverride::Config>( + std::move(r.substituteOverrideConfig).value()); + } + + tint::Program transformedProgram; + tint::transform::DataMap transformOutputs; + { + TRACE_EVENT0(tracePlatform.UnsafeGetValue(), General, "RunTransforms"); + DAWN_TRY_ASSIGN(transformedProgram, + RunTransforms(&transformManager, r.inputProgram, transformInputs, + &transformOutputs, nullptr)); + } + + if (auto* data = transformOutputs.Get<tint::transform::Renamer::Data>()) { + auto it = data->remappings.find(r.entryPointName.data()); + if (it != data->remappings.end()) { + *remappedEntryPointName = it->second; + } else { + DAWN_INVALID_IF(!r.disableSymbolRenaming, + "Could not find remapped name for entry point."); + + *remappedEntryPointName = r.entryPointName; + } + } else { + return DAWN_VALIDATION_ERROR("Transform output missing renamer data."); + } + + if (r.stage == SingleShaderStage::Compute) { + // Validate workgroup size after program runs transforms. + Extent3D _; + DAWN_TRY_ASSIGN(_, ValidateComputeStageWorkgroupSize( + transformedProgram, remappedEntryPointName->data(), r.limits)); + } + + if (r.stage == SingleShaderStage::Vertex) { + if (auto* data = transformOutputs.Get<tint::transform::FirstIndexOffset::Data>()) { + *usesVertexOrInstanceIndex = data->has_vertex_or_instance_index; + } else { + return DAWN_VALIDATION_ERROR("Transform output missing first index offset data."); + } + } + + tint::writer::hlsl::Options options; + options.disable_robustness = !r.isRobustnessEnabled; + options.disable_workgroup_init = r.disableWorkgroupInit; + options.binding_remapper_options = r.bindingRemapper; + options.external_texture_options = r.externalTextureOptions; + + if (r.usesNumWorkgroups) { + options.root_constant_binding_point = + tint::writer::BindingPoint{r.numWorkgroupsRegisterSpace, r.numWorkgroupsShaderRegister}; + } + // TODO(dawn:549): HLSL generation outputs the indices into the + // array_length_from_uniform buffer that were actually used. When the blob cache can + // store more than compiled shaders, we should reflect these used indices and store + // them as well. This would allow us to only upload root constants that are actually + // read by the shader. + options.array_length_from_uniform = r.arrayLengthFromUniform; + + if (r.stage == SingleShaderStage::Vertex) { + // Now that only vertex shader can have interstage outputs. + // Pass in the actually used interstage locations for tint to potentially truncate unused + // outputs. + options.interstage_locations = r.interstageLocations; + } + + options.polyfill_reflect_vec2_f32 = r.polyfillReflectVec2F32; + + TRACE_EVENT0(tracePlatform.UnsafeGetValue(), General, "tint::writer::hlsl::Generate"); + auto result = tint::writer::hlsl::Generate(&transformedProgram, options); + DAWN_INVALID_IF(!result.success, "An error occured while generating HLSL: %s", result.error); + + return std::move(result.hlsl); +} + +} // anonymous namespace + +ResultOrError<CompiledShader> CompileShader(d3d::D3DCompilationRequest r) { + CompiledShader compiledShader; + // Compile the source shader to HLSL. + std::string remappedEntryPoint; + DAWN_TRY_ASSIGN(compiledShader.hlslSource, + TranslateToHLSL(std::move(r.hlsl), r.tracePlatform, &remappedEntryPoint, + &compiledShader.usesVertexOrInstanceIndex)); + + switch (r.bytecode.compiler) { + case d3d::Compiler::DXC: { + TRACE_EVENT0(r.tracePlatform.UnsafeGetValue(), General, "CompileShaderDXC"); + ComPtr<IDxcBlob> compiledDXCShader; + DAWN_TRY_ASSIGN(compiledDXCShader, CompileShaderDXC(r.bytecode, remappedEntryPoint, + compiledShader.hlslSource)); + compiledShader.shaderBlob = CreateBlob(std::move(compiledDXCShader)); + break; + } + case d3d::Compiler::FXC: { + TRACE_EVENT0(r.tracePlatform.UnsafeGetValue(), General, "CompileShaderFXC"); + ComPtr<ID3DBlob> compiledFXCShader; + DAWN_TRY_ASSIGN(compiledFXCShader, CompileShaderFXC(r.bytecode, remappedEntryPoint, + compiledShader.hlslSource)); + compiledShader.shaderBlob = CreateBlob(std::move(compiledFXCShader)); + break; + } + } + + // If dumpShaders is false, we don't need the HLSL for logging. Clear the contents so it + // isn't stored into the cache. + if (!r.hlsl.dumpShaders) { + compiledShader.hlslSource = ""; + } + return compiledShader; +} + +} // namespace dawn::native::d3d
diff --git a/src/dawn/native/d3d/ShaderUtils.h b/src/dawn/native/d3d/ShaderUtils.h new file mode 100644 index 0000000..bbfc2b1 --- /dev/null +++ b/src/dawn/native/d3d/ShaderUtils.h
@@ -0,0 +1,43 @@ +// Copyright 2023 The Dawn 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_DAWN_NATIVE_D3D_SHADEUTILS_H_ +#define SRC_DAWN_NATIVE_D3D_SHADEUTILS_H_ + +#include <string> + +#include "dawn/native/Blob.h" +#include "dawn/native/Serializable.h" +#include "dawn/native/d3d/D3DCompilationRequest.h" +#include "dawn/native/d3d/d3d_platform.h" + +namespace dawn::native::d3d { + +#define COMPILED_SHADER_MEMBERS(X) \ + X(Blob, shaderBlob) \ + X(std::string, hlslSource) \ + X(bool, usesVertexOrInstanceIndex) + +// `CompiledShader` holds a ref to one of the various representations of shader blobs and +// information used to emulate vertex/instance index starts. It also holds the `hlslSource` for the +// shader compilation, which is only transiently available during Compile, and cleared before it +// returns. It is not written to or loaded from the cache unless Toggle dump_shaders is true. +DAWN_SERIALIZABLE(struct, CompiledShader, COMPILED_SHADER_MEMBERS){}; +#undef COMPILED_SHADER_MEMBERS + +ResultOrError<CompiledShader> CompileShader(d3d::D3DCompilationRequest r); + +} // namespace dawn::native::d3d + +#endif // SRC_DAWN_NATIVE_D3D_SHADEUTILS_H_
diff --git a/src/dawn/native/d3d12/ComputePipelineD3D12.cpp b/src/dawn/native/d3d12/ComputePipelineD3D12.cpp index e781f0f..8585940 100644 --- a/src/dawn/native/d3d12/ComputePipelineD3D12.cpp +++ b/src/dawn/native/d3d12/ComputePipelineD3D12.cpp
@@ -57,10 +57,10 @@ d3dDesc.pRootSignature = ToBackend(GetLayout())->GetRootSignature(); // TODO(dawn:549): Compile shader everytime before we implement compiled shader cache - CompiledShader compiledShader; + d3d::CompiledShader compiledShader; DAWN_TRY_ASSIGN(compiledShader, module->Compile(computeStage, SingleShaderStage::Compute, ToBackend(GetLayout()), compileFlags)); - d3dDesc.CS = compiledShader.GetD3D12ShaderBytecode(); + d3dDesc.CS = {compiledShader.shaderBlob.Data(), compiledShader.shaderBlob.Size()}; StreamIn(&mCacheKey, d3dDesc, ToBackend(GetLayout())->GetRootSignatureBlob());
diff --git a/src/dawn/native/d3d12/RenderPipelineD3D12.cpp b/src/dawn/native/d3d12/RenderPipelineD3D12.cpp index 6cfa55d..e6988e4 100644 --- a/src/dawn/native/d3d12/RenderPipelineD3D12.cpp +++ b/src/dawn/native/d3d12/RenderPipelineD3D12.cpp
@@ -380,7 +380,7 @@ shaders[SingleShaderStage::Vertex] = &descriptorD3D12.VS; shaders[SingleShaderStage::Fragment] = &descriptorD3D12.PS; - PerStage<CompiledShader> compiledShader; + PerStage<d3d::CompiledShader> compiledShader; std::bitset<kMaxInterStageShaderVariables>* usedInterstageVariables = nullptr; dawn::native::EntryPointMetadata fragmentEntryPoint; @@ -397,7 +397,8 @@ ToBackend(programmableStage.module) ->Compile(programmableStage, stage, ToBackend(GetLayout()), compileFlags, usedInterstageVariables)); - *shaders[stage] = compiledShader[stage].GetD3D12ShaderBytecode(); + *shaders[stage] = {compiledShader[stage].shaderBlob.Data(), + compiledShader[stage].shaderBlob.Size()}; } mUsesVertexOrInstanceIndex =
diff --git a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp index 745b27a..0c3d819 100644 --- a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp +++ b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
@@ -14,22 +14,14 @@ #include "dawn/native/d3d12/ShaderModuleD3D12.h" -#include <map> -#include <sstream> #include <string> -#include <unordered_map> -#include <unordered_set> #include <utility> -#include <vector> #include "dawn/common/Assert.h" #include "dawn/common/BitSetIterator.h" #include "dawn/common/Log.h" -#include "dawn/common/WindowsUtils.h" -#include "dawn/native/CacheKey.h" #include "dawn/native/Pipeline.h" #include "dawn/native/TintUtils.h" -#include "dawn/native/d3d/BlobD3D.h" #include "dawn/native/d3d/D3DCompilationRequest.h" #include "dawn/native/d3d/D3DError.h" #include "dawn/native/d3d12/AdapterD3D12.h" @@ -39,8 +31,6 @@ #include "dawn/native/d3d12/PipelineLayoutD3D12.h" #include "dawn/native/d3d12/PlatformFunctionsD3D12.h" #include "dawn/native/d3d12/UtilsD3D12.h" -#include "dawn/native/stream/BlobSource.h" -#include "dawn/native/stream/ByteVectorSink.h" #include "dawn/platform/DawnPlatform.h" #include "dawn/platform/tracing/TraceEvent.h" @@ -49,94 +39,6 @@ namespace dawn::native::d3d12 { namespace { - -std::vector<const wchar_t*> GetDXCArguments(uint32_t compileFlags, bool enable16BitTypes) { - std::vector<const wchar_t*> arguments; - if (compileFlags & D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY) { - arguments.push_back(L"/Gec"); - } - if (compileFlags & D3DCOMPILE_IEEE_STRICTNESS) { - arguments.push_back(L"/Gis"); - } - constexpr uint32_t d3dCompileFlagsBits = D3DCOMPILE_OPTIMIZATION_LEVEL2; - if (compileFlags & d3dCompileFlagsBits) { - switch (compileFlags & D3DCOMPILE_OPTIMIZATION_LEVEL2) { - case D3DCOMPILE_OPTIMIZATION_LEVEL0: - arguments.push_back(L"/O0"); - break; - case D3DCOMPILE_OPTIMIZATION_LEVEL2: - arguments.push_back(L"/O2"); - break; - case D3DCOMPILE_OPTIMIZATION_LEVEL3: - arguments.push_back(L"/O3"); - break; - } - } - if (compileFlags & D3DCOMPILE_DEBUG) { - arguments.push_back(L"/Zi"); - } - if (compileFlags & D3DCOMPILE_PACK_MATRIX_ROW_MAJOR) { - arguments.push_back(L"/Zpr"); - } - if (compileFlags & D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR) { - arguments.push_back(L"/Zpc"); - } - if (compileFlags & D3DCOMPILE_AVOID_FLOW_CONTROL) { - arguments.push_back(L"/Gfa"); - } - if (compileFlags & D3DCOMPILE_PREFER_FLOW_CONTROL) { - arguments.push_back(L"/Gfp"); - } - if (compileFlags & D3DCOMPILE_RESOURCES_MAY_ALIAS) { - arguments.push_back(L"/res_may_alias"); - } - - if (enable16BitTypes) { - // enable-16bit-types are only allowed in -HV 2018 (default) - arguments.push_back(L"/enable-16bit-types"); - } - - arguments.push_back(L"-HV"); - arguments.push_back(L"2018"); - - return arguments; -} - -ResultOrError<ComPtr<IDxcBlob>> CompileShaderDXC(const d3d::D3DBytecodeCompilationRequest& r, - const std::string& entryPointName, - const std::string& hlslSource) { - ComPtr<IDxcBlobEncoding> sourceBlob; - DAWN_TRY(CheckHRESULT(r.dxcLibrary->CreateBlobWithEncodingFromPinned( - hlslSource.c_str(), hlslSource.length(), CP_UTF8, &sourceBlob), - "DXC create blob")); - - std::wstring entryPointW; - DAWN_TRY_ASSIGN(entryPointW, d3d::ConvertStringToWstring(entryPointName)); - - std::vector<const wchar_t*> arguments = GetDXCArguments(r.compileFlags, r.hasShaderF16Feature); - - ComPtr<IDxcOperationResult> result; - DAWN_TRY(CheckHRESULT(r.dxcCompiler->Compile(sourceBlob.Get(), nullptr, entryPointW.c_str(), - r.dxcShaderProfile.data(), arguments.data(), - arguments.size(), nullptr, 0, nullptr, &result), - "DXC compile")); - - HRESULT hr; - DAWN_TRY(CheckHRESULT(result->GetStatus(&hr), "DXC get status")); - - if (FAILED(hr)) { - ComPtr<IDxcBlobEncoding> errors; - DAWN_TRY(CheckHRESULT(result->GetErrorBuffer(&errors), "DXC get error buffer")); - - return DAWN_VALIDATION_ERROR("DXC compile failed with: %s", - static_cast<char*>(errors->GetBufferPointer())); - } - - ComPtr<IDxcBlob> compiledShader; - DAWN_TRY(CheckHRESULT(result->GetResult(&compiledShader), "DXC get result")); - return std::move(compiledShader); -} - std::string CompileFlagsToStringFXC(uint32_t compileFlags) { struct Flag { uint32_t value; @@ -199,163 +101,6 @@ return result; } -ResultOrError<ComPtr<ID3DBlob>> CompileShaderFXC(const d3d::D3DBytecodeCompilationRequest& r, - const std::string& entryPointName, - const std::string& hlslSource) { - ComPtr<ID3DBlob> compiledShader; - ComPtr<ID3DBlob> errors; - - DAWN_INVALID_IF(FAILED(r.d3dCompile(hlslSource.c_str(), hlslSource.length(), nullptr, nullptr, - nullptr, entryPointName.c_str(), r.fxcShaderProfile.data(), - r.compileFlags, 0, &compiledShader, &errors)), - "D3D compile failed with: %s", static_cast<char*>(errors->GetBufferPointer())); - - return std::move(compiledShader); -} - -ResultOrError<std::string> TranslateToHLSL( - d3d::HlslCompilationRequest r, - CacheKey::UnsafeUnkeyedValue<dawn::platform::Platform*> tracePlatform, - std::string* remappedEntryPointName, - bool* usesVertexOrInstanceIndex) { - std::ostringstream errorStream; - errorStream << "Tint HLSL failure:" << std::endl; - - tint::transform::Manager transformManager; - tint::transform::DataMap transformInputs; - - // Run before the renamer so that the entry point name matches `entryPointName` still. - transformManager.Add<tint::transform::SingleEntryPoint>(); - transformInputs.Add<tint::transform::SingleEntryPoint::Config>(r.entryPointName.data()); - - // Needs to run before all other transforms so that they can use builtin names safely. - transformManager.Add<tint::transform::Renamer>(); - if (r.disableSymbolRenaming) { - // We still need to rename HLSL reserved keywords - transformInputs.Add<tint::transform::Renamer::Config>( - tint::transform::Renamer::Target::kHlslKeywords); - } - - if (r.stage == SingleShaderStage::Vertex) { - transformManager.Add<tint::transform::FirstIndexOffset>(); - transformInputs.Add<tint::transform::FirstIndexOffset::BindingPoint>( - r.firstIndexOffsetShaderRegister, r.firstIndexOffsetRegisterSpace); - } - - if (r.substituteOverrideConfig) { - // This needs to run after SingleEntryPoint transform which removes unused overrides for - // current entry point. - transformManager.Add<tint::transform::SubstituteOverride>(); - transformInputs.Add<tint::transform::SubstituteOverride::Config>( - std::move(r.substituteOverrideConfig).value()); - } - - tint::Program transformedProgram; - tint::transform::DataMap transformOutputs; - { - TRACE_EVENT0(tracePlatform.UnsafeGetValue(), General, "RunTransforms"); - DAWN_TRY_ASSIGN(transformedProgram, - RunTransforms(&transformManager, r.inputProgram, transformInputs, - &transformOutputs, nullptr)); - } - - if (auto* data = transformOutputs.Get<tint::transform::Renamer::Data>()) { - auto it = data->remappings.find(r.entryPointName.data()); - if (it != data->remappings.end()) { - *remappedEntryPointName = it->second; - } else { - DAWN_INVALID_IF(!r.disableSymbolRenaming, - "Could not find remapped name for entry point."); - - *remappedEntryPointName = r.entryPointName; - } - } else { - return DAWN_VALIDATION_ERROR("Transform output missing renamer data."); - } - - if (r.stage == SingleShaderStage::Compute) { - // Validate workgroup size after program runs transforms. - Extent3D _; - DAWN_TRY_ASSIGN(_, ValidateComputeStageWorkgroupSize( - transformedProgram, remappedEntryPointName->data(), r.limits)); - } - - if (r.stage == SingleShaderStage::Vertex) { - if (auto* data = transformOutputs.Get<tint::transform::FirstIndexOffset::Data>()) { - *usesVertexOrInstanceIndex = data->has_vertex_or_instance_index; - } else { - return DAWN_VALIDATION_ERROR("Transform output missing first index offset data."); - } - } - - tint::writer::hlsl::Options options; - options.disable_robustness = !r.isRobustnessEnabled; - options.disable_workgroup_init = r.disableWorkgroupInit; - options.binding_remapper_options = r.bindingRemapper; - options.external_texture_options = r.externalTextureOptions; - - if (r.usesNumWorkgroups) { - options.root_constant_binding_point = - tint::writer::BindingPoint{r.numWorkgroupsRegisterSpace, r.numWorkgroupsShaderRegister}; - } - // TODO(dawn:549): HLSL generation outputs the indices into the - // array_length_from_uniform buffer that were actually used. When the blob cache can - // store more than compiled shaders, we should reflect these used indices and store - // them as well. This would allow us to only upload root constants that are actually - // read by the shader. - options.array_length_from_uniform = r.arrayLengthFromUniform; - - if (r.stage == SingleShaderStage::Vertex) { - // Now that only vertex shader can have interstage outputs. - // Pass in the actually used interstage locations for tint to potentially truncate unused - // outputs. - options.interstage_locations = r.interstageLocations; - } - - options.polyfill_reflect_vec2_f32 = r.polyfillReflectVec2F32; - - TRACE_EVENT0(tracePlatform.UnsafeGetValue(), General, "tint::writer::hlsl::Generate"); - auto result = tint::writer::hlsl::Generate(&transformedProgram, options); - DAWN_INVALID_IF(!result.success, "An error occured while generating HLSL: %s", result.error); - - return std::move(result.hlsl); -} - -ResultOrError<CompiledShader> CompileShader(d3d::D3DCompilationRequest r) { - CompiledShader compiledShader; - // Compile the source shader to HLSL. - std::string remappedEntryPoint; - DAWN_TRY_ASSIGN(compiledShader.hlslSource, - TranslateToHLSL(std::move(r.hlsl), r.tracePlatform, &remappedEntryPoint, - &compiledShader.usesVertexOrInstanceIndex)); - - switch (r.bytecode.compiler) { - case d3d::Compiler::DXC: { - TRACE_EVENT0(r.tracePlatform.UnsafeGetValue(), General, "CompileShaderDXC"); - ComPtr<IDxcBlob> compiledDXCShader; - DAWN_TRY_ASSIGN(compiledDXCShader, CompileShaderDXC(r.bytecode, remappedEntryPoint, - compiledShader.hlslSource)); - compiledShader.shaderBlob = CreateBlob(std::move(compiledDXCShader)); - break; - } - case d3d::Compiler::FXC: { - TRACE_EVENT0(r.tracePlatform.UnsafeGetValue(), General, "CompileShaderFXC"); - ComPtr<ID3DBlob> compiledFXCShader; - DAWN_TRY_ASSIGN(compiledFXCShader, CompileShaderFXC(r.bytecode, remappedEntryPoint, - compiledShader.hlslSource)); - compiledShader.shaderBlob = CreateBlob(std::move(compiledFXCShader)); - break; - } - } - - // If dumpShaders is false, we don't need the HLSL for logging. Clear the contents so it - // isn't stored into the cache. - if (!r.hlsl.dumpShaders) { - compiledShader.hlslSource = ""; - } - return compiledShader; -} - } // anonymous namespace // static @@ -378,7 +123,7 @@ return InitializeBase(parseResult, compilationMessages); } -ResultOrError<CompiledShader> ShaderModule::Compile( +ResultOrError<d3d::CompiledShader> ShaderModule::Compile( const ProgrammableStage& programmableStage, SingleShaderStage stage, const PipelineLayout* layout, @@ -526,9 +271,9 @@ const CombinedLimits& limits = device->GetLimits(); req.hlsl.limits = LimitsForCompilationRequest::Create(limits.v1); - CacheResult<CompiledShader> compiledShader; - DAWN_TRY_LOAD_OR_RUN(compiledShader, device, std::move(req), CompiledShader::FromBlob, - CompileShader); + CacheResult<d3d::CompiledShader> compiledShader; + DAWN_TRY_LOAD_OR_RUN(compiledShader, device, std::move(req), d3d::CompiledShader::FromBlob, + d3d::CompileShader); if (device->IsToggleEnabled(Toggle::DumpShaders)) { std::ostringstream dumpedMsg; @@ -537,11 +282,11 @@ if (device->IsToggleEnabled(Toggle::UseDXC)) { dumpedMsg << "/* Dumped disassembled DXIL */" << std::endl; - D3D12_SHADER_BYTECODE code = compiledShader->GetD3D12ShaderBytecode(); + const Blob& shaderBlob = compiledShader->shaderBlob; ComPtr<IDxcBlobEncoding> dxcBlob; ComPtr<IDxcBlobEncoding> disassembly; if (FAILED(device->GetDxcLibrary()->CreateBlobWithEncodingFromPinned( - code.pShaderBytecode, code.BytecodeLength, 0, &dxcBlob)) || + shaderBlob.Data(), shaderBlob.Size(), 0, &dxcBlob)) || FAILED(device->GetDxcCompiler()->Disassemble(dxcBlob.Get(), &disassembly))) { dumpedMsg << "DXC disassemble failed" << std::endl; } else { @@ -554,13 +299,13 @@ << CompileFlagsToStringFXC(compileFlags) << std::endl; dumpedMsg << "/* Dumped disassembled DXBC */" << std::endl; ComPtr<ID3DBlob> disassembly; - D3D12_SHADER_BYTECODE code = compiledShader->GetD3D12ShaderBytecode(); + const Blob& shaderBlob = compiledShader->shaderBlob; UINT flags = // Some literals are printed as floats with precision(6) which is not enough // precision for values very close to 0, so always print literals as hex values. D3D_DISASM_PRINT_HEX_LITERALS; - if (FAILED(device->GetFunctions()->d3dDisassemble( - code.pShaderBytecode, code.BytecodeLength, flags, nullptr, &disassembly))) { + if (FAILED(device->GetFunctions()->d3dDisassemble(shaderBlob.Data(), shaderBlob.Size(), + flags, nullptr, &disassembly))) { dumpedMsg << "D3D disassemble failed" << std::endl; } else { dumpedMsg << std::string_view( @@ -575,13 +320,9 @@ // Clear the hlslSource. It is only used for logging and should not be used // outside of the compilation. - CompiledShader result = compiledShader.Acquire(); + d3d::CompiledShader result = compiledShader.Acquire(); result.hlslSource = ""; return result; } -D3D12_SHADER_BYTECODE CompiledShader::GetD3D12ShaderBytecode() const { - return {shaderBlob.Data(), shaderBlob.Size()}; -} - } // namespace dawn::native::d3d12
diff --git a/src/dawn/native/d3d12/ShaderModuleD3D12.h b/src/dawn/native/d3d12/ShaderModuleD3D12.h index f646117..9cf1c0d 100644 --- a/src/dawn/native/d3d12/ShaderModuleD3D12.h +++ b/src/dawn/native/d3d12/ShaderModuleD3D12.h
@@ -20,6 +20,7 @@ #include "dawn/native/Blob.h" #include "dawn/native/Serializable.h" #include "dawn/native/ShaderModule.h" +#include "dawn/native/d3d/ShaderUtils.h" #include "dawn/native/d3d12/d3d12_platform.h" namespace dawn::native { @@ -31,20 +32,6 @@ class Device; class PipelineLayout; -#define COMPILED_SHADER_MEMBERS(X) \ - X(Blob, shaderBlob) \ - X(std::string, hlslSource) \ - X(bool, usesVertexOrInstanceIndex) - -// `CompiledShader` holds a ref to one of the various representations of shader blobs and -// information used to emulate vertex/instance index starts. It also holds the `hlslSource` for the -// shader compilation, which is only transiently available during Compile, and cleared before it -// returns. It is not written to or loaded from the cache unless Toggle dump_shaders is true. -DAWN_SERIALIZABLE(struct, CompiledShader, COMPILED_SHADER_MEMBERS) { - D3D12_SHADER_BYTECODE GetD3D12ShaderBytecode() const; -}; -#undef COMPILED_SHADER_MEMBERS - class ShaderModule final : public ShaderModuleBase { public: static ResultOrError<Ref<ShaderModule>> Create(Device* device, @@ -52,7 +39,7 @@ ShaderModuleParseResult* parseResult, OwnedCompilationMessages* compilationMessages); - ResultOrError<CompiledShader> Compile( + ResultOrError<d3d::CompiledShader> Compile( const ProgrammableStage& programmableStage, SingleShaderStage stage, const PipelineLayout* layout,