diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2020-09-14 05:27:46 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2020-09-14 05:27:46 +0000 |
| commit | d748358793c89dd77a2c5dbbf3ca64050b1d3bb4 (patch) | |
| tree | 25008f90079aee9988a9e27851a31709df4777fa /Graphics/GLSLTools | |
| parent | Minor fix for timer query support detection in OpenGLES (diff) | |
| download | DiligentCore-d748358793c89dd77a2c5dbbf3ca64050b1d3bb4.tar.gz DiligentCore-d748358793c89dd77a2c5dbbf3ca64050b1d3bb4.zip | |
Refactoring shader compilation tools - part I (https://github.com/DiligentGraphics/DiligentCore/issues/160)
Diffstat (limited to 'Graphics/GLSLTools')
| -rw-r--r-- | Graphics/GLSLTools/CMakeLists.txt | 96 | ||||
| -rw-r--r-- | Graphics/GLSLTools/include/GLSLSourceBuilder.hpp | 48 | ||||
| -rw-r--r-- | Graphics/GLSLTools/include/SPIRVShaderResources.hpp | 412 | ||||
| -rw-r--r-- | Graphics/GLSLTools/include/SPIRVUtils.hpp | 49 | ||||
| -rw-r--r-- | Graphics/GLSLTools/src/GLSLSourceBuilder.cpp | 378 | ||||
| -rw-r--r-- | Graphics/GLSLTools/src/SPIRVShaderResources.cpp | 763 | ||||
| -rw-r--r-- | Graphics/GLSLTools/src/SPIRVUtils.cpp | 558 |
7 files changed, 0 insertions, 2304 deletions
diff --git a/Graphics/GLSLTools/CMakeLists.txt b/Graphics/GLSLTools/CMakeLists.txt deleted file mode 100644 index e6977dc8..00000000 --- a/Graphics/GLSLTools/CMakeLists.txt +++ /dev/null @@ -1,96 +0,0 @@ -cmake_minimum_required (VERSION 3.6) - -project(Diligent-GLSLTools CXX) - -set(INCLUDE - include/GLSLSourceBuilder.hpp -) - -set(SOURCE - src/GLSLSourceBuilder.cpp -) - -if(VULKAN_SUPPORTED) - list(APPEND SOURCE - src/SPIRVShaderResources.cpp - ) - list(APPEND INCLUDE - include/SPIRVShaderResources.hpp - ) - - if (NOT ${DILIGENT_NO_GLSLANG}) - list(APPEND SOURCE - src/SPIRVUtils.cpp - ) - list(APPEND INCLUDE - include/SPIRVUtils.hpp - ) - if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - # Disable the following warning: - # moving a local object in a return statement prevents copy elision [-Wpessimizing-move] - set_source_files_properties(src/SPIRVUtils.cpp - PROPERTIES - COMPILE_FLAGS -Wno-pessimizing-move - ) - endif() - endif() -endif() - -add_library(Diligent-GLSLTools STATIC ${SOURCE} ${INCLUDE}) - -target_include_directories(Diligent-GLSLTools -PUBLIC - include -PRIVATE - ../GraphicsEngine/include -) - -target_link_libraries(Diligent-GLSLTools -PRIVATE - Diligent-BuildSettings - Diligent-GraphicsAccessories - Diligent-Common -PUBLIC - Diligent-GraphicsEngineInterface -) - -target_compile_definitions(Diligent-GLSLTools PRIVATE DILIGENT_NO_HLSL=$<BOOL:${DILIGENT_NO_HLSL}>) -if (NOT ${DILIGENT_NO_HLSL}) - target_include_directories(Diligent-GLSLTools PRIVATE ../HLSL2GLSLConverterLib/include) - target_link_libraries(Diligent-GLSLTools PUBLIC Diligent-HLSL2GLSLConverterLib) -endif() - -if(VULKAN_SUPPORTED) - target_link_libraries(Diligent-GLSLTools - PRIVATE - spirv-cross-core - ) - - if (NOT ${DILIGENT_NO_GLSLANG}) - target_link_libraries(Diligent-GLSLTools - PRIVATE - glslang - SPIRV - SPIRV-Tools-opt - ) - - target_include_directories(Diligent-GLSLTools - PRIVATE - ../../ThirdParty/glslang - ) - endif() -endif() - -set_common_target_properties(Diligent-GLSLTools) - -source_group("src" FILES ${SOURCE}) -source_group("include" FILES ${INCLUDE}) -source_group("interface" FILES ${INTERFACE}) - -set_target_properties(Diligent-GLSLTools PROPERTIES - FOLDER DiligentCore/Graphics -) - -if(DILIGENT_INSTALL_CORE) - install_core_lib(Diligent-GLSLTools) -endif() diff --git a/Graphics/GLSLTools/include/GLSLSourceBuilder.hpp b/Graphics/GLSLTools/include/GLSLSourceBuilder.hpp deleted file mode 100644 index ffe36a4e..00000000 --- a/Graphics/GLSLTools/include/GLSLSourceBuilder.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2019-2020 Diligent Graphics LLC - * Copyright 2015-2019 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#pragma once - -#include "BasicTypes.h" -#include "GraphicsTypes.h" -#include "Shader.h" - -namespace Diligent -{ - -enum TargetGLSLCompiler -{ - glslang, - driver -}; - -String BuildGLSLSourceString(const ShaderCreateInfo& CreationAttribs, - const DeviceCaps& deviceCaps, - TargetGLSLCompiler TargetCompiler, - const char* ExtraDefinitions = nullptr); - -} // namespace Diligent
\ No newline at end of file diff --git a/Graphics/GLSLTools/include/SPIRVShaderResources.hpp b/Graphics/GLSLTools/include/SPIRVShaderResources.hpp deleted file mode 100644 index 7a1b93ce..00000000 --- a/Graphics/GLSLTools/include/SPIRVShaderResources.hpp +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Copyright 2019-2020 Diligent Graphics LLC - * Copyright 2015-2019 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#pragma once - -/// \file -/// Declaration of Diligent::SPIRVShaderResources class - -// SPIRVShaderResources class uses continuous chunk of memory to store all resources, as follows: -// -// m_MemoryBuffer m_TotalResources -// | | | -// | Uniform Buffers | Storage Buffers | Storage Images | Sampled Images | Atomic Counters | Separate Samplers | Separate Images | Stage Inputs | Resource Names | - -#include <memory> -#include <vector> -#include <sstream> - -#include "Shader.h" -#include "RenderDevice.h" -#include "STDAllocator.hpp" -#include "RefCntAutoPtr.hpp" -#include "StringPool.hpp" - -namespace diligent_spirv_cross -{ -class Compiler; -struct Resource; -} // namespace diligent_spirv_cross - -namespace Diligent -{ - -// sizeof(SPIRVShaderResourceAttribs) == 24, msvc x64 -struct SPIRVShaderResourceAttribs -{ - enum ResourceType : Uint8 - { - UniformBuffer = 0, - ROStorageBuffer, - RWStorageBuffer, - UniformTexelBuffer, - StorageTexelBuffer, - StorageImage, - SampledImage, - AtomicCounter, - SeparateImage, - SeparateSampler, - InputAttachment, - NumResourceTypes - }; - - // clang-format off - - static constexpr const Uint32 InvalidSepSmplrOrImgInd = static_cast<Uint32>(-1); - -/* 0 */const char* const Name; -/* 8 */const Uint16 ArraySize; -/* 10 */const ResourceType Type; -/* 11 */ // unused -private: - // Defines the mapping between separate samplers and seperate images when HLSL-style - // combined texture samplers are in use (i.e. texture2D g_Tex + sampler g_Tex_sampler). -/* 12 */ Uint32 SepSmplrOrImgInd = InvalidSepSmplrOrImgInd; -public: - // Offset in SPIRV words (uint32_t) of binding & descriptor set decorations in SPIRV binary -/* 16 */const uint32_t BindingDecorationOffset; -/* 20 */const uint32_t DescriptorSetDecorationOffset; -/* 24 */ // End of structure - - // clang-format on - - SPIRVShaderResourceAttribs(const diligent_spirv_cross::Compiler& Compiler, - const diligent_spirv_cross::Resource& Res, - const char* _Name, - ResourceType _Type, - Uint32 _SamplerOrSepImgInd = InvalidSepSmplrOrImgInd) noexcept; - - bool IsValidSepSamplerAssigned() const - { - VERIFY_EXPR(Type == SeparateImage); - return SepSmplrOrImgInd != InvalidSepSmplrOrImgInd; - } - - bool IsValidSepImageAssigned() const - { - VERIFY_EXPR(Type == SeparateSampler); - return SepSmplrOrImgInd != InvalidSepSmplrOrImgInd; - } - - Uint32 GetAssignedSepSamplerInd() const - { - VERIFY_EXPR(Type == SeparateImage); - return SepSmplrOrImgInd; - } - - Uint32 GetAssignedSepImageInd() const - { - VERIFY_EXPR(Type == SeparateSampler); - return SepSmplrOrImgInd; - } - - void AssignSeparateSampler(Uint32 SemSamplerInd) - { - VERIFY_EXPR(Type == SeparateImage); - SepSmplrOrImgInd = SemSamplerInd; - } - - void AssignSeparateImage(Uint32 SepImageInd) - { - VERIFY_EXPR(Type == SeparateSampler); - SepSmplrOrImgInd = SepImageInd; - } - - String GetPrintName(Uint32 ArrayInd) const - { - VERIFY_EXPR(ArrayInd < ArraySize); - if (ArraySize > 1) - { - std::stringstream ss; - ss << Name << '[' << ArrayInd << ']'; - return ss.str(); - } - else - return Name; - } - - bool IsCompatibleWith(const SPIRVShaderResourceAttribs& Attribs) const - { - // clang-format off - return ArraySize == Attribs.ArraySize && - Type == Attribs.Type && - SepSmplrOrImgInd == Attribs.SepSmplrOrImgInd; - // clang-format on - } - - ShaderResourceDesc GetResourceDesc() const; -}; -static_assert(sizeof(SPIRVShaderResourceAttribs) % sizeof(void*) == 0, "Size of SPIRVShaderResourceAttribs struct must be multiple of sizeof(void*)"); - -// sizeof(SPIRVShaderResourceAttribs) == 16, msvc x64 -struct SPIRVShaderStageInputAttribs -{ - // clang-format off - SPIRVShaderStageInputAttribs(const char* _Semantic, uint32_t _LocationDecorationOffset) : - Semantic {_Semantic}, - LocationDecorationOffset {_LocationDecorationOffset} - {} - // clang-format on - - const char* const Semantic; - const uint32_t LocationDecorationOffset; -}; -static_assert(sizeof(SPIRVShaderStageInputAttribs) % sizeof(void*) == 0, "Size of SPIRVShaderStageInputAttribs struct must be multiple of sizeof(void*)"); - -/// Diligent::SPIRVShaderResources class -class SPIRVShaderResources -{ -public: - SPIRVShaderResources(IMemoryAllocator& Allocator, - IRenderDevice* pRenderDevice, - std::vector<uint32_t> spirv_binary, - const ShaderDesc& shaderDesc, - const char* CombinedSamplerSuffix, - bool LoadShaderStageInputs, - std::string& EntryPoint); - - // clang-format off - SPIRVShaderResources (const SPIRVShaderResources&) = delete; - SPIRVShaderResources ( SPIRVShaderResources&&) = delete; - SPIRVShaderResources& operator = (const SPIRVShaderResources&) = delete; - SPIRVShaderResources& operator = ( SPIRVShaderResources&&) = delete; - // clang-format on - - ~SPIRVShaderResources(); - - // clang-format off - - Uint32 GetNumUBs ()const noexcept{ return (m_StorageBufferOffset - 0); } - Uint32 GetNumSBs ()const noexcept{ return (m_StorageImageOffset - m_StorageBufferOffset); } - Uint32 GetNumImgs ()const noexcept{ return (m_SampledImageOffset - m_StorageImageOffset); } - Uint32 GetNumSmpldImgs()const noexcept{ return (m_AtomicCounterOffset - m_SampledImageOffset); } - Uint32 GetNumACs ()const noexcept{ return (m_SeparateSamplerOffset - m_AtomicCounterOffset); } - Uint32 GetNumSepSmplrs()const noexcept{ return (m_SeparateImageOffset - m_SeparateSamplerOffset);} - Uint32 GetNumSepImgs ()const noexcept{ return (m_InputAttachmentOffset - m_SeparateImageOffset); } - Uint32 GetNumInptAtts ()const noexcept{ return (m_TotalResources - m_InputAttachmentOffset);} - Uint32 GetTotalResources() const noexcept { return m_TotalResources; } - Uint32 GetNumShaderStageInputs()const noexcept { return m_NumShaderStageInputs; } - - const SPIRVShaderResourceAttribs& GetUB (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumUBs(), 0 ); } - const SPIRVShaderResourceAttribs& GetSB (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSBs(), m_StorageBufferOffset ); } - const SPIRVShaderResourceAttribs& GetImg (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumImgs(), m_StorageImageOffset ); } - const SPIRVShaderResourceAttribs& GetSmpldImg(Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSmpldImgs(), m_SampledImageOffset ); } - const SPIRVShaderResourceAttribs& GetAC (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumACs(), m_AtomicCounterOffset ); } - const SPIRVShaderResourceAttribs& GetSepSmplr(Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSepSmplrs(), m_SeparateSamplerOffset); } - const SPIRVShaderResourceAttribs& GetSepImg (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumSepImgs(), m_SeparateImageOffset ); } - const SPIRVShaderResourceAttribs& GetInptAtt (Uint32 n)const noexcept{ return GetResAttribs(n, GetNumInptAtts(), m_InputAttachmentOffset); } - const SPIRVShaderResourceAttribs& GetResource(Uint32 n)const noexcept{ return GetResAttribs(n, GetTotalResources(), 0 ); } - - // clang-format on - - const SPIRVShaderStageInputAttribs& GetShaderStageInputAttribs(Uint32 n) const noexcept - { - VERIFY(n < m_NumShaderStageInputs, "Shader stage input index (", n, ") is out of range. Total input count: ", m_NumShaderStageInputs); - auto* ResourceMemoryEnd = reinterpret_cast<const SPIRVShaderResourceAttribs*>(m_MemoryBuffer.get()) + m_TotalResources; - return reinterpret_cast<const SPIRVShaderStageInputAttribs*>(ResourceMemoryEnd)[n]; - } - - const SPIRVShaderResourceAttribs& GetAssignedSepSampler(const SPIRVShaderResourceAttribs& SepImg) const - { - VERIFY(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage, "Separate samplers can only be assigned to separate images"); - VERIFY(SepImg.IsValidSepSamplerAssigned(), "This separate image is not assigned a separate sampler"); - return GetSepSmplr(SepImg.GetAssignedSepSamplerInd()); - } - - struct ResourceCounters - { - Uint32 NumUBs = 0; - Uint32 NumSBs = 0; - Uint32 NumImgs = 0; - Uint32 NumSmpldImgs = 0; - Uint32 NumACs = 0; - Uint32 NumSepSmplrs = 0; - Uint32 NumSepImgs = 0; - Uint32 NumInptAtts = 0; - }; - - SHADER_TYPE GetShaderType() const noexcept { return m_ShaderType; } - - // Process only resources listed in AllowedVarTypes - template <typename THandleUB, - typename THandleSB, - typename THandleImg, - typename THandleSmplImg, - typename THandleAC, - typename THandleSepSmpl, - typename THandleSepImg, - typename THandleInptAtt> - void ProcessResources(THandleUB HandleUB, - THandleSB HandleSB, - THandleImg HandleImg, - THandleSmplImg HandleSmplImg, - THandleAC HandleAC, - THandleSepSmpl HandleSepSmpl, - THandleSepImg HandleSepImg, - THandleInptAtt HandleInptAtt) const - { - for (Uint32 n = 0; n < GetNumUBs(); ++n) - { - const auto& UB = GetUB(n); - HandleUB(UB, n); - } - - for (Uint32 n = 0; n < GetNumSBs(); ++n) - { - const auto& SB = GetSB(n); - HandleSB(SB, n); - } - - for (Uint32 n = 0; n < GetNumImgs(); ++n) - { - const auto& Img = GetImg(n); - HandleImg(Img, n); - } - - for (Uint32 n = 0; n < GetNumSmpldImgs(); ++n) - { - const auto& SmplImg = GetSmpldImg(n); - HandleSmplImg(SmplImg, n); - } - - for (Uint32 n = 0; n < GetNumACs(); ++n) - { - const auto& AC = GetAC(n); - HandleAC(AC, n); - } - - for (Uint32 n = 0; n < GetNumSepSmplrs(); ++n) - { - const auto& SepSmpl = GetSepSmplr(n); - HandleSepSmpl(SepSmpl, n); - } - - for (Uint32 n = 0; n < GetNumSepImgs(); ++n) - { - const auto& SepImg = GetSepImg(n); - HandleSepImg(SepImg, n); - } - - for (Uint32 n = 0; n < GetNumInptAtts(); ++n) - { - const auto& InptAtt = GetInptAtt(n); - HandleInptAtt(InptAtt, n); - } - - static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please handle the new resource type here, if needed"); - } - - template <typename THandler> - void ProcessResources(THandler Handler) const - { - for (Uint32 n = 0; n < GetTotalResources(); ++n) - { - const auto& Res = GetResource(n); - Handler(Res, n); - } - } - - std::string DumpResources(); - - bool IsCompatibleWith(const SPIRVShaderResources& Resources) const; - - // clang-format off - - const char* GetCombinedSamplerSuffix() const { return m_CombinedSamplerSuffix; } - const char* GetShaderName() const { return m_ShaderName; } - bool IsUsingCombinedSamplers() const { return m_CombinedSamplerSuffix != nullptr; } - - // clang-format on - - bool IsHLSLSource() const { return m_IsHLSLSource; } - -private: - void Initialize(IMemoryAllocator& Allocator, - const ResourceCounters& Counters, - Uint32 NumShaderStageInputs, - size_t ResourceNamesPoolSize); - - SPIRVShaderResourceAttribs& GetResAttribs(Uint32 n, Uint32 NumResources, Uint32 Offset) noexcept - { - VERIFY(n < NumResources, "Resource index (", n, ") is out of range. Total resource count: ", NumResources); - VERIFY_EXPR(Offset + n < m_TotalResources); - return reinterpret_cast<SPIRVShaderResourceAttribs*>(m_MemoryBuffer.get())[Offset + n]; - } - - const SPIRVShaderResourceAttribs& GetResAttribs(Uint32 n, Uint32 NumResources, Uint32 Offset) const noexcept - { - VERIFY(n < NumResources, "Resource index (", n, ") is out of range. Total resource count: ", NumResources); - VERIFY_EXPR(Offset + n < m_TotalResources); - return reinterpret_cast<SPIRVShaderResourceAttribs*>(m_MemoryBuffer.get())[Offset + n]; - } - - // clang-format off - - SPIRVShaderResourceAttribs& GetUB (Uint32 n)noexcept{ return GetResAttribs(n, GetNumUBs(), 0 ); } - SPIRVShaderResourceAttribs& GetSB (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSBs(), m_StorageBufferOffset ); } - SPIRVShaderResourceAttribs& GetImg (Uint32 n)noexcept{ return GetResAttribs(n, GetNumImgs(), m_StorageImageOffset ); } - SPIRVShaderResourceAttribs& GetSmpldImg(Uint32 n)noexcept{ return GetResAttribs(n, GetNumSmpldImgs(), m_SampledImageOffset ); } - SPIRVShaderResourceAttribs& GetAC (Uint32 n)noexcept{ return GetResAttribs(n, GetNumACs(), m_AtomicCounterOffset ); } - SPIRVShaderResourceAttribs& GetSepSmplr(Uint32 n)noexcept{ return GetResAttribs(n, GetNumSepSmplrs(), m_SeparateSamplerOffset); } - SPIRVShaderResourceAttribs& GetSepImg (Uint32 n)noexcept{ return GetResAttribs(n, GetNumSepImgs(), m_SeparateImageOffset ); } - SPIRVShaderResourceAttribs& GetInptAtt (Uint32 n)noexcept{ return GetResAttribs(n, GetNumInptAtts(), m_InputAttachmentOffset); } - SPIRVShaderResourceAttribs& GetResource(Uint32 n)noexcept{ return GetResAttribs(n, GetTotalResources(), 0 ); } - - // clang-format on - - SPIRVShaderStageInputAttribs& GetShaderStageInputAttribs(Uint32 n) noexcept - { - return const_cast<SPIRVShaderStageInputAttribs&>(const_cast<const SPIRVShaderResources*>(this)->GetShaderStageInputAttribs(n)); - } - - // Memory buffer that holds all resources as continuous chunk of memory: - // | UBs | SBs | StrgImgs | SmplImgs | ACs | SepSamplers | SepImgs | Stage Inputs | Resource Names | - std::unique_ptr<void, STDDeleterRawMem<void>> m_MemoryBuffer; - - StringPool m_ResourceNames; - - const char* m_CombinedSamplerSuffix = nullptr; - const char* m_ShaderName = nullptr; - - using OffsetType = Uint16; - OffsetType m_StorageBufferOffset = 0; - OffsetType m_StorageImageOffset = 0; - OffsetType m_SampledImageOffset = 0; - OffsetType m_AtomicCounterOffset = 0; - OffsetType m_SeparateSamplerOffset = 0; - OffsetType m_SeparateImageOffset = 0; - OffsetType m_InputAttachmentOffset = 0; - OffsetType m_TotalResources = 0; - OffsetType m_NumShaderStageInputs = 0; - - SHADER_TYPE m_ShaderType = SHADER_TYPE_UNKNOWN; - - // Inidicates if the shader was compiled from HLSL source. - bool m_IsHLSLSource = false; -}; - -} // namespace Diligent diff --git a/Graphics/GLSLTools/include/SPIRVUtils.hpp b/Graphics/GLSLTools/include/SPIRVUtils.hpp deleted file mode 100644 index 50025303..00000000 --- a/Graphics/GLSLTools/include/SPIRVUtils.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2019-2020 Diligent Graphics LLC - * Copyright 2015-2019 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#pragma once - -#include <vector> -#include "Shader.h" -#include "DataBlob.h" - -namespace Diligent -{ - -void InitializeGlslang(); -void FinalizeGlslang(); - -std::vector<unsigned int> GLSLtoSPIRV(SHADER_TYPE ShaderType, - const char* ShaderSource, - int SourceCodeLen, - IDataBlob** ppCompilerOutput); - -std::vector<unsigned int> HLSLtoSPIRV(const ShaderCreateInfo& Attribs, - const char* ExtraDefinitions, - IDataBlob** ppCompilerOutput); - -} // namespace Diligent
\ No newline at end of file diff --git a/Graphics/GLSLTools/src/GLSLSourceBuilder.cpp b/Graphics/GLSLTools/src/GLSLSourceBuilder.cpp deleted file mode 100644 index dfb4d757..00000000 --- a/Graphics/GLSLTools/src/GLSLSourceBuilder.cpp +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright 2019-2020 Diligent Graphics LLC - * Copyright 2015-2019 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#include <cstring> -#include <sstream> - -#include "GLSLSourceBuilder.hpp" -#include "DebugUtilities.hpp" -#if !DILIGENT_NO_HLSL -# include "HLSL2GLSLConverterImpl.hpp" -#endif -#include "RefCntAutoPtr.hpp" -#include "DataBlobImpl.hpp" - -namespace Diligent -{ - -const char* GetShaderTypeDefines(SHADER_TYPE Type) -{ - switch (Type) - { - case SHADER_TYPE_VERTEX: - return "#define VERTEX_SHADER 1\n"; - - case SHADER_TYPE_PIXEL: - return "#define FRAGMENT_SHADER 1\n" - "#define PIXEL_SHADER 1\n"; - - case SHADER_TYPE_GEOMETRY: - return "#define GEOMETRY_SHADER 1\n"; - - case SHADER_TYPE_HULL: - return "#define TESS_CONTROL_SHADER 1\n" - "#define HULL_SHADER 1\n"; - - case SHADER_TYPE_DOMAIN: - return "#define TESS_EVALUATION_SHADER 1\n" - "#define DOMAIN_SHADER 1\n"; - break; - - case SHADER_TYPE_COMPUTE: - return "#define COMPUTE_SHADER 1\n"; - - case SHADER_TYPE_AMPLIFICATION: - return "#define TASK_SHADER 1\n" - "#define AMPLIFICATION_SHADER 1\n"; - - case SHADER_TYPE_MESH: - return "#define MESH_SHADER 1\n"; - - default: - UNEXPECTED("Unexpected shader type"); - return nullptr; - } -} - -String BuildGLSLSourceString(const ShaderCreateInfo& CreationAttribs, - const DeviceCaps& deviceCaps, - TargetGLSLCompiler TargetCompiler, - const char* ExtraDefinitions) -{ - String GLSLSource; - - if (CreationAttribs.SourceLanguage == SHADER_SOURCE_LANGUAGE_GLSL_VERBATIM && CreationAttribs.Macros != nullptr) - LOG_WARNING_MESSAGE("Shader macros are ignored when compiling GLSL verbatim"); - - if (CreationAttribs.SourceLanguage != SHADER_SOURCE_LANGUAGE_GLSL_VERBATIM) - { - auto ShaderType = CreationAttribs.Desc.ShaderType; - -#if PLATFORM_WIN32 || PLATFORM_LINUX - GLSLSource.append( - "#version 430 core\n" - "#define DESKTOP_GL 1\n"); -# if PLATFORM_WIN32 - GLSLSource.append("#define PLATFORM_WIN32 1\n"); -# elif PLATFORM_LINUX - GLSLSource.append("#define PLATFORM_LINUX 1\n"); -# else -# error Unexpected platform -# endif -#elif PLATFORM_MACOS - if (TargetCompiler == TargetGLSLCompiler::glslang) - GLSLSource.append("#version 430 core\n"); - else if (TargetCompiler == TargetGLSLCompiler::driver) - GLSLSource.append("#version 410 core\n"); - else - UNEXPECTED("Unexpected target GLSL compiler"); - - GLSLSource.append( - "#define DESKTOP_GL 1\n" - "#define PLATFORM_MACOS 1\n"); - -#elif PLATFORM_ANDROID || PLATFORM_IOS - bool IsES30 = false; - bool IsES31OrAbove = false; - bool IsES32OrAbove = false; - if (deviceCaps.DevType == RENDER_DEVICE_TYPE_VULKAN) - { - IsES30 = false; - IsES31OrAbove = true; - IsES32OrAbove = false; - GLSLSource.append("#version 310 es\n"); - } - else if (deviceCaps.DevType == RENDER_DEVICE_TYPE_GLES) - { - IsES30 = deviceCaps.MajorVersion == 3 && deviceCaps.MinorVersion == 0; - IsES31OrAbove = deviceCaps.MajorVersion > 3 || (deviceCaps.MajorVersion == 3 && deviceCaps.MinorVersion >= 1); - IsES32OrAbove = deviceCaps.MajorVersion > 3 || (deviceCaps.MajorVersion == 3 && deviceCaps.MinorVersion >= 2); - std::stringstream versionss; - versionss << "#version " << deviceCaps.MajorVersion << deviceCaps.MinorVersion << "0 es\n"; - GLSLSource.append(versionss.str()); - } - else - { - UNEXPECTED("Unexpected device type"); - } - - if (deviceCaps.Features.SeparablePrograms && !IsES31OrAbove) - GLSLSource.append("#extension GL_EXT_separate_shader_objects : enable\n"); - - if (deviceCaps.TexCaps.CubemapArraysSupported && !IsES32OrAbove) - GLSLSource.append("#extension GL_EXT_texture_cube_map_array : enable\n"); - - if (ShaderType == SHADER_TYPE_GEOMETRY && !IsES32OrAbove) - GLSLSource.append("#extension GL_EXT_geometry_shader : enable\n"); - - if ((ShaderType == SHADER_TYPE_HULL || ShaderType == SHADER_TYPE_DOMAIN) && !IsES32OrAbove) - GLSLSource.append("#extension GL_EXT_tessellation_shader : enable\n"); - - GLSLSource.append( - "#ifndef GL_ES\n" - "# define GL_ES 1\n" - "#endif\n"); - -# if PLATFORM_ANDROID - GLSLSource.append("#define PLATFORM_ANDROID 1\n"); -# elif PLATFORM_IOS - GLSLSource.append("#define PLATFORM_IOS 1\n"); -# else -# error "Unexpected platform" -# endif - - GLSLSource.append( - "precision highp float;\n" - "precision highp int;\n" - //"precision highp uint;\n" // This line causes shader compilation error on NVidia! - - "precision highp sampler2D;\n" - "precision highp sampler3D;\n" - "precision highp samplerCube;\n" - "precision highp samplerCubeShadow;\n" - - "precision highp sampler2DShadow;\n" - "precision highp sampler2DArray;\n" - "precision highp sampler2DArrayShadow;\n" - - "precision highp isampler2D;\n" - "precision highp isampler3D;\n" - "precision highp isamplerCube;\n" - "precision highp isampler2DArray;\n" - - "precision highp usampler2D;\n" - "precision highp usampler3D;\n" - "precision highp usamplerCube;\n" - "precision highp usampler2DArray;\n" // clang-format off - ); // clang-format on - - if (IsES32OrAbove) - { - GLSLSource.append( - "precision highp samplerBuffer;\n" - "precision highp isamplerBuffer;\n" - "precision highp usamplerBuffer;\n" // clang-format off - ); // clang-format on - } - - if (deviceCaps.TexCaps.CubemapArraysSupported) - { - GLSLSource.append( - "precision highp samplerCubeArray;\n" - "precision highp samplerCubeArrayShadow;\n" - "precision highp isamplerCubeArray;\n" - "precision highp usamplerCubeArray;\n" // clang-format off - ); // clang-format on - } - - if (deviceCaps.TexCaps.Texture2DMSSupported) - { - GLSLSource.append( - "precision highp sampler2DMS;\n" - "precision highp isampler2DMS;\n" - "precision highp usampler2DMS;\n" // clang-format off - ); // clang-format on - } - - if (deviceCaps.Features.ComputeShaders) - { - GLSLSource.append( - "precision highp image2D;\n" - "precision highp image3D;\n" - "precision highp imageCube;\n" - "precision highp image2DArray;\n" - - "precision highp iimage2D;\n" - "precision highp iimage3D;\n" - "precision highp iimageCube;\n" - "precision highp iimage2DArray;\n" - - "precision highp uimage2D;\n" - "precision highp uimage3D;\n" - "precision highp uimageCube;\n" - "precision highp uimage2DArray;\n" // clang-format off - ); // clang-format on - if (IsES32OrAbove) - { - GLSLSource.append( - "precision highp imageBuffer;\n" - "precision highp iimageBuffer;\n" - "precision highp uimageBuffer;\n" // clang-format off - ); // clang-format on - } - } - - if (IsES30 && deviceCaps.Features.SeparablePrograms && ShaderType == SHADER_TYPE_VERTEX) - { - // From https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_separate_shader_objects.gles.txt: - // - // When using GLSL ES 3.00 shaders in separable programs, gl_Position and - // gl_PointSize built-in outputs must be redeclared according to Section 7.5 - // of the OpenGL Shading Language Specification... - // - // add to GLSL ES 3.00 new section 7.5, Built-In Redeclaration and - // Separable Programs: - // - // "The following vertex shader outputs may be redeclared at global scope to - // specify a built-in output interface, with or without special qualifiers: - // - // gl_Position - // gl_PointSize - // - // When compiling shaders using either of the above variables, both such - // variables must be redeclared prior to use. ((Note: This restriction - // applies only to shaders using version 300 that enable the - // EXT_separate_shader_objects extension; shaders not enabling the - // extension do not have this requirement.)) A separable program object - // will fail to link if any attached shader uses one of the above variables - // without redeclaration." - GLSLSource.append("out vec4 gl_Position;\n"); - } - -#elif -# error "Undefined platform" -#endif - - // It would be much more convenient to use row_major matrices. - // But unfortunatelly on NVIDIA, the following directive - // layout(std140, row_major) uniform; - // does not have any effect on matrices that are part of structures - // So we have to use column-major matrices which are default in both - // DX and GLSL. - GLSLSource.append( - "layout(std140) uniform;\n"); - - if (ShaderType == SHADER_TYPE_VERTEX && TargetCompiler == TargetGLSLCompiler::glslang) - { - // https://github.com/KhronosGroup/GLSL/blob/master/extensions/khr/GL_KHR_vulkan_glsl.txt - GLSLSource.append("#define gl_VertexID gl_VertexIndex\n" - "#define gl_InstanceID gl_InstanceIndex\n"); - } - - if (const auto* ShaderTypeDefine = GetShaderTypeDefines(ShaderType)) - GLSLSource += ShaderTypeDefine; - - if (ExtraDefinitions != nullptr) - { - GLSLSource.append(ExtraDefinitions); - } - - if (CreationAttribs.Macros != nullptr) - { - auto* pMacro = CreationAttribs.Macros; - while (pMacro->Name != nullptr && pMacro->Definition != nullptr) - { - GLSLSource += "#define "; - GLSLSource += pMacro->Name; - GLSLSource += ' '; - GLSLSource += pMacro->Definition; - GLSLSource += "\n"; - ++pMacro; - } - } - } - - RefCntAutoPtr<IDataBlob> pFileData(MakeNewRCObj<DataBlobImpl>()(0)); - - auto ShaderSource = CreationAttribs.Source; - size_t SourceLen = 0; - if (ShaderSource) - { - SourceLen = strlen(ShaderSource); - } - else - { - VERIFY(CreationAttribs.pShaderSourceStreamFactory, "Input stream factory is null"); - RefCntAutoPtr<IFileStream> pSourceStream; - CreationAttribs.pShaderSourceStreamFactory->CreateInputStream(CreationAttribs.FilePath, &pSourceStream); - if (pSourceStream == nullptr) - LOG_ERROR_AND_THROW("Failed to open shader source file"); - - pSourceStream->ReadBlob(pFileData); - ShaderSource = reinterpret_cast<char*>(pFileData->GetDataPtr()); - SourceLen = pFileData->GetSize(); - } - - if (CreationAttribs.SourceLanguage == SHADER_SOURCE_LANGUAGE_HLSL) - { -#if DILIGENT_NO_HLSL - LOG_ERROR_AND_THROW("Unable to convert HLSL source to GLSL: HLSL support is disabled"); -#else - if (!CreationAttribs.UseCombinedTextureSamplers) - { - LOG_ERROR_AND_THROW("Combined texture samplers are required to convert HLSL source to GLSL"); - } - // Convert HLSL to GLSL - const auto& Converter = HLSL2GLSLConverterImpl::GetInstance(); - - HLSL2GLSLConverterImpl::ConversionAttribs Attribs; - Attribs.pSourceStreamFactory = CreationAttribs.pShaderSourceStreamFactory; - Attribs.ppConversionStream = CreationAttribs.ppConversionStream; - Attribs.HLSLSource = ShaderSource; - Attribs.NumSymbols = SourceLen; - Attribs.EntryPoint = CreationAttribs.EntryPoint; - Attribs.ShaderType = CreationAttribs.Desc.ShaderType; - Attribs.IncludeDefinitions = true; - Attribs.InputFileName = CreationAttribs.FilePath; - Attribs.SamplerSuffix = CreationAttribs.CombinedSamplerSuffix; - // Separate shader objects extension also allows input/output layout qualifiers for - // all shader stages. - // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_separate_shader_objects.txt - // (search for "Input Layout Qualifiers" and "Output Layout Qualifiers"). - Attribs.UseInOutLocationQualifiers = deviceCaps.Features.SeparablePrograms; - auto ConvertedSource = Converter.Convert(Attribs); - - GLSLSource.append(ConvertedSource); -#endif - } - else - GLSLSource.append(ShaderSource, SourceLen); - - return GLSLSource; -} - -} // namespace Diligent diff --git a/Graphics/GLSLTools/src/SPIRVShaderResources.cpp b/Graphics/GLSLTools/src/SPIRVShaderResources.cpp deleted file mode 100644 index 2ba5d90a..00000000 --- a/Graphics/GLSLTools/src/SPIRVShaderResources.cpp +++ /dev/null @@ -1,763 +0,0 @@ -/* - * Copyright 2019-2020 Diligent Graphics LLC - * Copyright 2015-2019 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#include <iomanip> -#include "SPIRVShaderResources.hpp" -#include "spirv_parser.hpp" -#include "spirv_cross.hpp" -#include "ShaderBase.hpp" -#include "GraphicsAccessories.hpp" -#include "StringTools.hpp" -#include "Align.hpp" - -namespace Diligent -{ - -template <typename Type> -Type GetResourceArraySize(const diligent_spirv_cross::Compiler& Compiler, - const diligent_spirv_cross::Resource& Res) -{ - const auto& type = Compiler.get_type(Res.type_id); - uint32_t arrSize = 1; - if (!type.array.empty()) - { - // https://github.com/KhronosGroup/SPIRV-Cross/wiki/Reflection-API-user-guide#querying-array-types - VERIFY(type.array.size() == 1, "Only one-dimensional arrays are currently supported"); - arrSize = type.array[0]; - } - VERIFY(arrSize <= std::numeric_limits<Type>::max(), "Array size exceeds maximum representable value ", std::numeric_limits<Type>::max()); - return static_cast<Type>(arrSize); -} - -static uint32_t GetDecorationOffset(const diligent_spirv_cross::Compiler& Compiler, - const diligent_spirv_cross::Resource& Res, - spv::Decoration Decoration) -{ - VERIFY(Compiler.has_decoration(Res.id, Decoration), "Resource \'", Res.name, "\' has no requested decoration"); - uint32_t offset = 0; - auto declared = Compiler.get_binary_offset_for_decoration(Res.id, Decoration, offset); - VERIFY(declared, "Requested decoration is not declared"); - (void)declared; - return offset; -} - -SPIRVShaderResourceAttribs::SPIRVShaderResourceAttribs(const diligent_spirv_cross::Compiler& Compiler, - const diligent_spirv_cross::Resource& Res, - const char* _Name, - ResourceType _Type, - Uint32 _SepSmplrOrImgInd) noexcept : - // clang-format off - Name {_Name}, - ArraySize {GetResourceArraySize<decltype(ArraySize)>(Compiler, Res)}, - Type {_Type}, - SepSmplrOrImgInd {_SepSmplrOrImgInd}, - BindingDecorationOffset {GetDecorationOffset(Compiler, Res, spv::Decoration::DecorationBinding)}, - DescriptorSetDecorationOffset {GetDecorationOffset(Compiler, Res, spv::Decoration::DecorationDescriptorSet)} -// clang-format on -{ - VERIFY(_SepSmplrOrImgInd == SPIRVShaderResourceAttribs::InvalidSepSmplrOrImgInd || - (_Type == ResourceType::SeparateSampler || _Type == ResourceType::SeparateImage), - "Only separate images or separate samplers can be assinged valid SepSmplrOrImgInd value"); -} - - -ShaderResourceDesc SPIRVShaderResourceAttribs::GetResourceDesc() const -{ - ShaderResourceDesc ResourceDesc; - ResourceDesc.Name = Name; - ResourceDesc.ArraySize = ArraySize; - - static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please handle the new resource type below"); - switch (Type) - { - case SPIRVShaderResourceAttribs::ResourceType::UniformBuffer: - ResourceDesc.Type = SHADER_RESOURCE_TYPE_CONSTANT_BUFFER; - break; - - case SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer: - // Read-only storage buffers map to buffer SRV - // https://github.com/KhronosGroup/SPIRV-Cross/wiki/Reflection-API-user-guide#read-write-vs-read-only-resources-for-hlsl - ResourceDesc.Type = SHADER_RESOURCE_TYPE_BUFFER_SRV; - break; - - case SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer: - ResourceDesc.Type = SHADER_RESOURCE_TYPE_BUFFER_UAV; - break; - - case SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer: - ResourceDesc.Type = SHADER_RESOURCE_TYPE_BUFFER_SRV; - break; - - case SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer: - ResourceDesc.Type = SHADER_RESOURCE_TYPE_BUFFER_UAV; - break; - - case SPIRVShaderResourceAttribs::ResourceType::StorageImage: - ResourceDesc.Type = SHADER_RESOURCE_TYPE_TEXTURE_UAV; - break; - - case SPIRVShaderResourceAttribs::ResourceType::SampledImage: - ResourceDesc.Type = SHADER_RESOURCE_TYPE_TEXTURE_SRV; - break; - - case SPIRVShaderResourceAttribs::ResourceType::AtomicCounter: - LOG_WARNING_MESSAGE("There is no appropriate shader resource type for atomic counter resource '", Name, "'"); - ResourceDesc.Type = SHADER_RESOURCE_TYPE_BUFFER_UAV; - break; - - case SPIRVShaderResourceAttribs::ResourceType::SeparateImage: - ResourceDesc.Type = SHADER_RESOURCE_TYPE_TEXTURE_SRV; - break; - - case SPIRVShaderResourceAttribs::ResourceType::SeparateSampler: - ResourceDesc.Type = SHADER_RESOURCE_TYPE_SAMPLER; - break; - - case SPIRVShaderResourceAttribs::ResourceType::InputAttachment: - ResourceDesc.Type = SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT; - break; - - default: - UNEXPECTED("Unknown SPIRV resource type"); - } - return ResourceDesc; -} - - -static spv::ExecutionModel ShaderTypeToExecutionModel(SHADER_TYPE ShaderType) -{ - static_assert(SHADER_TYPE_LAST == 0x080, "Please handle the new shader type in the switch below"); - switch (ShaderType) - { - // clang-format off - case SHADER_TYPE_VERTEX: return spv::ExecutionModelVertex; - case SHADER_TYPE_HULL: return spv::ExecutionModelTessellationControl; - case SHADER_TYPE_DOMAIN: return spv::ExecutionModelTessellationEvaluation; - case SHADER_TYPE_GEOMETRY: return spv::ExecutionModelGeometry; - case SHADER_TYPE_PIXEL: return spv::ExecutionModelFragment; - case SHADER_TYPE_COMPUTE: return spv::ExecutionModelGLCompute; - case SHADER_TYPE_AMPLIFICATION: return spv::ExecutionModelTaskNV; - case SHADER_TYPE_MESH: return spv::ExecutionModelMeshNV; - // clang-format on - default: - UNEXPECTED("Unexpected shader type"); - return spv::ExecutionModelVertex; - } -} - -const std::string& GetUBName(diligent_spirv_cross::Compiler& Compiler, - const diligent_spirv_cross::Resource& UB, - const diligent_spirv_cross::ParsedIR::Source& IRSource) -{ - // Consider the following HLSL constant buffer: - // - // cbuffer Constants - // { - // float4x4 g_WorldViewProj; - // }; - // - // glslang emits SPIRV as if the following GLSL was written: - // - // uniform Constants // UB.name - // { - // float4x4 g_WorldViewProj; - // }; // no instance name - // - // DXC emits the byte code that corresponds to the following GLSL: - // - // uniform type_Constants // UB.name - // { - // float4x4 g_WorldViewProj; - // }Constants; // get_name(UB.id) - // - // - // | glslang | DXC - // ------------------------------------------------------------------- - // UB.name | "Constants" | "type_Constants" - // Compiler.get_name(UB.id) | "" | "Constants" - // - // Note that for the byte code produced from GLSL, we must always - // use UB.name even if the instance name is present - - const auto& instance_name = Compiler.get_name(UB.id); - return (IRSource.hlsl && !instance_name.empty()) ? instance_name : UB.name; -} - -SPIRVShaderResources::SPIRVShaderResources(IMemoryAllocator& Allocator, - IRenderDevice* pRenderDevice, - std::vector<uint32_t> spirv_binary, - const ShaderDesc& shaderDesc, - const char* CombinedSamplerSuffix, - bool LoadShaderStageInputs, - std::string& EntryPoint) : - m_ShaderType{shaderDesc.ShaderType} -{ - // https://github.com/KhronosGroup/SPIRV-Cross/wiki/Reflection-API-user-guide - diligent_spirv_cross::Parser parser(move(spirv_binary)); - parser.parse(); - const auto ParsedIRSource = parser.get_parsed_ir().source; - m_IsHLSLSource = ParsedIRSource.hlsl; - diligent_spirv_cross::Compiler Compiler(std::move(parser.get_parsed_ir())); - - spv::ExecutionModel ExecutionModel = ShaderTypeToExecutionModel(shaderDesc.ShaderType); - auto EntryPoints = Compiler.get_entry_points_and_stages(); - for (const auto& CurrEntryPoint : EntryPoints) - { - if (CurrEntryPoint.execution_model == ExecutionModel) - { - if (!EntryPoint.empty()) - { - LOG_WARNING_MESSAGE("More than one entry point of type ", GetShaderTypeLiteralName(shaderDesc.ShaderType), " found in SPIRV binary for shader '", shaderDesc.Name, "'. The first one ('", EntryPoint, "') will be used."); - } - else - { - EntryPoint = CurrEntryPoint.name; - } - } - } - if (EntryPoint.empty()) - { - LOG_ERROR_AND_THROW("Unable to find entry point of type ", GetShaderTypeLiteralName(shaderDesc.ShaderType), " in SPIRV binary for shader '", shaderDesc.Name, "'"); - } - Compiler.set_entry_point(EntryPoint, ExecutionModel); - - // The SPIR-V is now parsed, and we can perform reflection on it. - diligent_spirv_cross::ShaderResources resources = Compiler.get_shader_resources(); - - size_t ResourceNamesPoolSize = 0; - for (const auto& ub : resources.uniform_buffers) - ResourceNamesPoolSize += GetUBName(Compiler, ub, ParsedIRSource).length() + 1; - static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please account for the new resource type below"); - for (auto* pResType : - { - &resources.storage_buffers, - &resources.storage_images, - &resources.sampled_images, - &resources.atomic_counters, - &resources.separate_images, - &resources.separate_samplers, - &resources.subpass_inputs - // clang-format off - }) - // clang-format on - { - for (const auto& res : *pResType) - ResourceNamesPoolSize += res.name.length() + 1; - } - - if (CombinedSamplerSuffix != nullptr) - { - ResourceNamesPoolSize += strlen(CombinedSamplerSuffix) + 1; - } - - VERIFY_EXPR(shaderDesc.Name != nullptr); - ResourceNamesPoolSize += strlen(shaderDesc.Name) + 1; - - Uint32 NumShaderStageInputs = 0; - - if (!m_IsHLSLSource || resources.stage_inputs.empty()) - LoadShaderStageInputs = false; - if (LoadShaderStageInputs) - { - const auto& Extensions = Compiler.get_declared_extensions(); - bool HlslFunctionality1 = false; - for (const auto& ext : Extensions) - { - HlslFunctionality1 = (ext == "SPV_GOOGLE_hlsl_functionality1"); - if (HlslFunctionality1) - break; - } - - if (HlslFunctionality1) - { - for (const auto& Input : resources.stage_inputs) - { - if (Compiler.has_decoration(Input.id, spv::Decoration::DecorationHlslSemanticGOOGLE)) - { - const auto& Semantic = Compiler.get_decoration_string(Input.id, spv::Decoration::DecorationHlslSemanticGOOGLE); - ResourceNamesPoolSize += Semantic.length() + 1; - ++NumShaderStageInputs; - } - else - { - LOG_ERROR_MESSAGE("Shader input '", Input.name, "' does not have DecorationHlslSemanticGOOGLE decoration, which is unexpected as the shader declares SPV_GOOGLE_hlsl_functionality1 extension"); - } - } - } - else - { - LoadShaderStageInputs = false; - if (m_IsHLSLSource) - { - LOG_WARNING_MESSAGE("SPIRV byte code of shader '", shaderDesc.Name, - "' does not use SPV_GOOGLE_hlsl_functionality1 extension. " - "As a result, it is not possible to get semantics of shader inputs and map them to proper locations. " - "The shader will still work correctly if all attributes are declared in ascending order without any gaps. " - "Enable SPV_GOOGLE_hlsl_functionality1 in your compiler to allow proper mapping of vertex shader inputs."); - } - } - } - - ResourceCounters ResCounters; - ResCounters.NumUBs = static_cast<Uint32>(resources.uniform_buffers.size()); - ResCounters.NumSBs = static_cast<Uint32>(resources.storage_buffers.size()); - ResCounters.NumImgs = static_cast<Uint32>(resources.storage_images.size()); - ResCounters.NumSmpldImgs = static_cast<Uint32>(resources.sampled_images.size()); - ResCounters.NumACs = static_cast<Uint32>(resources.atomic_counters.size()); - ResCounters.NumSepSmplrs = static_cast<Uint32>(resources.separate_samplers.size()); - ResCounters.NumSepImgs = static_cast<Uint32>(resources.separate_images.size()); - ResCounters.NumInptAtts = static_cast<Uint32>(resources.subpass_inputs.size()); - static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please set the new resource type counter here"); - Initialize(Allocator, ResCounters, NumShaderStageInputs, ResourceNamesPoolSize); - - { - Uint32 CurrUB = 0; - for (const auto& UB : resources.uniform_buffers) - { - const auto& name = GetUBName(Compiler, UB, ParsedIRSource); - new (&GetUB(CurrUB++)) - SPIRVShaderResourceAttribs(Compiler, - UB, - m_ResourceNames.CopyString(name), - SPIRVShaderResourceAttribs::ResourceType::UniformBuffer); - } - VERIFY_EXPR(CurrUB == GetNumUBs()); - } - - { - Uint32 CurrSB = 0; - for (const auto& SB : resources.storage_buffers) - { - auto BufferFlags = Compiler.get_buffer_block_flags(SB.id); - auto IsReadOnly = BufferFlags.get(spv::DecorationNonWritable); - auto ResType = IsReadOnly ? - SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer : - SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer; - new (&GetSB(CurrSB++)) - SPIRVShaderResourceAttribs(Compiler, - SB, - m_ResourceNames.CopyString(SB.name), - ResType); - } - VERIFY_EXPR(CurrSB == GetNumSBs()); - } - - { - Uint32 CurrSmplImg = 0; - for (const auto& SmplImg : resources.sampled_images) - { - const auto& type = Compiler.get_type(SmplImg.type_id); - auto ResType = type.image.dim == spv::DimBuffer ? - SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer : - SPIRVShaderResourceAttribs::ResourceType::SampledImage; - new (&GetSmpldImg(CurrSmplImg++)) - SPIRVShaderResourceAttribs(Compiler, - SmplImg, - m_ResourceNames.CopyString(SmplImg.name), - ResType); - } - VERIFY_EXPR(CurrSmplImg == GetNumSmpldImgs()); - } - - { - Uint32 CurrImg = 0; - for (const auto& Img : resources.storage_images) - { - const auto& type = Compiler.get_type(Img.type_id); - auto ResType = type.image.dim == spv::DimBuffer ? - SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer : - SPIRVShaderResourceAttribs::ResourceType::StorageImage; - new (&GetImg(CurrImg++)) - SPIRVShaderResourceAttribs(Compiler, - Img, - m_ResourceNames.CopyString(Img.name), - ResType); - } - VERIFY_EXPR(CurrImg == GetNumImgs()); - } - - { - Uint32 CurrAC = 0; - for (const auto& AC : resources.atomic_counters) - { - new (&GetAC(CurrAC++)) - SPIRVShaderResourceAttribs(Compiler, - AC, - m_ResourceNames.CopyString(AC.name), - SPIRVShaderResourceAttribs::ResourceType::AtomicCounter); - } - VERIFY_EXPR(CurrAC == GetNumACs()); - } - - { - Uint32 CurrSepSmpl = 0; - for (const auto& SepSam : resources.separate_samplers) - { - new (&GetSepSmplr(CurrSepSmpl++)) - SPIRVShaderResourceAttribs(Compiler, - SepSam, - m_ResourceNames.CopyString(SepSam.name), - SPIRVShaderResourceAttribs::ResourceType::SeparateSampler); - } - VERIFY_EXPR(CurrSepSmpl == GetNumSepSmplrs()); - } - - { - Uint32 CurrSepImg = 0; - for (const auto& SepImg : resources.separate_images) - { - const auto& type = Compiler.get_type(SepImg.type_id); - auto ResType = type.image.dim == spv::DimBuffer ? - SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer : - SPIRVShaderResourceAttribs::ResourceType::SeparateImage; - - Uint32 SamplerInd = SPIRVShaderResourceAttribs::InvalidSepSmplrOrImgInd; - if (CombinedSamplerSuffix != nullptr) - { - auto NumSepSmpls = GetNumSepSmplrs(); - for (SamplerInd = 0; SamplerInd < NumSepSmpls; ++SamplerInd) - { - auto& SepSmplr = GetSepSmplr(SamplerInd); - if (StreqSuff(SepSmplr.Name, SepImg.name.c_str(), CombinedSamplerSuffix)) - { - SepSmplr.AssignSeparateImage(CurrSepImg); - break; - } - } - if (SamplerInd == NumSepSmpls) - SamplerInd = SPIRVShaderResourceAttribs::InvalidSepSmplrOrImgInd; - else - { - if (ResType == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer) - { - LOG_WARNING_MESSAGE("Combined image sampler assigned to uniform texel buffer '", SepImg.name, "' will be ignored"); - SamplerInd = SPIRVShaderResourceAttribs::InvalidSepSmplrOrImgInd; - } - } - } - auto* pNewSepImg = new (&GetSepImg(CurrSepImg++)) - SPIRVShaderResourceAttribs(Compiler, - SepImg, - m_ResourceNames.CopyString(SepImg.name), - ResType, - SamplerInd); - if (ResType == SPIRVShaderResourceAttribs::ResourceType::SeparateImage && pNewSepImg->IsValidSepSamplerAssigned()) - { -#ifdef DILIGENT_DEVELOPMENT - const auto& SepSmplr = GetSepSmplr(pNewSepImg->GetAssignedSepSamplerInd()); - DEV_CHECK_ERR(SepSmplr.ArraySize == 1 || SepSmplr.ArraySize == pNewSepImg->ArraySize, - "Array size (", SepSmplr.ArraySize, ") of separate sampler variable '", - SepSmplr.Name, "' must be equal to 1 or be the same as the array size (", pNewSepImg->ArraySize, - ") of separate image variable '", pNewSepImg->Name, "' it is assigned to"); -#endif - } - } - VERIFY_EXPR(CurrSepImg == GetNumSepImgs()); - } - - { - Uint32 CurrSubpassInput = 0; - for (const auto& SubpassInput : resources.subpass_inputs) - { - new (&GetInptAtt(CurrSubpassInput++)) - SPIRVShaderResourceAttribs(Compiler, - SubpassInput, - m_ResourceNames.CopyString(SubpassInput.name), - SPIRVShaderResourceAttribs::ResourceType::InputAttachment); - } - VERIFY_EXPR(CurrSubpassInput == GetNumInptAtts()); - } - - static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please initialize SPIRVShaderResourceAttribs for the new resource type here"); - - if (CombinedSamplerSuffix != nullptr) - { - m_CombinedSamplerSuffix = m_ResourceNames.CopyString(CombinedSamplerSuffix); - } - - m_ShaderName = m_ResourceNames.CopyString(shaderDesc.Name); - - if (LoadShaderStageInputs) - { - Uint32 CurrStageInput = 0; - for (const auto& Input : resources.stage_inputs) - { - if (Compiler.has_decoration(Input.id, spv::Decoration::DecorationHlslSemanticGOOGLE)) - { - const auto& Semantic = Compiler.get_decoration_string(Input.id, spv::Decoration::DecorationHlslSemanticGOOGLE); - new (&GetShaderStageInputAttribs(CurrStageInput++)) - SPIRVShaderStageInputAttribs(m_ResourceNames.CopyString(Semantic), GetDecorationOffset(Compiler, Input, spv::Decoration::DecorationLocation)); - } - } - VERIFY_EXPR(CurrStageInput == GetNumShaderStageInputs()); - } - - VERIFY(m_ResourceNames.GetRemainingSize() == 0, "Names pool must be empty"); - - //LOG_INFO_MESSAGE(DumpResources()); - -#ifdef DILIGENT_DEVELOPMENT - if (CombinedSamplerSuffix != nullptr) - { - for (Uint32 n = 0; n < GetNumSepSmplrs(); ++n) - { - const auto& SepSmplr = GetSepSmplr(n); - if (!SepSmplr.IsValidSepImageAssigned()) - LOG_ERROR_MESSAGE("Shader '", shaderDesc.Name, "' uses combined texture samplers, but separate sampler '", SepSmplr.Name, "' is not assigned to any texture"); - } - } -#endif -} - -void SPIRVShaderResources::Initialize(IMemoryAllocator& Allocator, - const ResourceCounters& Counters, - Uint32 NumShaderStageInputs, - size_t ResourceNamesPoolSize) -{ - Uint32 CurrentOffset = 0; - constexpr Uint32 MaxOffset = std::numeric_limits<OffsetType>::max(); - auto AdvanceOffset = [&CurrentOffset, MaxOffset](Uint32 NumResources) { - VERIFY(CurrentOffset <= MaxOffset, "Current offset (", CurrentOffset, ") exceeds max allowed value (", MaxOffset, ")"); - (void)MaxOffset; - auto Offset = static_cast<OffsetType>(CurrentOffset); - CurrentOffset += NumResources; - return Offset; - }; - - auto UniformBufferOffset = AdvanceOffset(Counters.NumUBs); - (void)UniformBufferOffset; - m_StorageBufferOffset = AdvanceOffset(Counters.NumSBs); - m_StorageImageOffset = AdvanceOffset(Counters.NumImgs); - m_SampledImageOffset = AdvanceOffset(Counters.NumSmpldImgs); - m_AtomicCounterOffset = AdvanceOffset(Counters.NumACs); - m_SeparateSamplerOffset = AdvanceOffset(Counters.NumSepSmplrs); - m_SeparateImageOffset = AdvanceOffset(Counters.NumSepImgs); - m_InputAttachmentOffset = AdvanceOffset(Counters.NumInptAtts); - m_TotalResources = AdvanceOffset(0); - static_assert(SPIRVShaderResourceAttribs::ResourceType::NumResourceTypes == 11, "Please update the new resource type offset"); - - VERIFY(NumShaderStageInputs <= MaxOffset, "Max offset exceeded"); - m_NumShaderStageInputs = static_cast<OffsetType>(NumShaderStageInputs); - - auto AlignedResourceNamesPoolSize = Align(ResourceNamesPoolSize, sizeof(void*)); - - static_assert(sizeof(SPIRVShaderResourceAttribs) % sizeof(void*) == 0, "Size of SPIRVShaderResourceAttribs struct must be multiple of sizeof(void*)"); - // clang-format off - auto MemorySize = m_TotalResources * sizeof(SPIRVShaderResourceAttribs) + - m_NumShaderStageInputs * sizeof(SPIRVShaderStageInputAttribs) + - AlignedResourceNamesPoolSize * sizeof(char); - - VERIFY_EXPR(GetNumUBs() == Counters.NumUBs); - VERIFY_EXPR(GetNumSBs() == Counters.NumSBs); - VERIFY_EXPR(GetNumImgs() == Counters.NumImgs); - VERIFY_EXPR(GetNumSmpldImgs() == Counters.NumSmpldImgs); - VERIFY_EXPR(GetNumACs() == Counters.NumACs); - VERIFY_EXPR(GetNumSepSmplrs() == Counters.NumSepSmplrs); - VERIFY_EXPR(GetNumSepImgs() == Counters.NumSepImgs); - // clang-format on - - if (MemorySize) - { - auto* pRawMem = Allocator.Allocate(MemorySize, "Memory for shader resources", __FILE__, __LINE__); - m_MemoryBuffer = std::unique_ptr<void, STDDeleterRawMem<void>>(pRawMem, Allocator); - char* NamesPool = reinterpret_cast<char*>(m_MemoryBuffer.get()) + - m_TotalResources * sizeof(SPIRVShaderResourceAttribs) + - m_NumShaderStageInputs * sizeof(SPIRVShaderStageInputAttribs); - m_ResourceNames.AssignMemory(NamesPool, ResourceNamesPoolSize); - } -} - -SPIRVShaderResources::~SPIRVShaderResources() -{ - for (Uint32 n = 0; n < GetNumUBs(); ++n) - GetUB(n).~SPIRVShaderResourceAttribs(); - - for (Uint32 n = 0; n < GetNumSBs(); ++n) - GetSB(n).~SPIRVShaderResourceAttribs(); - - for (Uint32 n = 0; n < GetNumImgs(); ++n) - GetImg(n).~SPIRVShaderResourceAttribs(); - - for (Uint32 n = 0; n < GetNumSmpldImgs(); ++n) - GetSmpldImg(n).~SPIRVShaderResourceAttribs(); - - for (Uint32 n = 0; n < GetNumACs(); ++n) - GetAC(n).~SPIRVShaderResourceAttribs(); - - for (Uint32 n = 0; n < GetNumSepSmplrs(); ++n) - GetSepSmplr(n).~SPIRVShaderResourceAttribs(); - - for (Uint32 n = 0; n < GetNumSepImgs(); ++n) - GetSepImg(n).~SPIRVShaderResourceAttribs(); - - for (Uint32 n = 0; n < GetNumShaderStageInputs(); ++n) - GetShaderStageInputAttribs(n).~SPIRVShaderStageInputAttribs(); -} - - - -std::string SPIRVShaderResources::DumpResources() -{ - std::stringstream ss; - ss << "Shader '" << m_ShaderName << "' resource stats: total resources: " << GetTotalResources() << ":" << std::endl - << "UBs: " << GetNumUBs() << "; SBs: " << GetNumSBs() << "; Imgs: " << GetNumImgs() << "; Smpl Imgs: " << GetNumSmpldImgs() - << "; ACs: " << GetNumACs() << "; Sep Imgs: " << GetNumSepImgs() << "; Sep Smpls: " << GetNumSepSmplrs() << '.' << std::endl - << "Resources:"; - - Uint32 ResNum = 0; - auto DumpResource = [&ss, &ResNum](const SPIRVShaderResourceAttribs& Res) { - std::stringstream FullResNameSS; - FullResNameSS << '\'' << Res.Name; - if (Res.ArraySize > 1) - FullResNameSS << '[' << Res.ArraySize << ']'; - FullResNameSS << '\''; - ss << std::setw(32) << FullResNameSS.str(); - - if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage && Res.IsValidSepSamplerAssigned()) - { - ss << " Assigned sep sampler ind: " << Res.GetAssignedSepSamplerInd(); - } - else if (Res.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler && Res.IsValidSepImageAssigned()) - { - ss << " Assigned sep image ind: " << Res.GetAssignedSepImageInd(); - } - - ++ResNum; - }; - - ProcessResources( - [&](const SPIRVShaderResourceAttribs& UB, Uint32) // - { - VERIFY(UB.Type == SPIRVShaderResourceAttribs::ResourceType::UniformBuffer, "Unexpected resource type"); - ss << std::endl - << std::setw(3) << ResNum << " Uniform Buffer "; - DumpResource(UB); - }, - [&](const SPIRVShaderResourceAttribs& SB, Uint32) // - { - VERIFY(SB.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer || - SB.Type == SPIRVShaderResourceAttribs::ResourceType::RWStorageBuffer, - "Unexpected resource type"); - ss << std::endl - << std::setw(3) << ResNum - << (SB.Type == SPIRVShaderResourceAttribs::ResourceType::ROStorageBuffer ? " RO Storage Buffer" : " RW Storage Buffer"); - DumpResource(SB); - }, - [&](const SPIRVShaderResourceAttribs& Img, Uint32) // - { - if (Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageImage) - { - ss << std::endl - << std::setw(3) << ResNum << " Storage Image "; - } - else if (Img.Type == SPIRVShaderResourceAttribs::ResourceType::StorageTexelBuffer) - { - ss << std::endl - << std::setw(3) << ResNum << " Storage Txl Buff "; - } - else - UNEXPECTED("Unexpected resource type"); - DumpResource(Img); - }, - [&](const SPIRVShaderResourceAttribs& SmplImg, Uint32) // - { - if (SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::SampledImage) - { - ss << std::endl - << std::setw(3) << ResNum << " Sampled Image "; - } - else if (SmplImg.Type == SPIRVShaderResourceAttribs::ResourceType::UniformTexelBuffer) - { - ss << std::endl - << std::setw(3) << ResNum << " Uniform Txl Buff "; - } - else - UNEXPECTED("Unexpected resource type"); - DumpResource(SmplImg); - }, - [&](const SPIRVShaderResourceAttribs& AC, Uint32) // - { - VERIFY(AC.Type == SPIRVShaderResourceAttribs::ResourceType::AtomicCounter, "Unexpected resource type"); - ss << std::endl - << std::setw(3) << ResNum << " Atomic Cntr "; - DumpResource(AC); - }, - [&](const SPIRVShaderResourceAttribs& SepSmpl, Uint32) // - { - VERIFY(SepSmpl.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateSampler, "Unexpected resource type"); - ss << std::endl - << std::setw(3) << ResNum << " Separate Smpl "; - DumpResource(SepSmpl); - }, - [&](const SPIRVShaderResourceAttribs& SepImg, Uint32) // - { - VERIFY(SepImg.Type == SPIRVShaderResourceAttribs::ResourceType::SeparateImage, "Unexpected resource type"); - ss << std::endl - << std::setw(3) << ResNum << " Separate Img "; - DumpResource(SepImg); - }, - [&](const SPIRVShaderResourceAttribs& InptAtt, Uint32) // - { - VERIFY(InptAtt.Type == SPIRVShaderResourceAttribs::ResourceType::InputAttachment, "Unexpected resource type"); - ss << std::endl - << std::setw(3) << ResNum << " Input Attachment "; - DumpResource(InptAtt); - } // - ); - VERIFY_EXPR(ResNum == GetTotalResources()); - - return ss.str(); -} - - - -bool SPIRVShaderResources::IsCompatibleWith(const SPIRVShaderResources& Resources) const -{ - // clang-format off - if( GetNumUBs() != Resources.GetNumUBs() || - GetNumSBs() != Resources.GetNumSBs() || - GetNumImgs() != Resources.GetNumImgs() || - GetNumSmpldImgs() != Resources.GetNumSmpldImgs() || - GetNumACs() != Resources.GetNumACs() || - GetNumSepImgs() != Resources.GetNumSepImgs() || - GetNumSepSmplrs() != Resources.GetNumSepSmplrs()) - return false; - // clang-format on - VERIFY_EXPR(GetTotalResources() == Resources.GetTotalResources()); - - bool IsCompatible = true; - ProcessResources( - [&](const SPIRVShaderResourceAttribs& Res, Uint32 n) { - const auto& Res2 = Resources.GetResource(n); - if (!Res.IsCompatibleWith(Res2)) - IsCompatible = false; - }); - - return IsCompatible; -} - -} // namespace Diligent diff --git a/Graphics/GLSLTools/src/SPIRVUtils.cpp b/Graphics/GLSLTools/src/SPIRVUtils.cpp deleted file mode 100644 index 6543d4fb..00000000 --- a/Graphics/GLSLTools/src/SPIRVUtils.cpp +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Copyright 2019-2020 Diligent Graphics LLC - * Copyright 2015-2019 Egor Yusov - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * In no event and under no legal theory, whether in tort (including negligence), - * contract, or otherwise, unless required by applicable law (such as deliberate - * and grossly negligent acts) or agreed to in writing, shall any Contributor be - * liable for any damages, including any direct, indirect, special, incidental, - * or consequential damages of any character arising as a result of this License or - * out of the use or inability to use the software (including but not limited to damages - * for loss of goodwill, work stoppage, computer failure or malfunction, or any and - * all other commercial damages or losses), even if such Contributor has been advised - * of the possibility of such damages. - */ - -#include <unordered_set> -#include <unordered_map> -#include <memory> -#include <array> - -#if (defined(VK_USE_PLATFORM_IOS_MVK) || defined(VK_USE_PLATFORM_MACOS_MVK)) -# include <MoltenGLSLToSPIRVConverter/GLSLToSPIRVConverter.h> -#else -# define ENABLE_HLSL -# include "SPIRV/GlslangToSpv.h" -#endif - -#include "SPIRVUtils.hpp" -#include "DebugUtilities.hpp" -#include "DataBlobImpl.hpp" -#include "RefCntAutoPtr.hpp" - -#include "spirv-tools/optimizer.hpp" - -// clang-format off -static const char g_HLSLDefinitions[] = -{ -#include "../../GraphicsEngineD3DBase/include/HLSLDefinitions_inc.fxh" -}; -// clang-format on - -namespace Diligent -{ - -// Implemented in GLSLSourceBuilder.cpp -const char* GetShaderTypeDefines(SHADER_TYPE Type); - -void InitializeGlslang() -{ - glslang::InitializeProcess(); -} - -void FinalizeGlslang() -{ - glslang::FinalizeProcess(); -} - -EShLanguage ShaderTypeToShLanguage(SHADER_TYPE ShaderType) -{ - static_assert(SHADER_TYPE_LAST == 0x080, "Please handle the new shader type in the switch below"); - switch (ShaderType) - { - // clang-format off - case SHADER_TYPE_VERTEX: return EShLangVertex; - case SHADER_TYPE_HULL: return EShLangTessControl; - case SHADER_TYPE_DOMAIN: return EShLangTessEvaluation; - case SHADER_TYPE_GEOMETRY: return EShLangGeometry; - case SHADER_TYPE_PIXEL: return EShLangFragment; - case SHADER_TYPE_COMPUTE: return EShLangCompute; - case SHADER_TYPE_AMPLIFICATION: return EShLangTaskNV; - case SHADER_TYPE_MESH: return EShLangMeshNV; - // clang-format on - default: - UNEXPECTED("Unexpected shader type"); - return EShLangCount; - } -} - -static TBuiltInResource InitResources() -{ - TBuiltInResource Resources; - - Resources.maxLights = 32; - Resources.maxClipPlanes = 6; - Resources.maxTextureUnits = 32; - Resources.maxTextureCoords = 32; - Resources.maxVertexAttribs = 64; - Resources.maxVertexUniformComponents = 4096; - Resources.maxVaryingFloats = 64; - Resources.maxVertexTextureImageUnits = 32; - Resources.maxCombinedTextureImageUnits = 80; - Resources.maxTextureImageUnits = 32; - Resources.maxFragmentUniformComponents = 4096; - Resources.maxDrawBuffers = 32; - Resources.maxVertexUniformVectors = 128; - Resources.maxVaryingVectors = 8; - Resources.maxFragmentUniformVectors = 16; - Resources.maxVertexOutputVectors = 16; - Resources.maxFragmentInputVectors = 15; - Resources.minProgramTexelOffset = -8; - Resources.maxProgramTexelOffset = 7; - Resources.maxClipDistances = 8; - Resources.maxComputeWorkGroupCountX = 65535; - Resources.maxComputeWorkGroupCountY = 65535; - Resources.maxComputeWorkGroupCountZ = 65535; - Resources.maxComputeWorkGroupSizeX = 1024; - Resources.maxComputeWorkGroupSizeY = 1024; - Resources.maxComputeWorkGroupSizeZ = 64; - Resources.maxComputeUniformComponents = 1024; - Resources.maxComputeTextureImageUnits = 16; - Resources.maxComputeImageUniforms = 8; - Resources.maxComputeAtomicCounters = 8; - Resources.maxComputeAtomicCounterBuffers = 1; - Resources.maxVaryingComponents = 60; - Resources.maxVertexOutputComponents = 64; - Resources.maxGeometryInputComponents = 64; - Resources.maxGeometryOutputComponents = 128; - Resources.maxFragmentInputComponents = 128; - Resources.maxImageUnits = 8; - Resources.maxCombinedImageUnitsAndFragmentOutputs = 8; - Resources.maxCombinedShaderOutputResources = 8; - Resources.maxImageSamples = 0; - Resources.maxVertexImageUniforms = 0; - Resources.maxTessControlImageUniforms = 0; - Resources.maxTessEvaluationImageUniforms = 0; - Resources.maxGeometryImageUniforms = 0; - Resources.maxFragmentImageUniforms = 8; - Resources.maxCombinedImageUniforms = 8; - Resources.maxGeometryTextureImageUnits = 16; - Resources.maxGeometryOutputVertices = 256; - Resources.maxGeometryTotalOutputComponents = 1024; - Resources.maxGeometryUniformComponents = 1024; - Resources.maxGeometryVaryingComponents = 64; - Resources.maxTessControlInputComponents = 128; - Resources.maxTessControlOutputComponents = 128; - Resources.maxTessControlTextureImageUnits = 16; - Resources.maxTessControlUniformComponents = 1024; - Resources.maxTessControlTotalOutputComponents = 4096; - Resources.maxTessEvaluationInputComponents = 128; - Resources.maxTessEvaluationOutputComponents = 128; - Resources.maxTessEvaluationTextureImageUnits = 16; - Resources.maxTessEvaluationUniformComponents = 1024; - Resources.maxTessPatchComponents = 120; - Resources.maxPatchVertices = 32; - Resources.maxTessGenLevel = 64; - Resources.maxViewports = 16; - Resources.maxVertexAtomicCounters = 0; - Resources.maxTessControlAtomicCounters = 0; - Resources.maxTessEvaluationAtomicCounters = 0; - Resources.maxGeometryAtomicCounters = 0; - Resources.maxFragmentAtomicCounters = 8; - Resources.maxCombinedAtomicCounters = 8; - Resources.maxAtomicCounterBindings = 1; - Resources.maxVertexAtomicCounterBuffers = 0; - Resources.maxTessControlAtomicCounterBuffers = 0; - Resources.maxTessEvaluationAtomicCounterBuffers = 0; - Resources.maxGeometryAtomicCounterBuffers = 0; - Resources.maxFragmentAtomicCounterBuffers = 1; - Resources.maxCombinedAtomicCounterBuffers = 1; - Resources.maxAtomicCounterBufferSize = 16384; - Resources.maxTransformFeedbackBuffers = 4; - Resources.maxTransformFeedbackInterleavedComponents = 64; - Resources.maxCullDistances = 8; - Resources.maxCombinedClipAndCullDistances = 8; - Resources.maxSamples = 4; - Resources.maxMeshOutputVerticesNV = 256; - Resources.maxMeshOutputPrimitivesNV = 512; - Resources.maxMeshWorkGroupSizeX_NV = 32; - Resources.maxMeshWorkGroupSizeY_NV = 1; - Resources.maxMeshWorkGroupSizeZ_NV = 1; - Resources.maxTaskWorkGroupSizeX_NV = 32; - Resources.maxTaskWorkGroupSizeY_NV = 1; - Resources.maxTaskWorkGroupSizeZ_NV = 1; - Resources.maxMeshViewCountNV = 4; - - Resources.limits.nonInductiveForLoops = 1; - Resources.limits.whileLoops = 1; - Resources.limits.doWhileLoops = 1; - Resources.limits.generalUniformIndexing = 1; - Resources.limits.generalAttributeMatrixVectorIndexing = 1; - Resources.limits.generalVaryingIndexing = 1; - Resources.limits.generalSamplerIndexing = 1; - Resources.limits.generalVariableIndexing = 1; - Resources.limits.generalConstantMatrixVectorIndexing = 1; - - return Resources; -} - -class IoMapResolver final : public glslang::TIoMapResolver -{ -public: - // Should return true if the resulting/current binding would be okay. - // Basic idea is to do aliasing binding checks with this. - virtual bool validateBinding(EShLanguage stage, glslang::TVarEntryInfo& ent) override final - { - return true; - } - - // Should return a value >= 0 if the current binding should be overridden. - // Return -1 if the current binding (including no binding) should be kept. - virtual int resolveBinding(EShLanguage stage, glslang::TVarEntryInfo& ent) override final - { - // We do not care about actual binding value here. - // We only need decoration to be present in SPIRV - return 0; - } - - // Should return a value >= 0 if the current set should be overridden. - // Return -1 if the current set (including no set) should be kept. - virtual int resolveSet(EShLanguage stage, glslang::TVarEntryInfo& ent) override final - { - // We do not care about actual descriptor set value here. - // We only need decoration to be present in SPIRV - return 0; - } - - // Should return a value >= 0 if the current location should be overridden. - // Return -1 if the current location (including no location) should be kept. - virtual int resolveUniformLocation(EShLanguage stage, glslang::TVarEntryInfo& ent) override final - { - return -1; - } - - // Should return true if the resulting/current setup would be okay. - // Basic idea is to do aliasing checks and reject invalid semantic names. - virtual bool validateInOut(EShLanguage stage, glslang::TVarEntryInfo& ent) override final - { - return true; - } - - // Should return a value >= 0 if the current location should be overridden. - // Return -1 if the current location (including no location) should be kept. - virtual int resolveInOutLocation(EShLanguage stage, glslang::TVarEntryInfo& ent) override final - { - return -1; - } - - // Should return a value >= 0 if the current component index should be overridden. - // Return -1 if the current component index (including no index) should be kept. - virtual int resolveInOutComponent(EShLanguage stage, glslang::TVarEntryInfo& ent) override final - { - return -1; - } - - // Should return a value >= 0 if the current color index should be overridden. - // Return -1 if the current color index (including no index) should be kept. - virtual int resolveInOutIndex(EShLanguage stage, glslang::TVarEntryInfo& ent) override final - { - return -1; - } - - // Notification of a uniform variable - virtual void notifyBinding(EShLanguage stage, glslang::TVarEntryInfo& ent) override final - { - } - - // Notification of a in or out variable - virtual void notifyInOut(EShLanguage stage, glslang::TVarEntryInfo& ent) override final - { - } - - // Called by mapIO when it starts its notify pass for the given stage - virtual void beginNotifications(EShLanguage stage) override final - { - } - - // Called by mapIO when it has finished the notify pass - virtual void endNotifications(EShLanguage stage) override final - { - } - - // Called by mipIO when it starts its resolve pass for the given stage - virtual void beginResolve(EShLanguage stage) override final - { - } - - // Called by mapIO when it has finished the resolve pass - virtual void endResolve(EShLanguage stage) override final - { - } - - // Called by mapIO when it starts its symbol collect for teh given stage - virtual void beginCollect(EShLanguage stage) override final - { - } - - // Called by mapIO when it has finished the symbol collect - virtual void endCollect(EShLanguage stage) override final - { - } - - // Called by TSlotCollector to resolve storage locations or bindings - virtual void reserverStorageSlot(glslang::TVarEntryInfo& ent, TInfoSink& infoSink) override final - { - } - - // Called by TSlotCollector to resolve resource locations or bindings - virtual void reserverResourceSlot(glslang::TVarEntryInfo& ent, TInfoSink& infoSink) override final - { - } - - // Called by mapIO.addStage to set shader stage mask to mark a stage be added to this pipeline - virtual void addStage(EShLanguage stage) override final - { - } -}; - -static void LogCompilerError(const char* DebugOutputMessage, - const char* InfoLog, - const char* InfoDebugLog, - const char* ShaderSource, - size_t SourceCodeLen, - IDataBlob** ppCompilerOutput) -{ - std::string ErrorLog(InfoLog); - if (*InfoDebugLog != '\0') - { - ErrorLog.push_back('\n'); - ErrorLog.append(InfoDebugLog); - } - LOG_ERROR_MESSAGE(DebugOutputMessage, ErrorLog); - - if (ppCompilerOutput != nullptr) - { - auto* pOutputDataBlob = MakeNewRCObj<DataBlobImpl>()(SourceCodeLen + 1 + ErrorLog.length() + 1); - char* DataPtr = reinterpret_cast<char*>(pOutputDataBlob->GetDataPtr()); - memcpy(DataPtr, ErrorLog.data(), ErrorLog.length() + 1); - memcpy(DataPtr + ErrorLog.length() + 1, ShaderSource, SourceCodeLen + 1); - pOutputDataBlob->QueryInterface(IID_DataBlob, reinterpret_cast<IObject**>(ppCompilerOutput)); - } -} - -static std::vector<unsigned int> CompileShaderInternal(glslang::TShader& Shader, - EShMessages messages, - glslang::TShader::Includer* pIncluder, - const char* ShaderSource, - size_t SourceCodeLen, - IDataBlob** ppCompilerOutput) -{ - Shader.setAutoMapBindings(true); - TBuiltInResource Resources = InitResources(); - - auto ParseResult = pIncluder != nullptr ? - Shader.parse(&Resources, 100, false, messages, *pIncluder) : - Shader.parse(&Resources, 100, false, messages); - if (!ParseResult) - { - LogCompilerError("Failed to parse shader source: \n", Shader.getInfoLog(), Shader.getInfoDebugLog(), ShaderSource, SourceCodeLen, ppCompilerOutput); - return {}; - } - - glslang::TProgram Program; - Program.addShader(&Shader); - if (!Program.link(messages)) - { - LogCompilerError("Failed to link program: \n", Program.getInfoLog(), Program.getInfoDebugLog(), ShaderSource, SourceCodeLen, ppCompilerOutput); - return {}; - } - - IoMapResolver Resovler; - // This step is essential to set bindings and descriptor sets - Program.mapIO(&Resovler); - - std::vector<unsigned int> spirv; - glslang::GlslangToSpv(*Program.getIntermediate(Shader.getStage()), spirv); - - return std::move(spirv); -} - - -class IncluderImpl : public glslang::TShader::Includer -{ -public: - IncluderImpl(IShaderSourceInputStreamFactory* pInputStreamFactory) : - m_pInputStreamFactory(pInputStreamFactory) - {} - - // For the "system" or <>-style includes; search the "system" paths. - virtual IncludeResult* includeSystem(const char* headerName, - const char* /*includerName*/, - size_t /*inclusionDepth*/) - { - DEV_CHECK_ERR(m_pInputStreamFactory != nullptr, "The shader source conains #include directives, but no input stream factory was provided"); - RefCntAutoPtr<IFileStream> pSourceStream; - m_pInputStreamFactory->CreateInputStream(headerName, &pSourceStream); - if (pSourceStream == nullptr) - { - LOG_ERROR("Failed to open shader include file \"", headerName, "\". Check that the file exists"); - return nullptr; - } - - RefCntAutoPtr<IDataBlob> pFileData(MakeNewRCObj<DataBlobImpl>()(0)); - pSourceStream->ReadBlob(pFileData); - auto* pNewInclude = - new IncludeResult{ - headerName, - reinterpret_cast<const char*>(pFileData->GetDataPtr()), - pFileData->GetSize(), - nullptr}; - - m_IncludeRes.emplace(pNewInclude); - m_DataBlobs.emplace(pNewInclude, std::move(pFileData)); - return pNewInclude; - } - - // For the "local"-only aspect of a "" include. Should not search in the - // "system" paths, because on returning a failure, the parser will - // call includeSystem() to look in the "system" locations. - virtual IncludeResult* includeLocal(const char* /*headerName*/, - const char* /*includerName*/, - size_t /*inclusionDepth*/) - { - return nullptr; - } - - // Signals that the parser will no longer use the contents of the - // specified IncludeResult. - virtual void releaseInclude(IncludeResult* IncldRes) - { - m_DataBlobs.erase(IncldRes); - } - -private: - IShaderSourceInputStreamFactory* const m_pInputStreamFactory; - std::unordered_set<std::unique_ptr<IncludeResult>> m_IncludeRes; - std::unordered_map<IncludeResult*, RefCntAutoPtr<IDataBlob>> m_DataBlobs; -}; - -std::vector<unsigned int> HLSLtoSPIRV(const ShaderCreateInfo& Attribs, - const char* ExtraDefinitions, - IDataBlob** ppCompilerOutput) -{ - EShLanguage ShLang = ShaderTypeToShLanguage(Attribs.Desc.ShaderType); - glslang::TShader Shader{ShLang}; - EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules | EShMsgReadHlsl | EShMsgHlslLegalization); - - VERIFY_EXPR(Attribs.SourceLanguage == SHADER_SOURCE_LANGUAGE_HLSL); - - Shader.setEnvInput(glslang::EShSourceHlsl, ShLang, glslang::EShClientVulkan, 100); - Shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0); - Shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0); - Shader.setHlslIoMapping(true); - Shader.setEntryPoint(Attribs.EntryPoint); - Shader.setEnvTargetHlslFunctionality1(); - - RefCntAutoPtr<IDataBlob> pFileData(MakeNewRCObj<DataBlobImpl>()(0)); - - const char* SourceCode = 0; - int SourceCodeLen = 0; - if (Attribs.Source) - { - SourceCode = Attribs.Source; - SourceCodeLen = static_cast<int>(strlen(Attribs.Source)); - } - else - { - VERIFY(Attribs.pShaderSourceStreamFactory, "Input stream factory is null"); - RefCntAutoPtr<IFileStream> pSourceStream; - Attribs.pShaderSourceStreamFactory->CreateInputStream(Attribs.FilePath, &pSourceStream); - if (pSourceStream == nullptr) - LOG_ERROR_AND_THROW("Failed to open shader source file"); - - pSourceStream->ReadBlob(pFileData); - SourceCode = reinterpret_cast<char*>(pFileData->GetDataPtr()); - SourceCodeLen = static_cast<int>(pFileData->GetSize()); - } - - std::string Defines = g_HLSLDefinitions; - if (const auto* ShaderTypeDefine = GetShaderTypeDefines(Attribs.Desc.ShaderType)) - Defines += ShaderTypeDefine; - - if (ExtraDefinitions != nullptr) - Defines += ExtraDefinitions; - - if (Attribs.Macros != nullptr) - { - Defines += '\n'; - auto* pMacro = Attribs.Macros; - while (pMacro->Name != nullptr && pMacro->Definition != nullptr) - { - Defines += "#define "; - Defines += pMacro->Name; - Defines += ' '; - Defines += pMacro->Definition; - Defines += "\n"; - ++pMacro; - } - } - Shader.setPreamble(Defines.c_str()); - - const char* ShaderStrings[] = {SourceCode}; - const int ShaderStringLenghts[] = {SourceCodeLen}; - const char* Names[] = {Attribs.FilePath != nullptr ? Attribs.FilePath : ""}; - Shader.setStringsWithLengthsAndNames(ShaderStrings, ShaderStringLenghts, Names, 1); - - IncluderImpl Includer(Attribs.pShaderSourceStreamFactory); - - auto SPIRV = CompileShaderInternal(Shader, messages, &Includer, SourceCode, SourceCodeLen, ppCompilerOutput); - if (SPIRV.empty()) - return SPIRV; - - // SPIR-V bytecode generated from HLSL must be legalized to - // turn it into a valid vulkan SPIR-V shader - spvtools::Optimizer SpirvOptimizer(SPV_ENV_VULKAN_1_0); - SpirvOptimizer.RegisterLegalizationPasses(); - SpirvOptimizer.RegisterPerformancePasses(); - std::vector<uint32_t> LegalizedSPIRV; - if (SpirvOptimizer.Run(SPIRV.data(), SPIRV.size(), &LegalizedSPIRV)) - { - return std::move(LegalizedSPIRV); - } - else - { - LOG_ERROR("Failed to legalize SPIR-V shader generated by HLSL front-end. This may result in undefined behavior."); - return std::move(SPIRV); - } -} - -std::vector<unsigned int> GLSLtoSPIRV(const SHADER_TYPE ShaderType, const char* ShaderSource, int SourceCodeLen, IDataBlob** ppCompilerOutput) -{ - EShLanguage ShLang = ShaderTypeToShLanguage(ShaderType); - glslang::TShader Shader(ShLang); - - EShMessages messages = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules); - - const char* ShaderStrings[] = {ShaderSource}; - int Lenghts[] = {SourceCodeLen}; - Shader.setStringsWithLengths(ShaderStrings, Lenghts, 1); - - auto SPIRV = CompileShaderInternal(Shader, messages, nullptr, ShaderSource, SourceCodeLen, ppCompilerOutput); - - spvtools::Optimizer SpirvOptimizer(SPV_ENV_VULKAN_1_0); - SpirvOptimizer.RegisterPerformancePasses(); - std::vector<uint32_t> OptimizedSPIRV; - if (SpirvOptimizer.Run(SPIRV.data(), SPIRV.size(), &OptimizedSPIRV)) - { - return std::move(OptimizedSPIRV); - } - else - { - LOG_ERROR("Failed to optimize SPIR-V."); - return std::move(SPIRV); - } -} - -} // namespace Diligent |
