diff --git a/Graphics/GraphicsTools/CMakeLists.txt b/Graphics/GraphicsTools/CMakeLists.txt index d8378fbb6..56fc212c9 100644 --- a/Graphics/GraphicsTools/CMakeLists.txt +++ b/Graphics/GraphicsTools/CMakeLists.txt @@ -18,6 +18,7 @@ set(INTERFACE interface/ScreenCapture.hpp interface/ShaderMacroHelper.hpp interface/StreamingBuffer.hpp + interface/ShaderSourceFactoryUtils.h interface/TextureUploader.hpp interface/TextureUploaderBase.hpp interface/XXH128Hasher.hpp @@ -34,6 +35,7 @@ set(SOURCE src/GraphicsUtilities.cpp src/ScopedQueryHelper.cpp src/ScreenCapture.cpp + src/ShaderSourceFactoryUtils.cpp src/TextureUploader.cpp src/XXH128Hasher.cpp src/VertexPool.cpp diff --git a/Graphics/GraphicsTools/interface/ShaderSourceFactoryUtils.h b/Graphics/GraphicsTools/interface/ShaderSourceFactoryUtils.h new file mode 100644 index 000000000..00e6e3e17 --- /dev/null +++ b/Graphics/GraphicsTools/interface/ShaderSourceFactoryUtils.h @@ -0,0 +1,107 @@ +/* + * Copyright 2023 Diligent Graphics LLC + * + * 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 +/// Defines graphics engine utilities + +#include "../../GraphicsEngine/interface/Shader.h" + +DILIGENT_BEGIN_NAMESPACE(Diligent) + +#include "../../Primitives/interface/DefineGlobalFuncHelperMacros.h" + +/// Shader source file substitute info. +struct ShaderSourceFileSubstitueInfo +{ + /// Source file name. + const Char* Name DEFAULT_INITIALIZER(nullptr); + + /// Substitute file name. + const Char* Substitute DEFAULT_INITIALIZER(nullptr); + +#if DILIGENT_CPP_INTERFACE + constexpr ShaderSourceFileSubstitueInfo() noexcept + {} + + constexpr ShaderSourceFileSubstitueInfo(const Char* _Name, const Char* _Substitute) noexcept : + Name{_Name}, + Substitute{_Substitute} + {} +#endif +}; + +/// Compound shader source factory create info. +struct CompoundShaderSourceFactoryCreateInfo +{ + /// An array of shader source input stream factories. + IShaderSourceInputStreamFactory** ppFactories DEFAULT_INITIALIZER(nullptr); + + /// The number of factories in ppFactories array. + Uint32 NumFactories DEFAULT_INITIALIZER(0); + + /// An array of shader source file substitutes. + ShaderSourceFileSubstitueInfo* pFileSubstitutes DEFAULT_INITIALIZER(nullptr); + + /// The number of file substitutes in pFileSubstitutes array. + Uint32 NumFileSubstitutes DEFAULT_INITIALIZER(0); + +#if DILIGENT_CPP_INTERFACE + constexpr CompoundShaderSourceFactoryCreateInfo() noexcept + {} + + constexpr CompoundShaderSourceFactoryCreateInfo(IShaderSourceInputStreamFactory** _ppFactories, + Uint32 _NumFactories, + ShaderSourceFileSubstitueInfo* _pFileSubstitutes = nullptr, + Uint32 _NumFileSubstitutes = 0) noexcept : + ppFactories{_ppFactories}, + NumFactories{_NumFactories}, + pFileSubstitutes{_pFileSubstitutes}, + NumFileSubstitutes{_NumFileSubstitutes} + {} +#endif +}; +typedef struct CompoundShaderSourceFactoryCreateInfo CompoundShaderSourceFactoryCreateInfo; +// clang-format on + +/// Creates a compound shader source factory. +/// +/// \param [in] CreateInfo - Compound shader source factory create info, see Diligent::CompoundShaderSourceFactoryCreateInfo. +/// \param [out] ppFactory - Address of the memory location where the pointer to the created factory will be written. +/// +/// \remarks Compound shader source stream factory is a wrapper around multiple shader source stream factories. +/// It is used to combine multiple shader source stream factories into a single one. When a source file +/// is requested, the factory will iterate over all factories in the array and return the first one that +/// returns a non-null stream. +/// +/// The factory also allows substituting source file names. This is useful when the same shader source +/// is used for multiple shaders, but some of them require a modified version of the source. +void DILIGENT_GLOBAL_FUNCTION(CreateCompoundShaderSourceFactory)(const CompoundShaderSourceFactoryCreateInfo REF CreateInfo, IShaderSourceInputStreamFactory** ppFactory); + +#include "../../Primitives/interface/UndefGlobalFuncHelperMacros.h" + +DILIGENT_END_NAMESPACE // namespace Diligent diff --git a/Graphics/GraphicsTools/src/ShaderSourceFactoryUtils.cpp b/Graphics/GraphicsTools/src/ShaderSourceFactoryUtils.cpp new file mode 100644 index 000000000..58d67583d --- /dev/null +++ b/Graphics/GraphicsTools/src/ShaderSourceFactoryUtils.cpp @@ -0,0 +1,124 @@ +/* + * Copyright 2023 Diligent Graphics LLC + * + * 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 "ShaderSourceFactoryUtils.h" + +#include +#include + +#include "ObjectBase.hpp" +#include "HashUtils.hpp" +#include "RefCntAutoPtr.hpp" + +namespace Diligent +{ + +class CompoundShaderSourceFactory : public ObjectBase +{ +public: + using TBase = ObjectBase; + + static RefCntAutoPtr Create(const CompoundShaderSourceFactoryCreateInfo& CreateInfo) + { + return RefCntAutoPtr{MakeNewRCObj()(CreateInfo)}; + } + + CompoundShaderSourceFactory(IReferenceCounters* pRefCounters, + const CompoundShaderSourceFactoryCreateInfo& CI) : + TBase{pRefCounters} + { + if (CI.ppFactories != nullptr) + { + m_pFactories.reserve(CI.NumFactories); + for (Uint32 i = 0; i < CI.NumFactories; ++i) + { + m_pFactories.emplace_back(CI.ppFactories[i]); + } + } + + if (CI.pFileSubstitutes != nullptr) + { + for (Uint32 i = 0; i < CI.NumFileSubstitutes; ++i) + { + m_FileSubstituteMap.emplace(HashMapStringKey{CI.pFileSubstitutes[i].Name, true}, CI.pFileSubstitutes[i].Substitute); + } + } + } + + IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_IShaderSourceInputStreamFactory, TBase) + + virtual void DILIGENT_CALL_TYPE CreateInputStream(const Char* Name, + IFileStream** ppStream) override final + { + CreateInputStream2(Name, CREATE_SHADER_SOURCE_INPUT_STREAM_FLAG_NONE, ppStream); + } + + virtual void DILIGENT_CALL_TYPE CreateInputStream2(const Char* Name, + CREATE_SHADER_SOURCE_INPUT_STREAM_FLAGS Flags, + IFileStream** ppStream) override final + { + VERIFY_EXPR(ppStream != nullptr && *ppStream == nullptr); + if (!m_FileSubstituteMap.empty()) + { + auto it = m_FileSubstituteMap.find(Name); + if (it != m_FileSubstituteMap.end()) + Name = it->second.c_str(); + } + + for (size_t i = 0; i < m_pFactories.size() && *ppStream == nullptr; ++i) + { + if (m_pFactories[i]) + m_pFactories[i]->CreateInputStream2(Name, CREATE_SHADER_SOURCE_INPUT_STREAM_FLAG_SILENT, ppStream); + } + + if (*ppStream == nullptr && (Flags & CREATE_SHADER_SOURCE_INPUT_STREAM_FLAG_SILENT) != 0) + { + LOG_ERROR("Failed to create input stream for source file ", Name); + } + } + +private: + std::vector> m_pFactories; + + std::unordered_map m_FileSubstituteMap; +}; + +void CreateCompoundShaderSourceFactory(const CompoundShaderSourceFactoryCreateInfo& CreateInfo, IShaderSourceInputStreamFactory** ppFactory) +{ + auto pFactory = CompoundShaderSourceFactory::Create(CreateInfo); + pFactory->QueryInterface(IID_IShaderSourceInputStreamFactory, reinterpret_cast(ppFactory)); +} + +} // namespace Diligent + +extern "C" +{ + void Diligent_CreateCompoundShaderSourceFactory(const Diligent::CompoundShaderSourceFactoryCreateInfo& CreateInfo, + Diligent::IShaderSourceInputStreamFactory** ppFactory) + { + Diligent::CreateCompoundShaderSourceFactory(CreateInfo, ppFactory); + } +}