diff options
| author | azhirnov <zh1dron@gmail.com> | 2021-01-30 13:18:41 +0000 |
|---|---|---|
| committer | azhirnov <zh1dron@gmail.com> | 2021-02-03 05:57:28 +0000 |
| commit | 1c4c4e83082a02383bbe7a32af4450ad1a8029ef (patch) | |
| tree | 750d15565da117e1433602816ec70ccad91179f8 /Graphics/ShaderTools | |
| parent | Reworked PipelineResourceSignatureTest.CombinedImageSamplers to validate reso... (diff) | |
| download | DiligentCore-1c4c4e83082a02383bbe7a32af4450ad1a8029ef.tar.gz DiligentCore-1c4c4e83082a02383bbe7a32af4450ad1a8029ef.zip | |
added DXBC resource remapping
Diffstat (limited to 'Graphics/ShaderTools')
| -rw-r--r-- | Graphics/ShaderTools/CMakeLists.txt | 12 | ||||
| -rw-r--r-- | Graphics/ShaderTools/include/DXBCUtils.hpp | 58 | ||||
| -rw-r--r-- | Graphics/ShaderTools/src/DXBCUtils.cpp | 239 |
3 files changed, 309 insertions, 0 deletions
diff --git a/Graphics/ShaderTools/CMakeLists.txt b/Graphics/ShaderTools/CMakeLists.txt index b8201412..61dc51ac 100644 --- a/Graphics/ShaderTools/CMakeLists.txt +++ b/Graphics/ShaderTools/CMakeLists.txt @@ -29,6 +29,14 @@ if(ENABLE_HLSL) list(APPEND INCLUDE include/HLSLUtils.hpp) endif() +#if(D3D11_SUPPORTED OR D3D12_SUPPORTED) + list(APPEND SOURCE + src/DXBCUtils.cpp + ../../ThirdParty/GPUOpenShaderUtils/DXBCChecksum.cpp) + list(APPEND INCLUDE + include/DXBCUtils.hpp + ../../ThirdParty/GPUOpenShaderUtils/DXBCChecksum.h) +#endif() if((PLATFORM_WIN32 AND NOT MINGW_BUILD) OR PLATFORM_UNIVERSAL_WINDOWS OR PLATFORM_LINUX) set(DXC_SUPPORTED TRUE) @@ -97,6 +105,10 @@ if (DXC_SUPPORTED) target_include_directories(Diligent-ShaderTools PUBLIC ../../ThirdParty/DirectXShaderCompiler) endif() +#if(D3D11_SUPPORTED OR D3D12_SUPPORTED) + target_include_directories(Diligent-ShaderTools PRIVATE ../../ThirdParty/GPUOpenShaderUtils) +#endif() + target_link_libraries(Diligent-ShaderTools PRIVATE Diligent-BuildSettings diff --git a/Graphics/ShaderTools/include/DXBCUtils.hpp b/Graphics/ShaderTools/include/DXBCUtils.hpp new file mode 100644 index 00000000..75768c5c --- /dev/null +++ b/Graphics/ShaderTools/include/DXBCUtils.hpp @@ -0,0 +1,58 @@ +/* + * 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 <d3dcommon.h> +#include <unordered_map> + +#include "Constants.h" +#include "Shader.h" +#include "HashUtils.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>; + + /// \param [in] ResourceMap - Resource binding map. For every resource in the + /// byte code it must define the binding (shader register). + /// \param [inout] pBytecode - Byte code that will be patched. + static bool RemapDXBCResources(const TResourceBindingMap& ResourceMap, + ID3DBlob* pBytecode); +}; + +} // namespace Diligent diff --git a/Graphics/ShaderTools/src/DXBCUtils.cpp b/Graphics/ShaderTools/src/DXBCUtils.cpp new file mode 100644 index 00000000..40409178 --- /dev/null +++ b/Graphics/ShaderTools/src/DXBCUtils.cpp @@ -0,0 +1,239 @@ +/* + * 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. + */ + +#include <d3d11shader.h> +#include "DXBCUtils.hpp" +#include "DXBCChecksum.h" + +namespace Diligent +{ +namespace +{ +struct DXBCHeader +{ + Uint32 Magic; // 0..3 "DXBC" + Uint32 Checksum[4]; // 4..19 + Uint32 Reserved; // 20..23 + Uint32 TotalSize; // 24..27 + Uint32 ChunkCount; // 28..31 +}; +static_assert(sizeof(DXBCHeader) == 32, ""); + +struct ChunkHeader +{ + Uint32 Magic; // 0..3 fourCC + Uint32 Length; // 4..7 +}; + +struct ResourceDefChunkHeader : ChunkHeader +{ + Uint32 CBuffCount; // 8..11 + Uint32 CBuffOffset; // 12..15, from start of chunk data + Uint32 ResBindingCount; // 16..19 + Uint32 ResBindingOffset; // 20..23, from start of chunk data + Uint8 MinorVersion; // 24 + Uint8 MajorVersion; // 25 + Uint16 ShaderType; // 26..27 + Uint32 Flags; // 28..31 + Uint32 CreatorStringOffset; // 32..35, from start of chunk data +}; +static_assert(sizeof(ResourceDefChunkHeader) == 36, ""); + +struct ResourceBindingInfo11 +{ + Uint32 NameOffset; // 0..3, from start of chunk data + D3D_SHADER_INPUT_TYPE ShaderInputType; // 4..7 + D3D_RESOURCE_RETURN_TYPE ReturnType; // 8..11 + D3D_SRV_DIMENSION ViewDim; // 12..15 + Uint32 NumSamples; // 16..19 + Uint32 BindPoint; // 20..23 + Uint32 BindCount; // 24..27 + D3D_SHADER_INPUT_FLAGS ShaderInputFlags; // 28..31 +}; +static_assert(sizeof(ResourceBindingInfo11) == 32, ""); + +struct ResourceBindingInfo12 +{ + Uint32 NameOffset; // 0..3, from start of chunk data + D3D_SHADER_INPUT_TYPE ShaderInputType; // 4..7 + D3D_RESOURCE_RETURN_TYPE ReturnType; // 8..11 + D3D_SRV_DIMENSION ViewDim; // 12..15 + Uint32 NumSamples; // 16..19 + Uint32 BindPoint; // 20..23 + Uint32 BindCount; // 24..27 + D3D_SHADER_INPUT_FLAGS ShaderInputFlags; // 28..31 + Uint32 Space; // 32..35 + Uint32 Reserved; // 36..39 +}; +static_assert(sizeof(ResourceBindingInfo12) == 40, ""); + +#define FOURCC(a, b, c, d) (Uint32{(d) << 24} | Uint32{(c) << 16} | Uint32{(b) << 8} | Uint32{a}) + +constexpr Uint32 DXBCFourCC = FOURCC('D', 'X', 'B', 'C'); +constexpr Uint32 RDEFFourCC = FOURCC('R', 'D', 'E', 'F'); + + +bool RemapShaderResources(const DXBCUtils::TResourceBindingMap& ResourceMap, const void* EndPtr, ResourceDefChunkHeader* RDEFHeader) +{ + VERIFY_EXPR(RDEFHeader->Magic == RDEFFourCC); + VERIFY_EXPR((RDEFHeader->MajorVersion == 5 && RDEFHeader->MinorVersion == 0) || RDEFHeader->MajorVersion < 5); + + auto* Ptr = reinterpret_cast<char*>(RDEFHeader) + sizeof(ChunkHeader); + auto* ResBinding = reinterpret_cast<ResourceBindingInfo11*>(Ptr + RDEFHeader->ResBindingOffset); + VERIFY((ResBinding + RDEFHeader->ResBindingCount) <= EndPtr, "Resource bindings is outside of buffer range."); + + for (Uint32 r = 0; r < RDEFHeader->ResBindingCount; ++r) + { + auto& Res = ResBinding[r]; + const char* Name = Ptr + Res.NameOffset; + VERIFY(Name < EndPtr, "Resource name pointer is outside of buffer range."); + + auto Iter = ResourceMap.find(HashMapStringKey{Name}); + if (Iter == ResourceMap.end()) + { + LOG_ERROR("Failed to find '", Name, "' in ResourceMap."); + return false; + } + + if (Iter->second.Space != 0 && Iter->second.Space != ~0u) + { + LOG_ERROR("Can not change space for resource '", Name, "' because shader is not compiled for SM 5.1"); + return false; + } + + Res.BindPoint = Iter->second.BindPoint; + } + return true; +} + +bool RemapShaderResourcesSM51(const DXBCUtils::TResourceBindingMap& ResourceMap, const void* EndPtr, ResourceDefChunkHeader* RDEFHeader) +{ + VERIFY_EXPR(RDEFHeader->Magic == RDEFFourCC); + VERIFY_EXPR(RDEFHeader->MajorVersion == 5 && RDEFHeader->MinorVersion == 1); + + auto* Ptr = reinterpret_cast<char*>(RDEFHeader) + sizeof(ChunkHeader); + auto* ResBinding = reinterpret_cast<ResourceBindingInfo12*>(Ptr + RDEFHeader->ResBindingOffset); + VERIFY((ResBinding + RDEFHeader->ResBindingCount) <= EndPtr, "Resource bindings is outside of buffer range."); + + for (Uint32 r = 0; r < RDEFHeader->ResBindingCount; ++r) + { + auto& Res = ResBinding[r]; + const char* Name = Ptr + Res.NameOffset; + VERIFY(Name < EndPtr, "Resource name pointer is outside of buffer range."); + + auto Iter = ResourceMap.find(HashMapStringKey{Name}); + if (Iter == ResourceMap.end()) + { + LOG_ERROR("Failed to find '", Name, "' in ResourceMap."); + return false; + } + + Res.BindPoint = Iter->second.BindPoint; + Res.Space = Iter->second.Space; + } + return true; +} +} // namespace + + +bool DXBCUtils::RemapDXBCResources(const TResourceBindingMap& ResourceMap, + ID3DBlob* pBytecode) +{ + if (pBytecode == nullptr) + { + LOG_ERROR("pBytecode must not be null."); + return false; + } + + char* const Ptr = static_cast<char*>(pBytecode->GetBufferPointer()); + const auto Size = pBytecode->GetBufferSize(); + const void* const EndPtr = Ptr + Size; + + if (Size < sizeof(DXBCHeader)) + { + LOG_ERROR("Size of bytecode is too small."); + return false; + } + + auto& Header = *reinterpret_cast<DXBCHeader*>(Ptr); + VERIFY_EXPR(Header.TotalSize == Size); + +#ifdef DILIGENT_DEBUG + { + DWORD Checksum[4] = {}; + CalculateDXBCChecksum(reinterpret_cast<BYTE*>(Ptr), static_cast<DWORD>(Size), Checksum); + + VERIFY_EXPR(Checksum[0] == Header.Checksum[0]); + VERIFY_EXPR(Checksum[1] == Header.Checksum[1]); + VERIFY_EXPR(Checksum[2] == Header.Checksum[2]); + VERIFY_EXPR(Checksum[3] == Header.Checksum[3]); + } +#endif + + if (Header.Magic != DXBCFourCC) + { + LOG_ERROR("Bytecode header must contain 'DXBC' magic number."); + return false; + } + + const Uint32* Chunks = reinterpret_cast<Uint32*>(Ptr + sizeof(Header)); + bool Result = true; + + for (Uint32 i = 0; i < Header.ChunkCount; ++i) + { + auto& Chunk = *reinterpret_cast<ChunkHeader*>(Ptr + Chunks[i]); + VERIFY((&Chunk + 1) <= EndPtr, "Pointer to chunk is outside of buffer range."); + + if (Chunk.Magic == RDEFFourCC) + { + auto* RDEFHeader = reinterpret_cast<ResourceDefChunkHeader*>(&Chunk); + + if (RDEFHeader->MajorVersion == 5 && RDEFHeader->MinorVersion == 1) + Result = RemapShaderResourcesSM51(ResourceMap, EndPtr, RDEFHeader); + else + Result = RemapShaderResources(ResourceMap, EndPtr, RDEFHeader); + break; + } + } + + if (!Result) + { + LOG_ERROR("Failed to find chunk 'RDEF' with resource definition."); + return false; + } + + // update checksum + DWORD Checksum[4] = {}; + CalculateDXBCChecksum(reinterpret_cast<BYTE*>(Ptr), static_cast<DWORD>(Size), Checksum); + + static_assert(sizeof(Header.Checksum) == sizeof(Checksum), ""); + memcpy(Header.Checksum, Checksum, sizeof(Header.Checksum)); + + return true; +} + +} // namespace Diligent |
