diff options
| author | azhirnov <zh1dron@gmail.com> | 2021-02-05 21:35:37 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2021-03-19 00:31:35 +0000 |
| commit | 78fa6c94992a6d1a140da1354448a004e62c9683 (patch) | |
| tree | c21183a39d58ba9ccc89d9d8ea6fe1aa9de2ec35 /Graphics/ShaderTools | |
| parent | Merged master (diff) | |
| download | DiligentCore-78fa6c94992a6d1a140da1354448a004e62c9683.tar.gz DiligentCore-78fa6c94992a6d1a140da1354448a004e62c9683.zip | |
merged with resource_signature
Diffstat (limited to 'Graphics/ShaderTools')
| -rw-r--r-- | Graphics/ShaderTools/include/DXBCUtils.hpp | 26 | ||||
| -rw-r--r-- | Graphics/ShaderTools/include/DXCompiler.hpp | 8 | ||||
| -rw-r--r-- | Graphics/ShaderTools/include/ResourceBindingMap.hpp | 61 | ||||
| -rw-r--r-- | Graphics/ShaderTools/src/DXBCUtils.cpp | 6 | ||||
| -rw-r--r-- | Graphics/ShaderTools/src/DXCompiler.cpp | 210 |
5 files changed, 284 insertions, 27 deletions
diff --git a/Graphics/ShaderTools/include/DXBCUtils.hpp b/Graphics/ShaderTools/include/DXBCUtils.hpp index bb509908..20d26547 100644 --- a/Graphics/ShaderTools/include/DXBCUtils.hpp +++ b/Graphics/ShaderTools/include/DXBCUtils.hpp @@ -27,35 +27,29 @@ #pragma once -#include <unordered_map> +#include <d3dcommon.h> -#include "BasicTypes.h" -#include "HashUtils.hpp" +#include "Constants.h" +#include "Shader.h" +#include "ResourceBindingMap.hpp" namespace Diligent { struct DXBCUtils { - struct BindInfo - { - Uint32 BindPoint = ~0u; - Uint32 Space = ~0u; - }; - - /// A mapping from the resource name to the binding (shader register). - using TResourceBindingMap = std::unordered_map<HashMapStringKey, BindInfo, HashMapStringKey::Hasher>; + using BindInfo = ResourceBinding::BindInfo; + using TResourceBindingMap = ResourceBinding::TMap; /// Remaps resource bindings in the given DXBC byte code. /// \param [in] ResourceMap - Resource binding map. For every resource in the /// byte code it must define the binding (shader register). - /// \param [inout] pBytecode - Pointer to the byte code to be patched. - /// \param [in] Size - The byte code size, in bytes. - static bool RemapDXBCResources(const TResourceBindingMap& ResourceMap, - void* pBytecode, - size_t Size); + /// \param [inout] pBytecode - Byte code that will be patched. + static bool RemapResourceBindings(const TResourceBindingMap& ResourceMap, + void* pBytecode, + size_t Size); }; } // namespace Diligent diff --git a/Graphics/ShaderTools/include/DXCompiler.hpp b/Graphics/ShaderTools/include/DXCompiler.hpp index 4f1a4d1b..d373292d 100644 --- a/Graphics/ShaderTools/include/DXCompiler.hpp +++ b/Graphics/ShaderTools/include/DXCompiler.hpp @@ -29,13 +29,12 @@ #include <array> #include <vector> -#include <unordered_map> #include <memory> #include "Constants.h" #include "Shader.h" #include "DataBlob.h" -#include "HashUtils.hpp" +#include "ResourceBindingMap.hpp" // defined in dxcapi.h struct DxcDefine; @@ -86,9 +85,9 @@ public: std::vector<uint32_t>* pByteCode, IDataBlob** ppCompilerOutput) noexcept(false) = 0; - /// A mapping from the resource name to the binding (shader register). - using TResourceBindingMap = std::unordered_map<HashMapStringKey, Uint32, HashMapStringKey::Hasher>; + using BindInfo = ResourceBinding::BindInfo; + using TResourceBindingMap = ResourceBinding::TMap; /// Remaps resource bindings (shader registers) in the source byte code using the /// resource binding map. @@ -115,5 +114,6 @@ public: // path is used. std::unique_ptr<IDXCompiler> CreateDXCompiler(DXCompilerTarget Target, const char* pLibraryName); +bool IsDXILBytecode(const void* pBytecode, size_t Size); } // namespace Diligent diff --git a/Graphics/ShaderTools/include/ResourceBindingMap.hpp b/Graphics/ShaderTools/include/ResourceBindingMap.hpp new file mode 100644 index 00000000..b334b890 --- /dev/null +++ b/Graphics/ShaderTools/include/ResourceBindingMap.hpp @@ -0,0 +1,61 @@ +/* + * Copyright 2019-2021 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * 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. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +#include <unordered_map> + +#include "Constants.h" +#include "HashUtils.hpp" + +namespace Diligent +{ + +struct ResourceBinding +{ + struct BindInfo + { + // new bind point & space + Uint32 BindPoint = ~0u; + Uint32 Space = ~0u; + + // current (previous) bind point & space + mutable Uint32 SrcBindPoint = ~0u; + mutable Uint32 SrcSpace = ~0u; + + BindInfo() {} + + BindInfo(Uint32 _BindPoint, Uint32 _Space) : + BindPoint{_BindPoint}, Space{_Space} + {} + }; + + /// A mapping from the resource name to the binding (shader register). + using TMap = std::unordered_map<HashMapStringKey, BindInfo, HashMapStringKey::Hasher>; +}; + +} // namespace Diligent diff --git a/Graphics/ShaderTools/src/DXBCUtils.cpp b/Graphics/ShaderTools/src/DXBCUtils.cpp index 08f94fb2..e65e0350 100644 --- a/Graphics/ShaderTools/src/DXBCUtils.cpp +++ b/Graphics/ShaderTools/src/DXBCUtils.cpp @@ -154,9 +154,9 @@ bool RemapShaderResources(const DXBCUtils::TResourceBindingMap& ResourceMap, con } // namespace -bool DXBCUtils::RemapDXBCResources(const TResourceBindingMap& ResourceMap, - void* pBytecode, - size_t Size) +bool DXBCUtils::RemapResourceBindings(const TResourceBindingMap& ResourceMap, + void* pBytecode, + size_t Size) { if (pBytecode == nullptr) { diff --git a/Graphics/ShaderTools/src/DXCompiler.cpp b/Graphics/ShaderTools/src/DXCompiler.cpp index 09726b43..3164e67f 100644 --- a/Graphics/ShaderTools/src/DXCompiler.cpp +++ b/Graphics/ShaderTools/src/DXCompiler.cpp @@ -49,6 +49,8 @@ #include "HLSLUtils.hpp" +#include "dxc/DxilContainer/DxilContainer.h" + namespace Diligent { @@ -886,7 +888,8 @@ bool DXCompilerImpl::PatchDXIL(const TResourceBindingMap& ResourceMap, String& D // !158 = !{i32 0, %"class.RWTexture2D<vector<float, 4> >"* @"\01?g_ColorBuffer@@3V?$RWTexture2D@V?$vector@M$03@@@@A", !"g_ColorBuffer", i32 -1, i32 -1, i32 1, i32 2, i1 false, i1 false, i1 false, !159} const auto* Name = ResPair.first.GetStr(); - const auto& BindPoint = ResPair.second; + const auto Space = ResPair.second.Space; + const auto BindPoint = ResPair.second.BindPoint; const auto DxilName = String{"!\""} + Name + "\""; size_t pos = DXIL.find(DxilName); @@ -900,7 +903,7 @@ bool DXCompilerImpl::PatchDXIL(const TResourceBindingMap& ResourceMap, String& D // !"g_ColorBuffer", i32 -1, i32 -1, // ^ - auto ReplaceRecord = [&](const std::string& NewValue, const char* RecordName) // + auto ReplaceRecord = [&](const std::string& NewValue, const char* RecordName, Uint32& PrevValue) // { #define CHECK_PATCHING_ERROR(Cond, ...) \ if (!(Cond)) \ @@ -940,6 +943,7 @@ bool DXCompilerImpl::PatchDXIL(const TResourceBindingMap& ResourceMap, String& D // ^ // RecordEndPos + PrevValue = static_cast<Uint32>(std::stoi(DXIL.substr(pos, RecordEndPos - pos))); DXIL.replace(pos, RecordEndPos - pos, NewValue); // , i32 1 // ^ @@ -956,7 +960,7 @@ bool DXCompilerImpl::PatchDXIL(const TResourceBindingMap& ResourceMap, String& D // !"g_ColorBuffer", i32 -1, i32 -1, // ^ - if (!ReplaceRecord("0", "space")) + if (!ReplaceRecord(std::to_string(Space), "space", ResPair.second.SrcSpace)) { RemappingOK = false; continue; @@ -964,7 +968,7 @@ bool DXCompilerImpl::PatchDXIL(const TResourceBindingMap& ResourceMap, String& D // !"g_ColorBuffer", i32 0, i32 -1, // ^ - if (!ReplaceRecord(std::to_string(BindPoint), "binding")) + if (!ReplaceRecord(std::to_string(BindPoint), "binding", ResPair.second.SrcBindPoint)) { RemappingOK = false; continue; @@ -972,7 +976,205 @@ bool DXCompilerImpl::PatchDXIL(const TResourceBindingMap& ResourceMap, String& D // !"g_ColorBuffer", i32 0, i32 1, // ^ } + + // Patch createHandle command + static const String CallHandlePattern = " = call %dx.types.Handle @dx.op.createHandle("; + static const String SamplerPart = "_sampler"; + static const String CBufferPart = "_cbuffer"; + static const String TexturePart = "_texture_"; + static const String UAVPart = "_UAV_"; + + for (size_t startPos = 0; startPos < DXIL.size();) + { + // %dx.types.Handle @dx.op.createHandle( + // i32, ; opcode + // i8, ; resource class: SRV=0, UAV=1, CBV=2, Sampler=3 + // i32, ; resource range ID (constant) + // i32, ; index into the range + // i1) ; non-uniform resource index: false or true + + // Example: + // + // %cbConstants_cbuffer = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 2, i32 0, i32 0, i1 false) + + size_t callHandlePos = DXIL.find(CallHandlePattern, startPos); + if (callHandlePos == String::npos) + break; + + startPos = callHandlePos + CallHandlePattern.length(); + + // Parse resource name: %name_suffix + + size_t resNameEnd = callHandlePos; + size_t resNameStart = resNameEnd - 1; + bool partFound = false; + for (auto& pos = resNameStart; pos >= 0; --pos) + { + const char c = DXIL[pos]; + + if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) + continue; + + if (c == '_') + { + String part = DXIL.substr(pos, resNameEnd - pos); + if (!partFound && + (part == SamplerPart || part == CBufferPart || + (part.length() > TexturePart.length() && strncmp(part.c_str(), TexturePart.c_str(), TexturePart.length()) == 0) || + (part.length() > UAVPart.length() && strncmp(part.c_str(), UAVPart.c_str(), UAVPart.length()) == 0))) + { + resNameEnd = pos; + partFound = true; + } + continue; + } + + VERIFY_EXPR(c == '%'); + ++pos; + break; + } + + String resName = DXIL.substr(resNameStart, resNameEnd - resNameStart); + + auto Iter = ResourceMap.find(HashMapStringKey{resName.c_str()}); + if (Iter == ResourceMap.end()) + { + UNEXPECTED("Resource is not exists in ResourceMap"); + continue; + } + + size_t pos = startPos; + + const auto NextArg = [&DXIL, &pos]() { + ++pos; + for (; pos < DXIL.size(); ++pos) + { + const char c = DXIL[pos]; + if (c == ',') + return true; + if (c == ')' || c == '\n') + return false; + } + return false; + }; + + // skip opcode + // createHandle(i32 57, i8 2, i32 0, i32 0, i1 false) + // ^ + if (!NextArg()) + { + UNEXPECTED("Failed to parse createHandle()"); + continue; + } + VERIFY_EXPR(DXIL[pos + 2] == 'i' && DXIL[pos + 3] == '8' && DXIL[pos + 4] == ' '); + + // skip resource class + // createHandle(i32 57, i8 2, i32 0, i32 0, i1 false) + // ^ + if (!NextArg()) + { + UNEXPECTED("Failed to parse createHandle()"); + continue; + } + VERIFY_EXPR(DXIL[pos + 2] == 'i' && DXIL[pos + 3] == '3' && DXIL[pos + 4] == '2' && DXIL[pos + 5] == ' '); + + // skip resource range ID + // createHandle(i32 57, i8 2, i32 0, i32 0, i1 false) + // ^ + if (!NextArg()) + { + UNEXPECTED("Failed to parse createHandle()"); + continue; + } + VERIFY_EXPR(DXIL[pos + 2] == 'i' && DXIL[pos + 3] == '3' && DXIL[pos + 4] == '2' && DXIL[pos + 5] == ' '); + + const size_t indexStartPos = pos + 6; + VERIFY_EXPR(DXIL[indexStartPos] >= '0' && DXIL[indexStartPos] <= '9'); + + // find index end + // createHandle(i32 57, i8 2, i32 0, i32 0, i1 false) + // ^ + if (!NextArg()) + { + UNEXPECTED("Failed to parse createHandle()"); + continue; + } + VERIFY_EXPR(DXIL[pos + 2] == 'i' && DXIL[pos + 3] == '1' && DXIL[pos + 4] == ' '); + + const size_t indexEndPos = pos; + + // replace index + const Uint32 SrcIndex = static_cast<Uint32>(std::stoi(DXIL.substr(indexStartPos, indexEndPos - indexStartPos))); + VERIFY_EXPR(SrcIndex >= Iter->second.SrcBindPoint); + VERIFY_EXPR(Iter->second.SrcBindPoint != ~0u); + + const Uint32 IndexOffset = SrcIndex - Iter->second.SrcBindPoint; + VERIFY_EXPR((Iter->second.BindPoint + IndexOffset) >= Iter->second.BindPoint); + + const String NewIndexStr = std::to_string(Iter->second.BindPoint + IndexOffset); + DXIL.replace(DXIL.begin() + indexStartPos, DXIL.begin() + indexEndPos, NewIndexStr); + + startPos = indexStartPos + NewIndexStr.length(); + } return RemappingOK; } +bool IsDXILBytecode(const void* pBytecode, size_t Size) +{ + const auto* data_begin = reinterpret_cast<const uint8_t*>(pBytecode); + const auto* data_end = data_begin + Size; + const auto* ptr = data_begin; + + if (ptr + sizeof(hlsl::DxilContainerHeader) > data_end) + { + // No space for the container header + return false; + } + + // A DXIL container is composed of a header, a sequence of part lengths, and a sequence of parts. + // https://github.com/microsoft/DirectXShaderCompiler/blob/master/docs/DXIL.rst#dxil-container-format + const auto& ContainerHeader = *reinterpret_cast<const hlsl::DxilContainerHeader*>(ptr); + if (ContainerHeader.HeaderFourCC != hlsl::DFCC_Container) + { + // Incorrect FourCC + return false; + } + + if (ContainerHeader.Version.Major != hlsl::DxilContainerVersionMajor) + { + LOG_WARNING_MESSAGE("Unable to parse DXIL container: the container major version is ", Uint32{ContainerHeader.Version.Major}, + " while ", Uint32{hlsl::DxilContainerVersionMajor}, " is expected"); + return false; + } + + // The header is followed by uint32_t PartOffset[PartCount]; + // The offset is to a DxilPartHeader. + ptr += sizeof(hlsl::DxilContainerHeader); + if (ptr + sizeof(uint32_t) * ContainerHeader.PartCount > data_end) + { + // No space for offsets + return false; + } + + const auto* PartOffsets = reinterpret_cast<const uint32_t*>(ptr); + for (uint32_t part = 0; part < ContainerHeader.PartCount; ++part) + { + const auto Offset = PartOffsets[part]; + if (data_begin + Offset + sizeof(hlsl::DxilPartHeader) > data_end) + { + // No space for the part header + return false; + } + + const auto& PartHeader = *reinterpret_cast<const hlsl::DxilPartHeader*>(data_begin + Offset); + if (PartHeader.PartFourCC == hlsl::DFCC_DXIL) + { + // We found DXIL part + return true; + } + } + + return false; +} + } // namespace Diligent |
