diff --git a/BuildAll.py b/BuildAll.py index 9af0521d..384f45a3 100644 --- a/BuildAll.py +++ b/BuildAll.py @@ -64,6 +64,9 @@ def FindVS2017OrUpFolder(programFilesFolder, vsVersion, vsName): LogError("Could NOT find VS%s.\n" % vsName) return "" +def FindVS2022Folder(programFilesFolder): + return FindVS2017OrUpFolder(programFilesFolder, 17, "2022") + def FindVS2019Folder(programFilesFolder): return FindVS2017OrUpFolder(programFilesFolder, 16, "2019") @@ -132,7 +135,9 @@ def Build(hostPlatform, hostArch, buildSys, compiler, arch, configuration, tblge batCmd = BatchCommand(hostPlatform) if hostPlatform == "win": programFilesFolder = FindProgramFilesFolder() - if (buildSys == "vs2019") or ((buildSys == "ninja") and (compiler == "vc142")): + if (buildSys == "vs2022") or ((buildSys == "ninja") and (compiler == "vc143")): + vsFolder = FindVS2022Folder(programFilesFolder) + elif (buildSys == "vs2019") or ((buildSys == "ninja") and (compiler == "vc142")): vsFolder = FindVS2019Folder(programFilesFolder) elif (buildSys == "vs2017") or ((buildSys == "ninja") and (compiler == "vc141")): vsFolder = FindVS2017Folder(programFilesFolder) @@ -153,10 +158,13 @@ def Build(hostPlatform, hostArch, buildSys, compiler, arch, configuration, tblge else: LogError("Unsupported architecture.\n") vcToolset = "" - if (buildSys == "vs2019") and (compiler == "vc141"): + if (buildSys == "vs2022") and (compiler == "vc142"): + vcOption += " -vcvars_ver=14.2" + vcToolset = "v142," + elif ((buildSys == "vs2022") or (buildSys == "vs2019")) and (compiler == "vc141"): vcOption += " -vcvars_ver=14.1" vcToolset = "v141," - elif ((buildSys == "vs2019") or (buildSys == "vs2017")) and (compiler == "vc140"): + elif ((buildSys == "vs2022") or (buildSys == "vs2019") or (buildSys == "vs2017")) and (compiler == "vc140"): vcOption += " -vcvars_ver=14.0" vcToolset = "v140," batCmd.AddCommand("@call \"%sVCVARSALL.BAT\" %s" % (vsFolder, vcOption)) @@ -176,7 +184,9 @@ def Build(hostPlatform, hostArch, buildSys, compiler, arch, configuration, tblge else: batCmd.AddCommand("ninja -j%d" % parallel) else: - if buildSys == "vs2019": + if buildSys == "vs2022": + generator = "\"Visual Studio 17\"" + elif buildSys == "vs2019": generator = "\"Visual Studio 16\"" elif buildSys == "vs2017": generator = "\"Visual Studio 15\"" @@ -240,7 +250,9 @@ def Build(hostPlatform, hostArch, buildSys, compiler, arch, configuration, tblge if (argc > 2): compiler = sys.argv[2] else: - if buildSys == "vs2019": + if buildSys == "vs2022": + compiler = "vc143" + elif buildSys == "vs2019": compiler = "vc142" elif buildSys == "vs2017": compiler = "vc141" diff --git a/CI/AzurePipelines/ContinuousBuild.yml b/CI/AzurePipelines/ContinuousBuild.yml index bd39b452..a9c2c69c 100644 --- a/CI/AzurePipelines/ContinuousBuild.yml +++ b/CI/AzurePipelines/ContinuousBuild.yml @@ -7,6 +7,12 @@ steps: git config --global user.name "Dummy Name" displayName: 'Config git' +- task: UsePythonVersion@0 + inputs: + versionSpec: '3.x' + addToPath: true + architecture: 'x64' + - task: PythonScript@0 displayName: 'Build' inputs: diff --git a/External/CMakeLists.txt b/External/CMakeLists.txt index 5490b9bf..ff4ab557 100644 --- a/External/CMakeLists.txt +++ b/External/CMakeLists.txt @@ -1,6 +1,10 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. +if(NOT EXISTS ${git_executable}) + unset(git_executable CACHE) +endif() + find_program(git_executable NAMES git git.exe git.cmd) if(NOT git_executable) message(FATAL_ERROR "Failed to find git.") diff --git a/External/DirectXShaderCompiler.cmake b/External/DirectXShaderCompiler.cmake index 467de97c..1013bba2 100644 --- a/External/DirectXShaderCompiler.cmake +++ b/External/DirectXShaderCompiler.cmake @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -set(DirectXShaderCompiler_REV "634a23537df7e85512437a4976f9bf9fcd095e18") +set(DirectXShaderCompiler_REV "cc50c79df1272a358fbf8b16e85dc6a9e5bc2ead") UpdateExternalLib("DirectXShaderCompiler" "https://github.com/Microsoft/DirectXShaderCompiler.git" ${DirectXShaderCompiler_REV}) @@ -40,6 +40,7 @@ endif() set(SPIRV_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(SPIRV_SKIP_EXECUTABLES ON CACHE BOOL "" FORCE) set(SPIRV_SKIP_TESTS ON CACHE BOOL "" FORCE) + add_subdirectory(DirectXShaderCompiler EXCLUDE_FROM_ALL) foreach(target "clang" "dxc" @@ -53,9 +54,12 @@ foreach(target "ClangDiagnosticAnalysis" "ClangDiagnosticAST" "ClangDiagnosticComment" "ClangDiagnosticCommon" "ClangDiagnosticDriver" "ClangDiagnosticFrontend" "ClangDiagnosticGroups" "ClangDiagnosticIndexName" "ClangDiagnosticLex" "ClangDiagnosticParse" "ClangDiagnosticSema" "ClangDiagnosticSerialization" "ClangStmtNodes" - "LLVMAnalysis" "LLVMAsmParser" "LLVMBitReader" "LLVMBitWriter" "LLVMCore" "LLVMDxcSupport" "LLVMDXIL" "LLVMDxilContainer" + "DxcDisassembler" "DxcOptimizer" "DxilConstants" "DxilCounters" "DxilDocs" "DxilInstructions" "DxilIntrinsicTables" + "DxilMetadata" "DxilOperations" "DxilPIXPasses" "DxilShaderModel" "DxilShaderModelInc" "DxilSigPoint" "DxilValidation" "DxilValidationInc" + "HCTGen" "HLSLIntrinsicOp" "HLSLOptions" + "LLVMAnalysis" "LLVMAsmParser" "LLVMBitReader" "LLVMBitWriter" "LLVMCore" "LLVMDxcBindingTable" "LLVMDxcSupport" "LLVMDXIL" "LLVMDxilContainer" "LLVMDxilPIXPasses" "LLVMDxilRootSignature" "LLVMDxrFallback" "LLVMHLSL" "LLVMInstCombine" "LLVMipa" "LLVMipo" "LLVMIRReader" - "LLVMLinker" "LLVMLTO" "LLVMMSSupport" "LLVMOption" "LLVMPasses" "LLVMPassPrinters" "LLVMProfileData" "LLVMScalarOpts" "LLVMSupport" + "LLVMLinker" "LLVMMiniz" "LLVMMSSupport" "LLVMOption" "LLVMPasses" "LLVMPassPrinters" "LLVMProfileData" "LLVMScalarOpts" "LLVMSupport" "LLVMTableGen" "LLVMTarget" "LLVMTransformUtils" "LLVMVectorize" "ClangDriverOptions" "DxcEtw" "intrinsics_gen" "TablegenHLSLOptions" "clang-tblgen" "llvm-tblgen" "hlsl_dxcversion_autogen" "hlsl_version_autogen") diff --git a/External/SPIRV-Cross.cmake b/External/SPIRV-Cross.cmake index 1307d152..d3eaa5e7 100644 --- a/External/SPIRV-Cross.cmake +++ b/External/SPIRV-Cross.cmake @@ -1,10 +1,12 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -set(SPIRV_Cross_REV "8891bd35120ca91c252a66ccfdc3f9a9d03c70cd") +set(SPIRV_Cross_REV "37dfb3f45f4fc47c841f81e618c602f6f3de0f17") UpdateExternalLib("SPIRV-Cross" "https://github.com/KhronosGroup/SPIRV-Cross.git" ${SPIRV_Cross_REV}) +set(SPIRV_CROSS_ENABLE_TESTS OFF CACHE BOOL "" FORCE) + add_subdirectory(SPIRV-Cross EXCLUDE_FROM_ALL) foreach(target "spirv-cross" "spirv-cross-core" "spirv-cross-cpp" "spirv-cross-glsl" "spirv-cross-hlsl" "spirv-cross-msl" "spirv-cross-reflect" diff --git a/External/SPIRV-Header.cmake b/External/SPIRV-Header.cmake index 364e26b9..d8115f8e 100644 --- a/External/SPIRV-Header.cmake +++ b/External/SPIRV-Header.cmake @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -set(SPIRV_Headers_REV "3fdabd0da2932c276b25b9b4a988ba134eba1aa6") +set(SPIRV_Headers_REV "29817199b7069bac971e5365d180295d4b077ebe") UpdateExternalLib("SPIRV-Headers" "https://github.com/KhronosGroup/SPIRV-Headers.git" ${SPIRV_Headers_REV}) diff --git a/External/SPIRV-Tools.cmake b/External/SPIRV-Tools.cmake index a5e0c2cf..e1523c2c 100644 --- a/External/SPIRV-Tools.cmake +++ b/External/SPIRV-Tools.cmake @@ -1,19 +1,29 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -set(SPIRV_Tools_REV "c341f7a6cd441d05ca1347ee39f2f03f32225c59") +set(SPIRV_Tools_REV "1589720e1065bd163fb8e812f268413b13755f7c") UpdateExternalLib("SPIRV-Tools" "https://github.com/KhronosGroup/SPIRV-Tools.git" ${SPIRV_Tools_REV}) set(SPIRV_SKIP_EXECUTABLES ON CACHE BOOL "" FORCE) add_subdirectory(SPIRV-Tools EXCLUDE_FROM_ALL) + +if(MSVC) + target_compile_options(SPIRV-Tools-static + PRIVATE + /wd4819 + ) +endif() + foreach(target "core_tables" "enum_string_mapping" "extinst_tables" "spirv-tools-pkg-config" "spirv-tools-shared-pkg-config" "spirv-tools-build-version" "spirv-tools-header-DebugInfo" "SPIRV-Tools-link" "SPIRV-Tools-shared" - "spirv-tools-header-OpenCLDebugInfo100" "spirv-tools-vimsyntax" "spv-tools-cldi100" "spv-tools-clspvreflection" "spv-tools-debuginfo" "spv-tools-spv-amd-gs" - "spv-tools-spv-amd-sb" "spv-tools-spv-amd-sevp" "spv-tools-spv-amd-stm") + "spirv-tools-header-OpenCLDebugInfo100" "spirv-tools-header-NonSemanticShaderDebugInfo100" + "spirv-tools-vimsyntax" "spv-tools-cldi100" "spv-tools-shdi100" "spv-tools-clspvreflection" + "spv-tools-debuginfo" "spv-tools-spv-amd-gs" "spv-tools-spv-amd-sb" "spv-tools-spv-amd-sevp" + "spv-tools-spv-amd-stm") get_target_property(vsFolder ${target} FOLDER) if(NOT vsFolder) set(vsFolder "") diff --git a/Include/ShaderConductor/ShaderConductor.hpp b/Include/ShaderConductor/ShaderConductor.hpp index f709d6a8..e04d5ee1 100644 --- a/Include/ShaderConductor/ShaderConductor.hpp +++ b/Include/ShaderConductor/ShaderConductor.hpp @@ -121,6 +121,240 @@ namespace ShaderConductor BlobImpl* m_impl = nullptr; }; + class SC_API Reflection + { + public: + class ReflectionImpl; + struct VariableDesc; + + class SC_API ConstantBuffer + { + friend class ReflectionImpl; + + public: + ConstantBuffer() noexcept; + ConstantBuffer(const ConstantBuffer& other); + ConstantBuffer(ConstantBuffer&& other) noexcept; + ~ConstantBuffer() noexcept; + + ConstantBuffer& operator=(const ConstantBuffer& other); + ConstantBuffer& operator=(ConstantBuffer&& other) noexcept; + + bool Valid() const noexcept; + + const char* Name() const noexcept; + uint32_t Size() const noexcept; + + uint32_t NumVariables() const noexcept; + const VariableDesc* VariableByIndex(uint32_t index) const noexcept; + const VariableDesc* VariableByName(const char* name) const noexcept; + + private: + class ConstantBufferImpl; + ConstantBufferImpl* m_impl = nullptr; + }; + + class SC_API VariableType + { + friend class ConstantBuffer; + + public: + enum class DataType + { + Void, + + Bool, + Int, + Uint, + Float, + + Half, + Int16, + Uint16, + + Struct, + }; + + public: + VariableType() noexcept; + VariableType(const VariableType& other); + VariableType(VariableType&& other) noexcept; + ~VariableType() noexcept; + + VariableType& operator=(const VariableType& other); + VariableType& operator=(VariableType&& other) noexcept; + + bool Valid() const noexcept; + + const char* Name() const noexcept; + DataType Type() const noexcept; + uint32_t Rows() const noexcept; // Number of rows (for matrices, 1 for other numeric, 0 if not applicable) + uint32_t Columns() const noexcept; // Number of columns (for vectors & matrices, 1 for other numeric, 0 if not applicable) + uint32_t Elements() const noexcept; // Number of elements (0 if not an array) + uint32_t ElementStride() const noexcept; + + uint32_t NumMembers() const noexcept; + const VariableDesc* MemberByIndex(uint32_t index) const noexcept; + const VariableDesc* MemberByName(const char* name) const noexcept; + + private: + class VariableTypeImpl; + VariableTypeImpl* m_impl = nullptr; + }; + + struct ResourceDesc + { + char name[256]; // Name of the resource + ShaderResourceType type; // Type of resource (e.g. texture, cbuffer, etc.) + uint32_t space; + uint32_t bindPoint; // Starting bind point + uint32_t bindCount; // Number of contiguous bind points (for arrays) + }; + + struct VariableDesc + { + char name[256]; + VariableType type; + uint32_t offset; // Offset in cbuffer or stuct + uint32_t size; // Size of the variable + }; + + enum class ComponentMask : uint8_t + { + X = 0x1U, + Y = 0x2U, + Z = 0x4U, + W = 0x8U, + }; + + struct SignatureParameterDesc + { + char semantic[256]; + uint32_t semanticIndex; + uint32_t location; + VariableType::DataType componentType; + ComponentMask mask; + }; + + enum class PrimitiveTopology + { + Undefined, + Points, + Lines, + LineStrip, + Triangles, + TriangleStrip, + + LinesAdj, + LineStripAdj, + TrianglesAdj, + TriangleStripAdj, + + Patches_1_CtrlPoint, + Patches_2_CtrlPoint, + Patches_3_CtrlPoint, + Patches_4_CtrlPoint, + Patches_5_CtrlPoint, + Patches_6_CtrlPoint, + Patches_7_CtrlPoint, + Patches_8_CtrlPoint, + Patches_9_CtrlPoint, + Patches_10_CtrlPoint, + Patches_11_CtrlPoint, + Patches_12_CtrlPoint, + Patches_13_CtrlPoint, + Patches_14_CtrlPoint, + Patches_15_CtrlPoint, + Patches_16_CtrlPoint, + Patches_17_CtrlPoint, + Patches_18_CtrlPoint, + Patches_19_CtrlPoint, + Patches_20_CtrlPoint, + Patches_21_CtrlPoint, + Patches_22_CtrlPoint, + Patches_23_CtrlPoint, + Patches_24_CtrlPoint, + Patches_25_CtrlPoint, + Patches_26_CtrlPoint, + Patches_27_CtrlPoint, + Patches_28_CtrlPoint, + Patches_29_CtrlPoint, + Patches_30_CtrlPoint, + Patches_31_CtrlPoint, + Patches_32_CtrlPoint, + }; + + enum class TessellatorOutputPrimitive + { + Undefined, + Point, + Line, + TriangleCW, + TriangleCCW, + }; + + enum class TessellatorPartitioning + { + Undefined, + Integer, + Pow2, + FractionalOdd, + FractionalEven, + }; + + enum class TessellatorDomain + { + Undefined, + Line, + Triangle, + Quad, + }; + + public: + Reflection() noexcept; + Reflection(const Reflection& other); + Reflection(Reflection&& other) noexcept; + ~Reflection() noexcept; + + Reflection& operator=(const Reflection& other); + Reflection& operator=(Reflection&& other) noexcept; + + bool Valid() const noexcept; + + uint32_t NumResources() const noexcept; + const ResourceDesc* ResourceByIndex(uint32_t index) const noexcept; + const ResourceDesc* ResourceByName(const char* name) const noexcept; + + uint32_t NumConstantBuffers() const noexcept; + const ConstantBuffer* ConstantBufferByIndex(uint32_t index) const noexcept; + const ConstantBuffer* ConstantBufferByName(const char* name) const noexcept; + + uint32_t NumInputParameters() const noexcept; + const SignatureParameterDesc* InputParameter(uint32_t index) const noexcept; + uint32_t NumOutputParameters() const noexcept; + const SignatureParameterDesc* OutputParameter(uint32_t index) const noexcept; + + PrimitiveTopology GSHSInputPrimitive() const noexcept; + PrimitiveTopology GSOutputTopology() const noexcept; + uint32_t GSMaxNumOutputVertices() const noexcept; + uint32_t GSNumInstances() const noexcept; + + TessellatorOutputPrimitive HSOutputPrimitive() const noexcept; + TessellatorPartitioning HSPartitioning() const noexcept; + + TessellatorDomain HSDSTessellatorDomain() const noexcept; + uint32_t HSDSNumPatchConstantParameters() const noexcept; + const SignatureParameterDesc* HSDSPatchConstantParameter(uint32_t index) const noexcept; + uint32_t HSDSNumConrolPoints() const noexcept; + + uint32_t CSBlockSizeX() const noexcept; + uint32_t CSBlockSizeY() const noexcept; + uint32_t CSBlockSizeZ() const noexcept; + + private: + ReflectionImpl* m_impl = nullptr; + }; + class SC_API Compiler { public: @@ -182,6 +416,8 @@ namespace ShaderConductor int shiftAllSamplersBindings = 0; int shiftAllCBuffersBindings = 0; int shiftAllUABuffersBindings = 0; + + bool needReflection = false; }; struct TargetDesc @@ -191,22 +427,6 @@ namespace ShaderConductor bool asModule; }; - struct ReflectionDesc - { - char name[256]; // Name of the resource - ShaderResourceType type; // Type of resource (e.g. texture, cbuffer, etc.) - uint32_t bufferBindPoint; // Buffer's starting bind point - uint32_t bindPoint; // Starting bind point - uint32_t bindCount; // Number of contiguous bind points (for arrays) - }; - - struct ReflectionResultDesc - { - Blob descs; // The underneath type is ReflectionDesc - uint32_t descCount = 0; - uint32_t instructionCount = 0; - }; - struct ResultDesc { Blob target; @@ -215,7 +435,7 @@ namespace ShaderConductor Blob errorWarningMsg; bool hasError; - ReflectionResultDesc reflection; + Reflection reflection; }; struct DisassembleDesc @@ -250,6 +470,35 @@ namespace ShaderConductor static bool LinkSupport(); static ResultDesc Link(const LinkDesc& modules, const Options& options, const TargetDesc& target); }; + + inline Reflection::ComponentMask& operator|=(Reflection::ComponentMask& lhs, Reflection::ComponentMask rhs) + { + lhs = static_cast(static_cast(lhs) | static_cast(rhs)); + return lhs; + } + inline constexpr Reflection::ComponentMask operator|(Reflection::ComponentMask lhs, Reflection::ComponentMask rhs) + { + return static_cast(static_cast(lhs) | static_cast(rhs)); + } + + inline Reflection::ComponentMask& operator&=(Reflection::ComponentMask& lhs, Reflection::ComponentMask rhs) + { + lhs = static_cast(static_cast(lhs) & static_cast(rhs)); + return lhs; + } + inline constexpr Reflection::ComponentMask operator&(Reflection::ComponentMask lhs, Reflection::ComponentMask rhs) + { + return static_cast(static_cast(lhs) & static_cast(rhs)); + } + + inline bool HasAllFlags(Reflection::ComponentMask flags, Reflection::ComponentMask contains) + { + return (static_cast(flags) & static_cast(contains)) == static_cast(contains); + } + inline bool HasAnyFlags(Reflection::ComponentMask flags, Reflection::ComponentMask contains) + { + return (static_cast(flags) & static_cast(contains)) != 0; + } } // namespace ShaderConductor #endif // SHADER_CONDUCTOR_HPP diff --git a/Source/Core/ShaderConductor.cpp b/Source/Core/ShaderConductor.cpp index 3ccbde3f..30abd982 100644 --- a/Source/Core/ShaderConductor.cpp +++ b/Source/Core/ShaderConductor.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -43,10 +44,10 @@ #include #include #include +#include #include #include #include -#include #ifdef LLVM_ON_WIN32 #include @@ -325,103 +326,6 @@ namespace return result; } - - void ShaderReflection(Compiler::ReflectionResultDesc& result, IDxcBlob* dxilBlob) - { - CComPtr shaderReflection; - IFT(CreateDxcReflectionFromBlob(dxilBlob, shaderReflection)); - - D3D12_SHADER_DESC shaderDesc; - shaderReflection->GetDesc(&shaderDesc); - - std::vector vecReflectionDescs; - for (uint32_t resourceIndex = 0; resourceIndex < shaderDesc.BoundResources; ++resourceIndex) - { - D3D12_SHADER_INPUT_BIND_DESC bindDesc; - shaderReflection->GetResourceBindingDesc(resourceIndex, &bindDesc); - - Compiler::ReflectionDesc reflectionDesc{}; - - if (bindDesc.Type == D3D_SIT_CBUFFER || bindDesc.Type == D3D_SIT_TBUFFER) - { - ID3D12ShaderReflectionConstantBuffer* constantBuffer = shaderReflection->GetConstantBufferByName(bindDesc.Name); - - D3D12_SHADER_BUFFER_DESC bufferDesc; - constantBuffer->GetDesc(&bufferDesc); - - if (strcmp(bufferDesc.Name, "$Globals") == 0) - { - for (uint32_t variableIndex = 0; variableIndex < bufferDesc.Variables; ++variableIndex) - { - ID3D12ShaderReflectionVariable* variable = constantBuffer->GetVariableByIndex(variableIndex); - D3D12_SHADER_VARIABLE_DESC variableDesc; - variable->GetDesc(&variableDesc); - - std::strncpy(reflectionDesc.name, variableDesc.Name, - std::min(std::strlen(variableDesc.Name) + 1, sizeof(reflectionDesc.name))); - - reflectionDesc.type = ShaderResourceType::Parameter; - reflectionDesc.bufferBindPoint = bindDesc.BindPoint; - reflectionDesc.bindPoint = variableDesc.StartOffset; - reflectionDesc.bindCount = variableDesc.Size; - } - } - else - { - std::strncpy(reflectionDesc.name, bufferDesc.Name, - std::min(std::strlen(bufferDesc.Name) + 1, sizeof(reflectionDesc.name))); - - reflectionDesc.type = ShaderResourceType::ConstantBuffer; - reflectionDesc.bufferBindPoint = bindDesc.BindPoint; - reflectionDesc.bindPoint = 0; - reflectionDesc.bindCount = 0; - } - } - else - { - switch (bindDesc.Type) - { - case D3D_SIT_TEXTURE: - reflectionDesc.type = ShaderResourceType::Texture; - break; - - case D3D_SIT_SAMPLER: - reflectionDesc.type = ShaderResourceType::Sampler; - break; - - case D3D_SIT_STRUCTURED: - case D3D_SIT_BYTEADDRESS: - reflectionDesc.type = ShaderResourceType::ShaderResourceView; - break; - - case D3D_SIT_UAV_RWTYPED: - case D3D_SIT_UAV_RWSTRUCTURED: - case D3D_SIT_UAV_RWBYTEADDRESS: - case D3D_SIT_UAV_APPEND_STRUCTURED: - case D3D_SIT_UAV_CONSUME_STRUCTURED: - case D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER: - reflectionDesc.type = ShaderResourceType::UnorderedAccessView; - break; - - default: - llvm_unreachable("Unknown bind type."); - break; - } - - std::strncpy(reflectionDesc.name, bindDesc.Name, std::min(std::strlen(bindDesc.Name) + 1, sizeof(reflectionDesc.name))); - - reflectionDesc.bufferBindPoint = 0; - reflectionDesc.bindPoint = bindDesc.BindPoint; - reflectionDesc.bindCount = bindDesc.BindCount; - } - - vecReflectionDescs.push_back(reflectionDesc); - } - - result.descCount = static_cast(vecReflectionDescs.size()); - result.descs.Reset(vecReflectionDescs.data(), sizeof(Compiler::ReflectionDesc) * result.descCount); - result.instructionCount = shaderDesc.InstructionCount; - } #endif std::wstring ShaderProfileName(ShaderStage stage, Compiler::ShaderModel shaderModel) @@ -465,7 +369,13 @@ namespace return shaderProfile; } - void ConvertDxcResult(Compiler::ResultDesc& result, IDxcOperationResult* dxcResult, ShadingLanguage targetLanguage, bool asModule) +#ifdef LLVM_ON_WIN32 + Reflection MakeDxilReflection(IDxcBlob* dxilBlob); +#endif + Reflection MakeSpirVReflection(const spirv_cross::Compiler& compiler); + + void ConvertDxcResult(Compiler::ResultDesc& result, IDxcOperationResult* dxcResult, ShadingLanguage targetLanguage, bool asModule, + bool needReflection) { HRESULT status; IFT(dxcResult->GetStatus(&status)); @@ -493,16 +403,19 @@ namespace result.hasError = false; } -#ifdef LLVM_ON_WIN32 - if ((targetLanguage == ShadingLanguage::Dxil) && !asModule) + if (needReflection) { - // Gather reflection information only for ShadingLanguage::Dxil - ShaderReflection(result.reflection, program); - } +#ifdef LLVM_ON_WIN32 + if ((targetLanguage == ShadingLanguage::Dxil) && !asModule) + { + // Gather reflection information only for ShadingLanguage::Dxil. SPIR-V reflection is gathered when cross-compiling. + result.reflection = MakeDxilReflection(program); + } #else - SC_UNUSED(targetLanguage); - SC_UNUSED(asModule); + SC_UNUSED(targetLanguage); + SC_UNUSED(asModule); #endif + } } } @@ -675,7 +588,7 @@ namespace static_cast(dxcDefines.size()), includeHandler, &compileResult)); Compiler::ResultDesc ret{}; - ConvertDxcResult(ret, compileResult, targetLanguage, asModule); + ConvertDxcResult(ret, compileResult, targetLanguage, asModule, options.needReflection); return ret; } @@ -927,10 +840,10 @@ namespace const std::string targetStr = compiler->compile(); ret.target.Reset(targetStr.data(), static_cast(targetStr.size())); ret.hasError = false; - ret.reflection.descs.Reset(binaryResult.reflection.descs.Data(), - sizeof(Compiler::ReflectionDesc) * binaryResult.reflection.descCount); - ret.reflection.descCount = binaryResult.reflection.descCount; - ret.reflection.instructionCount = binaryResult.reflection.instructionCount; + if (options.needReflection) + { + ret.reflection = MakeSpirVReflection(*compiler); + } } catch (spirv_cross::CompilerError& error) { @@ -1038,6 +951,7 @@ namespace ShaderConductor { if (this != &other) { + delete m_impl; m_impl = std::move(other.m_impl); other.m_impl = nullptr; } @@ -1070,190 +984,2127 @@ namespace ShaderConductor } - Compiler::ResultDesc Compiler::Compile(const SourceDesc& source, const Options& options, const TargetDesc& target) - { - ResultDesc result; - Compiler::Compile(source, options, &target, 1, &result); - return result; - } - - void Compiler::Compile(const SourceDesc& source, const Options& options, const TargetDesc* targets, uint32_t numTargets, - ResultDesc* results) + class Reflection::VariableType::VariableTypeImpl { - SourceDesc sourceOverride = source; - if (!sourceOverride.entryPoint || (std::strlen(sourceOverride.entryPoint) == 0)) - { - sourceOverride.entryPoint = "main"; - } - if (!sourceOverride.loadIncludeCallback) + public: +#ifdef LLVM_ON_WIN32 + explicit VariableTypeImpl(ID3D12ShaderReflectionType* d3d12Type) { - sourceOverride.loadIncludeCallback = DefaultLoadCallback; - } + D3D12_SHADER_TYPE_DESC d3d12ShaderTypeDesc; + d3d12Type->GetDesc(&d3d12ShaderTypeDesc); - bool hasDxil = false; - bool hasDxilModule = false; - bool hasSpirV = false; - for (uint32_t i = 0; i < numTargets; ++i) - { - if (targets[i].language == ShadingLanguage::Dxil) + if (d3d12ShaderTypeDesc.Name) { - hasDxil = true; - if (targets[i].asModule) - { - hasDxilModule = true; - } + m_name = d3d12ShaderTypeDesc.Name; } - else + + switch (d3d12ShaderTypeDesc.Type) { - hasSpirV = true; - } - } + case D3D_SVT_BOOL: + m_type = DataType::Bool; + break; + case D3D_SVT_INT: + m_type = DataType::Int; + break; + case D3D_SVT_UINT: + m_type = DataType::Uint; + break; + case D3D_SVT_FLOAT: + m_type = DataType::Float; + break; + + case D3D_SVT_MIN16FLOAT: + m_type = DataType::Half; + break; + case D3D_SVT_MIN16INT: + m_type = DataType::Int16; + break; + case D3D_SVT_MIN16UINT: + m_type = DataType::Uint16; + break; + + case D3D_SVT_VOID: + if (d3d12ShaderTypeDesc.Class == D3D_SVC_STRUCT) + { + m_type = DataType::Struct; - ResultDesc dxilBinaryResult{}; - if (hasDxil) - { - dxilBinaryResult = CompileToBinary(sourceOverride, options, ShadingLanguage::Dxil, false); - } + for (uint32_t memberIndex = 0; memberIndex < d3d12ShaderTypeDesc.Members; ++memberIndex) + { + VariableDesc member{}; - ResultDesc dxilModuleBinaryResult{}; - if (hasDxilModule) - { - dxilModuleBinaryResult = CompileToBinary(sourceOverride, options, ShadingLanguage::Dxil, true); - } + const char* memberName = d3d12Type->GetMemberTypeName(memberIndex); + std::strncpy(member.name, memberName, sizeof(member.name)); - ResultDesc spirvBinaryResult{}; - if (hasSpirV) - { - spirvBinaryResult = CompileToBinary(sourceOverride, options, ShadingLanguage::SpirV, false); - } + ID3D12ShaderReflectionType* d3d12MemberType = d3d12Type->GetMemberTypeByIndex(memberIndex); + member.type = Make(d3d12MemberType); - for (uint32_t i = 0; i < numTargets; ++i) - { - ResultDesc binaryResult; - if (targets[i].language == ShadingLanguage::Dxil) - { - if (targets[i].asModule) - { - binaryResult = dxilModuleBinaryResult; + D3D12_SHADER_TYPE_DESC d3d12MemberTypeDesc; + d3d12MemberType->GetDesc(&d3d12MemberTypeDesc); + + member.offset = d3d12MemberTypeDesc.Offset; + if (d3d12MemberTypeDesc.Elements == 0) + { + member.size = 0; + } + else + { + member.size = (member.type.Elements() - 1) * member.type.ElementStride(); + } + member.size += member.type.Rows() * member.type.Columns() * 4; + + m_members.emplace_back(std::move(member)); + } } else { - binaryResult = dxilBinaryResult; + m_type = DataType::Void; } + break; + + default: + llvm_unreachable("Unsupported variable type."); + } + + m_rows = d3d12ShaderTypeDesc.Rows; + m_columns = d3d12ShaderTypeDesc.Columns; + m_elements = d3d12ShaderTypeDesc.Elements; + + if (m_elements > 0) + { + m_elementStride = m_rows * 16; } else { - binaryResult = spirvBinaryResult; + m_elementStride = 0; } - - results[i] = ConvertBinary(binaryResult, sourceOverride, options, targets[i]); } - } +#endif - Compiler::ResultDesc Compiler::Disassemble(const DisassembleDesc& source) - { - assert((source.language == ShadingLanguage::SpirV) || (source.language == ShadingLanguage::Dxil)); + VariableTypeImpl(const spirv_cross::Compiler& compiler, const spirv_cross::SPIRType& spirvParentReflectionType, + uint32_t variableIndex, const spirv_cross::SPIRType& spirvReflectionType) + { + switch (spirvReflectionType.basetype) + { + case spirv_cross::SPIRType::Boolean: + m_type = DataType::Bool; + m_name = "bool"; + break; + case spirv_cross::SPIRType::Int: + m_type = DataType::Int; + m_name = "int"; + break; + case spirv_cross::SPIRType::UInt: + m_type = DataType::Uint; + m_name = "uint"; + break; + case spirv_cross::SPIRType::Float: + m_type = DataType::Float; + m_name = "float"; + break; + + case spirv_cross::SPIRType::Half: + m_type = DataType::Half; + m_name = "half"; + break; + case spirv_cross::SPIRType::Short: + m_type = DataType::Int16; + m_name = "int16_t"; + break; + case spirv_cross::SPIRType::UShort: + m_type = DataType::Uint16; + m_name = "uint16_t"; + break; + + case spirv_cross::SPIRType::Struct: + m_type = DataType::Struct; + m_name = compiler.get_name(spirvReflectionType.self); + + for (uint32_t memberIndex = 0; memberIndex < spirvReflectionType.member_types.size(); ++memberIndex) + { + VariableDesc member{}; - Compiler::ResultDesc ret; + const std::string& memberName = compiler.get_member_name(spirvReflectionType.self, memberIndex); + std::strncpy(member.name, memberName.c_str(), sizeof(member.name)); - ret.isText = true; + member.type = Make(compiler, spirvReflectionType, memberIndex, compiler.get_type(spirvReflectionType.member_types[memberIndex])); - if (source.language == ShadingLanguage::SpirV) - { - const uint32_t* spirvIr = reinterpret_cast(source.binary); - const size_t spirvSize = source.binarySize / sizeof(uint32_t); + member.offset = compiler.type_struct_member_offset(spirvReflectionType, memberIndex); + member.size = static_cast(compiler.get_declared_struct_member_size(spirvReflectionType, memberIndex)); - spv_context context = spvContextCreate(SPV_ENV_UNIVERSAL_1_3); - uint32_t options = SPV_BINARY_TO_TEXT_OPTION_NONE | SPV_BINARY_TO_TEXT_OPTION_INDENT | SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES; - spv_text text = nullptr; - spv_diagnostic diagnostic = nullptr; + m_members.emplace_back(std::move(member)); + } + break; - spv_result_t error = spvBinaryToText(context, spirvIr, spirvSize, options, &text, &diagnostic); - spvContextDestroy(context); + case spirv_cross::SPIRType::Void: + m_type = DataType::Void; + m_name = "void"; + break; - if (error) + default: + llvm_unreachable("Unsupported variable type."); + break; + } + + if (spirvReflectionType.columns == 1) { - ret.errorWarningMsg.Reset(diagnostic->error, static_cast(std::strlen(diagnostic->error))); - ret.hasError = true; - spvDiagnosticDestroy(diagnostic); + if (spirvReflectionType.vecsize > 1) + { + m_name += std::to_string(spirvReflectionType.vecsize); + } } else { - const std::string disassemble = text->str; - ret.target.Reset(disassemble.data(), static_cast(disassemble.size())); - ret.hasError = false; + m_name += std::to_string(spirvReflectionType.columns) + 'x' + std::to_string(spirvReflectionType.vecsize); } - spvTextDestroy(text); - } - else - { - CComPtr blob; - CComPtr disassembly; - IFT(Dxcompiler::Instance().Library()->CreateBlobWithEncodingOnHeapCopy(source.binary, source.binarySize, CP_UTF8, &blob)); - IFT(Dxcompiler::Instance().Compiler()->Disassemble(blob, &disassembly)); + m_rows = spirvReflectionType.columns; + m_columns = spirvReflectionType.vecsize; + if (compiler.has_member_decoration(spirvParentReflectionType.self, variableIndex, spv::DecorationColMajor)) + { + std::swap(m_rows, m_columns); + } + if (spirvReflectionType.array.empty()) + { + m_elements = 0; + } + else + { + m_elements = spirvReflectionType.array[0]; + } - if (disassembly != nullptr) + if (!spirvReflectionType.array.empty()) { - // Remove the tailing \0 - ret.target.Reset(disassembly->GetBufferPointer(), static_cast(disassembly->GetBufferSize() - 1)); - ret.hasError = false; + m_elementStride = compiler.type_struct_member_array_stride(spirvParentReflectionType, variableIndex); } else { - ret.hasError = true; + m_elementStride = 0; } } - return ret; - } + const char* Name() const noexcept + { + return m_name.c_str(); + } - bool Compiler::LinkSupport() - { - return Dxcompiler::Instance().LinkerSupport(); - } + DataType Type() const noexcept + { + return m_type; + } - Compiler::ResultDesc Compiler::Link(const LinkDesc& modules, const Compiler::Options& options, const TargetDesc& target) - { - auto linker = Dxcompiler::Instance().CreateLinker(); - IFTPTR(linker); + uint32_t Rows() const noexcept + { + return m_rows; + } - auto* library = Dxcompiler::Instance().Library(); + uint32_t Columns() const noexcept + { + return m_columns; + } - std::vector moduleNames(modules.numModules); - std::vector moduleNamesUtf16(modules.numModules); - std::vector> moduleBlobs(modules.numModules); - for (uint32_t i = 0; i < modules.numModules; ++i) + uint32_t Elements() const noexcept { - IFTARG(modules.modules[i] != nullptr); + return m_elements; + } - IFT(library->CreateBlobWithEncodingOnHeapCopy(modules.modules[i]->target.Data(), modules.modules[i]->target.Size(), CP_UTF8, - &moduleBlobs[i])); - IFTARG(moduleBlobs[i]->GetBufferSize() >= 4); + uint32_t ElementStride() const noexcept + { + return m_elementStride; + } - Unicode::UTF8ToUTF16String(modules.modules[i]->name, &moduleNames[i]); - moduleNamesUtf16[i] = moduleNames[i].c_str(); - IFT(linker->RegisterLibrary(moduleNamesUtf16[i], moduleBlobs[i])); + uint32_t NumMembers() const noexcept + { + return static_cast(m_members.size()); } - std::wstring entryPointUtf16; - Unicode::UTF8ToUTF16String(modules.entryPoint, &entryPointUtf16); + const VariableDesc* MemberByIndex(uint32_t index) const noexcept + { + if (index < m_members.size()) + { + return &m_members[index]; + } - const std::wstring shaderProfile = ShaderProfileName(modules.stage, options.shaderModel); - CComPtr linkResult; - IFT(linker->Link(entryPointUtf16.c_str(), shaderProfile.c_str(), moduleNamesUtf16.data(), - static_cast(moduleNamesUtf16.size()), nullptr, 0, &linkResult)); + return nullptr; + } - Compiler::ResultDesc binaryResult{}; - ConvertDxcResult(binaryResult, linkResult, ShadingLanguage::Dxil, false); + const VariableDesc* MemberByName(const char* name) const noexcept + { + for (const auto& member : m_members) + { + if (std::strcmp(member.name, name) == 0) + { + return &member; + } + } - Compiler::SourceDesc source{}; - source.entryPoint = modules.entryPoint; - source.stage = modules.stage; - return ConvertBinary(binaryResult, source, options, target); + return nullptr; + } + +#ifdef LLVM_ON_WIN32 + static VariableType Make(ID3D12ShaderReflectionType* d3d12ReflectionType) + { + VariableType ret; + ret.m_impl = new VariableTypeImpl(d3d12ReflectionType); + return ret; + } +#endif + + static VariableType Make(const spirv_cross::Compiler& compiler, const spirv_cross::SPIRType& spirvParentReflectionType, uint32_t variableIndex, + const spirv_cross::SPIRType& spirvReflectionType) + { + VariableType ret; + ret.m_impl = new VariableTypeImpl(compiler, spirvParentReflectionType, variableIndex, spirvReflectionType); + return ret; + } + + private: + std::string m_name; + DataType m_type; + uint32_t m_rows; + uint32_t m_columns; + uint32_t m_elements; + uint32_t m_elementStride; + + std::vector m_members; + }; + + Reflection::VariableType::VariableType() noexcept = default; + + Reflection::VariableType::VariableType(const VariableType& other) : m_impl(other.m_impl ? new VariableTypeImpl(*other.m_impl) : nullptr) + { + } + + Reflection::VariableType::VariableType(VariableType&& other) noexcept : m_impl(std::move(other.m_impl)) + { + other.m_impl = nullptr; + } + + Reflection::VariableType::~VariableType() noexcept + { + delete m_impl; + } + + Reflection::VariableType& Reflection::VariableType::operator=(const VariableType& other) + { + if (this != &other) + { + delete m_impl; + m_impl = nullptr; + + if (other.m_impl) + { + m_impl = new VariableTypeImpl(*other.m_impl); + } + } + return *this; + } + + Reflection::VariableType& Reflection::VariableType::operator=(VariableType&& other) noexcept + { + if (this != &other) + { + delete m_impl; + m_impl = std::move(other.m_impl); + other.m_impl = nullptr; + } + return *this; + } + + bool Reflection::VariableType::Valid() const noexcept + { + return m_impl != nullptr; + } + + const char* Reflection::VariableType::Name() const noexcept + { + return m_impl->Name(); + } + + Reflection::VariableType::DataType Reflection::VariableType::Type() const noexcept + { + return m_impl->Type(); + } + + uint32_t Reflection::VariableType::Rows() const noexcept + { + return m_impl->Rows(); + } + + uint32_t Reflection::VariableType::Columns() const noexcept + { + return m_impl->Columns(); + } + + uint32_t Reflection::VariableType::Elements() const noexcept + { + return m_impl->Elements(); + } + + uint32_t Reflection::VariableType::ElementStride() const noexcept + { + return m_impl->ElementStride(); + } + + uint32_t Reflection::VariableType::NumMembers() const noexcept + { + return m_impl->NumMembers(); + } + + const Reflection::VariableDesc* Reflection::VariableType::MemberByIndex(uint32_t index) const noexcept + { + return m_impl->MemberByIndex(index); + } + + const Reflection::VariableDesc* Reflection::VariableType::MemberByName(const char* name) const noexcept + { + return m_impl->MemberByName(name); + } + + + class Reflection::ConstantBuffer::ConstantBufferImpl + { + public: +#ifdef LLVM_ON_WIN32 + explicit ConstantBufferImpl(ID3D12ShaderReflectionConstantBuffer* constantBuffer) + { + D3D12_SHADER_BUFFER_DESC bufferDesc; + constantBuffer->GetDesc(&bufferDesc); + + m_name = bufferDesc.Name; + + for (uint32_t variableIndex = 0; variableIndex < bufferDesc.Variables; ++variableIndex) + { + ID3D12ShaderReflectionVariable* variable = constantBuffer->GetVariableByIndex(variableIndex); + D3D12_SHADER_VARIABLE_DESC d3d12VariableDesc; + variable->GetDesc(&d3d12VariableDesc); + + VariableDesc variableDesc{}; + + std::strncpy(variableDesc.name, d3d12VariableDesc.Name, sizeof(variableDesc.name)); + + variableDesc.type = VariableType::VariableTypeImpl::Make(variable->GetType()); + + variableDesc.offset = d3d12VariableDesc.StartOffset; + variableDesc.size = d3d12VariableDesc.Size; + + m_variableDescs.emplace_back(std::move(variableDesc)); + } + + m_size = bufferDesc.Size; + } +#endif + + explicit ConstantBufferImpl(const spirv_cross::Compiler& compiler, const spirv_cross::Resource& resource) + { + const auto& cbufferType = compiler.get_type(resource.type_id); + + m_name = compiler.get_name(resource.id); + + for (uint32_t variableIndex = 0; variableIndex < cbufferType.member_types.size(); ++variableIndex) + { + VariableDesc variableDesc{}; + + const std::string& varName = compiler.get_member_name(cbufferType.self, variableIndex); + std::strncpy(variableDesc.name, varName.c_str(), sizeof(variableDesc.name)); + + variableDesc.type = VariableType::VariableTypeImpl::Make(compiler, cbufferType, variableIndex, + compiler.get_type(cbufferType.member_types[variableIndex])); + + variableDesc.offset = compiler.type_struct_member_offset(cbufferType, variableIndex); + variableDesc.size = static_cast(compiler.get_declared_struct_member_size(cbufferType, variableIndex)); + + m_variableDescs.emplace_back(std::move(variableDesc)); + } + + m_size = static_cast(compiler.get_declared_struct_size(cbufferType)); + } + + const char* Name() const noexcept + { + return m_name.c_str(); + } + + uint32_t Size() const noexcept + { + return m_size; + } + + uint32_t NumVariables() const noexcept + { + return static_cast(m_variableDescs.size()); + } + + const VariableDesc* VariableByIndex(uint32_t index) const noexcept + { + if (index < m_variableDescs.size()) + { + return &m_variableDescs[index]; + } + + return nullptr; + } + + const VariableDesc* VariableByName(const char* name) const noexcept + { + for (const auto& variableDesc : m_variableDescs) + { + if (std::strcmp(variableDesc.name, name) == 0) + { + return &variableDesc; + } + } + + return nullptr; + } + +#ifdef LLVM_ON_WIN32 + static ConstantBuffer Make(ID3D12ShaderReflectionConstantBuffer* constantBuffer) + { + ConstantBuffer ret; + ret.m_impl = new ConstantBufferImpl(constantBuffer); + return ret; + } +#endif + + static ConstantBuffer Make(const spirv_cross::Compiler& compiler, const spirv_cross::Resource& resource) + { + ConstantBuffer ret; + ret.m_impl = new ConstantBufferImpl(compiler, resource); + return ret; + } + + private: + std::string m_name; + uint32_t m_size; + std::vector m_variableDescs; + }; + + Reflection::ConstantBuffer::ConstantBuffer() noexcept = default; + + Reflection::ConstantBuffer::ConstantBuffer(const ConstantBuffer& other) + : m_impl(other.m_impl ? new ConstantBufferImpl(*other.m_impl) : nullptr) + { + } + + Reflection::ConstantBuffer::ConstantBuffer(ConstantBuffer&& other) noexcept : m_impl(std::move(other.m_impl)) + { + other.m_impl = nullptr; + } + + Reflection::ConstantBuffer::~ConstantBuffer() noexcept + { + delete m_impl; + } + + Reflection::ConstantBuffer& Reflection::ConstantBuffer::operator=(const ConstantBuffer& other) + { + if (this != &other) + { + delete m_impl; + m_impl = nullptr; + + if (other.m_impl) + { + m_impl = new ConstantBufferImpl(*other.m_impl); + } + } + return *this; + } + + Reflection::ConstantBuffer& Reflection::ConstantBuffer::operator=(ConstantBuffer&& other) noexcept + { + if (this != &other) + { + delete m_impl; + m_impl = std::move(other.m_impl); + other.m_impl = nullptr; + } + return *this; + } + + bool Reflection::ConstantBuffer::Valid() const noexcept + { + return m_impl != nullptr; + } + + const char* Reflection::ConstantBuffer::Name() const noexcept + { + return m_impl->Name(); + } + + uint32_t Reflection::ConstantBuffer::Size() const noexcept + { + return m_impl->Size(); + } + + uint32_t Reflection::ConstantBuffer::NumVariables() const noexcept + { + return m_impl->NumVariables(); + } + + const Reflection::VariableDesc* Reflection::ConstantBuffer::VariableByIndex(uint32_t index) const noexcept + { + return m_impl->VariableByIndex(index); + } + + const Reflection::VariableDesc* Reflection::ConstantBuffer::VariableByName(const char* name) const noexcept + { + return m_impl->VariableByName(name); + } + + + class Reflection::ReflectionImpl + { + public: +#ifdef LLVM_ON_WIN32 + explicit ReflectionImpl(IDxcBlob* dxilBlob) + { + CComPtr shaderReflection; + IFT(CreateDxcReflectionFromBlob(dxilBlob, shaderReflection)); + + D3D12_SHADER_DESC shaderDesc; + shaderReflection->GetDesc(&shaderDesc); + + for (uint32_t resourceIndex = 0; resourceIndex < shaderDesc.BoundResources; ++resourceIndex) + { + D3D12_SHADER_INPUT_BIND_DESC bindDesc; + shaderReflection->GetResourceBindingDesc(resourceIndex, &bindDesc); + + ResourceDesc reflectionDesc{}; + + std::strncpy(reflectionDesc.name, bindDesc.Name, sizeof(reflectionDesc.name)); + reflectionDesc.space = bindDesc.Space; + reflectionDesc.bindPoint = bindDesc.BindPoint; + reflectionDesc.bindCount = bindDesc.BindCount; + + if (bindDesc.Type == D3D_SIT_CBUFFER || bindDesc.Type == D3D_SIT_TBUFFER) + { + reflectionDesc.type = ShaderResourceType::ConstantBuffer; + + ID3D12ShaderReflectionConstantBuffer* constantBuffer = shaderReflection->GetConstantBufferByName(bindDesc.Name); + m_constantBuffers.emplace_back(ConstantBuffer::ConstantBufferImpl::Make(constantBuffer)); + } + else + { + switch (bindDesc.Type) + { + case D3D_SIT_TEXTURE: + reflectionDesc.type = ShaderResourceType::Texture; + break; + + case D3D_SIT_SAMPLER: + reflectionDesc.type = ShaderResourceType::Sampler; + break; + + case D3D_SIT_STRUCTURED: + case D3D_SIT_BYTEADDRESS: + reflectionDesc.type = ShaderResourceType::ShaderResourceView; + break; + + case D3D_SIT_UAV_RWTYPED: + case D3D_SIT_UAV_RWSTRUCTURED: + case D3D_SIT_UAV_RWBYTEADDRESS: + case D3D_SIT_UAV_APPEND_STRUCTURED: + case D3D_SIT_UAV_CONSUME_STRUCTURED: + case D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER: + reflectionDesc.type = ShaderResourceType::UnorderedAccessView; + break; + + default: + llvm_unreachable("Unknown bind type."); + break; + } + } + + m_resourceDescs.emplace_back(std::move(reflectionDesc)); + } + + for (uint32_t inputParamIndex = 0; inputParamIndex < shaderDesc.InputParameters; ++inputParamIndex) + { + SignatureParameterDesc paramDesc{}; + + D3D12_SIGNATURE_PARAMETER_DESC signatureParamDesc; + shaderReflection->GetInputParameterDesc(inputParamIndex, &signatureParamDesc); + + std::strncpy(paramDesc.semantic, signatureParamDesc.SemanticName, sizeof(paramDesc.semantic)); + paramDesc.semanticIndex = signatureParamDesc.SemanticIndex; + paramDesc.location = signatureParamDesc.Register; + switch (signatureParamDesc.ComponentType) + { + case D3D_REGISTER_COMPONENT_UINT32: + paramDesc.componentType = VariableType::DataType::Uint; + break; + case D3D_REGISTER_COMPONENT_SINT32: + paramDesc.componentType = VariableType::DataType::Int; + break; + case D3D_REGISTER_COMPONENT_FLOAT32: + paramDesc.componentType = VariableType::DataType::Float; + break; + + default: + llvm_unreachable("Unsupported input component type."); + break; + } + paramDesc.mask = static_cast(signatureParamDesc.Mask); + + m_inputParams.emplace_back(std::move(paramDesc)); + } + + for (uint32_t outputParamIndex = 0; outputParamIndex < shaderDesc.OutputParameters; ++outputParamIndex) + { + SignatureParameterDesc paramDesc{}; + + D3D12_SIGNATURE_PARAMETER_DESC signatureParamDesc; + shaderReflection->GetOutputParameterDesc(outputParamIndex, &signatureParamDesc); + + std::strncpy(paramDesc.semantic, signatureParamDesc.SemanticName, sizeof(paramDesc.semantic)); + paramDesc.semanticIndex = signatureParamDesc.SemanticIndex; + paramDesc.location = signatureParamDesc.Register; + switch (signatureParamDesc.ComponentType) + { + case D3D_REGISTER_COMPONENT_UINT32: + paramDesc.componentType = VariableType::DataType::Uint; + break; + case D3D_REGISTER_COMPONENT_SINT32: + paramDesc.componentType = VariableType::DataType::Int; + break; + case D3D_REGISTER_COMPONENT_FLOAT32: + paramDesc.componentType = VariableType::DataType::Float; + break; + + default: + llvm_unreachable("Unsupported output component type."); + break; + } + paramDesc.mask = static_cast(signatureParamDesc.Mask); + + m_outputParams.emplace_back(std::move(paramDesc)); + } + + switch (shaderDesc.InputPrimitive) + { + case D3D_PRIMITIVE_UNDEFINED: + m_gsHSInputPrimitive = PrimitiveTopology::Undefined; + break; + case D3D_PRIMITIVE_POINT: + m_gsHSInputPrimitive = PrimitiveTopology::Points; + break; + case D3D_PRIMITIVE_LINE: + m_gsHSInputPrimitive = PrimitiveTopology::Lines; + break; + case D3D_PRIMITIVE_TRIANGLE: + m_gsHSInputPrimitive = PrimitiveTopology::Triangles; + break; + case D3D_PRIMITIVE_LINE_ADJ: + m_gsHSInputPrimitive = PrimitiveTopology::LinesAdj; + break; + case D3D_PRIMITIVE_TRIANGLE_ADJ: + m_gsHSInputPrimitive = PrimitiveTopology::TrianglesAdj; + break; + case D3D_PRIMITIVE_1_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_1_CtrlPoint; + break; + case D3D_PRIMITIVE_2_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_2_CtrlPoint; + break; + case D3D_PRIMITIVE_3_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_3_CtrlPoint; + break; + case D3D_PRIMITIVE_4_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_4_CtrlPoint; + break; + case D3D_PRIMITIVE_5_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_5_CtrlPoint; + break; + case D3D_PRIMITIVE_6_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_6_CtrlPoint; + break; + case D3D_PRIMITIVE_7_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_7_CtrlPoint; + break; + case D3D_PRIMITIVE_8_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_8_CtrlPoint; + break; + case D3D_PRIMITIVE_9_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_9_CtrlPoint; + break; + case D3D_PRIMITIVE_10_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_10_CtrlPoint; + break; + case D3D_PRIMITIVE_11_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_11_CtrlPoint; + break; + case D3D_PRIMITIVE_12_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_12_CtrlPoint; + break; + case D3D_PRIMITIVE_13_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_13_CtrlPoint; + break; + case D3D_PRIMITIVE_14_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_14_CtrlPoint; + break; + case D3D_PRIMITIVE_15_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_15_CtrlPoint; + break; + case D3D_PRIMITIVE_16_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_16_CtrlPoint; + break; + case D3D_PRIMITIVE_17_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_17_CtrlPoint; + break; + case D3D_PRIMITIVE_18_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_18_CtrlPoint; + break; + case D3D_PRIMITIVE_19_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_19_CtrlPoint; + break; + case D3D_PRIMITIVE_20_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_20_CtrlPoint; + break; + case D3D_PRIMITIVE_21_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_21_CtrlPoint; + break; + case D3D_PRIMITIVE_22_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_22_CtrlPoint; + break; + case D3D_PRIMITIVE_23_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_23_CtrlPoint; + break; + case D3D_PRIMITIVE_24_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_24_CtrlPoint; + break; + case D3D_PRIMITIVE_25_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_25_CtrlPoint; + break; + case D3D_PRIMITIVE_26_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_26_CtrlPoint; + break; + case D3D_PRIMITIVE_27_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_27_CtrlPoint; + break; + case D3D_PRIMITIVE_28_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_28_CtrlPoint; + break; + case D3D_PRIMITIVE_29_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_29_CtrlPoint; + break; + case D3D_PRIMITIVE_30_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_30_CtrlPoint; + break; + case D3D_PRIMITIVE_31_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_31_CtrlPoint; + break; + case D3D_PRIMITIVE_32_CONTROL_POINT_PATCH: + m_gsHSInputPrimitive = PrimitiveTopology::Patches_32_CtrlPoint; + break; + + default: + llvm_unreachable("Unsupported input primitive type."); + break; + } + + switch (shaderDesc.GSOutputTopology) + { + case D3D_PRIMITIVE_TOPOLOGY_UNDEFINED: + m_gsOutputTopology = PrimitiveTopology::Undefined; + break; + case D3D_PRIMITIVE_TOPOLOGY_POINTLIST: + m_gsOutputTopology = PrimitiveTopology::Points; + break; + case D3D_PRIMITIVE_TOPOLOGY_LINELIST: + m_gsOutputTopology = PrimitiveTopology::Lines; + break; + case D3D_PRIMITIVE_TOPOLOGY_LINESTRIP: + m_gsOutputTopology = PrimitiveTopology::LineStrip; + break; + case D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST: + m_gsOutputTopology = PrimitiveTopology::Triangles; + break; + case D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP: + m_gsOutputTopology = PrimitiveTopology::TriangleStrip; + break; + case D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ: + m_gsOutputTopology = PrimitiveTopology::LinesAdj; + break; + case D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ: + m_gsOutputTopology = PrimitiveTopology::LineStripAdj; + break; + case D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ: + m_gsOutputTopology = PrimitiveTopology::TrianglesAdj; + break; + case D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ: + m_gsOutputTopology = PrimitiveTopology::TriangleStripAdj; + break; + case D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_1_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_2_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_3_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_4_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_5_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_6_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_7_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_8_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_9_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_10_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_11_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_12_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_13_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_14_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_15_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_16_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_17_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_18_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_19_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_20_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_21_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_22_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_23_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_24_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_25_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_26_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_27_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_28_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_29_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_30_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_31_CtrlPoint; + break; + case D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST: + m_gsOutputTopology = PrimitiveTopology::Patches_32_CtrlPoint; + break; + + default: + llvm_unreachable("Unsupported output topoloty type."); + break; + } + + m_gsMaxNumOutputVertices = shaderDesc.GSMaxOutputVertexCount; + m_gsNumInstances = shaderDesc.cGSInstanceCount; + + switch (shaderDesc.HSOutputPrimitive) + { + case D3D_TESSELLATOR_OUTPUT_UNDEFINED: + m_hsOutputPrimitive = TessellatorOutputPrimitive::Undefined; + break; + case D3D_TESSELLATOR_OUTPUT_POINT: + m_hsOutputPrimitive = TessellatorOutputPrimitive::Point; + break; + case D3D_TESSELLATOR_OUTPUT_LINE: + m_hsOutputPrimitive = TessellatorOutputPrimitive::Line; + break; + case D3D_TESSELLATOR_OUTPUT_TRIANGLE_CW: + m_hsOutputPrimitive = TessellatorOutputPrimitive::TriangleCW; + break; + case D3D_TESSELLATOR_OUTPUT_TRIANGLE_CCW: + m_hsOutputPrimitive = TessellatorOutputPrimitive::TriangleCCW; + break; + + default: + llvm_unreachable("Unsupported output primitive type."); + break; + } + + switch (shaderDesc.HSPartitioning) + { + case D3D_TESSELLATOR_PARTITIONING_UNDEFINED: + m_hsPartitioning = TessellatorPartitioning::Undefined; + break; + case D3D_TESSELLATOR_PARTITIONING_INTEGER: + m_hsPartitioning = TessellatorPartitioning::Integer; + break; + case D3D_TESSELLATOR_PARTITIONING_POW2: + m_hsPartitioning = TessellatorPartitioning::Pow2; + break; + case D3D_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD: + m_hsPartitioning = TessellatorPartitioning::FractionalOdd; + break; + case D3D_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN: + m_hsPartitioning = TessellatorPartitioning::FractionalEven; + break; + + default: + llvm_unreachable("Unsupported partitioning type."); + break; + } + + switch (shaderDesc.TessellatorDomain) + { + case D3D_TESSELLATOR_DOMAIN_UNDEFINED: + m_hSDSTessellatorDomain = TessellatorDomain::Undefined; + break; + case D3D_TESSELLATOR_DOMAIN_ISOLINE: + m_hSDSTessellatorDomain = TessellatorDomain::Line; + break; + case D3D_TESSELLATOR_DOMAIN_TRI: + m_hSDSTessellatorDomain = TessellatorDomain::Triangle; + break; + case D3D_TESSELLATOR_DOMAIN_QUAD: + m_hSDSTessellatorDomain = TessellatorDomain::Quad; + break; + + default: + llvm_unreachable("Unsupported tessellator domain type."); + break; + } + + for (uint32_t patchConstantParamIndex = 0; patchConstantParamIndex < shaderDesc.PatchConstantParameters; + ++patchConstantParamIndex) + { + SignatureParameterDesc paramDesc{}; + + D3D12_SIGNATURE_PARAMETER_DESC signatureParamDesc; + shaderReflection->GetPatchConstantParameterDesc(patchConstantParamIndex, &signatureParamDesc); + + std::strncpy(paramDesc.semantic, signatureParamDesc.SemanticName, sizeof(paramDesc.semantic)); + paramDesc.semanticIndex = signatureParamDesc.SemanticIndex; + paramDesc.location = signatureParamDesc.Register; + switch (signatureParamDesc.ComponentType) + { + case D3D_REGISTER_COMPONENT_UINT32: + paramDesc.componentType = VariableType::DataType::Uint; + break; + case D3D_REGISTER_COMPONENT_SINT32: + paramDesc.componentType = VariableType::DataType::Int; + break; + case D3D_REGISTER_COMPONENT_FLOAT32: + paramDesc.componentType = VariableType::DataType::Float; + break; + + default: + llvm_unreachable("Unsupported patch constant component type."); + break; + } + paramDesc.mask = static_cast(signatureParamDesc.Mask); + + m_hsDSPatchConstantParams.emplace_back(std::move(paramDesc)); + } + + m_hsDSNumCtrlPoints = shaderDesc.cControlPoints; + + shaderReflection->GetThreadGroupSize(&m_csBlockSizeX, &m_csBlockSizeY, &m_csBlockSizeZ); + } +#endif + + explicit ReflectionImpl(const spirv_cross::Compiler& compiler) + { + spirv_cross::ShaderResources resources = compiler.get_shader_resources(); + + for (const auto& resource : resources.uniform_buffers) + { + ResourceDesc reflectionDesc{}; + this->ExtractReflection(reflectionDesc, compiler, resource.id); + reflectionDesc.type = ShaderResourceType::ConstantBuffer; + + m_resourceDescs.emplace_back(std::move(reflectionDesc)); + + m_constantBuffers.emplace_back(ConstantBuffer::ConstantBufferImpl::Make(compiler, resource)); + } + + for (const auto& resource : resources.storage_buffers) + { + ResourceDesc reflectionDesc{}; + this->ExtractReflection(reflectionDesc, compiler, resource.id); + + const spirv_cross::Bitset& typeFlags = compiler.get_decoration_bitset(compiler.get_type(resource.type_id).self); + const auto& type = compiler.get_type(resource.type_id); + + const bool ssboBlock = type.storage == spv::StorageClassStorageBuffer || + (type.storage == spv::StorageClassUniform && typeFlags.get(spv::DecorationBufferBlock)); + if (ssboBlock) + { + spirv_cross::Bitset buffer_flags = compiler.get_buffer_block_flags(resource.id); + if (buffer_flags.get(spv::DecorationNonWritable)) + { + reflectionDesc.type = ShaderResourceType::ShaderResourceView; + } + else + { + reflectionDesc.type = ShaderResourceType::UnorderedAccessView; + } + } + else + { + reflectionDesc.type = ShaderResourceType::ShaderResourceView; + } + + m_resourceDescs.emplace_back(std::move(reflectionDesc)); + } + + for (const auto& resource : resources.storage_images) + { + ResourceDesc reflectionDesc{}; + this->ExtractReflection(reflectionDesc, compiler, resource.id); + reflectionDesc.type = ShaderResourceType::UnorderedAccessView; + + m_resourceDescs.emplace_back(std::move(reflectionDesc)); + } + + for (const auto& resource : resources.separate_images) + { + ResourceDesc reflectionDesc{}; + this->ExtractReflection(reflectionDesc, compiler, resource.id); + reflectionDesc.type = ShaderResourceType::Texture; + + m_resourceDescs.emplace_back(std::move(reflectionDesc)); + } + + for (const auto& resource : resources.separate_samplers) + { + ResourceDesc reflectionDesc{}; + this->ExtractReflection(reflectionDesc, compiler, resource.id); + reflectionDesc.type = ShaderResourceType::Sampler; + + m_resourceDescs.emplace_back(std::move(reflectionDesc)); + } + + uint32_t combinedBinding = 0; + for (const auto& resource : resources.sampled_images) + { + ResourceDesc reflectionDesc{}; + this->ExtractReflection(reflectionDesc, compiler, resource.id); + reflectionDesc.bindPoint = combinedBinding; + reflectionDesc.type = ShaderResourceType::Texture; + + m_resourceDescs.emplace_back(std::move(reflectionDesc)); + ++combinedBinding; + } + + for (const auto& inputParam : resources.builtin_inputs) + { + const std::string semantic = this->ExtractBuiltInemantic(inputParam.builtin); + if (!semantic.empty()) + { + SignatureParameterDesc paramDesc{}; + this->ExtractParameter(paramDesc, compiler, inputParam.resource, semantic); + + const auto& type = compiler.get_type(inputParam.resource.type_id); + switch (inputParam.builtin) + { + case spv::BuiltInTessLevelInner: + case spv::BuiltInTessLevelOuter: + for (uint32_t patchConstantParamIndex = 0; patchConstantParamIndex < type.array[0]; ++patchConstantParamIndex) + { + if (inputParam.builtin == spv::BuiltInTessLevelOuter) + { + paramDesc.semanticIndex = patchConstantParamIndex; + paramDesc.mask = ComponentMask::W; + } + else + { + paramDesc.semanticIndex = 0; + paramDesc.mask = ComponentMask::X; + } + + m_hsDSPatchConstantParams.emplace_back(std::move(paramDesc)); + } + break; + + default: + m_inputParams.emplace_back(std::move(paramDesc)); + break; + } + } + } + + for (const auto& inputParam : resources.stage_inputs) + { + SignatureParameterDesc paramDesc{}; + this->ExtractParameter(paramDesc, compiler, inputParam); + + if (compiler.get_decoration(inputParam.id, spv::DecorationPatch)) + { + m_hsDSPatchConstantParams.emplace_back(std::move(paramDesc)); + } + else + { + m_inputParams.emplace_back(std::move(paramDesc)); + } + } + + for (const auto& outputParam : resources.builtin_outputs) + { + const std::string semantic = this->ExtractBuiltInemantic(outputParam.builtin); + if (!semantic.empty()) + { + SignatureParameterDesc paramDesc{}; + const auto& type = compiler.get_type(outputParam.resource.type_id); + this->ExtractParameter(paramDesc, compiler, outputParam.resource, semantic); + + switch (type.basetype) + { + case spirv_cross::SPIRType::UInt: + paramDesc.componentType = VariableType::DataType::Uint; + break; + case spirv_cross::SPIRType::Int: + paramDesc.componentType = VariableType::DataType::Int; + break; + case spirv_cross::SPIRType::Float: + paramDesc.componentType = VariableType::DataType::Float; + break; + + default: + llvm_unreachable("Unsupported parameter component type."); + break; + } + + if (type.vecsize > 0) + { + paramDesc.mask = ComponentMask::X; + } + if (type.vecsize > 1) + { + paramDesc.mask |= ComponentMask::Y; + } + if (type.vecsize > 2) + { + paramDesc.mask |= ComponentMask::Z; + } + if (type.vecsize > 3) + { + paramDesc.mask |= ComponentMask::W; + } + + switch (outputParam.builtin) + { + case spv::BuiltInTessLevelInner: + case spv::BuiltInTessLevelOuter: + for (uint32_t patchConstantParamIndex = 0; patchConstantParamIndex < type.array[0]; ++patchConstantParamIndex) + { + paramDesc.semanticIndex = patchConstantParamIndex; + + if (outputParam.builtin == spv::BuiltInTessLevelOuter) + { + paramDesc.mask = ComponentMask::W; + } + else + { + paramDesc.mask = ComponentMask::X; + } + + m_hsDSPatchConstantParams.emplace_back(std::move(paramDesc)); + } + break; + + default: + m_outputParams.emplace_back(std::move(paramDesc)); + break; + } + } + } + + for (const auto& outputParam : resources.stage_outputs) + { + SignatureParameterDesc paramDesc{}; + this->ExtractParameter(paramDesc, compiler, outputParam); + + m_outputParams.emplace_back(std::move(paramDesc)); + } + + m_gsHSInputPrimitive = Reflection::PrimitiveTopology::Undefined; + m_gsOutputTopology = Reflection::PrimitiveTopology::Undefined; + m_gsMaxNumOutputVertices = 0; + m_gsNumInstances = 0; + m_hsOutputPrimitive = Reflection::TessellatorOutputPrimitive::Undefined; + m_hsPartitioning = Reflection::TessellatorPartitioning::Undefined; + m_hSDSTessellatorDomain = Reflection::TessellatorDomain::Undefined; + m_hsDSNumCtrlPoints = 0; + m_csBlockSizeX = m_csBlockSizeY = m_csBlockSizeZ = 0; + + const auto& modes = compiler.get_execution_mode_bitset(); + switch (compiler.get_execution_model()) + { + case spv::ExecutionModelTessellationControl: + if (modes.get(spv::ExecutionModeOutputVertices)) + { + m_hsDSNumCtrlPoints = compiler.get_execution_mode_argument(spv::ExecutionModeOutputVertices, 0); + switch (m_hsDSNumCtrlPoints) + { + case 2: + m_hSDSTessellatorDomain = TessellatorDomain::Line; + break; + case 3: + m_hSDSTessellatorDomain = TessellatorDomain::Triangle; + break; + case 4: + m_hSDSTessellatorDomain = TessellatorDomain::Quad; + break; + + default: + break; + } + } + + if (modes.get(spv::ExecutionModeInputPoints)) + { + m_gsHSInputPrimitive = PrimitiveTopology::Patches_1_CtrlPoint; + } + else if (modes.get(spv::ExecutionModeInputLines)) + { + m_gsHSInputPrimitive = PrimitiveTopology::Patches_2_CtrlPoint; + } + else if (modes.get(spv::ExecutionModeTriangles)) + { + m_gsHSInputPrimitive = PrimitiveTopology::Patches_3_CtrlPoint; + } + + if (modes.get(spv::ExecutionModeVertexOrderCw)) + { + m_hsOutputPrimitive = TessellatorOutputPrimitive::TriangleCW; + } + else if (modes.get(spv::ExecutionModeVertexOrderCcw)) + { + m_hsOutputPrimitive = TessellatorOutputPrimitive::TriangleCCW; + } + + if (modes.get(spv::ExecutionModeSpacingEqual)) + { + m_hsPartitioning = TessellatorPartitioning::Integer; + } + else if (modes.get(spv::ExecutionModeSpacingFractionalOdd)) + { + m_hsPartitioning = TessellatorPartitioning::FractionalOdd; + } + else if (modes.get(spv::ExecutionModeSpacingFractionalOdd)) + { + m_hsPartitioning = TessellatorPartitioning::FractionalEven; + } + break; + + case spv::ExecutionModelTessellationEvaluation: + if (modes.get(spv::ExecutionModeIsolines)) + { + m_hSDSTessellatorDomain = TessellatorDomain::Line; + m_hsDSNumCtrlPoints = 2; + } + else if (modes.get(spv::ExecutionModeTriangles)) + { + m_hSDSTessellatorDomain = TessellatorDomain::Triangle; + m_hsDSNumCtrlPoints = 3; + } + else if (modes.get(spv::ExecutionModeQuads)) + { + m_hSDSTessellatorDomain = TessellatorDomain::Quad; + m_hsDSNumCtrlPoints = 4; + } + break; + + case spv::ExecutionModelGeometry: + if (modes.get(spv::ExecutionModeOutputVertices)) + { + m_gsMaxNumOutputVertices = compiler.get_execution_mode_argument(spv::ExecutionModeOutputVertices, 0); + } + + if (modes.get(spv::ExecutionModeInvocations)) + { + m_gsNumInstances = compiler.get_execution_mode_argument(spv::ExecutionModeInvocations, 0); + } + + if (modes.get(spv::ExecutionModeInputPoints)) + { + m_gsHSInputPrimitive = PrimitiveTopology::Points; + } + else if (modes.get(spv::ExecutionModeInputLines)) + { + m_gsHSInputPrimitive = PrimitiveTopology::Lines; + } + else if (modes.get(spv::ExecutionModeTriangles)) + { + m_gsHSInputPrimitive = PrimitiveTopology::Triangles; + } + else if (modes.get(spv::ExecutionModeInputLinesAdjacency)) + { + m_gsHSInputPrimitive = PrimitiveTopology::LinesAdj; + } + else if (modes.get(spv::ExecutionModeInputTrianglesAdjacency)) + { + m_gsHSInputPrimitive = PrimitiveTopology::TrianglesAdj; + } + + if (modes.get(spv::ExecutionModeOutputPoints)) + { + m_gsOutputTopology = PrimitiveTopology::Points; + } + else if (modes.get(spv::ExecutionModeOutputLineStrip)) + { + m_gsOutputTopology = PrimitiveTopology::LineStrip; + } + else if (modes.get(spv::ExecutionModeOutputTriangleStrip)) + { + m_gsOutputTopology = PrimitiveTopology::TriangleStrip; + } + break; + + case spv::ExecutionModelGLCompute: + { + spirv_cross::SpecializationConstant spec_x, spec_y, spec_z; + compiler.get_work_group_size_specialization_constants(spec_x, spec_y, spec_z); + + m_csBlockSizeX = spec_x.id != spirv_cross::ID(0) ? spec_x.constant_id + : compiler.get_execution_mode_argument(spv::ExecutionModeLocalSize, 0); + m_csBlockSizeY = spec_y.id != spirv_cross::ID(0) ? spec_y.constant_id + : compiler.get_execution_mode_argument(spv::ExecutionModeLocalSize, 1); + m_csBlockSizeZ = spec_z.id != spirv_cross::ID(0) ? spec_z.constant_id + : compiler.get_execution_mode_argument(spv::ExecutionModeLocalSize, 2); + break; + } + + default: + break; + } + } + + uint32_t NumResources() const noexcept + { + return static_cast(m_resourceDescs.size()); + } + + const ResourceDesc* ResourceByIndex(uint32_t index) const noexcept + { + if (index < m_resourceDescs.size()) + { + return &m_resourceDescs[index]; + } + + return nullptr; + } + + const ResourceDesc* ResourceByName(const char* name) const noexcept + { + for (const auto& resourceDesc : m_resourceDescs) + { + if (std::strcmp(resourceDesc.name, name) == 0) + { + return &resourceDesc; + } + } + + return nullptr; + } + + uint32_t NumConstantBuffers() const noexcept + { + return static_cast(m_constantBuffers.size()); + } + + const ConstantBuffer* ConstantBufferByIndex(uint32_t index) const noexcept + { + if (index < m_resourceDescs.size()) + { + return &m_constantBuffers[index]; + } + + return nullptr; + } + + const ConstantBuffer* ConstantBufferByName(const char* name) const noexcept + { + for (const auto& cbuffer : m_constantBuffers) + { + if (std::strcmp(cbuffer.Name(), name) == 0) + { + return &cbuffer; + } + } + + return nullptr; + } + + uint32_t NumInputParameters() const noexcept + { + return static_cast(m_inputParams.size()); + } + + const SignatureParameterDesc* InputParameter(uint32_t index) const noexcept + { + if (index < m_inputParams.size()) + { + return &m_inputParams[index]; + } + + return nullptr; + } + + uint32_t NumOutputParameters() const noexcept + { + return static_cast(m_outputParams.size()); + } + + const SignatureParameterDesc* OutputParameter(uint32_t index) const noexcept + { + if (index < m_outputParams.size()) + { + return &m_outputParams[index]; + } + + return nullptr; + } + + PrimitiveTopology GSHSInputPrimitive() const noexcept + { + return m_gsHSInputPrimitive; + } + + PrimitiveTopology GSOutputTopology() const noexcept + { + return m_gsOutputTopology; + } + + uint32_t GSMaxNumOutputVertices() const noexcept + { + return m_gsMaxNumOutputVertices; + } + + uint32_t GSNumInstances() const noexcept + { + return m_gsNumInstances; + } + + TessellatorOutputPrimitive HSOutputPrimitive() const noexcept + { + return m_hsOutputPrimitive; + } + + TessellatorPartitioning HSPartitioning() const noexcept + { + return m_hsPartitioning; + } + + TessellatorDomain HSDSTessellatorDomain() const noexcept + { + return m_hSDSTessellatorDomain; + } + + uint32_t HSDSNumPatchConstantParameters() const noexcept + { + return static_cast(m_hsDSPatchConstantParams.size()); + } + + const SignatureParameterDesc* HSDSPatchConstantParameter(uint32_t index) const noexcept + { + if (index < m_hsDSPatchConstantParams.size()) + { + return &m_hsDSPatchConstantParams[index]; + } + + return nullptr; + } + + uint32_t HSDSNumConrolPoints() const noexcept + { + return m_hsDSNumCtrlPoints; + } + + uint32_t CSBlockSizeX() const noexcept + { + return m_csBlockSizeX; + } + + uint32_t CSBlockSizeY() const noexcept + { + return m_csBlockSizeY; + } + + uint32_t CSBlockSizeZ() const noexcept + { + return m_csBlockSizeZ; + } + +#ifdef LLVM_ON_WIN32 + static Reflection Make(IDxcBlob* dxilBlob) + { + Reflection ret; + ret.m_impl = new ReflectionImpl(dxilBlob); + return ret; + } +#endif + + static Reflection Make(const spirv_cross::Compiler& compiler) + { + Reflection ret; + ret.m_impl = new ReflectionImpl(compiler); + return ret; + } + + private: + static std::string ExtractBuiltInemantic(spv::BuiltIn builtin) + { + std::string semantic; + switch (builtin) + { + case spv::BuiltInPosition: + case spv::BuiltInFragCoord: + semantic = "SV_Position"; + break; + + case spv::BuiltInFragDepth: + semantic = "SV_Depth"; + break; + + case spv::BuiltInVertexId: + case spv::BuiltInVertexIndex: + semantic = "SV_VertexID"; + break; + + case spv::BuiltInInstanceId: + case spv::BuiltInInstanceIndex: + semantic = "SV_InstanceID"; + break; + + case spv::BuiltInSampleId: + semantic = "SV_SampleIndex"; + break; + + case spv::BuiltInSampleMask: + semantic = "SV_Coverage"; + break; + + case spv::BuiltInTessLevelInner: + semantic = "SV_InsideTessFactor"; + break; + + case spv::BuiltInTessLevelOuter: + semantic = "SV_TessFactor"; + break; + + case spv::BuiltInGlobalInvocationId: + case spv::BuiltInLocalInvocationId: + case spv::BuiltInLocalInvocationIndex: + case spv::BuiltInWorkgroupId: + case spv::BuiltInFrontFacing: + case spv::BuiltInInvocationId: + case spv::BuiltInPrimitiveId: + case spv::BuiltInTessCoord: + break; + + default: + llvm_unreachable("Unsupported builtin."); + } + return semantic; + } + + static void ExtractReflection(ResourceDesc& reflectionDesc, const spirv_cross::Compiler& compiler, spirv_cross::ID id) + { + const uint32_t descSet = compiler.get_decoration(id, spv::DecorationDescriptorSet); + const uint32_t binding = compiler.get_decoration(id, spv::DecorationBinding); + + const std::string& res_name = compiler.get_name(id); + std::strncpy(reflectionDesc.name, res_name.c_str(), sizeof(reflectionDesc.name)); + reflectionDesc.space = descSet; + reflectionDesc.bindPoint = binding; + reflectionDesc.bindCount = 1; + } + + static void ExtractParameter(SignatureParameterDesc& paramDesc, const spirv_cross::Compiler& compiler, + const spirv_cross::Resource& resource, const std::string& semantic) + { + paramDesc.semanticIndex = 0; + for (auto iter = semantic.rbegin(); iter != semantic.rend(); ++iter) + { + if (!std::isdigit(*iter)) + { + const int sep = static_cast(std::distance(semantic.begin(), iter.base())); + const std::string indexPart = semantic.substr(sep); + if (indexPart.empty()) + { + paramDesc.semanticIndex = 0; + } + else + { + paramDesc.semanticIndex = std::atoi(indexPart.c_str()); + } + std::strncpy(paramDesc.semantic, semantic.c_str(), std::min(sep, sizeof(paramDesc.semantic))); + break; + } + } + + const auto& type = compiler.get_type(resource.type_id); + switch (type.basetype) + { + case spirv_cross::SPIRType::UInt: + paramDesc.componentType = VariableType::DataType::Uint; + break; + case spirv_cross::SPIRType::Int: + paramDesc.componentType = VariableType::DataType::Int; + break; + case spirv_cross::SPIRType::Float: + paramDesc.componentType = VariableType::DataType::Float; + break; + + default: + llvm_unreachable("Unsupported parameter component type."); + break; + } + + if (type.vecsize > 0) + { + paramDesc.mask = ComponentMask::X; + } + if (type.vecsize > 1) + { + paramDesc.mask |= ComponentMask::Y; + } + if (type.vecsize > 2) + { + paramDesc.mask |= ComponentMask::Z; + } + if (type.vecsize > 3) + { + paramDesc.mask |= ComponentMask::W; + } + + paramDesc.location = compiler.get_decoration(resource.id, spv::DecorationLocation); + } + + static void ExtractParameter(SignatureParameterDesc& paramDesc, const spirv_cross::Compiler& compiler, + const spirv_cross::Resource& resource) + { + ExtractParameter(paramDesc, compiler, resource, compiler.get_name(resource.id)); + } + + private: + std::vector m_resourceDescs; + std::vector m_constantBuffers; + + std::vector m_inputParams; + std::vector m_outputParams; + + PrimitiveTopology m_gsHSInputPrimitive; + PrimitiveTopology m_gsOutputTopology; + uint32_t m_gsMaxNumOutputVertices; + uint32_t m_gsNumInstances; + + TessellatorOutputPrimitive m_hsOutputPrimitive; + TessellatorPartitioning m_hsPartitioning; + TessellatorDomain m_hSDSTessellatorDomain; + std::vector m_hsDSPatchConstantParams; + uint32_t m_hsDSNumCtrlPoints; + + uint32_t m_csBlockSizeX; + uint32_t m_csBlockSizeY; + uint32_t m_csBlockSizeZ; + }; + + Reflection::Reflection() noexcept = default; + + Reflection::Reflection(const Reflection& other) : m_impl(other.m_impl ? new ReflectionImpl(*other.m_impl) : nullptr) + { + } + + Reflection::Reflection(Reflection&& other) noexcept : m_impl(std::move(other.m_impl)) + { + other.m_impl = nullptr; + } + + Reflection::~Reflection() noexcept + { + delete m_impl; + } + + Reflection& Reflection::operator=(const Reflection& other) + { + if (this != &other) + { + delete m_impl; + m_impl = nullptr; + + if (other.m_impl) + { + m_impl = new ReflectionImpl(*other.m_impl); + } + } + return *this; + } + + Reflection& Reflection::operator=(Reflection&& other) noexcept + { + if (this != &other) + { + delete m_impl; + m_impl = std::move(other.m_impl); + other.m_impl = nullptr; + } + return *this; + } + + bool Reflection::Valid() const noexcept + { + return m_impl != nullptr; + } + + uint32_t Reflection::NumResources() const noexcept + { + return m_impl->NumResources(); + } + + const Reflection::ResourceDesc* Reflection::ResourceByIndex(uint32_t index) const noexcept + { + return m_impl->ResourceByIndex(index); + } + + const Reflection::ResourceDesc* Reflection::ResourceByName(const char* name) const noexcept + { + return m_impl->ResourceByName(name); + } + + uint32_t Reflection::NumConstantBuffers() const noexcept + { + return m_impl->NumConstantBuffers(); + } + + const Reflection::ConstantBuffer* Reflection::ConstantBufferByIndex(uint32_t index) const noexcept + { + return m_impl->ConstantBufferByIndex(index); + } + + const Reflection::ConstantBuffer* Reflection::ConstantBufferByName(const char* name) const noexcept + { + return m_impl->ConstantBufferByName(name); + } + + uint32_t Reflection::NumInputParameters() const noexcept + { + return m_impl->NumInputParameters(); + } + + const Reflection::SignatureParameterDesc* Reflection::InputParameter(uint32_t index) const noexcept + { + return m_impl->InputParameter(index); + } + + uint32_t Reflection::NumOutputParameters() const noexcept + { + return m_impl->NumOutputParameters(); + } + + const Reflection::SignatureParameterDesc* Reflection::OutputParameter(uint32_t index) const noexcept + { + return m_impl->OutputParameter(index); + } + + Reflection::PrimitiveTopology Reflection::GSHSInputPrimitive() const noexcept + { + return m_impl->GSHSInputPrimitive(); + } + + Reflection::PrimitiveTopology Reflection::GSOutputTopology() const noexcept + { + return m_impl->GSOutputTopology(); + } + + uint32_t Reflection::GSMaxNumOutputVertices() const noexcept + { + return m_impl->GSMaxNumOutputVertices(); + } + + uint32_t Reflection::GSNumInstances() const noexcept + { + return m_impl->GSNumInstances(); + } + + Reflection::TessellatorOutputPrimitive Reflection::HSOutputPrimitive() const noexcept + { + return m_impl->HSOutputPrimitive(); + } + + Reflection::TessellatorPartitioning Reflection::HSPartitioning() const noexcept + { + return m_impl->HSPartitioning(); + } + + Reflection::TessellatorDomain Reflection::HSDSTessellatorDomain() const noexcept + { + return m_impl->HSDSTessellatorDomain(); + } + + uint32_t Reflection::HSDSNumPatchConstantParameters() const noexcept + { + return m_impl->HSDSNumPatchConstantParameters(); + } + + const Reflection::SignatureParameterDesc* Reflection::HSDSPatchConstantParameter(uint32_t index) const noexcept + { + return m_impl->HSDSPatchConstantParameter(index); + } + + uint32_t Reflection::HSDSNumConrolPoints() const noexcept + { + return m_impl->HSDSNumConrolPoints(); + } + + uint32_t Reflection::CSBlockSizeX() const noexcept + { + return m_impl->CSBlockSizeX(); + } + + uint32_t Reflection::CSBlockSizeY() const noexcept + { + return m_impl->CSBlockSizeY(); + } + + uint32_t Reflection::CSBlockSizeZ() const noexcept + { + return m_impl->CSBlockSizeZ(); + } + + + Compiler::ResultDesc Compiler::Compile(const SourceDesc& source, const Options& options, const TargetDesc& target) + { + ResultDesc result; + Compiler::Compile(source, options, &target, 1, &result); + return result; + } + + void Compiler::Compile(const SourceDesc& source, const Options& options, const TargetDesc* targets, uint32_t numTargets, + ResultDesc* results) + { + SourceDesc sourceOverride = source; + if (!sourceOverride.entryPoint || (std::strlen(sourceOverride.entryPoint) == 0)) + { + sourceOverride.entryPoint = "main"; + } + if (!sourceOverride.loadIncludeCallback) + { + sourceOverride.loadIncludeCallback = DefaultLoadCallback; + } + + bool hasDxil = false; + bool hasDxilModule = false; + bool hasSpirV = false; + for (uint32_t i = 0; i < numTargets; ++i) + { + if (targets[i].language == ShadingLanguage::Dxil) + { + hasDxil = true; + if (targets[i].asModule) + { + hasDxilModule = true; + } + } + else + { + hasSpirV = true; + } + } + + ResultDesc dxilBinaryResult{}; + if (hasDxil) + { + dxilBinaryResult = CompileToBinary(sourceOverride, options, ShadingLanguage::Dxil, false); + } + + ResultDesc dxilModuleBinaryResult{}; + if (hasDxilModule) + { + dxilModuleBinaryResult = CompileToBinary(sourceOverride, options, ShadingLanguage::Dxil, true); + } + + ResultDesc spirvBinaryResult{}; + if (hasSpirV) + { + spirvBinaryResult = CompileToBinary(sourceOverride, options, ShadingLanguage::SpirV, false); + } + + for (uint32_t i = 0; i < numTargets; ++i) + { + ResultDesc binaryResult; + if (targets[i].language == ShadingLanguage::Dxil) + { + if (targets[i].asModule) + { + binaryResult = dxilModuleBinaryResult; + } + else + { + binaryResult = dxilBinaryResult; + } + } + else + { + binaryResult = spirvBinaryResult; + } + + results[i] = ConvertBinary(binaryResult, sourceOverride, options, targets[i]); + } + } + + Compiler::ResultDesc Compiler::Disassemble(const DisassembleDesc& source) + { + assert((source.language == ShadingLanguage::SpirV) || (source.language == ShadingLanguage::Dxil)); + + Compiler::ResultDesc ret; + + ret.isText = true; + + if (source.language == ShadingLanguage::SpirV) + { + const uint32_t* spirvIr = reinterpret_cast(source.binary); + const size_t spirvSize = source.binarySize / sizeof(uint32_t); + + spv_context context = spvContextCreate(SPV_ENV_UNIVERSAL_1_3); + uint32_t options = SPV_BINARY_TO_TEXT_OPTION_NONE | SPV_BINARY_TO_TEXT_OPTION_INDENT | SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES; + spv_text text = nullptr; + spv_diagnostic diagnostic = nullptr; + + spv_result_t error = spvBinaryToText(context, spirvIr, spirvSize, options, &text, &diagnostic); + spvContextDestroy(context); + + if (error) + { + ret.errorWarningMsg.Reset(diagnostic->error, static_cast(std::strlen(diagnostic->error))); + ret.hasError = true; + spvDiagnosticDestroy(diagnostic); + } + else + { + const std::string disassemble = text->str; + ret.target.Reset(disassemble.data(), static_cast(disassemble.size())); + ret.hasError = false; + } + + spvTextDestroy(text); + } + else + { + CComPtr blob; + CComPtr disassembly; + IFT(Dxcompiler::Instance().Library()->CreateBlobWithEncodingOnHeapCopy(source.binary, source.binarySize, CP_UTF8, &blob)); + IFT(Dxcompiler::Instance().Compiler()->Disassemble(blob, &disassembly)); + + if (disassembly != nullptr) + { + // Remove the tailing \0 + ret.target.Reset(disassembly->GetBufferPointer(), static_cast(disassembly->GetBufferSize() - 1)); + ret.hasError = false; + } + else + { + ret.hasError = true; + } + } + + return ret; + } + + bool Compiler::LinkSupport() + { + return Dxcompiler::Instance().LinkerSupport(); + } + + Compiler::ResultDesc Compiler::Link(const LinkDesc& modules, const Compiler::Options& options, const TargetDesc& target) + { + auto linker = Dxcompiler::Instance().CreateLinker(); + IFTPTR(linker); + + auto* library = Dxcompiler::Instance().Library(); + + std::vector moduleNames(modules.numModules); + std::vector moduleNamesUtf16(modules.numModules); + std::vector> moduleBlobs(modules.numModules); + for (uint32_t i = 0; i < modules.numModules; ++i) + { + IFTARG(modules.modules[i] != nullptr); + + IFT(library->CreateBlobWithEncodingOnHeapCopy(modules.modules[i]->target.Data(), modules.modules[i]->target.Size(), CP_UTF8, + &moduleBlobs[i])); + IFTARG(moduleBlobs[i]->GetBufferSize() >= 4); + + Unicode::UTF8ToUTF16String(modules.modules[i]->name, &moduleNames[i]); + moduleNamesUtf16[i] = moduleNames[i].c_str(); + IFT(linker->RegisterLibrary(moduleNamesUtf16[i], moduleBlobs[i])); + } + + std::wstring entryPointUtf16; + Unicode::UTF8ToUTF16String(modules.entryPoint, &entryPointUtf16); + + const std::wstring shaderProfile = ShaderProfileName(modules.stage, options.shaderModel); + CComPtr linkResult; + IFT(linker->Link(entryPointUtf16.c_str(), shaderProfile.c_str(), moduleNamesUtf16.data(), + static_cast(moduleNamesUtf16.size()), nullptr, 0, &linkResult)); + + Compiler::ResultDesc binaryResult{}; + ConvertDxcResult(binaryResult, linkResult, ShadingLanguage::Dxil, false, false); + + Compiler::SourceDesc source{}; + source.entryPoint = modules.entryPoint; + source.stage = modules.stage; + return ConvertBinary(binaryResult, source, options, target); } } // namespace ShaderConductor +namespace +{ +#ifdef LLVM_ON_WIN32 + Reflection MakeDxilReflection(IDxcBlob* dxilBlob) + { + return Reflection::ReflectionImpl::Make(dxilBlob); + } +#endif + + Reflection MakeSpirVReflection(const spirv_cross::Compiler& compiler) + { + return Reflection::ReflectionImpl::Make(compiler); + } +} // namespace + #ifdef _WIN32 BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) { diff --git a/Source/Tests/CMakeLists.txt b/Source/Tests/CMakeLists.txt index c3dff849..025efce3 100644 --- a/Source/Tests/CMakeLists.txt +++ b/Source/Tests/CMakeLists.txt @@ -3,8 +3,14 @@ set(EXE_NAME ShaderConductorTest) +set(HEADER_FILES + Common.hpp +) + set(SOURCE_FILES - ShaderConductorTest.cpp + Common.cpp + CrossCompileTest.cpp + ReflectionTest.cpp ) set(DATA_INC_FILES @@ -38,11 +44,12 @@ set_source_files_properties(${DATA_FILES} PROPERTIES VS_TOOL_OVERRIDE "None" ) +source_group("Header Files" FILES ${HEADER_FILES}) source_group("Source Files" FILES ${SOURCE_FILES}) source_group("Data Files\\Input" FILES ${DATA_FILES}) source_group("Data Files\\Input\\Inc" FILES ${DATA_INC_FILES}) -add_executable(${EXE_NAME} ${SOURCE_FILES} ${DATA_FILES} ${DATA_INC_FILES}) +add_executable(${EXE_NAME} ${HEADER_FILES} ${SOURCE_FILES} ${DATA_FILES} ${DATA_INC_FILES}) target_compile_definitions(${EXE_NAME} PRIVATE diff --git a/Source/Tests/Common.cpp b/Source/Tests/Common.cpp new file mode 100644 index 00000000..e85c6fa7 --- /dev/null +++ b/Source/Tests/Common.cpp @@ -0,0 +1,88 @@ +/* + * ShaderConductor + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons + * to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "Common.hpp" + +#include + +#include +#include +#include + +namespace ShaderConductor +{ + std::vector LoadFile(const std::string& name, bool isText) + { + std::vector ret; + std::ios_base::openmode mode = std::ios_base::in; + if (!isText) + { + mode |= std::ios_base::binary; + } + std::ifstream file(name, mode); + if (file) + { + file.seekg(0, std::ios::end); + ret.resize(static_cast(file.tellg())); + file.seekg(0, std::ios::beg); + file.read(reinterpret_cast(ret.data()), ret.size()); + ret.resize(static_cast(file.gcount())); + } + return ret; + } + + void CompareWithExpected(const std::vector& actual, bool isText, const std::string& compareName) + { + std::vector expected = LoadFile(TEST_DATA_DIR "Expected/" + compareName, isText); + if (expected != actual) + { + if (!actual.empty()) + { + std::ios_base::openmode mode = std::ios_base::out; + if (!isText) + { + mode |= std::ios_base::binary; + } + std::ofstream actualFile(TEST_DATA_DIR "Result/" + compareName, mode); + actualFile.write(reinterpret_cast(actual.data()), actual.size()); + } + } + + EXPECT_EQ(std::string(expected.begin(), expected.end()), std::string(actual.begin(), actual.end())); + } +} // namespace ShaderConductor + +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + + int retVal = RUN_ALL_TESTS(); + if (retVal != 0) + { + getchar(); + } + + return retVal; +} diff --git a/Source/Tests/Common.hpp b/Source/Tests/Common.hpp new file mode 100644 index 00000000..d5876af8 --- /dev/null +++ b/Source/Tests/Common.hpp @@ -0,0 +1,40 @@ +/* + * ShaderConductor + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons + * to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef SHADER_CONDUCTOR_TEST_COMMON_HPP +#define SHADER_CONDUCTOR_TEST_COMMON_HPP + +#pragma once + +#include +#include + +namespace ShaderConductor +{ + std::vector LoadFile(const std::string& name, bool isText); + void CompareWithExpected(const std::vector& actual, bool isText, const std::string& compareName); +} // namespace ShaderConductor + +#endif diff --git a/Source/Tests/ShaderConductorTest.cpp b/Source/Tests/CrossCompileTest.cpp similarity index 92% rename from Source/Tests/ShaderConductorTest.cpp rename to Source/Tests/CrossCompileTest.cpp index e5763529..0e6ad830 100644 --- a/Source/Tests/ShaderConductorTest.cpp +++ b/Source/Tests/CrossCompileTest.cpp @@ -25,10 +25,10 @@ #include +#include "Common.hpp" + #include -#include -#include #include #include #include @@ -37,46 +37,6 @@ using namespace ShaderConductor; namespace { - std::vector LoadFile(const std::string& name, bool isText) - { - std::vector ret; - std::ios_base::openmode mode = std::ios_base::in; - if (!isText) - { - mode |= std::ios_base::binary; - } - std::ifstream file(name, mode); - if (file) - { - file.seekg(0, std::ios::end); - ret.resize(static_cast(file.tellg())); - file.seekg(0, std::ios::beg); - file.read(reinterpret_cast(ret.data()), ret.size()); - ret.resize(static_cast(file.gcount())); - } - return ret; - } - - void CompareWithExpected(const std::vector& actual, bool isText, const std::string& compareName) - { - std::vector expected = LoadFile(TEST_DATA_DIR "Expected/" + compareName, isText); - if (expected != actual) - { - if (!actual.empty()) - { - std::ios_base::openmode mode = std::ios_base::out; - if (!isText) - { - mode |= std::ios_base::binary; - } - std::ofstream actualFile(TEST_DATA_DIR "Result/" + compareName, mode); - actualFile.write(reinterpret_cast(actual.data()), actual.size()); - } - } - - EXPECT_EQ(std::string(expected.begin(), expected.end()), std::string(actual.begin(), actual.end())); - } - void HlslToAnyTest(const std::string& name, const Compiler::SourceDesc& source, const Compiler::Options& options, const std::vector& targets, const std::vector& expectSuccessFlags) { @@ -642,16 +602,3 @@ namespace } } } // namespace - -int main(int argc, char** argv) -{ - testing::InitGoogleTest(&argc, argv); - - int retVal = RUN_ALL_TESTS(); - if (retVal != 0) - { - getchar(); - } - - return retVal; -} diff --git a/Source/Tests/Data/Expected/CalcLight+Diffuse.Debug.dxilasm b/Source/Tests/Data/Expected/CalcLight+Diffuse.Debug.dxilasm index 29184df7..cfb8cf4a 100644 --- a/Source/Tests/Data/Expected/CalcLight+Diffuse.Debug.dxilasm +++ b/Source/Tests/Data/Expected/CalcLight+Diffuse.Debug.dxilasm @@ -15,8 +15,8 @@ ; -------------------- ----- ------ -------- -------- ------- ------ ; SV_Target 0 xyzw 0 TARGET float xyzw ; -; shader debug name: d81432b398a9151e6a076b6b827882eb.pdb -; shader hash: d81432b398a9151e6a076b6b827882eb +; shader debug name: 1c9ff017e8c534734cdc26123d89517a.pdb +; shader hash: 1c9ff017e8c534734cdc26123d89517a ; ; Pipeline Runtime Information: ; @@ -45,14 +45,7 @@ ; cbuffer cbPS ; { ; -; struct cbPS -; { -; -; float3 diffColor; ; Offset: 0 -; float3 specColor; ; Offset: 16 -; float shininess; ; Offset: 28 -; -; } cbPS; ; Offset: 0 Size: 32 +; [32 x i8] (type annotation not present) ; ; } ; @@ -75,12 +68,9 @@ ; target triple = "dxil-ms-dx" -%cbPS = type { <3 x float>, <3 x float>, float } %dx.types.CBufRet.f32 = type { float, float, float, float } %dx.types.Handle = type { i8* } -@cbPS = external constant %cbPS - ; Function Attrs: nounwind readnone declare float @dx.op.loadInput.f32(i32, i32, i32, i8, i32) #0 @@ -135,37 +125,32 @@ attributes #2 = { nounwind } !dx.valver = !{!2} !dx.shaderModel = !{!3} !dx.resources = !{!4} -!dx.typeAnnotations = !{!7, !12} -!dx.viewIdState = !{!16} -!dx.entryPoints = !{!17} +!dx.typeAnnotations = !{!7} +!dx.viewIdState = !{!11} +!dx.entryPoints = !{!12} !0 = !{!"clang version 3.7 (tags/RELEASE_370/final)"} !1 = !{i32 1, i32 0} -!2 = !{i32 1, i32 6} +!2 = !{i32 1, i32 7} !3 = !{!"ps", i32 6, i32 0} !4 = !{null, null, !5, null} !5 = !{!6} -!6 = !{i32 0, %cbPS* undef, !"cbPS", i32 0, i32 0, i32 1, i32 32, null} -!7 = !{i32 0, %cbPS undef, !8} -!8 = !{i32 32, !9, !10, !11} -!9 = !{i32 6, !"diffColor", i32 3, i32 0, i32 7, i32 9} -!10 = !{i32 6, !"specColor", i32 3, i32 16, i32 7, i32 9} -!11 = !{i32 6, !"shininess", i32 3, i32 28, i32 7, i32 9} -!12 = !{i32 1, void ()* @main, !13} -!13 = !{!14} -!14 = !{i32 0, !15, !15} -!15 = !{} -!16 = !{[17 x i32] [i32 15, i32 4, i32 0, i32 0, i32 0, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7, i32 0, i32 0, i32 0, i32 0]} -!17 = !{void ()* @main, !"main", !18, !4, null} -!18 = !{!19, !27, null} -!19 = !{!20, !22, !24, !25} -!20 = !{i32 0, !"SV_Position", i8 9, i8 3, !21, i8 4, i32 1, i8 4, i32 0, i8 0, null} -!21 = !{i32 0} -!22 = !{i32 1, !"NORMAL", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 1, i8 0, !23} -!23 = !{i32 3, i32 7} -!24 = !{i32 2, !"TEXCOORD", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 2, i8 0, !23} -!25 = !{i32 3, !"TEXCOORD", i8 9, i8 0, !26, i8 2, i32 1, i8 3, i32 3, i8 0, null} -!26 = !{i32 1} -!27 = !{!28} -!28 = !{i32 0, !"SV_Target", i8 9, i8 16, !21, i8 0, i32 1, i8 4, i32 0, i8 0, !29} -!29 = !{i32 3, i32 15} +!6 = !{i32 0, %dx.types.Handle* undef, !"cbPS", i32 0, i32 0, i32 1, i32 32, null} +!7 = !{i32 1, void ()* @main, !8} +!8 = !{!9} +!9 = !{i32 0, !10, !10} +!10 = !{} +!11 = !{[17 x i32] [i32 15, i32 4, i32 0, i32 0, i32 0, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7, i32 0, i32 0, i32 0, i32 0]} +!12 = !{void ()* @main, !"main", !13, !4, null} +!13 = !{!14, !22, null} +!14 = !{!15, !17, !19, !20} +!15 = !{i32 0, !"SV_Position", i8 9, i8 3, !16, i8 4, i32 1, i8 4, i32 0, i8 0, null} +!16 = !{i32 0} +!17 = !{i32 1, !"NORMAL", i8 9, i8 0, !16, i8 2, i32 1, i8 3, i32 1, i8 0, !18} +!18 = !{i32 3, i32 7} +!19 = !{i32 2, !"TEXCOORD", i8 9, i8 0, !16, i8 2, i32 1, i8 3, i32 2, i8 0, !18} +!20 = !{i32 3, !"TEXCOORD", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 3, i8 0, null} +!21 = !{i32 1} +!22 = !{!23} +!23 = !{i32 0, !"SV_Target", i8 9, i8 16, !16, i8 0, i32 1, i8 4, i32 0, i8 0, !24} +!24 = !{i32 3, i32 15} diff --git a/Source/Tests/Data/Expected/CalcLight+Diffuse.Release.dxilasm b/Source/Tests/Data/Expected/CalcLight+Diffuse.Release.dxilasm index 4bdfb903..d11ad679 100644 --- a/Source/Tests/Data/Expected/CalcLight+Diffuse.Release.dxilasm +++ b/Source/Tests/Data/Expected/CalcLight+Diffuse.Release.dxilasm @@ -15,8 +15,8 @@ ; -------------------- ----- ------ -------- -------- ------- ------ ; SV_Target 0 xyzw 0 TARGET float xyzw ; -; shader debug name: ad90c6ff56d81fd333e64a2bf70453fc.pdb -; shader hash: ad90c6ff56d81fd333e64a2bf70453fc +; shader debug name: c247268630a3fe54e4153ff9c6dc82e1.pdb +; shader hash: c247268630a3fe54e4153ff9c6dc82e1 ; ; Pipeline Runtime Information: ; @@ -45,14 +45,7 @@ ; cbuffer cbPS ; { ; -; struct cbPS -; { -; -; float3 diffColor; ; Offset: 0 -; float3 specColor; ; Offset: 16 -; float shininess; ; Offset: 28 -; -; } cbPS; ; Offset: 0 Size: 32 +; [32 x i8] (type annotation not present) ; ; } ; @@ -75,12 +68,9 @@ ; target triple = "dxil-ms-dx" -%cbPS = type { <3 x float>, <3 x float>, float } %dx.types.CBufRet.f32 = type { float, float, float, float } %dx.types.Handle = type { i8* } -@cbPS = external constant %cbPS - ; Function Attrs: nounwind readnone declare float @dx.op.loadInput.f32(i32, i32, i32, i8, i32) #0 @@ -134,37 +124,32 @@ attributes #2 = { nounwind } !dx.valver = !{!2} !dx.shaderModel = !{!3} !dx.resources = !{!4} -!dx.typeAnnotations = !{!7, !12} -!dx.viewIdState = !{!16} -!dx.entryPoints = !{!17} +!dx.typeAnnotations = !{!7} +!dx.viewIdState = !{!11} +!dx.entryPoints = !{!12} !0 = !{!"clang version 3.7 (tags/RELEASE_370/final)"} !1 = !{i32 1, i32 0} -!2 = !{i32 1, i32 6} +!2 = !{i32 1, i32 7} !3 = !{!"ps", i32 6, i32 0} !4 = !{null, null, !5, null} !5 = !{!6} -!6 = !{i32 0, %cbPS* undef, !"cbPS", i32 0, i32 0, i32 1, i32 32, null} -!7 = !{i32 0, %cbPS undef, !8} -!8 = !{i32 32, !9, !10, !11} -!9 = !{i32 6, !"diffColor", i32 3, i32 0, i32 7, i32 9} -!10 = !{i32 6, !"specColor", i32 3, i32 16, i32 7, i32 9} -!11 = !{i32 6, !"shininess", i32 3, i32 28, i32 7, i32 9} -!12 = !{i32 1, void ()* @main, !13} -!13 = !{!14} -!14 = !{i32 0, !15, !15} -!15 = !{} -!16 = !{[17 x i32] [i32 15, i32 4, i32 0, i32 0, i32 0, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7, i32 0, i32 0, i32 0, i32 0]} -!17 = !{void ()* @main, !"main", !18, !4, null} -!18 = !{!19, !27, null} -!19 = !{!20, !22, !24, !25} -!20 = !{i32 0, !"SV_Position", i8 9, i8 3, !21, i8 4, i32 1, i8 4, i32 0, i8 0, null} -!21 = !{i32 0} -!22 = !{i32 1, !"NORMAL", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 1, i8 0, !23} -!23 = !{i32 3, i32 7} -!24 = !{i32 2, !"TEXCOORD", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 2, i8 0, !23} -!25 = !{i32 3, !"TEXCOORD", i8 9, i8 0, !26, i8 2, i32 1, i8 3, i32 3, i8 0, null} -!26 = !{i32 1} -!27 = !{!28} -!28 = !{i32 0, !"SV_Target", i8 9, i8 16, !21, i8 0, i32 1, i8 4, i32 0, i8 0, !29} -!29 = !{i32 3, i32 15} +!6 = !{i32 0, %dx.types.Handle* undef, !"cbPS", i32 0, i32 0, i32 1, i32 32, null} +!7 = !{i32 1, void ()* @main, !8} +!8 = !{!9} +!9 = !{i32 0, !10, !10} +!10 = !{} +!11 = !{[17 x i32] [i32 15, i32 4, i32 0, i32 0, i32 0, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7, i32 0, i32 0, i32 0, i32 0]} +!12 = !{void ()* @main, !"main", !13, !4, null} +!13 = !{!14, !22, null} +!14 = !{!15, !17, !19, !20} +!15 = !{i32 0, !"SV_Position", i8 9, i8 3, !16, i8 4, i32 1, i8 4, i32 0, i8 0, null} +!16 = !{i32 0} +!17 = !{i32 1, !"NORMAL", i8 9, i8 0, !16, i8 2, i32 1, i8 3, i32 1, i8 0, !18} +!18 = !{i32 3, i32 7} +!19 = !{i32 2, !"TEXCOORD", i8 9, i8 0, !16, i8 2, i32 1, i8 3, i32 2, i8 0, !18} +!20 = !{i32 3, !"TEXCOORD", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 3, i8 0, null} +!21 = !{i32 1} +!22 = !{!23} +!23 = !{i32 0, !"SV_Target", i8 9, i8 16, !16, i8 0, i32 1, i8 4, i32 0, i8 0, !24} +!24 = !{i32 3, i32 15} diff --git a/Source/Tests/Data/Expected/CalcLight+DiffuseSpecular.Debug.dxilasm b/Source/Tests/Data/Expected/CalcLight+DiffuseSpecular.Debug.dxilasm index 0c66a2b1..859ddbd5 100644 --- a/Source/Tests/Data/Expected/CalcLight+DiffuseSpecular.Debug.dxilasm +++ b/Source/Tests/Data/Expected/CalcLight+DiffuseSpecular.Debug.dxilasm @@ -15,8 +15,8 @@ ; -------------------- ----- ------ -------- -------- ------- ------ ; SV_Target 0 xyzw 0 TARGET float xyzw ; -; shader debug name: 65620ef187dc1e38cb91d8208665ef7d.pdb -; shader hash: 65620ef187dc1e38cb91d8208665ef7d +; shader debug name: 25518f9e3687a943487e772bc4f7808c.pdb +; shader hash: 25518f9e3687a943487e772bc4f7808c ; ; Pipeline Runtime Information: ; @@ -45,14 +45,7 @@ ; cbuffer cbPS ; { ; -; struct cbPS -; { -; -; float3 diffColor; ; Offset: 0 -; float3 specColor; ; Offset: 16 -; float shininess; ; Offset: 28 -; -; } cbPS; ; Offset: 0 Size: 32 +; [32 x i8] (type annotation not present) ; ; } ; @@ -75,12 +68,9 @@ ; target triple = "dxil-ms-dx" -%cbPS = type { <3 x float>, <3 x float>, float } %dx.types.CBufRet.f32 = type { float, float, float, float } %dx.types.Handle = type { i8* } -@cbPS = external constant %cbPS - ; Function Attrs: nounwind readnone declare float @dx.op.loadInput.f32(i32, i32, i32, i8, i32) #0 @@ -181,37 +171,32 @@ attributes #2 = { nounwind } !dx.valver = !{!2} !dx.shaderModel = !{!3} !dx.resources = !{!4} -!dx.typeAnnotations = !{!7, !12} -!dx.viewIdState = !{!16} -!dx.entryPoints = !{!17} +!dx.typeAnnotations = !{!7} +!dx.viewIdState = !{!11} +!dx.entryPoints = !{!12} !0 = !{!"clang version 3.7 (tags/RELEASE_370/final)"} !1 = !{i32 1, i32 0} -!2 = !{i32 1, i32 6} +!2 = !{i32 1, i32 7} !3 = !{!"ps", i32 6, i32 0} !4 = !{null, null, !5, null} !5 = !{!6} -!6 = !{i32 0, %cbPS* undef, !"cbPS", i32 0, i32 0, i32 1, i32 32, null} -!7 = !{i32 0, %cbPS undef, !8} -!8 = !{i32 32, !9, !10, !11} -!9 = !{i32 6, !"diffColor", i32 3, i32 0, i32 7, i32 9} -!10 = !{i32 6, !"specColor", i32 3, i32 16, i32 7, i32 9} -!11 = !{i32 6, !"shininess", i32 3, i32 28, i32 7, i32 9} -!12 = !{i32 1, void ()* @main, !13} -!13 = !{!14} -!14 = !{i32 0, !15, !15} -!15 = !{} -!16 = !{[17 x i32] [i32 15, i32 4, i32 0, i32 0, i32 0, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7]} -!17 = !{void ()* @main, !"main", !18, !4, null} -!18 = !{!19, !27, null} -!19 = !{!20, !22, !24, !25} -!20 = !{i32 0, !"SV_Position", i8 9, i8 3, !21, i8 4, i32 1, i8 4, i32 0, i8 0, null} -!21 = !{i32 0} -!22 = !{i32 1, !"NORMAL", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 1, i8 0, !23} -!23 = !{i32 3, i32 7} -!24 = !{i32 2, !"TEXCOORD", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 2, i8 0, !23} -!25 = !{i32 3, !"TEXCOORD", i8 9, i8 0, !26, i8 2, i32 1, i8 3, i32 3, i8 0, !23} -!26 = !{i32 1} -!27 = !{!28} -!28 = !{i32 0, !"SV_Target", i8 9, i8 16, !21, i8 0, i32 1, i8 4, i32 0, i8 0, !29} -!29 = !{i32 3, i32 15} +!6 = !{i32 0, %dx.types.Handle* undef, !"cbPS", i32 0, i32 0, i32 1, i32 32, null} +!7 = !{i32 1, void ()* @main, !8} +!8 = !{!9} +!9 = !{i32 0, !10, !10} +!10 = !{} +!11 = !{[17 x i32] [i32 15, i32 4, i32 0, i32 0, i32 0, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7]} +!12 = !{void ()* @main, !"main", !13, !4, null} +!13 = !{!14, !22, null} +!14 = !{!15, !17, !19, !20} +!15 = !{i32 0, !"SV_Position", i8 9, i8 3, !16, i8 4, i32 1, i8 4, i32 0, i8 0, null} +!16 = !{i32 0} +!17 = !{i32 1, !"NORMAL", i8 9, i8 0, !16, i8 2, i32 1, i8 3, i32 1, i8 0, !18} +!18 = !{i32 3, i32 7} +!19 = !{i32 2, !"TEXCOORD", i8 9, i8 0, !16, i8 2, i32 1, i8 3, i32 2, i8 0, !18} +!20 = !{i32 3, !"TEXCOORD", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 3, i8 0, !18} +!21 = !{i32 1} +!22 = !{!23} +!23 = !{i32 0, !"SV_Target", i8 9, i8 16, !16, i8 0, i32 1, i8 4, i32 0, i8 0, !24} +!24 = !{i32 3, i32 15} diff --git a/Source/Tests/Data/Expected/CalcLight+DiffuseSpecular.Release.dxilasm b/Source/Tests/Data/Expected/CalcLight+DiffuseSpecular.Release.dxilasm index fde43471..08f95c29 100644 --- a/Source/Tests/Data/Expected/CalcLight+DiffuseSpecular.Release.dxilasm +++ b/Source/Tests/Data/Expected/CalcLight+DiffuseSpecular.Release.dxilasm @@ -15,8 +15,8 @@ ; -------------------- ----- ------ -------- -------- ------- ------ ; SV_Target 0 xyzw 0 TARGET float xyzw ; -; shader debug name: 7f14de892298c5aa041b655c7a09b6e5.pdb -; shader hash: 7f14de892298c5aa041b655c7a09b6e5 +; shader debug name: 98d2b1bcd83bf049601636cc5a9e1e37.pdb +; shader hash: 98d2b1bcd83bf049601636cc5a9e1e37 ; ; Pipeline Runtime Information: ; @@ -45,14 +45,7 @@ ; cbuffer cbPS ; { ; -; struct cbPS -; { -; -; float3 diffColor; ; Offset: 0 -; float3 specColor; ; Offset: 16 -; float shininess; ; Offset: 28 -; -; } cbPS; ; Offset: 0 Size: 32 +; [32 x i8] (type annotation not present) ; ; } ; @@ -75,12 +68,9 @@ ; target triple = "dxil-ms-dx" -%cbPS = type { <3 x float>, <3 x float>, float } %dx.types.CBufRet.f32 = type { float, float, float, float } %dx.types.Handle = type { i8* } -@cbPS = external constant %cbPS - ; Function Attrs: nounwind readnone declare float @dx.op.loadInput.f32(i32, i32, i32, i8, i32) #0 @@ -132,35 +122,35 @@ define void @main() { %.i06.i = fcmp fast ogt float %12, 0.000000e+00 %.i17.i = fcmp fast ogt float %13, 0.000000e+00 %.i28.i = fcmp fast ogt float %14, 0.000000e+00 - %.i010.i = fsub fast float 1.000000e+00, %12 - %.i112.i = fsub fast float 1.000000e+00, %13 - %.i214.i = fsub fast float 1.000000e+00, %14 + %.i09.i = fsub fast float 1.000000e+00, %12 + %.i110.i = fsub fast float 1.000000e+00, %13 + %.i211.i = fsub fast float 1.000000e+00, %14 %24 = fsub fast float 1.000000e+00, %Saturate.i %Log.i = call float @dx.op.unary.f32(i32 23, float %24) #2 ; Log(value) %25 = fmul fast float %Log.i, 5.000000e+00 %Exp.i = call float @dx.op.unary.f32(i32 21, float %25) #2 ; Exp(value) - %.i015.i = fmul fast float %Exp.i, %.i010.i - %.i116.i = fmul fast float %Exp.i, %.i112.i - %.i217.i = fmul fast float %Exp.i, %.i214.i - %.i019.i = fadd fast float %.i015.i, %12 - %.i121.i = fadd fast float %.i116.i, %13 - %.i223.i = fadd fast float %.i217.i, %14 - %26 = select i1 %.i06.i, float %.i019.i, float 0.000000e+00 - %27 = select i1 %.i17.i, float %.i121.i, float 0.000000e+00 - %28 = select i1 %.i28.i, float %.i223.i, float 0.000000e+00 - %.i024.i = fmul fast float %.i0.i, %26 - %.i125.i = fmul fast float %.i0.i, %27 - %.i226.i = fmul fast float %.i0.i, %28 - %.i027.i = fadd fast float %.i024.i, %16 - %.i128.i = fadd fast float %.i125.i, %17 - %.i229.i = fadd fast float %.i226.i, %18 + %.i012.i = fmul fast float %Exp.i, %.i09.i + %.i113.i = fmul fast float %Exp.i, %.i110.i + %.i214.i = fmul fast float %Exp.i, %.i211.i + %.i015.i = fadd fast float %.i012.i, %12 + %.i116.i = fadd fast float %.i113.i, %13 + %.i217.i = fadd fast float %.i214.i, %14 + %26 = select i1 %.i06.i, float %.i015.i, float 0.000000e+00 + %27 = select i1 %.i17.i, float %.i116.i, float 0.000000e+00 + %28 = select i1 %.i28.i, float %.i217.i, float 0.000000e+00 + %.i018.i = fmul fast float %.i0.i, %26 + %.i119.i = fmul fast float %.i0.i, %27 + %.i220.i = fmul fast float %.i0.i, %28 + %.i021.i = fadd fast float %.i018.i, %16 + %.i122.i = fadd fast float %.i119.i, %17 + %.i223.i = fadd fast float %.i220.i, %18 %29 = call float @dx.op.dot3.f32(i32 55, float %7, float %8, float %9, float %4, float %5, float %6) #2 ; Dot3(ax,ay,az,bx,by,bz) - %.i030.i = fmul fast float %.i027.i, %29 - %.i131.i = fmul fast float %.i128.i, %29 - %.i232.i = fmul fast float %.i229.i, %29 - %FMax3.i = call float @dx.op.binary.f32(i32 35, float %.i030.i, float 0.000000e+00) #2 ; FMax(a,b) - %FMax4.i = call float @dx.op.binary.f32(i32 35, float %.i131.i, float 0.000000e+00) #2 ; FMax(a,b) - %FMax5.i = call float @dx.op.binary.f32(i32 35, float %.i232.i, float 0.000000e+00) #2 ; FMax(a,b) + %.i024.i = fmul fast float %.i021.i, %29 + %.i125.i = fmul fast float %.i122.i, %29 + %.i226.i = fmul fast float %.i223.i, %29 + %FMax3.i = call float @dx.op.binary.f32(i32 35, float %.i024.i, float 0.000000e+00) #2 ; FMax(a,b) + %FMax4.i = call float @dx.op.binary.f32(i32 35, float %.i125.i, float 0.000000e+00) #2 ; FMax(a,b) + %FMax5.i = call float @dx.op.binary.f32(i32 35, float %.i226.i, float 0.000000e+00) #2 ; FMax(a,b) call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float %FMax3.i) ; StoreOutput(outputSigId,rowIndex,colIndex,value) call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float %FMax4.i) ; StoreOutput(outputSigId,rowIndex,colIndex,value) call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float %FMax5.i) ; StoreOutput(outputSigId,rowIndex,colIndex,value) @@ -180,37 +170,32 @@ attributes #2 = { nounwind } !dx.valver = !{!2} !dx.shaderModel = !{!3} !dx.resources = !{!4} -!dx.typeAnnotations = !{!7, !12} -!dx.viewIdState = !{!16} -!dx.entryPoints = !{!17} +!dx.typeAnnotations = !{!7} +!dx.viewIdState = !{!11} +!dx.entryPoints = !{!12} !0 = !{!"clang version 3.7 (tags/RELEASE_370/final)"} !1 = !{i32 1, i32 0} -!2 = !{i32 1, i32 6} +!2 = !{i32 1, i32 7} !3 = !{!"ps", i32 6, i32 0} !4 = !{null, null, !5, null} !5 = !{!6} -!6 = !{i32 0, %cbPS* undef, !"cbPS", i32 0, i32 0, i32 1, i32 32, null} -!7 = !{i32 0, %cbPS undef, !8} -!8 = !{i32 32, !9, !10, !11} -!9 = !{i32 6, !"diffColor", i32 3, i32 0, i32 7, i32 9} -!10 = !{i32 6, !"specColor", i32 3, i32 16, i32 7, i32 9} -!11 = !{i32 6, !"shininess", i32 3, i32 28, i32 7, i32 9} -!12 = !{i32 1, void ()* @main, !13} -!13 = !{!14} -!14 = !{i32 0, !15, !15} -!15 = !{} -!16 = !{[17 x i32] [i32 15, i32 4, i32 0, i32 0, i32 0, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7]} -!17 = !{void ()* @main, !"main", !18, !4, null} -!18 = !{!19, !27, null} -!19 = !{!20, !22, !24, !25} -!20 = !{i32 0, !"SV_Position", i8 9, i8 3, !21, i8 4, i32 1, i8 4, i32 0, i8 0, null} -!21 = !{i32 0} -!22 = !{i32 1, !"NORMAL", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 1, i8 0, !23} -!23 = !{i32 3, i32 7} -!24 = !{i32 2, !"TEXCOORD", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 2, i8 0, !23} -!25 = !{i32 3, !"TEXCOORD", i8 9, i8 0, !26, i8 2, i32 1, i8 3, i32 3, i8 0, !23} -!26 = !{i32 1} -!27 = !{!28} -!28 = !{i32 0, !"SV_Target", i8 9, i8 16, !21, i8 0, i32 1, i8 4, i32 0, i8 0, !29} -!29 = !{i32 3, i32 15} +!6 = !{i32 0, %dx.types.Handle* undef, !"cbPS", i32 0, i32 0, i32 1, i32 32, null} +!7 = !{i32 1, void ()* @main, !8} +!8 = !{!9} +!9 = !{i32 0, !10, !10} +!10 = !{} +!11 = !{[17 x i32] [i32 15, i32 4, i32 0, i32 0, i32 0, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7, i32 0, i32 7, i32 7, i32 7]} +!12 = !{void ()* @main, !"main", !13, !4, null} +!13 = !{!14, !22, null} +!14 = !{!15, !17, !19, !20} +!15 = !{i32 0, !"SV_Position", i8 9, i8 3, !16, i8 4, i32 1, i8 4, i32 0, i8 0, null} +!16 = !{i32 0} +!17 = !{i32 1, !"NORMAL", i8 9, i8 0, !16, i8 2, i32 1, i8 3, i32 1, i8 0, !18} +!18 = !{i32 3, i32 7} +!19 = !{i32 2, !"TEXCOORD", i8 9, i8 0, !16, i8 2, i32 1, i8 3, i32 2, i8 0, !18} +!20 = !{i32 3, !"TEXCOORD", i8 9, i8 0, !21, i8 2, i32 1, i8 3, i32 3, i8 0, !18} +!21 = !{i32 1} +!22 = !{!23} +!23 = !{i32 0, !"SV_Target", i8 9, i8 16, !16, i8 0, i32 1, i8 4, i32 0, i8 0, !24} +!24 = !{i32 3, i32 15} diff --git a/Source/Tests/Data/Expected/DetailTessellation_HS.300.essl b/Source/Tests/Data/Expected/DetailTessellation_HS.300.essl index e171e8f9..6a52f4d2 100644 --- a/Source/Tests/Data/Expected/DetailTessellation_HS.300.essl +++ b/Source/Tests/Data/Expected/DetailTessellation_HS.300.essl @@ -26,27 +26,27 @@ out vec3 out_var_LIGHTVECTORTS[3]; void main() { - vec3 _58_unrolled[3]; + vec3 _59_unrolled[3]; for (int i = 0; i < int(3); i++) { - _58_unrolled[i] = in_var_WORLDPOS[i]; + _59_unrolled[i] = in_var_WORLDPOS[i]; } - vec3 _59_unrolled[3]; + vec3 _60_unrolled[3]; for (int i = 0; i < int(3); i++) { - _59_unrolled[i] = in_var_NORMAL[i]; + _60_unrolled[i] = in_var_NORMAL[i]; } - vec2 _60_unrolled[3]; + vec2 _61_unrolled[3]; for (int i = 0; i < int(3); i++) { - _60_unrolled[i] = in_var_TEXCOORD0[i]; + _61_unrolled[i] = in_var_TEXCOORD0[i]; } - vec3 _61_unrolled[3]; + vec3 _62_unrolled[3]; for (int i = 0; i < int(3); i++) { - _61_unrolled[i] = in_var_LIGHTVECTORTS[i]; + _62_unrolled[i] = in_var_LIGHTVECTORTS[i]; } - VS_OUTPUT_HS_INPUT param_var_inputPatch[3] = VS_OUTPUT_HS_INPUT[](VS_OUTPUT_HS_INPUT(_58_unrolled[0], _59_unrolled[0], _60_unrolled[0], _61_unrolled[0]), VS_OUTPUT_HS_INPUT(_58_unrolled[1], _59_unrolled[1], _60_unrolled[1], _61_unrolled[1]), VS_OUTPUT_HS_INPUT(_58_unrolled[2], _59_unrolled[2], _60_unrolled[2], _61_unrolled[2])); + VS_OUTPUT_HS_INPUT param_var_inputPatch[3] = VS_OUTPUT_HS_INPUT[](VS_OUTPUT_HS_INPUT(_59_unrolled[0], _60_unrolled[0], _61_unrolled[0], _62_unrolled[0]), VS_OUTPUT_HS_INPUT(_59_unrolled[1], _60_unrolled[1], _61_unrolled[1], _62_unrolled[1]), VS_OUTPUT_HS_INPUT(_59_unrolled[2], _60_unrolled[2], _61_unrolled[2], _62_unrolled[2])); out_var_WORLDPOS[gl_InvocationID] = param_var_inputPatch[gl_InvocationID].worldPos; out_var_NORMAL[gl_InvocationID] = param_var_inputPatch[gl_InvocationID].normal; out_var_TEXCOORD0[gl_InvocationID] = param_var_inputPatch[gl_InvocationID].texCoord; diff --git a/Source/Tests/Data/Expected/DetailTessellation_HS.300.glsl b/Source/Tests/Data/Expected/DetailTessellation_HS.300.glsl index 63408365..af83a326 100644 --- a/Source/Tests/Data/Expected/DetailTessellation_HS.300.glsl +++ b/Source/Tests/Data/Expected/DetailTessellation_HS.300.glsl @@ -27,27 +27,27 @@ layout(location = 0) out vec3 out_var_LIGHTVECTORTS[3]; void main() { - vec3 _58_unrolled[3]; + vec3 _59_unrolled[3]; for (int i = 0; i < int(3); i++) { - _58_unrolled[i] = in_var_WORLDPOS[i]; + _59_unrolled[i] = in_var_WORLDPOS[i]; } - vec3 _59_unrolled[3]; + vec3 _60_unrolled[3]; for (int i = 0; i < int(3); i++) { - _59_unrolled[i] = in_var_NORMAL[i]; + _60_unrolled[i] = in_var_NORMAL[i]; } - vec2 _60_unrolled[3]; + vec2 _61_unrolled[3]; for (int i = 0; i < int(3); i++) { - _60_unrolled[i] = in_var_TEXCOORD0[i]; + _61_unrolled[i] = in_var_TEXCOORD0[i]; } - vec3 _61_unrolled[3]; + vec3 _62_unrolled[3]; for (int i = 0; i < int(3); i++) { - _61_unrolled[i] = in_var_LIGHTVECTORTS[i]; + _62_unrolled[i] = in_var_LIGHTVECTORTS[i]; } - VS_OUTPUT_HS_INPUT param_var_inputPatch[3] = VS_OUTPUT_HS_INPUT[](VS_OUTPUT_HS_INPUT(_58_unrolled[0], _59_unrolled[0], _60_unrolled[0], _61_unrolled[0]), VS_OUTPUT_HS_INPUT(_58_unrolled[1], _59_unrolled[1], _60_unrolled[1], _61_unrolled[1]), VS_OUTPUT_HS_INPUT(_58_unrolled[2], _59_unrolled[2], _60_unrolled[2], _61_unrolled[2])); + VS_OUTPUT_HS_INPUT param_var_inputPatch[3] = VS_OUTPUT_HS_INPUT[](VS_OUTPUT_HS_INPUT(_59_unrolled[0], _60_unrolled[0], _61_unrolled[0], _62_unrolled[0]), VS_OUTPUT_HS_INPUT(_59_unrolled[1], _60_unrolled[1], _61_unrolled[1], _62_unrolled[1]), VS_OUTPUT_HS_INPUT(_59_unrolled[2], _60_unrolled[2], _61_unrolled[2], _62_unrolled[2])); out_var_WORLDPOS[gl_InvocationID] = param_var_inputPatch[gl_InvocationID].worldPos; out_var_NORMAL[gl_InvocationID] = param_var_inputPatch[gl_InvocationID].normal; out_var_TEXCOORD0[gl_InvocationID] = param_var_inputPatch[gl_InvocationID].texCoord; diff --git a/Source/Tests/Data/Expected/DetailTessellation_HS.310.essl b/Source/Tests/Data/Expected/DetailTessellation_HS.310.essl index 9e012501..5fdb913d 100644 --- a/Source/Tests/Data/Expected/DetailTessellation_HS.310.essl +++ b/Source/Tests/Data/Expected/DetailTessellation_HS.310.essl @@ -26,27 +26,27 @@ layout(location = 0) out vec3 out_var_LIGHTVECTORTS[3]; void main() { - vec3 _58_unrolled[3]; + vec3 _59_unrolled[3]; for (int i = 0; i < int(3); i++) { - _58_unrolled[i] = in_var_WORLDPOS[i]; + _59_unrolled[i] = in_var_WORLDPOS[i]; } - vec3 _59_unrolled[3]; + vec3 _60_unrolled[3]; for (int i = 0; i < int(3); i++) { - _59_unrolled[i] = in_var_NORMAL[i]; + _60_unrolled[i] = in_var_NORMAL[i]; } - vec2 _60_unrolled[3]; + vec2 _61_unrolled[3]; for (int i = 0; i < int(3); i++) { - _60_unrolled[i] = in_var_TEXCOORD0[i]; + _61_unrolled[i] = in_var_TEXCOORD0[i]; } - vec3 _61_unrolled[3]; + vec3 _62_unrolled[3]; for (int i = 0; i < int(3); i++) { - _61_unrolled[i] = in_var_LIGHTVECTORTS[i]; + _62_unrolled[i] = in_var_LIGHTVECTORTS[i]; } - VS_OUTPUT_HS_INPUT param_var_inputPatch[3] = VS_OUTPUT_HS_INPUT[](VS_OUTPUT_HS_INPUT(_58_unrolled[0], _59_unrolled[0], _60_unrolled[0], _61_unrolled[0]), VS_OUTPUT_HS_INPUT(_58_unrolled[1], _59_unrolled[1], _60_unrolled[1], _61_unrolled[1]), VS_OUTPUT_HS_INPUT(_58_unrolled[2], _59_unrolled[2], _60_unrolled[2], _61_unrolled[2])); + VS_OUTPUT_HS_INPUT param_var_inputPatch[3] = VS_OUTPUT_HS_INPUT[](VS_OUTPUT_HS_INPUT(_59_unrolled[0], _60_unrolled[0], _61_unrolled[0], _62_unrolled[0]), VS_OUTPUT_HS_INPUT(_59_unrolled[1], _60_unrolled[1], _61_unrolled[1], _62_unrolled[1]), VS_OUTPUT_HS_INPUT(_59_unrolled[2], _60_unrolled[2], _61_unrolled[2], _62_unrolled[2])); out_var_WORLDPOS[gl_InvocationID] = param_var_inputPatch[gl_InvocationID].worldPos; out_var_NORMAL[gl_InvocationID] = param_var_inputPatch[gl_InvocationID].normal; out_var_TEXCOORD0[gl_InvocationID] = param_var_inputPatch[gl_InvocationID].texCoord; diff --git a/Source/Tests/Data/Expected/DetailTessellation_HS.410.glsl b/Source/Tests/Data/Expected/DetailTessellation_HS.410.glsl index 7a4865b1..f0e031d3 100644 --- a/Source/Tests/Data/Expected/DetailTessellation_HS.410.glsl +++ b/Source/Tests/Data/Expected/DetailTessellation_HS.410.glsl @@ -25,27 +25,27 @@ layout(location = 0) out vec3 out_var_LIGHTVECTORTS[3]; void main() { - vec3 _58_unrolled[3]; + vec3 _59_unrolled[3]; for (int i = 0; i < int(3); i++) { - _58_unrolled[i] = in_var_WORLDPOS[i]; + _59_unrolled[i] = in_var_WORLDPOS[i]; } - vec3 _59_unrolled[3]; + vec3 _60_unrolled[3]; for (int i = 0; i < int(3); i++) { - _59_unrolled[i] = in_var_NORMAL[i]; + _60_unrolled[i] = in_var_NORMAL[i]; } - vec2 _60_unrolled[3]; + vec2 _61_unrolled[3]; for (int i = 0; i < int(3); i++) { - _60_unrolled[i] = in_var_TEXCOORD0[i]; + _61_unrolled[i] = in_var_TEXCOORD0[i]; } - vec3 _61_unrolled[3]; + vec3 _62_unrolled[3]; for (int i = 0; i < int(3); i++) { - _61_unrolled[i] = in_var_LIGHTVECTORTS[i]; + _62_unrolled[i] = in_var_LIGHTVECTORTS[i]; } - VS_OUTPUT_HS_INPUT param_var_inputPatch[3] = VS_OUTPUT_HS_INPUT[](VS_OUTPUT_HS_INPUT(_58_unrolled[0], _59_unrolled[0], _60_unrolled[0], _61_unrolled[0]), VS_OUTPUT_HS_INPUT(_58_unrolled[1], _59_unrolled[1], _60_unrolled[1], _61_unrolled[1]), VS_OUTPUT_HS_INPUT(_58_unrolled[2], _59_unrolled[2], _60_unrolled[2], _61_unrolled[2])); + VS_OUTPUT_HS_INPUT param_var_inputPatch[3] = VS_OUTPUT_HS_INPUT[](VS_OUTPUT_HS_INPUT(_59_unrolled[0], _60_unrolled[0], _61_unrolled[0], _62_unrolled[0]), VS_OUTPUT_HS_INPUT(_59_unrolled[1], _60_unrolled[1], _61_unrolled[1], _62_unrolled[1]), VS_OUTPUT_HS_INPUT(_59_unrolled[2], _60_unrolled[2], _61_unrolled[2], _62_unrolled[2])); out_var_WORLDPOS[gl_InvocationID] = param_var_inputPatch[gl_InvocationID].worldPos; out_var_NORMAL[gl_InvocationID] = param_var_inputPatch[gl_InvocationID].normal; out_var_TEXCOORD0[gl_InvocationID] = param_var_inputPatch[gl_InvocationID].texCoord; diff --git a/Source/Tests/Data/Expected/DetailTessellation_HS.msl b/Source/Tests/Data/Expected/DetailTessellation_HS.msl index ae523267..826e8dcd 100644 --- a/Source/Tests/Data/Expected/DetailTessellation_HS.msl +++ b/Source/Tests/Data/Expected/DetailTessellation_HS.msl @@ -81,13 +81,13 @@ kernel void main0(main0_in in [[stage_in]], constant type_cbMain& cbMain [[buffe threadgroup_barrier(mem_flags::mem_threadgroup); if (gl_InvocationID >= 3) return; - spvUnsafeArray _58 = spvUnsafeArray({ gl_in[0].in_var_WORLDPOS, gl_in[1].in_var_WORLDPOS, gl_in[2].in_var_WORLDPOS }); - spvUnsafeArray _59 = spvUnsafeArray({ gl_in[0].in_var_NORMAL, gl_in[1].in_var_NORMAL, gl_in[2].in_var_NORMAL }); - spvUnsafeArray _60 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD0, gl_in[1].in_var_TEXCOORD0, gl_in[2].in_var_TEXCOORD0 }); - spvUnsafeArray _61 = spvUnsafeArray({ gl_in[0].in_var_LIGHTVECTORTS, gl_in[1].in_var_LIGHTVECTORTS, gl_in[2].in_var_LIGHTVECTORTS }); - spvUnsafeArray _77 = spvUnsafeArray({ VS_OUTPUT_HS_INPUT{ _58[0], _59[0], _60[0], _61[0] }, VS_OUTPUT_HS_INPUT{ _58[1], _59[1], _60[1], _61[1] }, VS_OUTPUT_HS_INPUT{ _58[2], _59[2], _60[2], _61[2] } }); + spvUnsafeArray _59 = spvUnsafeArray({ gl_in[0].in_var_WORLDPOS, gl_in[1].in_var_WORLDPOS, gl_in[2].in_var_WORLDPOS }); + spvUnsafeArray _60 = spvUnsafeArray({ gl_in[0].in_var_NORMAL, gl_in[1].in_var_NORMAL, gl_in[2].in_var_NORMAL }); + spvUnsafeArray _61 = spvUnsafeArray({ gl_in[0].in_var_TEXCOORD0, gl_in[1].in_var_TEXCOORD0, gl_in[2].in_var_TEXCOORD0 }); + spvUnsafeArray _62 = spvUnsafeArray({ gl_in[0].in_var_LIGHTVECTORTS, gl_in[1].in_var_LIGHTVECTORTS, gl_in[2].in_var_LIGHTVECTORTS }); + spvUnsafeArray _78 = spvUnsafeArray({ VS_OUTPUT_HS_INPUT{ _59[0], _60[0], _61[0], _62[0] }, VS_OUTPUT_HS_INPUT{ _59[1], _60[1], _61[1], _62[1] }, VS_OUTPUT_HS_INPUT{ _59[2], _60[2], _61[2], _62[2] } }); spvUnsafeArray param_var_inputPatch; - param_var_inputPatch = _77; + param_var_inputPatch = _78; gl_out[gl_InvocationID].out_var_WORLDPOS = param_var_inputPatch[gl_InvocationID].worldPos; gl_out[gl_InvocationID].out_var_NORMAL = param_var_inputPatch[gl_InvocationID].normal; gl_out[gl_InvocationID].out_var_TEXCOORD0 = param_var_inputPatch[gl_InvocationID].texCoord; diff --git a/Source/Tests/Data/Expected/Fluid_CS.300.glsl b/Source/Tests/Data/Expected/Fluid_CS.300.glsl index 973990d2..3e55cb32 100644 --- a/Source/Tests/Data/Expected/Fluid_CS.300.glsl +++ b/Source/Tests/Data/Expected/Fluid_CS.300.glsl @@ -3,6 +3,13 @@ #extension GL_ARB_separate_shader_objects : require layout(local_size_x = 256, local_size_y = 1, local_size_z = 1) in; +struct Scene +{ + float wallStiffness; + vec4 gravity; + vec3 planes[4]; +}; + struct Particle { vec2 position; @@ -17,9 +24,7 @@ struct ParticleForces layout(std140) uniform type_cbSimulationConstants { float timeStep; - float wallStiffness; - vec4 gravity; - vec3 planes[4]; + Scene scene; } cbSimulationConstants; layout(std430) buffer type_RWStructuredBuffer_Particle @@ -43,8 +48,8 @@ void main() vec2 _54 = particlesRO._m0[gl_GlobalInvocationID.x].velocity; vec2 _56 = particlesForcesRO._m0[gl_GlobalInvocationID.x].acceleration; vec3 _59 = vec3(_52, 1.0); - float _67 = -cbSimulationConstants.wallStiffness; - vec2 _102 = _54 + ((((((_56 + (cbSimulationConstants.planes[0u].xy * (min(dot(_59, cbSimulationConstants.planes[0u]), 0.0) * _67))) + (cbSimulationConstants.planes[1u].xy * (min(dot(_59, cbSimulationConstants.planes[1u]), 0.0) * _67))) + (cbSimulationConstants.planes[2u].xy * (min(dot(_59, cbSimulationConstants.planes[2u]), 0.0) * _67))) + (cbSimulationConstants.planes[3u].xy * (min(dot(_59, cbSimulationConstants.planes[3u]), 0.0) * _67))) + cbSimulationConstants.gravity.xy) * cbSimulationConstants.timeStep); + float _67 = -cbSimulationConstants.scene.wallStiffness; + vec2 _102 = _54 + ((((((_56 + (cbSimulationConstants.scene.planes[0u].xy * (min(dot(_59, cbSimulationConstants.scene.planes[0u]), 0.0) * _67))) + (cbSimulationConstants.scene.planes[1u].xy * (min(dot(_59, cbSimulationConstants.scene.planes[1u]), 0.0) * _67))) + (cbSimulationConstants.scene.planes[2u].xy * (min(dot(_59, cbSimulationConstants.scene.planes[2u]), 0.0) * _67))) + (cbSimulationConstants.scene.planes[3u].xy * (min(dot(_59, cbSimulationConstants.scene.planes[3u]), 0.0) * _67))) + cbSimulationConstants.scene.gravity.xy) * cbSimulationConstants.timeStep); particlesRW._m0[gl_GlobalInvocationID.x].position = _52 + (_102 * cbSimulationConstants.timeStep); particlesRW._m0[gl_GlobalInvocationID.x].velocity = _102; } diff --git a/Source/Tests/Data/Expected/Fluid_CS.310.essl b/Source/Tests/Data/Expected/Fluid_CS.310.essl index 15cf2619..134b8c86 100644 --- a/Source/Tests/Data/Expected/Fluid_CS.310.essl +++ b/Source/Tests/Data/Expected/Fluid_CS.310.essl @@ -1,6 +1,13 @@ #version 310 es layout(local_size_x = 256, local_size_y = 1, local_size_z = 1) in; +struct Scene +{ + float wallStiffness; + vec4 gravity; + vec3 planes[4]; +}; + struct Particle { vec2 position; @@ -15,9 +22,7 @@ struct ParticleForces layout(binding = 0, std140) uniform type_cbSimulationConstants { float timeStep; - float wallStiffness; - vec4 gravity; - vec3 planes[4]; + Scene scene; } cbSimulationConstants; layout(binding = 0, std430) buffer type_RWStructuredBuffer_Particle @@ -41,8 +46,8 @@ void main() vec2 _54 = particlesRO._m0[gl_GlobalInvocationID.x].velocity; vec2 _56 = particlesForcesRO._m0[gl_GlobalInvocationID.x].acceleration; vec3 _59 = vec3(_52, 1.0); - float _67 = -cbSimulationConstants.wallStiffness; - vec2 _102 = _54 + ((((((_56 + (cbSimulationConstants.planes[0u].xy * (min(dot(_59, cbSimulationConstants.planes[0u]), 0.0) * _67))) + (cbSimulationConstants.planes[1u].xy * (min(dot(_59, cbSimulationConstants.planes[1u]), 0.0) * _67))) + (cbSimulationConstants.planes[2u].xy * (min(dot(_59, cbSimulationConstants.planes[2u]), 0.0) * _67))) + (cbSimulationConstants.planes[3u].xy * (min(dot(_59, cbSimulationConstants.planes[3u]), 0.0) * _67))) + cbSimulationConstants.gravity.xy) * cbSimulationConstants.timeStep); + float _67 = -cbSimulationConstants.scene.wallStiffness; + vec2 _102 = _54 + ((((((_56 + (cbSimulationConstants.scene.planes[0u].xy * (min(dot(_59, cbSimulationConstants.scene.planes[0u]), 0.0) * _67))) + (cbSimulationConstants.scene.planes[1u].xy * (min(dot(_59, cbSimulationConstants.scene.planes[1u]), 0.0) * _67))) + (cbSimulationConstants.scene.planes[2u].xy * (min(dot(_59, cbSimulationConstants.scene.planes[2u]), 0.0) * _67))) + (cbSimulationConstants.scene.planes[3u].xy * (min(dot(_59, cbSimulationConstants.scene.planes[3u]), 0.0) * _67))) + cbSimulationConstants.scene.gravity.xy) * cbSimulationConstants.timeStep); particlesRW._m0[gl_GlobalInvocationID.x].position = _52 + (_102 * cbSimulationConstants.timeStep); particlesRW._m0[gl_GlobalInvocationID.x].velocity = _102; } diff --git a/Source/Tests/Data/Expected/Fluid_CS.410.glsl b/Source/Tests/Data/Expected/Fluid_CS.410.glsl index ad246a45..3dea9b7a 100644 --- a/Source/Tests/Data/Expected/Fluid_CS.410.glsl +++ b/Source/Tests/Data/Expected/Fluid_CS.410.glsl @@ -2,6 +2,13 @@ #extension GL_ARB_compute_shader : require layout(local_size_x = 256, local_size_y = 1, local_size_z = 1) in; +struct Scene +{ + float wallStiffness; + vec4 gravity; + vec3 planes[4]; +}; + struct Particle { vec2 position; @@ -16,9 +23,7 @@ struct ParticleForces layout(std140) uniform type_cbSimulationConstants { float timeStep; - float wallStiffness; - vec4 gravity; - vec3 planes[4]; + Scene scene; } cbSimulationConstants; layout(std430) buffer type_RWStructuredBuffer_Particle @@ -42,8 +47,8 @@ void main() vec2 _54 = particlesRO._m0[gl_GlobalInvocationID.x].velocity; vec2 _56 = particlesForcesRO._m0[gl_GlobalInvocationID.x].acceleration; vec3 _59 = vec3(_52, 1.0); - float _67 = -cbSimulationConstants.wallStiffness; - vec2 _102 = _54 + ((((((_56 + (cbSimulationConstants.planes[0u].xy * (min(dot(_59, cbSimulationConstants.planes[0u]), 0.0) * _67))) + (cbSimulationConstants.planes[1u].xy * (min(dot(_59, cbSimulationConstants.planes[1u]), 0.0) * _67))) + (cbSimulationConstants.planes[2u].xy * (min(dot(_59, cbSimulationConstants.planes[2u]), 0.0) * _67))) + (cbSimulationConstants.planes[3u].xy * (min(dot(_59, cbSimulationConstants.planes[3u]), 0.0) * _67))) + cbSimulationConstants.gravity.xy) * cbSimulationConstants.timeStep); + float _67 = -cbSimulationConstants.scene.wallStiffness; + vec2 _102 = _54 + ((((((_56 + (cbSimulationConstants.scene.planes[0u].xy * (min(dot(_59, cbSimulationConstants.scene.planes[0u]), 0.0) * _67))) + (cbSimulationConstants.scene.planes[1u].xy * (min(dot(_59, cbSimulationConstants.scene.planes[1u]), 0.0) * _67))) + (cbSimulationConstants.scene.planes[2u].xy * (min(dot(_59, cbSimulationConstants.scene.planes[2u]), 0.0) * _67))) + (cbSimulationConstants.scene.planes[3u].xy * (min(dot(_59, cbSimulationConstants.scene.planes[3u]), 0.0) * _67))) + cbSimulationConstants.scene.gravity.xy) * cbSimulationConstants.timeStep); particlesRW._m0[gl_GlobalInvocationID.x].position = _52 + (_102 * cbSimulationConstants.timeStep); particlesRW._m0[gl_GlobalInvocationID.x].velocity = _102; } diff --git a/Source/Tests/Data/Expected/Fluid_CS.50.hlsl b/Source/Tests/Data/Expected/Fluid_CS.50.hlsl index 5d0456fb..6c773c5f 100644 --- a/Source/Tests/Data/Expected/Fluid_CS.50.hlsl +++ b/Source/Tests/Data/Expected/Fluid_CS.50.hlsl @@ -1,3 +1,10 @@ +struct Scene +{ + float wallStiffness; + float4 gravity; + float3 planes[4]; +}; + struct Particle { float2 position; @@ -12,9 +19,7 @@ struct ParticleForces cbuffer type_cbSimulationConstants : register(b0) { float cbSimulationConstants_timeStep : packoffset(c0); - float cbSimulationConstants_wallStiffness : packoffset(c0.y); - float4 cbSimulationConstants_gravity : packoffset(c1); - float3 cbSimulationConstants_planes[4] : packoffset(c2); + Scene cbSimulationConstants_scene : packoffset(c1); }; RWByteAddressBuffer particlesRW : register(u0); @@ -33,8 +38,8 @@ void comp_main() float2 _54 = asfloat(particlesRO.Load2(gl_GlobalInvocationID.x * 16 + 8)); float2 _56 = asfloat(particlesForcesRO.Load2(gl_GlobalInvocationID.x * 8 + 0)); float3 _59 = float3(_52, 1.0f); - float _67 = -cbSimulationConstants_wallStiffness; - float2 _102 = _54 + ((((((_56 + (cbSimulationConstants_planes[0u].xy * (min(dot(_59, cbSimulationConstants_planes[0u]), 0.0f) * _67))) + (cbSimulationConstants_planes[1u].xy * (min(dot(_59, cbSimulationConstants_planes[1u]), 0.0f) * _67))) + (cbSimulationConstants_planes[2u].xy * (min(dot(_59, cbSimulationConstants_planes[2u]), 0.0f) * _67))) + (cbSimulationConstants_planes[3u].xy * (min(dot(_59, cbSimulationConstants_planes[3u]), 0.0f) * _67))) + cbSimulationConstants_gravity.xy) * cbSimulationConstants_timeStep); + float _67 = -cbSimulationConstants_scene.wallStiffness; + float2 _102 = _54 + ((((((_56 + (cbSimulationConstants_scene.planes[0u].xy * (min(dot(_59, cbSimulationConstants_scene.planes[0u]), 0.0f) * _67))) + (cbSimulationConstants_scene.planes[1u].xy * (min(dot(_59, cbSimulationConstants_scene.planes[1u]), 0.0f) * _67))) + (cbSimulationConstants_scene.planes[2u].xy * (min(dot(_59, cbSimulationConstants_scene.planes[2u]), 0.0f) * _67))) + (cbSimulationConstants_scene.planes[3u].xy * (min(dot(_59, cbSimulationConstants_scene.planes[3u]), 0.0f) * _67))) + cbSimulationConstants_scene.gravity.xy) * cbSimulationConstants_timeStep); particlesRW.Store2(gl_GlobalInvocationID.x * 16 + 0, asuint(_52 + (_102 * cbSimulationConstants_timeStep))); particlesRW.Store2(gl_GlobalInvocationID.x * 16 + 8, asuint(_102)); } diff --git a/Source/Tests/Data/Expected/Fluid_CS.msl b/Source/Tests/Data/Expected/Fluid_CS.msl index 02457339..a30857ed 100644 --- a/Source/Tests/Data/Expected/Fluid_CS.msl +++ b/Source/Tests/Data/Expected/Fluid_CS.msl @@ -3,14 +3,19 @@ using namespace metal; -struct type_cbSimulationConstants +struct Scene { - float timeStep; float wallStiffness; float4 gravity; float3 planes[4]; }; +struct type_cbSimulationConstants +{ + float timeStep; + Scene scene; +}; + struct Particle { float2 position; @@ -43,8 +48,8 @@ kernel void main0(constant type_cbSimulationConstants& cbSimulationConstants [[b float2 _54 = particlesRO._m0[gl_GlobalInvocationID.x].velocity; float2 _56 = particlesForcesRO._m0[gl_GlobalInvocationID.x].acceleration; float3 _59 = float3(_52, 1.0); - float _67 = -cbSimulationConstants.wallStiffness; - float2 _102 = _54 + ((((((_56 + (cbSimulationConstants.planes[0u].xy * (fast::min(dot(_59, cbSimulationConstants.planes[0u]), 0.0) * _67))) + (cbSimulationConstants.planes[1u].xy * (fast::min(dot(_59, cbSimulationConstants.planes[1u]), 0.0) * _67))) + (cbSimulationConstants.planes[2u].xy * (fast::min(dot(_59, cbSimulationConstants.planes[2u]), 0.0) * _67))) + (cbSimulationConstants.planes[3u].xy * (fast::min(dot(_59, cbSimulationConstants.planes[3u]), 0.0) * _67))) + cbSimulationConstants.gravity.xy) * cbSimulationConstants.timeStep); + float _67 = -cbSimulationConstants.scene.wallStiffness; + float2 _102 = _54 + ((((((_56 + (cbSimulationConstants.scene.planes[0u].xy * (fast::min(dot(_59, cbSimulationConstants.scene.planes[0u]), 0.0) * _67))) + (cbSimulationConstants.scene.planes[1u].xy * (fast::min(dot(_59, cbSimulationConstants.scene.planes[1u]), 0.0) * _67))) + (cbSimulationConstants.scene.planes[2u].xy * (fast::min(dot(_59, cbSimulationConstants.scene.planes[2u]), 0.0) * _67))) + (cbSimulationConstants.scene.planes[3u].xy * (fast::min(dot(_59, cbSimulationConstants.scene.planes[3u]), 0.0) * _67))) + cbSimulationConstants.scene.gravity.xy) * cbSimulationConstants.timeStep); particlesRW._m0[gl_GlobalInvocationID.x].position = _52 + (_102 * cbSimulationConstants.timeStep); particlesRW._m0[gl_GlobalInvocationID.x].velocity = _102; } diff --git a/Source/Tests/Data/Expected/Transform_VS_ColumnMajor.300.glsl b/Source/Tests/Data/Expected/Transform_VS_ColumnMajor.300.glsl index ebd8cc28..86ef1136 100644 --- a/Source/Tests/Data/Expected/Transform_VS_ColumnMajor.300.glsl +++ b/Source/Tests/Data/Expected/Transform_VS_ColumnMajor.300.glsl @@ -13,8 +13,10 @@ layout(std140) uniform type_cbVS in vec4 in_var_POSITION; +mat4 spvWorkaroundRowMajor(mat4 wrap) { return wrap; } + void main() { - gl_Position = cbVS.wvp * in_var_POSITION; + gl_Position = spvWorkaroundRowMajor(cbVS.wvp) * in_var_POSITION; } diff --git a/Source/Tests/Data/Input/Fluid_CS.hlsl b/Source/Tests/Data/Input/Fluid_CS.hlsl index eb5ca57b..7bb07441 100644 --- a/Source/Tests/Data/Input/Fluid_CS.hlsl +++ b/Source/Tests/Data/Input/Fluid_CS.hlsl @@ -12,15 +12,20 @@ struct ParticleForces float2 acceleration; }; -cbuffer cbSimulationConstants : register(b0) +struct Scene { - float timeStep; float wallStiffness; float4 gravity; float3 planes[4]; }; +cbuffer cbSimulationConstants : register(b0) +{ + float timeStep; + Scene scene; +}; + RWStructuredBuffer particlesRW : register(u0); StructuredBuffer particlesRO : register(t0); @@ -38,11 +43,11 @@ void main(uint3 dtid : SV_DispatchThreadID, uint gi : SV_GroupIndex) [unroll] for (uint i = 0 ; i < 4 ; ++i) { - float dist = dot(float3(position, 1), planes[i]); - acceleration += min(dist, 0) * -wallStiffness * planes[i].xy; + float dist = dot(float3(position, 1), scene.planes[i]); + acceleration += min(dist, 0) * -scene.wallStiffness * scene.planes[i].xy; } - acceleration += gravity.xy; + acceleration += scene.gravity.xy; velocity += timeStep * acceleration; position += timeStep * velocity; diff --git a/Source/Tests/ReflectionTest.cpp b/Source/Tests/ReflectionTest.cpp new file mode 100644 index 00000000..a4db155a --- /dev/null +++ b/Source/Tests/ReflectionTest.cpp @@ -0,0 +1,1105 @@ +/* + * ShaderConductor + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. + * + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this + * software and associated documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons + * to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "Common.hpp" + +#include + +#include +#include + +using namespace ShaderConductor; + +namespace +{ + struct ReflectionTestTarget + { + Compiler::TargetDesc target; + bool isText; + std::string inputParamPrefix; + std::string outputParamPrefix; + }; + + const ReflectionTestTarget testTargets[] = {{{ShadingLanguage::Dxil, ""}, false, "", ""}, + {{ShadingLanguage::Glsl, "410"}, true, "in_var_", "out_var_"}}; + + TEST(ReflectionTest, VertexShader) + { + const std::string fileName = TEST_DATA_DIR "Input/Transform_VS.hlsl"; + + std::vector input = LoadFile(fileName, true); + const std::string source = std::string(reinterpret_cast(input.data()), input.size()); + + Compiler::Options options{}; + options.needReflection = true; + + for (const auto& testTarget : testTargets) + { + const auto result = + Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::VertexShader}, options, testTarget.target); + + EXPECT_FALSE(result.hasError); + EXPECT_EQ(result.isText, testTarget.isText); + + if (!result.reflection.Valid()) + { + GTEST_SKIP_("Dxil Reflection is not supported on this platform"); + } + + EXPECT_EQ(result.reflection.NumInputParameters(), 1U); + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(0); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "POSITION").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + EXPECT_EQ(inputParam->location, 0U); + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | + Reflection::ComponentMask::W); + } + EXPECT_EQ(result.reflection.InputParameter(1), nullptr); + + EXPECT_EQ(result.reflection.NumOutputParameters(), 1U); + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(0); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, "SV_Position"); + EXPECT_EQ(outputParam->semanticIndex, 0U); + EXPECT_EQ(outputParam->location, 0U); + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | + Reflection::ComponentMask::W); + } + EXPECT_EQ(result.reflection.OutputParameter(1), nullptr); + + EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 0U); + EXPECT_EQ(result.reflection.GSNumInstances(), 0U); + + EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::Undefined); + EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::Undefined); + + EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Undefined); + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 0U); + EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 0U); + + EXPECT_EQ(result.reflection.CSBlockSizeX(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeY(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeZ(), 0U); + + EXPECT_EQ(result.reflection.NumResources(), 1U); + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByIndex(0); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "cbVS"); + EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + EXPECT_EQ(result.reflection.ResourceByIndex(1), nullptr); + + const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); + EXPECT_NE(cbuffer, nullptr); + EXPECT_STREQ(cbuffer->Name(), "cbVS"); + EXPECT_EQ(cbuffer->Size(), 64U); + + EXPECT_EQ(cbuffer->NumVariables(), 1U); + { + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "wvp"); + EXPECT_STREQ(variable->type.Name(), "float4x4"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(variable->type.Rows(), 4U); + EXPECT_EQ(variable->type.Columns(), 4U); + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->offset, 0U); + EXPECT_EQ(variable->size, 64U); + } + EXPECT_EQ(result.reflection.ConstantBufferByIndex(1), nullptr); + } + } + } + + TEST(ReflectionTest, HullShader) + { + const std::string fileName = TEST_DATA_DIR "Input/DetailTessellation_HS.hlsl"; + + std::vector input = LoadFile(fileName, true); + const std::string source = std::string(reinterpret_cast(input.data()), input.size()); + + Compiler::Options options{}; + options.needReflection = true; + + for (const auto& testTarget : testTargets) + { + const auto result = + Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::HullShader}, options, testTarget.target); + + EXPECT_FALSE(result.hasError); + EXPECT_EQ(result.isText, testTarget.isText); + + if (!result.reflection.Valid()) + { + GTEST_SKIP_("Dxil Reflection is not supported on this platform"); + } + + EXPECT_EQ(result.reflection.NumInputParameters(), 4U); + { + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(0); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "WORLDPOS").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + EXPECT_EQ(inputParam->location, 0U); + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(1); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "NORMAL").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + EXPECT_EQ(inputParam->location, 1U); + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(2); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "TEXCOORD").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + EXPECT_EQ(inputParam->location, 2U); + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + } + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(3); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "LIGHTVECTORTS").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + EXPECT_EQ(inputParam->location, 3U); + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + } + + EXPECT_EQ(result.reflection.NumOutputParameters(), 4U); + { + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(0); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, (testTarget.outputParamPrefix + "WORLDPOS").c_str()); + EXPECT_EQ(outputParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(outputParam->location, 0U); + } + else + { + EXPECT_EQ(outputParam->location, 3U); + } + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, + Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(1); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, (testTarget.outputParamPrefix + "NORMAL").c_str()); + EXPECT_EQ(outputParam->semanticIndex, 0U); + EXPECT_EQ(outputParam->location, 1U); + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, + Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(2); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, (testTarget.outputParamPrefix + "TEXCOORD").c_str()); + EXPECT_EQ(outputParam->semanticIndex, 0U); + EXPECT_EQ(outputParam->location, 2U); + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + } + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(3); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, (testTarget.outputParamPrefix + "LIGHTVECTORTS").c_str()); + EXPECT_EQ(outputParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(outputParam->location, 3U); + } + else + { + EXPECT_EQ(outputParam->location, 0U); + } + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, + Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + } + + EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Patches_3_CtrlPoint); + EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 0U); + EXPECT_EQ(result.reflection.GSNumInstances(), 0U); + + EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::TriangleCW); + EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::FractionalOdd); + + EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Triangle); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 4U); + } + else + { + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 6U); + } + { + uint32_t numTessFactors; + if (testTarget.target.language == ShadingLanguage::Dxil) + { + numTessFactors = 3; + } + else + { + numTessFactors = 4; + } + for (uint32_t i = 0; i < numTessFactors; ++i) + { + const Reflection::SignatureParameterDesc* patchConstantParam = result.reflection.HSDSPatchConstantParameter(i); + EXPECT_NE(patchConstantParam, nullptr); + EXPECT_STRCASEEQ(patchConstantParam->semantic, "SV_TessFactor"); + EXPECT_EQ(patchConstantParam->semanticIndex, i); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(patchConstantParam->location, i); + } + else + { + EXPECT_EQ(patchConstantParam->location, 0U); + } + EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(patchConstantParam->mask, Reflection::ComponentMask::W); + } + { + const Reflection::SignatureParameterDesc* patchConstantParam = + result.reflection.HSDSPatchConstantParameter(numTessFactors); + EXPECT_NE(patchConstantParam, nullptr); + EXPECT_STRCASEEQ(patchConstantParam->semantic, "SV_InsideTessFactor"); + EXPECT_EQ(patchConstantParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(patchConstantParam->location, 3U); + } + else + { + EXPECT_EQ(patchConstantParam->location, 0U); + } + EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(patchConstantParam->mask, Reflection::ComponentMask::X); + } + } + EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 3U); + + EXPECT_EQ(result.reflection.CSBlockSizeX(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeY(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeZ(), 0U); + + EXPECT_EQ(result.reflection.NumResources(), 1U); + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByIndex(0); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "cbMain"); + EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + + const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); + EXPECT_NE(cbuffer, nullptr); + EXPECT_STRCASEEQ(cbuffer->Name(), "cbMain"); + EXPECT_EQ(cbuffer->Size(), 16U); + + EXPECT_EQ(cbuffer->NumVariables(), 1U); + { + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "tessellationFactor"); + EXPECT_STREQ(variable->type.Name(), "float4"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(variable->type.Rows(), 1U); + EXPECT_EQ(variable->type.Columns(), 4U); + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->offset, 0U); + EXPECT_EQ(variable->size, 16U); + } + } + } + } + + TEST(ReflectionTest, DomainShader) + { + const std::string fileName = TEST_DATA_DIR "Input/PNTriangles_DS.hlsl"; + + std::vector input = LoadFile(fileName, true); + const std::string source = std::string(reinterpret_cast(input.data()), input.size()); + + Compiler::Options options{}; + options.needReflection = true; + + for (const auto& testTarget : testTargets) + { + const auto result = + Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::DomainShader}, options, testTarget.target); + + EXPECT_FALSE(result.hasError); + EXPECT_EQ(result.isText, testTarget.isText); + + if (!result.reflection.Valid()) + { + GTEST_SKIP_("Dxil Reflection is not supported on this platform"); + } + + EXPECT_EQ(result.reflection.NumInputParameters(), 2U); + { + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(0); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "POSITION").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(inputParam->location, 0U); + } + else + { + EXPECT_EQ(inputParam->location, 1U); + } + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(1); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "TEXCOORD").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(inputParam->location, 1U); + } + else + { + EXPECT_EQ(inputParam->location, 8U); + } + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + } + } + + EXPECT_EQ(result.reflection.NumOutputParameters(), 2U); + { + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(0); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, "SV_Position"); + EXPECT_EQ(outputParam->semanticIndex, 0U); + EXPECT_EQ(outputParam->location, 0U); + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | + Reflection::ComponentMask::Z | Reflection::ComponentMask::W); + } + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(1); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, (testTarget.outputParamPrefix + "TEXCOORD").c_str()); + EXPECT_EQ(outputParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(outputParam->location, 1U); + } + else + { + EXPECT_EQ(outputParam->location, 0U); + } + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + } + } + + EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 0U); + EXPECT_EQ(result.reflection.GSNumInstances(), 0U); + + EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::Undefined); + EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::Undefined); + + EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Triangle); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 11U); + } + else + { + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 13U); + } + { + uint32_t numTessFactors; + if (testTarget.target.language == ShadingLanguage::Dxil) + { + numTessFactors = 3; + } + else + { + numTessFactors = 4; + } + for (uint32_t i = 0; i < numTessFactors; ++i) + { + const Reflection::SignatureParameterDesc* patchConstantParam = result.reflection.HSDSPatchConstantParameter(i); + EXPECT_NE(patchConstantParam, nullptr); + EXPECT_STRCASEEQ(patchConstantParam->semantic, "SV_TessFactor"); + EXPECT_EQ(patchConstantParam->semanticIndex, i); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(patchConstantParam->location, i); + } + else + { + EXPECT_EQ(patchConstantParam->location, 0U); + } + EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(patchConstantParam->mask, Reflection::ComponentMask::W); + } + { + const Reflection::SignatureParameterDesc* patchConstantParam = + result.reflection.HSDSPatchConstantParameter(numTessFactors); + EXPECT_NE(patchConstantParam, nullptr); + EXPECT_STRCASEEQ(patchConstantParam->semantic, "SV_InsideTessFactor"); + EXPECT_EQ(patchConstantParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(patchConstantParam->location, 3U); + } + else + { + EXPECT_EQ(patchConstantParam->location, 0U); + } + EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(patchConstantParam->mask, Reflection::ComponentMask::X); + } + + uint32_t base; + if (testTarget.target.language == ShadingLanguage::Dxil) + { + base = 4; + } + else + { + base = 6; + } + + const uint32_t dxilLocations[] = {0, 1, 2, 4, 5, 6}; + const uint32_t spirvLocations[] = {2, 3, 4, 5, 6, 7}; + for (uint32_t i = 0; i < 6; ++i) + { + const Reflection::SignatureParameterDesc* patchConstantParam = result.reflection.HSDSPatchConstantParameter(base + i); + EXPECT_NE(patchConstantParam, nullptr); + EXPECT_STRCASEEQ(patchConstantParam->semantic, (testTarget.inputParamPrefix + "POSITION").c_str()); + EXPECT_EQ(patchConstantParam->semanticIndex, i + 3); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(patchConstantParam->location, dxilLocations[i]); + } + else + { + EXPECT_EQ(patchConstantParam->location, spirvLocations[i]); + } + EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(patchConstantParam->mask, + Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + { + const Reflection::SignatureParameterDesc* patchConstantParam = result.reflection.HSDSPatchConstantParameter(base + 6); + EXPECT_NE(patchConstantParam, nullptr); + EXPECT_STRCASEEQ(patchConstantParam->semantic, (testTarget.inputParamPrefix + "CENTER").c_str()); + EXPECT_EQ(patchConstantParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(patchConstantParam->location, 7U); + } + else + { + EXPECT_EQ(patchConstantParam->location, 0U); + } + EXPECT_EQ(patchConstantParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(patchConstantParam->mask, + Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z); + } + } + EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 3U); + + EXPECT_EQ(result.reflection.CSBlockSizeX(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeY(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeZ(), 0U); + + EXPECT_EQ(result.reflection.NumResources(), 1U); + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByIndex(0); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "cbPNTriangles"); + EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + + const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); + EXPECT_NE(cbuffer, nullptr); + EXPECT_STREQ(cbuffer->Name(), "cbPNTriangles"); + EXPECT_EQ(cbuffer->Size(), 80U); + + EXPECT_EQ(cbuffer->NumVariables(), 2U); + { + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "viewProj"); + EXPECT_STREQ(variable->type.Name(), "float4x4"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(variable->type.Rows(), 4U); + EXPECT_EQ(variable->type.Columns(), 4U); + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->offset, 0U); + EXPECT_EQ(variable->size, 64U); + } + { + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(1); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "lightDir"); + EXPECT_STREQ(variable->type.Name(), "float4"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(variable->type.Rows(), 1U); + EXPECT_EQ(variable->type.Columns(), 4U); + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->offset, 64U); + EXPECT_EQ(variable->size, 16U); + } + } + } + } + + TEST(ReflectionTest, GeometryShader) + { + const std::string fileName = TEST_DATA_DIR "Input/Particle_GS.hlsl"; + + std::vector input = LoadFile(fileName, true); + const std::string source = std::string(reinterpret_cast(input.data()), input.size()); + + Compiler::Options options{}; + options.needReflection = true; + + for (const auto& testTarget : testTargets) + { + std::vector defines = {{"FIXED_VERTEX_RADIUS", "5.0"}}; + const auto result = Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::GeometryShader, defines.data(), + static_cast(defines.size())}, + options, testTarget.target); + + EXPECT_FALSE(result.hasError); + EXPECT_EQ(result.isText, testTarget.isText); + + if (!result.reflection.Valid()) + { + GTEST_SKIP_("Dxil Reflection is not supported on this platform"); + } + + EXPECT_EQ(result.reflection.NumInputParameters(), 1U); + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(0); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "POSITION").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + EXPECT_EQ(inputParam->location, 0U); + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | + Reflection::ComponentMask::W); + } + + EXPECT_EQ(result.reflection.NumOutputParameters(), 2U); + { + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(0); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, "SV_Position"); + EXPECT_EQ(outputParam->semanticIndex, 0U); + EXPECT_EQ(outputParam->location, 0U); + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | + Reflection::ComponentMask::Z | Reflection::ComponentMask::W); + } + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(1); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, (testTarget.outputParamPrefix + "TEXCOORD").c_str()); + EXPECT_EQ(outputParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(outputParam->location, 1U); + } + else + { + EXPECT_EQ(outputParam->location, 0U); + } + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + } + } + + EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Points); + EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::TriangleStrip); + EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 4U); + EXPECT_EQ(result.reflection.GSNumInstances(), 1U); + + EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::Undefined); + EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::Undefined); + + EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Undefined); + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 0U); + EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 0U); + + EXPECT_EQ(result.reflection.CSBlockSizeX(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeY(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeZ(), 0U); + + EXPECT_EQ(result.reflection.NumResources(), 1U); + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByIndex(0); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "cbMain"); + EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + + const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); + EXPECT_NE(cbuffer, nullptr); + EXPECT_STREQ(cbuffer->Name(), "cbMain"); + EXPECT_EQ(cbuffer->Size(), 128U); + + EXPECT_EQ(cbuffer->NumVariables(), 2U); + { + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "invView"); + EXPECT_STREQ(variable->type.Name(), "float4x4"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(variable->type.Rows(), 4U); + EXPECT_EQ(variable->type.Columns(), 4U); + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->offset, 0U); + EXPECT_EQ(variable->size, 64U); + } + { + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(1); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "viewProj"); + EXPECT_STREQ(variable->type.Name(), "float4x4"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(variable->type.Rows(), 4U); + EXPECT_EQ(variable->type.Columns(), 4U); + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->offset, 64U); + EXPECT_EQ(variable->size, 64U); + } + } + } + } + + TEST(ReflectionTest, PixelShader) + { + const std::string fileName = TEST_DATA_DIR "Input/ToneMapping_PS.hlsl"; + + std::vector input = LoadFile(fileName, true); + const std::string source = std::string(reinterpret_cast(input.data()), input.size()); + + Compiler::Options options{}; + options.needReflection = true; + + for (const auto& testTarget : testTargets) + { + const auto result = + Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::PixelShader}, options, testTarget.target); + + EXPECT_FALSE(result.hasError); + EXPECT_EQ(result.isText, testTarget.isText); + + if (!result.reflection.Valid()) + { + GTEST_SKIP_("Dxil Reflection is not supported on this platform"); + } + + EXPECT_EQ(result.reflection.NumInputParameters(), 2U); + { + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(0); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, "SV_Position"); + EXPECT_EQ(inputParam->semanticIndex, 0U); + EXPECT_EQ(inputParam->location, 0U); + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | + Reflection::ComponentMask::W); + } + { + const Reflection::SignatureParameterDesc* inputParam = result.reflection.InputParameter(1); + EXPECT_NE(inputParam, nullptr); + EXPECT_STRCASEEQ(inputParam->semantic, (testTarget.inputParamPrefix + "TEXCOORD").c_str()); + EXPECT_EQ(inputParam->semanticIndex, 0U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(inputParam->location, 1U); + } + else + { + EXPECT_EQ(inputParam->location, 0U); + } + EXPECT_EQ(inputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(inputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y); + } + } + + EXPECT_EQ(result.reflection.NumOutputParameters(), 1U); + { + const Reflection::SignatureParameterDesc* outputParam = result.reflection.OutputParameter(0); + EXPECT_NE(outputParam, nullptr); + EXPECT_STRCASEEQ(outputParam->semantic, (testTarget.outputParamPrefix + "SV_Target").c_str()); + EXPECT_EQ(outputParam->semanticIndex, 0U); + EXPECT_EQ(outputParam->location, 0U); + EXPECT_EQ(outputParam->componentType, Reflection::VariableType::DataType::Float); + EXPECT_EQ(outputParam->mask, Reflection::ComponentMask::X | Reflection::ComponentMask::Y | Reflection::ComponentMask::Z | + Reflection::ComponentMask::W); + } + + EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 0U); + EXPECT_EQ(result.reflection.GSNumInstances(), 0U); + + EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::Undefined); + EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::Undefined); + + EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Undefined); + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 0U); + EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 0U); + + EXPECT_EQ(result.reflection.CSBlockSizeX(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeY(), 0U); + EXPECT_EQ(result.reflection.CSBlockSizeZ(), 0U); + + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(result.reflection.NumResources(), 6U); + } + else + { + EXPECT_EQ(result.reflection.NumResources(), 9U); + } + { + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("cbPS"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "cbPS"); + EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + + const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); + EXPECT_NE(cbuffer, nullptr); + EXPECT_STREQ(cbuffer->Name(), "cbPS"); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(cbuffer->Size(), 16U); + } + else + { + EXPECT_EQ(cbuffer->Size(), 4U); + } + + EXPECT_EQ(cbuffer->NumVariables(), 1U); + { + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "lumStrength"); + EXPECT_STREQ(variable->type.Name(), "float"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(variable->type.Rows(), 1U); + EXPECT_EQ(variable->type.Columns(), 1U); + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->offset, 0U); + EXPECT_EQ(variable->size, 4U); + } + } + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("pointSampler"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "pointSampler"); + EXPECT_EQ(resource->type, ShaderResourceType::Sampler); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + } + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("linearSampler"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "linearSampler"); + EXPECT_EQ(resource->type, ShaderResourceType::Sampler); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 1U); + EXPECT_EQ(resource->bindCount, 1U); + } + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("colorTex"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "colorTex"); + EXPECT_EQ(resource->type, ShaderResourceType::Texture); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + } + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("lumTex"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "lumTex"); + EXPECT_EQ(resource->type, ShaderResourceType::Texture); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 1U); + EXPECT_EQ(resource->bindCount, 1U); + } + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("bloomTex"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "bloomTex"); + EXPECT_EQ(resource->type, ShaderResourceType::Texture); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 2U); + EXPECT_EQ(resource->bindCount, 1U); + } + EXPECT_EQ(result.reflection.ResourceByName("NotExists"), nullptr); + } + } + } + + TEST(ReflectionTest, ComputeShader) + { + const std::string fileName = TEST_DATA_DIR "Input/Fluid_CS.hlsl"; + + std::vector input = LoadFile(fileName, true); + const std::string source = std::string(reinterpret_cast(input.data()), input.size()); + + Compiler::Options options{}; + options.needReflection = true; + + for (const auto& testTarget : testTargets) + { + const auto result = + Compiler::Compile({source.c_str(), fileName.c_str(), "main", ShaderStage::ComputeShader}, options, testTarget.target); + + EXPECT_FALSE(result.hasError); + EXPECT_EQ(result.isText, testTarget.isText); + + if (!result.reflection.Valid()) + { + GTEST_SKIP_("Dxil Reflection is not supported on this platform"); + } + + EXPECT_EQ(result.reflection.NumInputParameters(), 0U); + EXPECT_EQ(result.reflection.NumOutputParameters(), 0U); + + EXPECT_EQ(result.reflection.GSHSInputPrimitive(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSOutputTopology(), Reflection::PrimitiveTopology::Undefined); + EXPECT_EQ(result.reflection.GSMaxNumOutputVertices(), 0U); + EXPECT_EQ(result.reflection.GSNumInstances(), 0U); + + EXPECT_EQ(result.reflection.HSOutputPrimitive(), Reflection::TessellatorOutputPrimitive::Undefined); + EXPECT_EQ(result.reflection.HSPartitioning(), Reflection::TessellatorPartitioning::Undefined); + + EXPECT_EQ(result.reflection.HSDSTessellatorDomain(), Reflection::TessellatorDomain::Undefined); + EXPECT_EQ(result.reflection.HSDSNumPatchConstantParameters(), 0U); + EXPECT_EQ(result.reflection.HSDSNumConrolPoints(), 0U); + + EXPECT_EQ(result.reflection.CSBlockSizeX(), 256U); + EXPECT_EQ(result.reflection.CSBlockSizeY(), 1U); + EXPECT_EQ(result.reflection.CSBlockSizeZ(), 1U); + + EXPECT_EQ(result.reflection.NumResources(), 4U); + { + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("cbSimulationConstants"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "cbSimulationConstants"); + EXPECT_EQ(resource->type, ShaderResourceType::ConstantBuffer); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + + const Reflection::ConstantBuffer* cbuffer = result.reflection.ConstantBufferByIndex(0); + EXPECT_NE(cbuffer, nullptr); + EXPECT_STREQ(cbuffer->Name(), "cbSimulationConstants"); + EXPECT_EQ(cbuffer->Size(), 112U); + + EXPECT_EQ(cbuffer->NumVariables(), 2U); + { + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(0); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "timeStep"); + EXPECT_STREQ(variable->type.Name(), "float"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(variable->type.Rows(), 1U); + EXPECT_EQ(variable->type.Columns(), 1U); + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->offset, 0U); + EXPECT_EQ(variable->size, 4U); + } + { + const Reflection::VariableDesc* variable = cbuffer->VariableByIndex(1); + EXPECT_NE(variable, nullptr); + EXPECT_STREQ(variable->name, "scene"); + EXPECT_STREQ(variable->type.Name(), "Scene"); + EXPECT_EQ(variable->type.Type(), Reflection::VariableType::DataType::Struct); + EXPECT_EQ(variable->type.Rows(), 1U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(variable->type.Columns(), 17U); + } + else + { + EXPECT_EQ(variable->type.Columns(), 1U); + } + EXPECT_EQ(variable->type.Elements(), 0U); + EXPECT_EQ(variable->type.ElementStride(), 0U); + EXPECT_EQ(variable->type.NumMembers(), 3U); + EXPECT_EQ(variable->offset, 16U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(variable->size, 92U); + } + else + { + EXPECT_EQ(variable->size, 96U); + } + + { + const Reflection::VariableDesc* member = variable->type.MemberByIndex(0); + EXPECT_NE(member, nullptr); + EXPECT_STREQ(member->name, "wallStiffness"); + EXPECT_STREQ(member->type.Name(), "float"); + EXPECT_EQ(member->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(member->type.Rows(), 1U); + EXPECT_EQ(member->type.Columns(), 1U); + EXPECT_EQ(member->type.Elements(), 0U); + EXPECT_EQ(member->type.ElementStride(), 0U); + EXPECT_EQ(member->offset, 0U); + EXPECT_EQ(member->size, 4U); + } + { + const Reflection::VariableDesc* member = variable->type.MemberByIndex(1); + EXPECT_NE(member, nullptr); + EXPECT_STREQ(member->name, "gravity"); + EXPECT_STREQ(member->type.Name(), "float4"); + EXPECT_EQ(member->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(member->type.Rows(), 1U); + EXPECT_EQ(member->type.Columns(), 4U); + EXPECT_EQ(member->type.Elements(), 0U); + EXPECT_EQ(member->type.ElementStride(), 0U); + EXPECT_EQ(member->offset, 16U); + EXPECT_EQ(member->size, 16U); + } + { + const Reflection::VariableDesc* member = variable->type.MemberByIndex(2); + EXPECT_NE(member, nullptr); + EXPECT_STREQ(member->name, "planes"); + EXPECT_STREQ(member->type.Name(), "float3"); + EXPECT_EQ(member->type.Type(), Reflection::VariableType::DataType::Float); + EXPECT_EQ(member->type.Rows(), 1U); + EXPECT_EQ(member->type.Columns(), 3U); + EXPECT_EQ(member->type.Elements(), 4U); + EXPECT_EQ(member->type.ElementStride(), 16U); + EXPECT_EQ(member->offset, 32U); + if (testTarget.target.language == ShadingLanguage::Dxil) + { + EXPECT_EQ(member->size, 60U); + } + else + { + EXPECT_EQ(member->size, 64U); + } + } + } + } + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("particlesRO"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "particlesRO"); + EXPECT_EQ(resource->type, ShaderResourceType::ShaderResourceView); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + } + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("particlesForcesRO"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "particlesForcesRO"); + EXPECT_EQ(resource->type, ShaderResourceType::ShaderResourceView); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 2U); + EXPECT_EQ(resource->bindCount, 1U); + } + { + const Reflection::ResourceDesc* resource = result.reflection.ResourceByName("particlesRW"); + EXPECT_NE(resource, nullptr); + EXPECT_STREQ(resource->name, "particlesRW"); + EXPECT_EQ(resource->type, ShaderResourceType::UnorderedAccessView); + EXPECT_EQ(resource->space, 0U); + EXPECT_EQ(resource->bindPoint, 0U); + EXPECT_EQ(resource->bindCount, 1U); + } + } + } + } +} // namespace diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 1bfe7deb..28cbb5b5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -153,6 +153,45 @@ stages: steps: - template: CI/AzurePipelines/ContinuousBuild.yml + - job: Windows_vc143_x64 + pool: + vmImage: windows-2022 + + variables: + compiler: vc143 + combination: 'win-$(compiler)-$(platform)-$(configuration)' + buildFolder: 'Build/ninja-$(combination)' + installCommand: 'choco install ninja' + testCommand: './$(buildFolder)/Bin/ShaderConductorTest.exe' + artifactBinaries: | + Bin/ShaderConductor.dll + Bin/ShaderConductorCmd.exe + Bin/dxcompiler.dll + Lib/ShaderConductor.lib + + steps: + - template: CI/AzurePipelines/ContinuousBuild.yml + + - job: Windows_vc143_arm64 + pool: + vmImage: windows-2022 + + variables: + compiler: vc143 + platform: arm64 + combination: 'win-$(compiler)-$(platform)-$(configuration)' + buildFolder: 'Build/ninja-$(combination)' + installCommand: 'choco install ninja' + testCommand: '' + artifactBinaries: | + Bin/ShaderConductor.dll + Bin/ShaderConductorCmd.exe + Bin/dxcompiler.dll + Lib/ShaderConductor.lib + + steps: + - template: CI/AzurePipelines/ContinuousBuild.yml + - job: Linux_gcc7 pool: vmImage: Ubuntu-18.04 @@ -251,14 +290,13 @@ stages: - job: macOS_10_clang pool: - vmImage: macOS 10.14 + vmImage: macOS-10.15 variables: compiler: clang9 combination: 'osx-$(compiler)-$(platform)-$(configuration)' buildFolder: 'Build/ninja-$(combination)' installCommand: | - brew update brew install ninja testCommand: './$(buildFolder)/Bin/ShaderConductorTest' artifactBinaries: |