From 8e24a0919d30f939140e776bc5e64bd77767e99c Mon Sep 17 00:00:00 2001 From: Egor Yusov Date: Sun, 12 Nov 2017 18:54:50 -0800 Subject: Updated to Diligent Engine 2.1 --- .../build/Win32/GraphicsTools.vcxproj | 4 +- .../build/Win32/GraphicsTools.vcxproj.filters | 3 - .../Windows.Shared/GraphicsTools.Shared.vcxitems | 13 + .../GraphicsTools.Shared.vcxitems.filters | 33 +++ .../build/Windows.Shared/GraphicsTools.props | 2 +- .../GraphicsTools/include/CommonlyUsedStates.h | 76 +++++ .../GraphicsTools/include/FreeBlockListManager.h | 276 ----------------- .../include/FreeBlockListManagerGPU.h | 85 ------ Graphics/GraphicsTools/include/GraphicsUtilities.h | 34 ++- Graphics/GraphicsTools/include/RingBuffer.h | 43 +-- Graphics/GraphicsTools/include/ShaderMacroHelper.h | 49 ++-- Graphics/GraphicsTools/include/TextureUploader.h | 72 +++++ .../GraphicsTools/include/TextureUploaderBase.h | 79 +++++ .../GraphicsTools/include/TextureUploaderD3D11.h | 44 +++ .../GraphicsTools/include/TextureUploaderD3D12.h | 45 +++ Graphics/GraphicsTools/include/TextureUploaderGL.h | 45 +++ .../include/VariableSizeGPUAllocationsManager.h | 20 +- Graphics/GraphicsTools/readme.md | 26 ++ .../src/BasicShaderSourceStreamFactory.cpp | 4 +- Graphics/GraphicsTools/src/GraphicsUtilities.cpp | 258 +++++++++++++++- Graphics/GraphicsTools/src/TextureUploader.cpp | 52 ++++ .../GraphicsTools/src/TextureUploaderD3D11.cpp | 326 +++++++++++++++++++++ .../GraphicsTools/src/TextureUploaderD3D12.cpp | 274 +++++++++++++++++ Graphics/GraphicsTools/src/TextureUploaderGL.cpp | 271 +++++++++++++++++ 24 files changed, 1709 insertions(+), 425 deletions(-) create mode 100644 Graphics/GraphicsTools/include/CommonlyUsedStates.h delete mode 100644 Graphics/GraphicsTools/include/FreeBlockListManager.h delete mode 100644 Graphics/GraphicsTools/include/FreeBlockListManagerGPU.h create mode 100644 Graphics/GraphicsTools/include/TextureUploader.h create mode 100644 Graphics/GraphicsTools/include/TextureUploaderBase.h create mode 100644 Graphics/GraphicsTools/include/TextureUploaderD3D11.h create mode 100644 Graphics/GraphicsTools/include/TextureUploaderD3D12.h create mode 100644 Graphics/GraphicsTools/include/TextureUploaderGL.h create mode 100644 Graphics/GraphicsTools/readme.md create mode 100644 Graphics/GraphicsTools/src/TextureUploader.cpp create mode 100644 Graphics/GraphicsTools/src/TextureUploaderD3D11.cpp create mode 100644 Graphics/GraphicsTools/src/TextureUploaderD3D12.cpp create mode 100644 Graphics/GraphicsTools/src/TextureUploaderGL.cpp (limited to 'Graphics/GraphicsTools') diff --git a/Graphics/GraphicsTools/build/Win32/GraphicsTools.vcxproj b/Graphics/GraphicsTools/build/Win32/GraphicsTools.vcxproj index a1020462..985d47c3 100644 --- a/Graphics/GraphicsTools/build/Win32/GraphicsTools.vcxproj +++ b/Graphics/GraphicsTools/build/Win32/GraphicsTools.vcxproj @@ -30,6 +30,7 @@ {C6014499-0CF2-43EC-A773-A4E354FB2D74} Win32Proj GraphicsTools + 10.0.10240.0 @@ -146,9 +147,6 @@ true - - - diff --git a/Graphics/GraphicsTools/build/Win32/GraphicsTools.vcxproj.filters b/Graphics/GraphicsTools/build/Win32/GraphicsTools.vcxproj.filters index 89d44e9e..ba635331 100644 --- a/Graphics/GraphicsTools/build/Win32/GraphicsTools.vcxproj.filters +++ b/Graphics/GraphicsTools/build/Win32/GraphicsTools.vcxproj.filters @@ -10,9 +10,6 @@ h;hh;hpp;hxx;hm;inl;inc;xsd - - - jni diff --git a/Graphics/GraphicsTools/build/Windows.Shared/GraphicsTools.Shared.vcxitems b/Graphics/GraphicsTools/build/Windows.Shared/GraphicsTools.Shared.vcxitems index 050502cc..879867a4 100644 --- a/Graphics/GraphicsTools/build/Windows.Shared/GraphicsTools.Shared.vcxitems +++ b/Graphics/GraphicsTools/build/Windows.Shared/GraphicsTools.Shared.vcxitems @@ -18,6 +18,12 @@ + + + + + + @@ -31,10 +37,17 @@ Create + + + + false + + + \ No newline at end of file diff --git a/Graphics/GraphicsTools/build/Windows.Shared/GraphicsTools.Shared.vcxitems.filters b/Graphics/GraphicsTools/build/Windows.Shared/GraphicsTools.Shared.vcxitems.filters index 8d2bdcc1..99fee601 100644 --- a/Graphics/GraphicsTools/build/Windows.Shared/GraphicsTools.Shared.vcxitems.filters +++ b/Graphics/GraphicsTools/build/Windows.Shared/GraphicsTools.Shared.vcxitems.filters @@ -30,6 +30,24 @@ include + + include + + + include + + + include + + + include + + + include + + + include + @@ -41,8 +59,23 @@ src + + src + + + src + + + src + + + src + + + + \ No newline at end of file diff --git a/Graphics/GraphicsTools/build/Windows.Shared/GraphicsTools.props b/Graphics/GraphicsTools/build/Windows.Shared/GraphicsTools.props index 4da87146..c2ad8f8a 100644 --- a/Graphics/GraphicsTools/build/Windows.Shared/GraphicsTools.props +++ b/Graphics/GraphicsTools/build/Windows.Shared/GraphicsTools.props @@ -6,7 +6,7 @@ ..\..\.. - $(GraphicsRoot)\GraphicsTools\include;$(GraphicsRoot)\GraphicsEngine\interface;$(GraphicsRoot)\TextureLoader\interface;$(EngineRoot)\Common\include;$(EngineRoot)\Common\interface;$(EngineRoot)\Platforms\interface;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(IncludePath) + $(GraphicsRoot)\GraphicsTools\include;$(GraphicsRoot)\GraphicsEngine\interface;$(GraphicsRoot)\GraphicsEngineD3D11\interface;$(GraphicsRoot)\GraphicsEngineD3D12\interface;$(GraphicsRoot)\GraphicsEngineD3DBase\include;$(GraphicsRoot)\GraphicsEngineOpenGL\interface;$(GraphicsRoot)\TextureLoader\interface;$(EngineRoot)\Common\include;$(EngineRoot)\Common\interface;$(EngineRoot)\Platforms\interface;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(IncludePath) diff --git a/Graphics/GraphicsTools/include/CommonlyUsedStates.h b/Graphics/GraphicsTools/include/CommonlyUsedStates.h new file mode 100644 index 00000000..899a0b15 --- /dev/null +++ b/Graphics/GraphicsTools/include/CommonlyUsedStates.h @@ -0,0 +1,76 @@ +/* Copyright 2015-2017 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 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * 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 "GraphicsTypes.h" +#include "DepthStencilState.h" +#include "BlendState.h" +#include "RasterizerState.h" +#include "Sampler.h" + +namespace Diligent +{ + // Common depth-stencil states + const DepthStencilStateDesc DSS_DisableDepth(False, False); + + // Common rasterizer states + const RasterizerStateDesc RS_SolidFillNoCull(FILL_MODE_SOLID, CULL_MODE_NONE); + + const RasterizerStateDesc RS_WireFillNoCull(FILL_MODE_WIREFRAME, CULL_MODE_NONE, false, 1, 0.f, 1.f); + + + // Common sampler states + const SamplerDesc Sam_LinearClamp(FILTER_TYPE_LINEAR, FILTER_TYPE_LINEAR, FILTER_TYPE_LINEAR, + TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP); + + const SamplerDesc Sam_PointClamp(FILTER_TYPE_POINT, FILTER_TYPE_POINT, FILTER_TYPE_POINT, + TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP); + + const SamplerDesc Sam_LinearMirror(FILTER_TYPE_LINEAR, FILTER_TYPE_LINEAR, FILTER_TYPE_LINEAR, + TEXTURE_ADDRESS_MIRROR, TEXTURE_ADDRESS_MIRROR, TEXTURE_ADDRESS_MIRROR); + + const SamplerDesc Sam_PointWrap(FILTER_TYPE_POINT, FILTER_TYPE_POINT, FILTER_TYPE_POINT, + TEXTURE_ADDRESS_WRAP, TEXTURE_ADDRESS_WRAP, TEXTURE_ADDRESS_WRAP); + + const SamplerDesc Sam_LinearWrap(FILTER_TYPE_LINEAR, FILTER_TYPE_LINEAR, FILTER_TYPE_LINEAR, + TEXTURE_ADDRESS_WRAP, TEXTURE_ADDRESS_WRAP, TEXTURE_ADDRESS_WRAP); + + const SamplerDesc Sam_Aniso2xClamp(FILTER_TYPE_ANISOTROPIC, FILTER_TYPE_ANISOTROPIC, FILTER_TYPE_ANISOTROPIC, + TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP, 0.f, 2); + + const SamplerDesc Sam_Aniso4xClamp(FILTER_TYPE_ANISOTROPIC, FILTER_TYPE_ANISOTROPIC, FILTER_TYPE_ANISOTROPIC, + TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP, 0.f, 4); + + const SamplerDesc Sam_Aniso8xClamp(FILTER_TYPE_ANISOTROPIC, FILTER_TYPE_ANISOTROPIC, FILTER_TYPE_ANISOTROPIC, + TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP, 0.f, 8); + + const SamplerDesc Sam_Aniso16xClamp(FILTER_TYPE_ANISOTROPIC, FILTER_TYPE_ANISOTROPIC, FILTER_TYPE_ANISOTROPIC, + TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP, TEXTURE_ADDRESS_CLAMP, 0.f, 16); + + const SamplerDesc Sam_Aniso8xWrap(FILTER_TYPE_ANISOTROPIC, FILTER_TYPE_ANISOTROPIC, FILTER_TYPE_ANISOTROPIC, + TEXTURE_ADDRESS_WRAP, TEXTURE_ADDRESS_WRAP, TEXTURE_ADDRESS_WRAP, 0.f, 8); +} diff --git a/Graphics/GraphicsTools/include/FreeBlockListManager.h b/Graphics/GraphicsTools/include/FreeBlockListManager.h deleted file mode 100644 index 7eb9d931..00000000 --- a/Graphics/GraphicsTools/include/FreeBlockListManager.h +++ /dev/null @@ -1,276 +0,0 @@ -/* Copyright 2015-2016 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 - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. - * - * 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 -#include "MemoryAllocator.h" -#include "FixedBlockMemoryAllocator.h" -#include "STDAllocator.h" -#include "DebugUtilities.h" - -namespace Diligent -{ - class FreeBlockListManager - { - public: - typedef size_t OffsetType; - typedef std::pair FrameNumOffsetPair; - - struct FreeBlockInfo; - typedef std::map, // Standard ordering - STDAllocatorRawMem> // Raw memory allocator - > TFreeBlocksByOffsetMap; - typedef std::multimap, // Standard ordering - STDAllocatorRawMem> // Raw memory allocator - > TFreeBlocksBySizeMap; - - struct FreeBlockInfo - { - // Block size (no reserved space) - OffsetType Size; - - // Iterator referencing this block in the multimap sorted by the block size - TFreeBlocksBySizeMap::iterator OrderBySizeIt; - - FreeBlockInfo(OffsetType _Size) : Size(_Size){} - }; - - static const OffsetType InvalidOffset = static_cast(-1); - - FreeBlockListManager(OffsetType MaxSize, IMemoryAllocator &Allocator) : - m_MaxSize(MaxSize), - m_FreeSize(MaxSize), - m_FreeBlocks( STD_ALLOCATOR_RAW_MEM(TFreeBlocksByOffsetMap::value_type, Allocator, "Allocator for std::map") ), - m_FreeBlocksBySize( STD_ALLOCATOR_RAW_MEM(TFreeBlocksBySizeMap::value_type, Allocator, "multimap") ) - { - AddNewBlock(0, m_MaxSize); - -#ifdef _DEBUG - DbgVerifyList(); -#endif - } - - ~FreeBlockListManager() - { - if( !m_FreeBlocks.empty() || !m_FreeBlocksBySize.empty() ) - { - VERIFY(m_FreeBlocks.size() == 1, "Single free block is expected"); - VERIFY(m_FreeBlocks.begin()->first == 0, "Head chunk offset is expected to be 0"); - VERIFY(m_FreeBlocks.begin()->second.Size == m_MaxSize, "Head chunk size is expected to be ", m_MaxSize); - - VERIFY(m_FreeBlocksBySize.size() == 1, "Single free block is expected"); - VERIFY(m_FreeBlocksBySize.begin()->first == m_MaxSize, "Head chunk size is expected to be ", m_MaxSize); - VERIFY(m_FreeBlocksBySize.begin()->second == m_FreeBlocks.begin(), "Incorrect first block"); - } - } - - FreeBlockListManager(FreeBlockListManager&& rhs) : - m_FreeBlocks(std::move(rhs.m_FreeBlocks)), - m_FreeBlocksBySize(std::move(rhs.m_FreeBlocksBySize)), - m_MaxSize(rhs.m_MaxSize), - m_FreeSize(rhs.m_FreeSize) - { - rhs.m_MaxSize = 0; - rhs.m_FreeSize = 0; - } - FreeBlockListManager& operator = (FreeBlockListManager&& rhs) = default; - FreeBlockListManager(const FreeBlockListManager&) = delete; - FreeBlockListManager& operator = (const FreeBlockListManager&) = delete; - - OffsetType Allocate(OffsetType Size) - { - VERIFY_EXPR(Size != 0); - if(m_FreeSize < Size) - return InvalidOffset; - - // Get the first block that is >= Size - auto SmallestBlockItIt = m_FreeBlocksBySize.lower_bound(Size); - if(SmallestBlockItIt == m_FreeBlocksBySize.end()) - return InvalidOffset; - - auto SmallestBlockIt = SmallestBlockItIt->second; - VERIFY_EXPR(Size <= SmallestBlockIt->second.Size); - - auto Offset = SmallestBlockIt->first; - auto NewOffset = Offset + Size; - auto NewSize = SmallestBlockIt->second.Size - Size; - VERIFY_EXPR(SmallestBlockItIt == SmallestBlockIt->second.OrderBySizeIt); - m_FreeBlocksBySize.erase(SmallestBlockItIt); - m_FreeBlocks.erase(SmallestBlockIt); - if (NewSize > 0) - { - AddNewBlock(NewOffset, NewSize); - } - - m_FreeSize -= Size; - -#ifdef _DEBUG - DbgVerifyList(); -#endif - return Offset; - } - - void Free(OffsetType Offset, OffsetType Size) - { - VERIFY_EXPR(Offset+Size <= m_MaxSize); - - auto NextBlockIt = m_FreeBlocks.upper_bound(Offset); // First element > -#ifdef _DEBUG - { - auto LowBnd = m_FreeBlocks.lower_bound(Offset); // First element >= - // Since zero-size allocations are not allowed, lower bound must always be equal upper bound - VERIFY_EXPR(LowBnd == NextBlockIt); - } -#endif - VERIFY_EXPR(NextBlockIt == m_FreeBlocks.end() || Offset <= NextBlockIt->first + NextBlockIt->second.Size); - auto PrevBlockIt = NextBlockIt; - if(PrevBlockIt != m_FreeBlocks.begin()) - { - --PrevBlockIt; - VERIFY_EXPR(Offset >= PrevBlockIt->first + PrevBlockIt->second.Size); - } - else - PrevBlockIt = m_FreeBlocks.end(); - - OffsetType NewSize, NewOffset; - if(PrevBlockIt != m_FreeBlocks.end() && Offset == PrevBlockIt->first + PrevBlockIt->second.Size) - { - // PrevBlock.Offset Offset - // | | - // |<-----PrevBlock.Size----->|<------Size-------->| - // - NewSize = PrevBlockIt->second.Size + Size; - NewOffset = PrevBlockIt->first; - - if (NextBlockIt != m_FreeBlocks.end() && Offset + Size == NextBlockIt->first) - { - // PrevBlock.Offset Offset NextBlock.Offset - // | | | - // |<-----PrevBlock.Size----->|<------Size-------->|<-----NextBlock.Size----->| - // - NewSize += NextBlockIt->second.Size; - m_FreeBlocksBySize.erase(PrevBlockIt->second.OrderBySizeIt); - m_FreeBlocksBySize.erase(NextBlockIt->second.OrderBySizeIt); - ++NextBlockIt; - m_FreeBlocks.erase(PrevBlockIt, NextBlockIt); - } - else - { - // PrevBlock.Offset Offset NextBlock.Offset - // | | | - // |<-----PrevBlock.Size----->|<------Size-------->| ~ ~ ~ |<-----NextBlock.Size----->| - // - m_FreeBlocksBySize.erase(PrevBlockIt->second.OrderBySizeIt); - m_FreeBlocks.erase(PrevBlockIt); - } - } - else if (NextBlockIt != m_FreeBlocks.end() && Offset + Size == NextBlockIt->first) - { - // PrevBlock.Offset Offset NextBlock.Offset - // | | | - // |<-----PrevBlock.Size----->| ~ ~ ~ |<------Size-------->|<-----NextBlock.Size----->| - // - NewSize = Size + NextBlockIt->second.Size; - NewOffset = Offset; - m_FreeBlocksBySize.erase(NextBlockIt->second.OrderBySizeIt); - m_FreeBlocks.erase(NextBlockIt); - } - else - { - // PrevBlock.Offset Offset NextBlock.Offset - // | | | - // |<-----PrevBlock.Size----->| ~ ~ ~ |<------Size-------->| ~ ~ ~ |<-----NextBlock.Size----->| - // - NewSize = Size; - NewOffset = Offset; - } - - AddNewBlock(NewOffset, NewSize); - - m_FreeSize += Size; -#ifdef _DEBUG - DbgVerifyList(); -#endif - } - - OffsetType GetMaxSize()const{return m_MaxSize;} - bool IsFull()const{ return m_FreeSize==0; }; - bool IsEmpty()const{ return m_FreeSize==m_MaxSize; }; - OffsetType GetFreeSize()const{return m_FreeSize;} - -#ifdef _DEBUG - size_t DbgGetNumFreeBlocks()const{return m_FreeBlocks.size();} -#endif - - private: - void AddNewBlock(OffsetType Offset, OffsetType Size) - { - auto NewBlockIt = m_FreeBlocks.emplace(Offset, Size); - VERIFY_EXPR(NewBlockIt.second); - auto OrderIt = m_FreeBlocksBySize.emplace(Size, NewBlockIt.first); - NewBlockIt.first->second.OrderBySizeIt = OrderIt; - } - - -#ifdef _DEBUG - void DbgVerifyList() - { - OffsetType TotalFreeSize = 0; - - auto BlockIt = m_FreeBlocks.begin(); - auto PrevBlockIt = m_FreeBlocks.end(); - VERIFY_EXPR(m_FreeBlocks.size() == m_FreeBlocksBySize.size()); - while (BlockIt != m_FreeBlocks.end()) - { - VERIFY_EXPR(BlockIt->first >= 0 && BlockIt->first + BlockIt->second.Size <= m_MaxSize); - VERIFY_EXPR(BlockIt == BlockIt->second.OrderBySizeIt->second); - VERIFY(PrevBlockIt == m_FreeBlocks.end() || BlockIt->first > PrevBlockIt->first + PrevBlockIt->second.Size, "Adjoint blocks detected" ); - TotalFreeSize += BlockIt->second.Size; - - PrevBlockIt = BlockIt; - ++BlockIt; - } - - auto OrderIt = m_FreeBlocksBySize.begin(); - while (OrderIt != m_FreeBlocksBySize.end()) - { - VERIFY_EXPR(OrderIt->first == OrderIt->second->second.Size); - ++OrderIt; - } - - VERIFY_EXPR(TotalFreeSize == m_FreeSize); - } -#endif - - TFreeBlocksByOffsetMap m_FreeBlocks; - TFreeBlocksBySizeMap m_FreeBlocksBySize; - - OffsetType m_MaxSize = 0; - OffsetType m_FreeSize = 0; - }; -} diff --git a/Graphics/GraphicsTools/include/FreeBlockListManagerGPU.h b/Graphics/GraphicsTools/include/FreeBlockListManagerGPU.h deleted file mode 100644 index f2961bd3..00000000 --- a/Graphics/GraphicsTools/include/FreeBlockListManagerGPU.h +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright 2015-2016 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 - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. - * - * 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 -#include "FreeBlockListManager.h" -#include "STDAllocator.h" - -namespace Diligent -{ - class FreeBlockListManagerGPU : public FreeBlockListManager - { - private: - struct FreedAllocationInfo - { - OffsetType Offset; - OffsetType Size; - Uint64 FrameNumber; - FreedAllocationInfo(OffsetType _Offset, OffsetType _Size, Uint64 _FrameNumber) : - Offset(_Offset), Size(_Size), FrameNumber(_FrameNumber) - {} - }; - - public: - FreeBlockListManagerGPU(OffsetType MaxSize, IMemoryAllocator &Allocator) : - FreeBlockListManager(MaxSize, Allocator), - m_StaleAllocations(0, FreedAllocationInfo(0,0,0), STD_ALLOCATOR_RAW_MEM(FreedAllocationInfo, Allocator, "Allocator for deque< FreedAllocationInfo>" )) - {} - - ~FreeBlockListManagerGPU() - { - VERIFY(m_StaleAllocations.empty(), "Not all stale allocations released"); - } - - // = default causes compiler error when instantiating std::vector::emplace_back() in Visual Studio 2015 (Version 14.0.23107.0 D14REL) - FreeBlockListManagerGPU(FreeBlockListManagerGPU&& rhs) : - FreeBlockListManager(std::move(rhs)), - m_StaleAllocations(std::move(rhs.m_StaleAllocations)) - { - } - - FreeBlockListManagerGPU& operator = (FreeBlockListManagerGPU&& rhs) = default; - FreeBlockListManagerGPU(const FreeBlockListManagerGPU&) = delete; - FreeBlockListManagerGPU& operator = (const FreeBlockListManagerGPU&) = delete; - - void Free(OffsetType Offset, OffsetType Size, Uint64 FrameNumber) - { - m_StaleAllocations.emplace_back(Offset, Size, FrameNumber); - } - - void ReleaseCompletedFrames(Uint64 NumCompletedFrames) - { - while(!m_StaleAllocations.empty() && m_StaleAllocations.front().FrameNumber < NumCompletedFrames) - { - auto &OldestAllocation = m_StaleAllocations.front(); - FreeBlockListManager::Free(OldestAllocation.Offset, OldestAllocation.Size); - m_StaleAllocations.pop_front(); - } - } - - private: - std::deque< FreedAllocationInfo, STDAllocatorRawMem > m_StaleAllocations; - }; -} diff --git a/Graphics/GraphicsTools/include/GraphicsUtilities.h b/Graphics/GraphicsTools/include/GraphicsUtilities.h index f13684fd..a0cc2247 100644 --- a/Graphics/GraphicsTools/include/GraphicsUtilities.h +++ b/Graphics/GraphicsTools/include/GraphicsUtilities.h @@ -131,6 +131,36 @@ const Char* GetValueTypeString( VALUE_TYPE Val ); /// format attributes. const TextureFormatAttribs& GetTextureFormatAttribs(TEXTURE_FORMAT Format); +/// Returns the default format for a specified texture view type + +/// The default view is defined as follows: +/// * For a fully qualified texture format, the SRV/RTV/UAV view format is the same as texture format; +/// DSV format, if avaialble, is adjusted accrodingly (R32_FLOAT -> D32_FLOAT) +/// * For 32-bit typeless formats, default view is XXXX32_FLOAT (where XXXX are the actual format components)\n +/// * For 16-bit typeless formats, default view is XXXX16_FLOAT (where XXXX are the actual format components)\n +/// ** R16_TYPELESS is special. If BIND_DEPTH_STENCIL flag is set, it is translated to R16_UNORM/D16_UNORM; +/// otherwise it is translated to R16_FLOAT. +/// * For 8-bit typeless formats, default view is XXXX8_UNORM (where XXXX are the actual format components)\n +/// * sRGB is always chosen if it is available (RGBA8_UNORM_SRGB, TEX_FORMAT_BC1_UNORM_SRGB, etc.) +/// * For combined depth-stencil formats, SRV format references depth component (R24_UNORM_X8_TYPELESS for D24S8 formats, and +/// R32_FLOAT_X8X24_TYPELESS for D32S8X24 formats) +/// * For compressed formats, only SRV format is defined +/// +/// \param [in] Format - texture format, for which the view format is requested +/// \param [in] ViewType - texture view type +/// \param [in] BindFlags - texture bind flags +/// \return texture view type format +TEXTURE_FORMAT GetDefaultTextureViewFormat(TEXTURE_FORMAT TextureFormat, TEXTURE_VIEW_TYPE ViewType, Uint32 BindFlags); + +/// Returns the default format for a specified texture view type + +/// \param [in] TexDesc - texture description +/// \param [in] ViewType - texture view type +/// \return texture view type format +inline TEXTURE_FORMAT GetDefaultTextureViewFormat(const TextureDesc &TexDesc, TEXTURE_VIEW_TYPE ViewType) +{ + return GetDefaultTextureViewFormat(TexDesc.Format, ViewType, TexDesc.BindFlags); +} /// Returns the literal name of a texture view type. For instance, /// for a shader resource view, "TEXTURE_VIEW_SHADER_RESOURCE" will be returned. @@ -225,6 +255,6 @@ Uint32 ComputeMipLevelsCount( Uint32 Width ); Uint32 ComputeMipLevelsCount( Uint32 Width, Uint32 Height ); Uint32 ComputeMipLevelsCount( Uint32 Width, Uint32 Height, Uint32 Depth ); -void CreateUniformBuffer( IRenderDevice *pDevice, Uint32 Size, IBuffer **ppBuffer, USAGE Usage = USAGE_DYNAMIC, Uint32 BindFlag = BIND_UNIFORM_BUFFER, Uint32 CPUAccessFlags = CPU_ACCESS_WRITE ); - +void CreateUniformBuffer( IRenderDevice *pDevice, Uint32 Size, const Char *Name, IBuffer **ppBuffer, USAGE Usage = USAGE_DYNAMIC, Uint32 BindFlag = BIND_UNIFORM_BUFFER, Uint32 CPUAccessFlags = CPU_ACCESS_WRITE ); +void GenerateCheckerBoardPattern(Uint32 Width, Uint32 Height, TEXTURE_FORMAT Fmt, Uint32 HorzCells, Uint32 VertCells, Uint8 *pData, Uint32 StrideInBytes ); } diff --git a/Graphics/GraphicsTools/include/RingBuffer.h b/Graphics/GraphicsTools/include/RingBuffer.h index 8c4119ac..e053eefe 100644 --- a/Graphics/GraphicsTools/include/RingBuffer.h +++ b/Graphics/GraphicsTools/include/RingBuffer.h @@ -41,23 +41,26 @@ namespace Diligent typedef size_t OffsetType; struct FrameTailAttribs { - FrameTailAttribs(Uint64 fn, OffsetType off, OffsetType sz) : - FrameNum(fn), + FrameTailAttribs(Uint64 fv, OffsetType off, OffsetType sz) : + FenceValue(fv), Offset(off), Size(sz) {} - Uint64 FrameNum; + + // Fence value associated with the command list in which + // the allocation could have been referenced last time + Uint64 FenceValue; OffsetType Offset; OffsetType Size; }; static const OffsetType InvalidOffset = static_cast(-1); - RingBuffer(OffsetType MaxSize, IMemoryAllocator &Allocator) : + RingBuffer(OffsetType MaxSize, IMemoryAllocator &Allocator)noexcept : m_CompletedFrameTails(0, FrameTailAttribs(0,0,0), STD_ALLOCATOR_RAW_MEM(FrameTailAttribs, Allocator, "Allocator for vector" )), m_MaxSize(MaxSize) {} - RingBuffer(RingBuffer&& rhs) : + RingBuffer(RingBuffer&& rhs)noexcept : m_CompletedFrameTails(std::move(rhs.m_CompletedFrameTails)), m_Head(rhs.m_Head), m_Tail(rhs.m_Tail), @@ -72,12 +75,7 @@ namespace Diligent rhs.m_CurrFrameSize = 0; } - ~RingBuffer() - { - VERIFY(m_UsedSize==0, "All space in the ring buffer must be released") - } - - RingBuffer& operator = (RingBuffer&& rhs) + RingBuffer& operator = (RingBuffer&& rhs)noexcept { m_CompletedFrameTails = std::move(rhs.m_CompletedFrameTails); m_Head = rhs.m_Head; @@ -98,6 +96,11 @@ namespace Diligent RingBuffer(const RingBuffer&) = delete; RingBuffer& operator = (const RingBuffer&) = delete; + ~RingBuffer() + { + VERIFY(m_UsedSize==0, "All space in the ring buffer must be released") + } + OffsetType Allocate(OffsetType Size) { if(IsFull()) @@ -147,24 +150,24 @@ namespace Diligent return InvalidOffset; } - // FrameNum is the number of the frame (or command list) in which the tail + // FenceValue is the fence value associated with the command list in which the tail // could have been referenced last time // See http://diligentgraphics.com/diligent-engine/architecture/d3d12/managing-resource-lifetimes/ - void FinishCurrentFrame(Uint64 FrameNum) + void FinishCurrentFrame(Uint64 FenceValue) { - m_CompletedFrameTails.emplace_back(FrameNum, m_Tail, m_CurrFrameSize); + m_CompletedFrameTails.emplace_back(FenceValue, m_Tail, m_CurrFrameSize); m_CurrFrameSize = 0; } - // NumCompletedFrames is the number of completed frames (or command lists) + // CompletedFenceValue indicates GPU progress // See http://diligentgraphics.com/diligent-engine/architecture/d3d12/managing-resource-lifetimes/ - void ReleaseCompletedFrames(Uint64 NumCompletedFrames) + void ReleaseCompletedFrames(Uint64 CompletedFenceValue) { - // Command list is completed when its number is strictly less than the number of completed frames - while(!m_CompletedFrameTails.empty() && m_CompletedFrameTails.front().FrameNum < NumCompletedFrames) + // We can release all tails whose associated fence value is less than or equal to CompletedFenceValue + while(!m_CompletedFrameTails.empty() && m_CompletedFrameTails.front().FenceValue <= CompletedFenceValue) { const auto &OldestFrameTail = m_CompletedFrameTails.front(); - VERIFY_EXPR(OldestFrameTail.Size <= m_MaxSize); + VERIFY_EXPR(OldestFrameTail.Size <= m_UsedSize); m_UsedSize -= OldestFrameTail.Size; m_Head = OldestFrameTail.Offset; m_CompletedFrameTails.pop_front(); @@ -177,7 +180,7 @@ namespace Diligent OffsetType GetUsedSize()const{return m_UsedSize;} private: - // Consider the following scenario for 1024 buffer: + // Consider the following scenario for a 1024-byte buffer: // Allocate(512) // // h t m diff --git a/Graphics/GraphicsTools/include/ShaderMacroHelper.h b/Graphics/GraphicsTools/include/ShaderMacroHelper.h index 1beec624..15a2137b 100644 --- a/Graphics/GraphicsTools/include/ShaderMacroHelper.h +++ b/Graphics/GraphicsTools/include/ShaderMacroHelper.h @@ -36,6 +36,7 @@ // assume any responsibility for any errors which may appear in this software nor any // responsibility to update it. //-------------------------------------------------------------------------------------- +#pragma once #include #include @@ -51,12 +52,10 @@ namespace Diligent class ShaderMacroHelper { public: - ShaderMacroHelper() : m_bIsFinalized(false) {} template void AddShaderMacro( const Diligent::Char* Name, DefintionType Definition ) { - assert( !m_bIsFinalized ); std::ostringstream ss; ss << Definition; AddShaderMacro( Name, ss.str().c_str() ); @@ -64,49 +63,61 @@ public: void Finalize() { - ShaderMacro LastMacro = {NULL, NULL}; - m_Macros.push_back(LastMacro); - m_bIsFinalized = true; + if (!m_bIsFinalized) + { + m_Macros.emplace_back(nullptr, nullptr); + m_bIsFinalized = true; + } } + void Reopen() + { + if (m_bIsFinalized) + { + VERIFY_EXPR(m_Macros.size() > 0 && m_Macros.back().Name == nullptr && m_Macros.back().Definition == nullptr); + m_Macros.pop_back(); + m_bIsFinalized = false; + } + } + + void Clear() + { + m_Macros.clear(); + m_DefinitionsPool.clear(); + m_bIsFinalized = false; + } + operator const ShaderMacro* () { - assert( !m_Macros.size() || m_bIsFinalized ); - if( m_Macros.size() && !m_bIsFinalized ) + if (m_Macros.size() > 0 && !m_bIsFinalized) Finalize(); - return m_Macros.size() ? &m_Macros[0] : NULL; + return m_Macros.size() ? m_Macros.data() : nullptr; } private: std::vector< ShaderMacro > m_Macros; - std::set< std::string > m_DefinitionsPull; - bool m_bIsFinalized; + std::set< std::string > m_DefinitionsPool; + bool m_bIsFinalized = false; }; template<> inline void ShaderMacroHelper::AddShaderMacro( const Diligent::Char* Name, const Diligent::Char* Definition ) { - VERIFY_EXPR( !m_bIsFinalized ); - ShaderMacro NewMacro = - { - Name, - m_DefinitionsPull.insert(Definition).first->c_str() - }; - m_Macros.push_back(NewMacro); + Reopen(); + auto *PooledDefinition = m_DefinitionsPool.insert(Definition).first->c_str(); + m_Macros.emplace_back(Name, PooledDefinition); } template<> inline void ShaderMacroHelper::AddShaderMacro( const Diligent::Char* Name, bool Definition ) { - assert( !m_bIsFinalized ); AddShaderMacro( Name, Definition ? "1" : "0"); } template<> inline void ShaderMacroHelper::AddShaderMacro( const Diligent::Char* Name, float Definition ) { - assert( !m_bIsFinalized ); std::ostringstream ss; // Make sure that when floating point represents integer, it is still diff --git a/Graphics/GraphicsTools/include/TextureUploader.h b/Graphics/GraphicsTools/include/TextureUploader.h new file mode 100644 index 00000000..9f528ad3 --- /dev/null +++ b/Graphics/GraphicsTools/include/TextureUploader.h @@ -0,0 +1,72 @@ +/* Copyright 2015-2017 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 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * 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 "RenderDevice.h" +#include "DeviceContext.h" + +namespace Diligent +{ + struct UploadBufferDesc + { + Uint32 Width = 0; + Uint32 Height = 0; + Uint32 Depth = 1; + TEXTURE_FORMAT Format = TEX_FORMAT_UNKNOWN; + + bool operator == (const UploadBufferDesc &rhs) const + { + return Width == rhs.Width && + Height == rhs.Height && + Depth == rhs.Depth && + Format == rhs.Format; + } + }; + + class IUploadBuffer : public IObject + { + public: + virtual void WaitForCopyScheduled() = 0; + virtual void* GetDataPtr() = 0; + virtual size_t GetRowStride() const = 0; + virtual size_t GetDepthStride()const = 0; + virtual const UploadBufferDesc& GetDesc()const = 0; + }; + + struct TextureUploaderDesc + { + + }; + + class ITextureUploader : public IObject + { + public: + virtual void RenderThreadUpdate(IDeviceContext *pContext) = 0; + virtual void AllocateUploadBuffer(const UploadBufferDesc& Desc, bool IsRenderThread, IUploadBuffer **ppBuffer) = 0; + virtual void ScheduleGPUCopy(ITexture *pDstTexture, Uint32 ArraySlice, Uint32 MipLevel, IUploadBuffer *pUploadBuffer) = 0; + virtual void RecycleBuffer(IUploadBuffer *pUploadBuffer) = 0; + }; + + void CreateTextureUploader(IRenderDevice *pDevice, const TextureUploaderDesc& Desc, ITextureUploader **ppUploader); +} diff --git a/Graphics/GraphicsTools/include/TextureUploaderBase.h b/Graphics/GraphicsTools/include/TextureUploaderBase.h new file mode 100644 index 00000000..0bd43bcd --- /dev/null +++ b/Graphics/GraphicsTools/include/TextureUploaderBase.h @@ -0,0 +1,79 @@ +/* Copyright 2015-2017 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 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * 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 "TextureUploader.h" +#include "ObjectBase.h" +#include "HashUtils.h" +#include "RefCntAutoPtr.h" + +namespace std +{ + template<> + struct hash + { + size_t operator()(const Diligent::UploadBufferDesc &Desc) const + { + return Diligent::ComputeHash(Desc.Width, Desc.Height, Desc.Depth, static_cast(Desc.Format)); + } + }; +} + +namespace Diligent +{ + class UploadBufferBase : public ObjectBase + { + public: + UploadBufferBase(IReferenceCounters *pRefCounters, const UploadBufferDesc &Desc) : + ObjectBase(pRefCounters), + m_Desc(Desc) + { + } + + virtual void WaitForCopyScheduled() = 0; + virtual void* GetDataPtr() override final { return m_pData; } + virtual size_t GetRowStride() const override final{ return m_RowStride; } + virtual size_t GetDepthStride()const override final{ return m_DepthStride; } + virtual const UploadBufferDesc& GetDesc()const override final{ return m_Desc; } + + protected: + const UploadBufferDesc m_Desc; + void* m_pData = 0; + size_t m_RowStride = 0; + size_t m_DepthStride = 0; + }; + + class TextureUploaderBase : public ObjectBase + { + public: + TextureUploaderBase(IReferenceCounters *pRefCounters, IRenderDevice *pDevice, const TextureUploaderDesc Desc) : + ObjectBase(pRefCounters), + m_pDevice(pDevice) + {} + + protected: + RefCntAutoPtr m_pDevice; + }; + +} diff --git a/Graphics/GraphicsTools/include/TextureUploaderD3D11.h b/Graphics/GraphicsTools/include/TextureUploaderD3D11.h new file mode 100644 index 00000000..48d48aa3 --- /dev/null +++ b/Graphics/GraphicsTools/include/TextureUploaderD3D11.h @@ -0,0 +1,44 @@ +/* Copyright 2015-2017 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 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * 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 "TextureUploaderBase.h" +namespace Diligent +{ + class TextureUploaderD3D11 : public TextureUploaderBase + { + public: + TextureUploaderD3D11(IReferenceCounters *pRefCounters, IRenderDevice *pDevice, const TextureUploaderDesc Desc); + ~TextureUploaderD3D11(); + virtual void RenderThreadUpdate(IDeviceContext *pContext)override final; + + virtual void AllocateUploadBuffer(const UploadBufferDesc& Desc, bool IsRenderThread, IUploadBuffer **ppBuffer)override final; + virtual void ScheduleGPUCopy(ITexture *pDstTexture, Uint32 ArraySlice, Uint32 MipLevel, IUploadBuffer *pUploadBuffer)override final; + virtual void RecycleBuffer(IUploadBuffer *pUploadBuffer)override final; + + private: + struct InternalData; + std::unique_ptr m_pInternalData; + }; +} \ No newline at end of file diff --git a/Graphics/GraphicsTools/include/TextureUploaderD3D12.h b/Graphics/GraphicsTools/include/TextureUploaderD3D12.h new file mode 100644 index 00000000..ff11ec9c --- /dev/null +++ b/Graphics/GraphicsTools/include/TextureUploaderD3D12.h @@ -0,0 +1,45 @@ +/* Copyright 2015-2017 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 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * 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 "TextureUploaderBase.h" + +namespace Diligent +{ + class TextureUploaderD3D12 : public TextureUploaderBase + { + public: + TextureUploaderD3D12(IReferenceCounters *pRefCounters, IRenderDevice *pDevice, const TextureUploaderDesc Desc); + ~TextureUploaderD3D12(); + virtual void RenderThreadUpdate(IDeviceContext *pContext)override final; + + virtual void AllocateUploadBuffer(const UploadBufferDesc& Desc, bool IsRenderThread, IUploadBuffer **ppBuffer)override final; + virtual void ScheduleGPUCopy(ITexture *pDstTexture, Uint32 ArraySlice, Uint32 MipLevel, IUploadBuffer *pUploadBuffer)override final; + virtual void RecycleBuffer(IUploadBuffer *pUploadBuffer)override final; + + private: + struct InternalData; + std::unique_ptr m_pInternalData; + }; +} diff --git a/Graphics/GraphicsTools/include/TextureUploaderGL.h b/Graphics/GraphicsTools/include/TextureUploaderGL.h new file mode 100644 index 00000000..5e868870 --- /dev/null +++ b/Graphics/GraphicsTools/include/TextureUploaderGL.h @@ -0,0 +1,45 @@ +/* Copyright 2015-2017 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 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * 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 "TextureUploaderBase.h" + +namespace Diligent +{ + class TextureUploaderGL : public TextureUploaderBase + { + public: + TextureUploaderGL(IReferenceCounters *pRefCounters, IRenderDevice *pDevice, const TextureUploaderDesc Desc); + ~TextureUploaderGL(); + virtual void RenderThreadUpdate(IDeviceContext *pContext)override final; + + virtual void AllocateUploadBuffer(const UploadBufferDesc& Desc, bool IsRenderThread, IUploadBuffer **ppBuffer)override final; + virtual void ScheduleGPUCopy(ITexture *pDstTexture, Uint32 ArraySlice, Uint32 MipLevel, IUploadBuffer *pUploadBuffer)override final; + virtual void RecycleBuffer(IUploadBuffer *pUploadBuffer)override final; + + private: + struct InternalData; + std::unique_ptr m_pInternalData; + }; +} diff --git a/Graphics/GraphicsTools/include/VariableSizeGPUAllocationsManager.h b/Graphics/GraphicsTools/include/VariableSizeGPUAllocationsManager.h index b1cb9693..f299ca07 100644 --- a/Graphics/GraphicsTools/include/VariableSizeGPUAllocationsManager.h +++ b/Graphics/GraphicsTools/include/VariableSizeGPUAllocationsManager.h @@ -42,9 +42,9 @@ namespace Diligent { OffsetType Offset; OffsetType Size; - Uint64 CmdListNumber; - StaleAllocationAttribs(OffsetType _Offset, OffsetType _Size, Uint64 _CmdListNumber) : - Offset(_Offset), Size(_Size), CmdListNumber(_CmdListNumber) + Uint64 FenceValue; + StaleAllocationAttribs(OffsetType _Offset, OffsetType _Size, Uint64 _FenceValue) : + Offset(_Offset), Size(_Size), FenceValue(_FenceValue) {} }; @@ -73,22 +73,22 @@ namespace Diligent VariableSizeGPUAllocationsManager(const VariableSizeGPUAllocationsManager&) = delete; VariableSizeGPUAllocationsManager& operator = (const VariableSizeGPUAllocationsManager&) = delete; - void Free(OffsetType Offset, OffsetType Size, Uint64 CmdListNumber) + void Free(OffsetType Offset, OffsetType Size, Uint64 FenceValue) { // Do not release the block immediately, but add // it to the queue instead - m_StaleAllocations.emplace_back(Offset, Size, CmdListNumber); + m_StaleAllocations.emplace_back(Offset, Size, FenceValue); m_StaleAllocationsSize += Size; } // Releases stale allocation from completed command lists - // The method takes the NUMBER of completed cmd lists (N) - // and releases all allocations whose number n < N - // (n == N is NOT released) - void ReleaseStaleAllocations(Uint64 NumCompletedCmdLists) + // The method takes the last known completed fence value N + // and releases all allocations whose associated fence value + // is at most N (n <= N) + void ReleaseStaleAllocations(Uint64 LastCompletedFenceValue) { // Free all allocations from the beginning of the queue that belong to completed command lists - while(!m_StaleAllocations.empty() && m_StaleAllocations.front().CmdListNumber < NumCompletedCmdLists) + while(!m_StaleAllocations.empty() && m_StaleAllocations.front().FenceValue <= LastCompletedFenceValue) { auto &OldestAllocation = m_StaleAllocations.front(); VariableSizeAllocationsManager::Free(OldestAllocation.Offset, OldestAllocation.Size); diff --git a/Graphics/GraphicsTools/readme.md b/Graphics/GraphicsTools/readme.md new file mode 100644 index 00000000..08d612d5 --- /dev/null +++ b/Graphics/GraphicsTools/readme.md @@ -0,0 +1,26 @@ + +# GraphicsTools + +Implementation of common grpahics Utilities + +# Release Notes + +## 2.1 + +### New features + +* Added [TextureUploader](include/TextureUploaderGL.h) interface and its implementations on + [D3D11](include/TextureUploaderD3D11.h), [D3D12](include/TextureUploaderD3D12.h), [OpenGL/GLES](include/TextureUploaderGL.h) + +## 2.0 + +Reworked the API to follow D3D12 style + +## 1.0 + +Initial release + + +**Copyright 2015-2017 Egor Yusov** + +[Diligent Graphics](http://diligentgraphics.com) \ No newline at end of file diff --git a/Graphics/GraphicsTools/src/BasicShaderSourceStreamFactory.cpp b/Graphics/GraphicsTools/src/BasicShaderSourceStreamFactory.cpp index 6c1db669..b35d3427 100644 --- a/Graphics/GraphicsTools/src/BasicShaderSourceStreamFactory.cpp +++ b/Graphics/GraphicsTools/src/BasicShaderSourceStreamFactory.cpp @@ -63,7 +63,7 @@ namespace Diligent String FullPath = SearchDir + ( (Name[0] == '\\' || Name[0] == '/') ? Name + 1 : Name); if( !FileSystem::FileExists( FullPath.c_str() ) ) continue; - pBasicFileStream = new BasicFileStream( FullPath.c_str(), EFileAccessMode::Read ); + pBasicFileStream = MakeNewRCObj()( FullPath.c_str(), EFileAccessMode::Read ); if( pBasicFileStream->IsValid() ) { bFileCreated = true; @@ -81,7 +81,7 @@ namespace Diligent else { *ppStream = nullptr; - LOG_ERROR_AND_THROW( "Failed to create input stream for source file ", Name ) + LOG_ERROR( "Failed to create input stream for source file ", Name ) } } } \ No newline at end of file diff --git a/Graphics/GraphicsTools/src/GraphicsUtilities.cpp b/Graphics/GraphicsTools/src/GraphicsUtilities.cpp index e0ae1dce..9b5beb4f 100644 --- a/Graphics/GraphicsTools/src/GraphicsUtilities.cpp +++ b/Graphics/GraphicsTools/src/GraphicsUtilities.cpp @@ -25,6 +25,9 @@ #include "GraphicsUtilities.h" #include "DebugUtilities.h" #include +#include + +#define PI_F 3.1415926f namespace Diligent { @@ -61,9 +64,184 @@ const Char* GetValueTypeString( VALUE_TYPE Val ) } } +class TexFormatToViewFormatConverter +{ +public: + TexFormatToViewFormatConverter() + { + static_assert(TEXTURE_VIEW_SHADER_RESOURCE == 1, "TEXTURE_VIEW_SHADER_RESOURCE == 1 expected"); + static_assert(TEXTURE_VIEW_RENDER_TARGET == 2, "TEXTURE_VIEW_RENDER_TARGET == 2 expected"); + static_assert(TEXTURE_VIEW_DEPTH_STENCIL == 3, "TEXTURE_VIEW_DEPTH_STENCIL == 3 expected"); + static_assert(TEXTURE_VIEW_UNORDERED_ACCESS == 4, "TEXTURE_VIEW_UNORDERED_ACCESS == 4 expected"); +#define INIT_TEX_VIEW_FORMAT_INFO(TexFmt, SRVFmt, RTVFmt, DSVFmt, UAVFmt)\ + {\ + m_ViewFormats[ TexFmt ][TEXTURE_VIEW_SHADER_RESOURCE-1] = TEX_FORMAT_##SRVFmt; \ + m_ViewFormats[ TexFmt ][TEXTURE_VIEW_RENDER_TARGET-1] = TEX_FORMAT_##RTVFmt; \ + m_ViewFormats[ TexFmt ][TEXTURE_VIEW_DEPTH_STENCIL-1] = TEX_FORMAT_##DSVFmt; \ + m_ViewFormats[ TexFmt ][TEXTURE_VIEW_UNORDERED_ACCESS-1] = TEX_FORMAT_##UAVFmt; \ + } + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA32_TYPELESS, RGBA32_FLOAT, RGBA32_FLOAT, UNKNOWN, RGBA32_FLOAT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA32_FLOAT, RGBA32_FLOAT, RGBA32_FLOAT, UNKNOWN, RGBA32_FLOAT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA32_UINT, RGBA32_UINT, RGBA32_UINT, UNKNOWN, RGBA32_UINT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA32_SINT, RGBA32_SINT, RGBA32_SINT, UNKNOWN, RGBA32_SINT); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGB32_TYPELESS, RGB32_FLOAT, RGB32_FLOAT, UNKNOWN, RGB32_FLOAT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGB32_FLOAT, RGB32_FLOAT, RGB32_FLOAT, UNKNOWN, RGB32_FLOAT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGB32_UINT, RGB32_UINT, RGB32_UINT, UNKNOWN, RGB32_UINT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGB32_SINT, RGB32_SINT, RGB32_SINT, UNKNOWN, RGB32_SINT); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA16_TYPELESS, RGBA16_FLOAT, RGBA16_FLOAT, UNKNOWN, RGBA16_FLOAT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA16_FLOAT, RGBA16_FLOAT, RGBA16_FLOAT, UNKNOWN, RGBA16_FLOAT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA16_UNORM, RGBA16_UNORM, RGBA16_UNORM, UNKNOWN, RGBA16_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA16_UINT, RGBA16_UINT, RGBA16_UINT, UNKNOWN, RGBA16_UINT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA16_SNORM, RGBA16_SNORM, RGBA16_SNORM, UNKNOWN, RGBA16_SNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA16_SINT, RGBA16_SINT, RGBA16_SINT, UNKNOWN, RGBA16_SINT); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG32_TYPELESS, RG32_FLOAT, RG32_FLOAT, UNKNOWN, RG32_FLOAT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG32_FLOAT, RG32_FLOAT, RG32_FLOAT, UNKNOWN, RG32_FLOAT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG32_UINT, RG32_UINT, RG32_UINT, UNKNOWN, RG32_UINT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG32_SINT, RG32_SINT, RG32_SINT, UNKNOWN, RG32_SINT); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R32G8X24_TYPELESS, R32_FLOAT_X8X24_TYPELESS, UNKNOWN, D32_FLOAT_S8X24_UINT, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_D32_FLOAT_S8X24_UINT, R32_FLOAT_X8X24_TYPELESS, UNKNOWN, D32_FLOAT_S8X24_UINT, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R32_FLOAT_X8X24_TYPELESS,R32_FLOAT_X8X24_TYPELESS, UNKNOWN, D32_FLOAT_S8X24_UINT, R32_FLOAT_X8X24_TYPELESS); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_X32_TYPELESS_G8X24_UINT, X32_TYPELESS_G8X24_UINT, UNKNOWN, D32_FLOAT_S8X24_UINT, X32_TYPELESS_G8X24_UINT); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGB10A2_TYPELESS, RGB10A2_UNORM, RGB10A2_UNORM, UNKNOWN, RGB10A2_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGB10A2_UNORM, RGB10A2_UNORM, RGB10A2_UNORM, UNKNOWN, RGB10A2_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGB10A2_UINT, RGB10A2_UINT, RGB10A2_UINT, UNKNOWN, RGB10A2_UINT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R11G11B10_FLOAT, R11G11B10_FLOAT, R11G11B10_FLOAT, UNKNOWN, R11G11B10_FLOAT); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA8_TYPELESS, RGBA8_UNORM_SRGB, RGBA8_UNORM_SRGB, UNKNOWN, RGBA8_UNORM_SRGB); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA8_UNORM, RGBA8_UNORM, RGBA8_UNORM, UNKNOWN, RGBA8_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA8_UNORM_SRGB, RGBA8_UNORM_SRGB, RGBA8_UNORM_SRGB, UNKNOWN, RGBA8_UNORM_SRGB); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA8_UINT, RGBA8_UINT, RGBA8_UINT, UNKNOWN, RGBA8_UINT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA8_SNORM, RGBA8_SNORM, RGBA8_SNORM, UNKNOWN, RGBA8_SNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGBA8_SINT, RGBA8_SINT, RGBA8_SINT, UNKNOWN, RGBA8_SINT); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG16_TYPELESS, RG16_FLOAT, RG16_FLOAT, UNKNOWN, RG16_FLOAT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG16_FLOAT, RG16_FLOAT, RG16_FLOAT, UNKNOWN, RG16_FLOAT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG16_UNORM, RG16_UNORM, RG16_UNORM, UNKNOWN, RG16_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG16_UINT, RG16_UINT, RG16_UINT, UNKNOWN, RG16_UINT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG16_SNORM, RG16_SNORM, RG16_SNORM, UNKNOWN, RG16_SNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG16_SINT, RG16_SINT, RG16_SINT, UNKNOWN, RG16_SINT); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R32_TYPELESS, R32_FLOAT, R32_FLOAT, D32_FLOAT, R32_FLOAT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_D32_FLOAT, R32_FLOAT, R32_FLOAT, D32_FLOAT, R32_FLOAT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R32_FLOAT, R32_FLOAT, R32_FLOAT, D32_FLOAT, R32_FLOAT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R32_UINT, R32_UINT, R32_UINT, UNKNOWN, R32_UINT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R32_SINT, R32_SINT, R32_SINT, UNKNOWN, R32_SINT); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R24G8_TYPELESS, R24_UNORM_X8_TYPELESS, UNKNOWN, D24_UNORM_S8_UINT, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_D24_UNORM_S8_UINT, R24_UNORM_X8_TYPELESS, UNKNOWN, D24_UNORM_S8_UINT, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R24_UNORM_X8_TYPELESS, R24_UNORM_X8_TYPELESS, UNKNOWN, D24_UNORM_S8_UINT, R24_UNORM_X8_TYPELESS); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_X24_TYPELESS_G8_UINT, X24_TYPELESS_G8_UINT, UNKNOWN, D24_UNORM_S8_UINT, X24_TYPELESS_G8_UINT); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG8_TYPELESS, RG8_UNORM, RG8_UNORM, UNKNOWN, RG8_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG8_UNORM, RG8_UNORM, RG8_UNORM, UNKNOWN, RG8_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG8_UINT, RG8_UINT, RG8_UINT, UNKNOWN, RG8_UINT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG8_SNORM, RG8_SNORM, RG8_SNORM, UNKNOWN, RG8_SNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG8_SINT, RG8_SINT, RG8_SINT, UNKNOWN, RG8_SINT); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R16_TYPELESS, R16_FLOAT, R16_FLOAT, UNKNOWN, R16_FLOAT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R16_FLOAT, R16_FLOAT, R16_FLOAT, UNKNOWN, R16_FLOAT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_D16_UNORM, R16_UNORM, R16_UNORM, D16_UNORM, R16_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R16_UNORM, R16_UNORM, R16_UNORM, D16_UNORM, R16_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R16_UINT, R16_UINT, R16_UINT, UNKNOWN, R16_UINT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R16_SNORM, R16_SNORM, R16_SNORM, UNKNOWN, R16_SNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R16_SINT, R16_SINT, R16_SINT, UNKNOWN, R16_SINT); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R8_TYPELESS, R8_UNORM, R8_UNORM, UNKNOWN, R8_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R8_UNORM, R8_UNORM, R8_UNORM, UNKNOWN, R8_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R8_UINT, R8_UINT, R8_UINT, UNKNOWN, R8_UINT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R8_SNORM, R8_SNORM, R8_SNORM, UNKNOWN, R8_SNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R8_SINT, R8_SINT, R8_SINT, UNKNOWN, R8_SINT); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_A8_UNORM, A8_UNORM, A8_UNORM, UNKNOWN, A8_UNORM); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R1_UNORM, R1_UNORM, R1_UNORM, UNKNOWN, R1_UNORM); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RGB9E5_SHAREDEXP, RGB9E5_SHAREDEXP, RGB9E5_SHAREDEXP, UNKNOWN, RGB9E5_SHAREDEXP); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_RG8_B8G8_UNORM, RG8_B8G8_UNORM, RG8_B8G8_UNORM, UNKNOWN, RG8_B8G8_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_G8R8_G8B8_UNORM, G8R8_G8B8_UNORM, G8R8_G8B8_UNORM, UNKNOWN, G8R8_G8B8_UNORM); + + // http://www.g-truc.net/post-0335.html + // http://renderingpipeline.com/2012/07/texture-compression/ + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC1_TYPELESS, BC1_UNORM_SRGB, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC1_UNORM, BC1_UNORM, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC1_UNORM_SRGB, BC1_UNORM_SRGB, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC2_TYPELESS, BC2_UNORM_SRGB, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC2_UNORM, BC2_UNORM, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC2_UNORM_SRGB, BC2_UNORM_SRGB, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC3_TYPELESS, BC3_UNORM_SRGB, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC3_UNORM, BC3_UNORM, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC3_UNORM_SRGB, BC3_UNORM_SRGB, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC4_TYPELESS, BC4_UNORM, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC4_UNORM, BC4_UNORM, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC4_SNORM, BC4_SNORM, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC5_TYPELESS, BC5_UNORM, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC5_UNORM, BC5_UNORM, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC5_SNORM, BC5_SNORM, UNKNOWN, UNKNOWN, UNKNOWN); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_B5G6R5_UNORM, B5G6R5_UNORM, B5G6R5_UNORM, UNKNOWN, B5G6R5_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_B5G5R5A1_UNORM, B5G5R5A1_UNORM, B5G5R5A1_UNORM, UNKNOWN, B5G5R5A1_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BGRA8_UNORM, BGRA8_UNORM, BGRA8_UNORM, UNKNOWN, BGRA8_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BGRX8_UNORM, BGRX8_UNORM, BGRX8_UNORM, UNKNOWN, BGRX8_UNORM); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_R10G10B10_XR_BIAS_A2_UNORM, R10G10B10_XR_BIAS_A2_UNORM, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BGRA8_TYPELESS, BGRA8_UNORM_SRGB, BGRA8_UNORM_SRGB, UNKNOWN, BGRA8_UNORM_SRGB); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BGRA8_UNORM_SRGB, BGRA8_UNORM_SRGB, BGRA8_UNORM_SRGB, UNKNOWN, BGRA8_UNORM_SRGB); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BGRX8_TYPELESS, BGRX8_UNORM_SRGB, BGRX8_UNORM_SRGB, UNKNOWN, BGRX8_UNORM_SRGB); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BGRX8_UNORM_SRGB, BGRX8_UNORM_SRGB, BGRX8_UNORM_SRGB, UNKNOWN, BGRX8_UNORM_SRGB); + + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC6H_TYPELESS, BC6H_UF16, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC6H_UF16, BC6H_UF16, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC6H_SF16, BC6H_SF16, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC7_TYPELESS, BC7_UNORM_SRGB, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC7_UNORM, BC7_UNORM, UNKNOWN, UNKNOWN, UNKNOWN); + INIT_TEX_VIEW_FORMAT_INFO( TEX_FORMAT_BC7_UNORM_SRGB, BC7_UNORM_SRGB, UNKNOWN, UNKNOWN, UNKNOWN); +#undef INIT_TVIEW_FORMAT_INFO + } + + TEXTURE_FORMAT GetViewFormat(TEXTURE_FORMAT Format, TEXTURE_VIEW_TYPE ViewType, Uint32 BindFlags) + { + VERIFY(ViewType > TEXTURE_VIEW_UNDEFINED && ViewType < TEXTURE_VIEW_NUM_VIEWS, "Unexpected texture view type"); + VERIFY(Format >= TEX_FORMAT_UNKNOWN && Format < TEX_FORMAT_NUM_FORMATS, "Unknown texture format"); + switch (Format) + { + case TEX_FORMAT_R16_TYPELESS: + { + if (BindFlags & BIND_DEPTH_STENCIL) + { + static TEXTURE_FORMAT D16_ViewFmts[] = + { + TEX_FORMAT_R16_UNORM, TEX_FORMAT_R16_UNORM, TEX_FORMAT_D16_UNORM, TEX_FORMAT_R16_UNORM + }; + return D16_ViewFmts[ViewType - 1]; + } + } + + default: /*do nothing*/break; + } + + return m_ViewFormats[Format][ViewType-1]; + } + +private: + + TEXTURE_FORMAT m_ViewFormats[TEX_FORMAT_NUM_FORMATS][TEXTURE_VIEW_NUM_VIEWS-1]; +}; + +TEXTURE_FORMAT GetDefaultTextureViewFormat(TEXTURE_FORMAT TextureFormat, TEXTURE_VIEW_TYPE ViewType, Uint32 BindFlags) +{ + static TexFormatToViewFormatConverter FmtConverter; + return FmtConverter.GetViewFormat(TextureFormat, ViewType, BindFlags); +} + const TextureFormatAttribs& GetTextureFormatAttribs( TEXTURE_FORMAT Format ) { - static TextureFormatAttribs FmtAttribs[TEX_FORMAT_NUM_FORMATS] = {}; + static TextureFormatAttribs FmtAttribs[TEX_FORMAT_NUM_FORMATS]; static bool bIsInit = false; // Note that this implementation is thread-safe // Even if two threads try to call the function at the same time, @@ -516,7 +694,7 @@ static const Char* GetBufferModeString( BUFFER_MODE Mode ) { #define INIT_BUFF_MODE_STR(Mode)BufferModeStrings[Mode] = #Mode INIT_BUFF_MODE_STR( BUFFER_MODE_UNDEFINED ); - INIT_BUFF_MODE_STR( BUFFER_MODE_FORMATED ); + INIT_BUFF_MODE_STR( BUFFER_MODE_FORMATTED ); INIT_BUFF_MODE_STR( BUFFER_MODE_STRUCTURED ); #undef INIT_BUFF_MODE_STR static_assert(BUFFER_MODE_NUM_MODES == BUFFER_MODE_STRUCTURED + 1, "Not all buffer mode strings initialized."); @@ -556,7 +734,7 @@ String GetBufferDescString( const BufferDesc &Desc ) Str += "; Mode: "; Str += GetBufferModeString(Desc.Mode); - if( Desc.Mode == BUFFER_MODE_FORMATED ) + if( Desc.Mode == BUFFER_MODE_FORMATTED ) { Str += "; Format: "; Str += GetValueTypeString( Desc.Format.ValueType ); @@ -601,9 +779,10 @@ Uint32 ComputeMipLevelsCount( Uint32 Width, Uint32 Height, Uint32 Depth ) return ComputeMipLevelsCount( std::max(std::max( Width, Height ), Depth) ); } -void CreateUniformBuffer( IRenderDevice *pDevice, Uint32 Size, IBuffer **ppBuffer, USAGE Usage, Uint32 BindFlag, Uint32 CPUAccessFlags) +void CreateUniformBuffer( IRenderDevice *pDevice, Uint32 Size, const Char *Name, IBuffer **ppBuffer, USAGE Usage, Uint32 BindFlag, Uint32 CPUAccessFlags) { BufferDesc CBDesc; + CBDesc.Name = Name; CBDesc.uiSizeInBytes = Size; CBDesc.Usage = Usage; CBDesc.BindFlags = BindFlag; @@ -611,4 +790,75 @@ void CreateUniformBuffer( IRenderDevice *pDevice, Uint32 Size, IBuffer **ppBuffe pDevice->CreateBuffer( CBDesc, BufferData(), ppBuffer ); } +template +void GenerateCheckerBoardPatternInternal(Uint32 Width, Uint32 Height, TEXTURE_FORMAT Fmt, Uint32 HorzCells, Uint32 VertCells, Uint8 *pData, Uint32 StrideInBytes, TConverter Converter) +{ + const auto& FmtAttribs = GetTextureFormatAttribs(Fmt); + for (Uint32 y = 0; y < Height; ++y) + { + for (Uint32 x = 0; x < Width; ++x) + { + float horzWave = sin((static_cast(x) + 0.5f) / static_cast(Width) * PI_F * static_cast(HorzCells)); + float vertWave = sin((static_cast(y) + 0.5f) / static_cast(Height) * PI_F * static_cast(VertCells)); + float val = horzWave * vertWave; + val = std::max( std::min( val*20.f, +1.f), -1.f ); + val = val * 0.5f + 1.f; + val = val * 0.5f + 0.25f; + Uint8 *pDstTexel = pData + x * FmtAttribs.NumComponents * FmtAttribs.ComponentSize + y * StrideInBytes; + Converter(pDstTexel, FmtAttribs.NumComponents, val); + } + } +} + +static float LinearToSRGB(float x) +{ + // This is exactly the sRGB curve + //return x < 0.0031308 ? 12.92 * x : 1.055 * pow(abs(x), 1.0 / 2.4) - 0.055; + + // This is cheaper but nearly equivalent + return x < 0.0031308f ? 12.92f * x : 1.13005f * sqrtf(abs(x - 0.00228f)) - 0.13448f * x + 0.005719f; +} + + +void GenerateCheckerBoardPattern(Uint32 Width, Uint32 Height, TEXTURE_FORMAT Fmt, Uint32 HorzCells, Uint32 VertCells, Uint8 *pData, Uint32 StrideInBytes) +{ + const auto& FmtAttribs = GetTextureFormatAttribs(Fmt); + switch (FmtAttribs.ComponentType) + { + case COMPONENT_TYPE_UINT: + case COMPONENT_TYPE_UNORM: + GenerateCheckerBoardPatternInternal(Width, Height, Fmt, HorzCells, VertCells, pData, StrideInBytes, + [](Uint8 *pDstTexel, Uint32 NumComponents, float fVal) + { + Uint8 uVal = static_cast(fVal * 255.f); + for (Uint32 c = 0; c < NumComponents; ++c) + pDstTexel[c] = uVal; + }); + break; + + case COMPONENT_TYPE_UNORM_SRGB: + GenerateCheckerBoardPatternInternal(Width, Height, Fmt, HorzCells, VertCells, pData, StrideInBytes, + [](Uint8 *pDstTexel, Uint32 NumComponents, float fVal) + { + Uint8 uVal = static_cast( LinearToSRGB(fVal) * 255.f); + for (Uint32 c = 0; c < NumComponents; ++c) + pDstTexel[c] = uVal; + }); + break; + + case COMPONENT_TYPE_FLOAT: + GenerateCheckerBoardPatternInternal(Width, Height, Fmt, HorzCells, VertCells, pData, StrideInBytes, + [](Uint8 *pDstTexel, Uint32 NumComponents, float fVal) + { + for (Uint32 c = 0; c < NumComponents; ++c) + (reinterpret_cast(pDstTexel))[c] = fVal; + }); + break; + + default: + UNSUPPORTED("Unsupported component type") + return; + } +} + } diff --git a/Graphics/GraphicsTools/src/TextureUploader.cpp b/Graphics/GraphicsTools/src/TextureUploader.cpp new file mode 100644 index 00000000..f056f162 --- /dev/null +++ b/Graphics/GraphicsTools/src/TextureUploader.cpp @@ -0,0 +1,52 @@ +/* Copyright 2015-2017 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 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * 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 "pch.h" +#include "TextureUploaderD3D11.h" +#include "TextureUploaderD3D12.h" +#include "TextureUploaderGL.h" + +namespace Diligent +{ + void CreateTextureUploader(IRenderDevice *pDevice, const TextureUploaderDesc& Desc, ITextureUploader **ppUploader) + { + *ppUploader = nullptr; + switch (pDevice->GetDeviceCaps().DevType) + { + case DeviceType::D3D11: + *ppUploader = MakeNewRCObj()( pDevice, Desc ); + break; + + case DeviceType::D3D12: + *ppUploader = MakeNewRCObj()( pDevice, Desc ); + break; + + case DeviceType::OpenGLES: + case DeviceType::OpenGL: + *ppUploader = MakeNewRCObj()( pDevice, Desc ); + break; + } + if (*ppUploader != nullptr) + (*ppUploader)->AddRef(); + } +} diff --git a/Graphics/GraphicsTools/src/TextureUploaderD3D11.cpp b/Graphics/GraphicsTools/src/TextureUploaderD3D11.cpp new file mode 100644 index 00000000..3677f7eb --- /dev/null +++ b/Graphics/GraphicsTools/src/TextureUploaderD3D11.cpp @@ -0,0 +1,326 @@ +/* Copyright 2015-2017 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 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * 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 "pch.h" + +#include +#include +#include +#include +#include + +#include "TextureUploaderD3D11.h" +#include "RenderDeviceD3D11.h" +#include "DeviceContextD3D11.h" +#include "TextureD3D11.h" +#include "DXGITypeConversions.h" + +namespace Diligent +{ + class UploadBufferD3D11 : public UploadBufferBase + { + public: + UploadBufferD3D11(Diligent::IReferenceCounters *pRefCounters, const UploadBufferDesc &Desc, ID3D11Texture2D *pStagingTexture) : + UploadBufferBase(pRefCounters, Desc), + m_pStagingTexture(pStagingTexture) + {} + + ~UploadBufferD3D11() + { + if(m_pStagingTexture) + LOG_INFO_MESSAGE("UploadBufferD3D11: releasing ", m_Desc.Width, 'x', m_Desc.Height, " Fmt=", m_Desc.Format, " staging texture") + } + + void SetDataPtr(void *pData, size_t RowStride, size_t DepthStride) + { + m_pData = pData; + m_RowStride = RowStride; + m_DepthStride = DepthStride; + } + + // http://en.cppreference.com/w/cpp/thread/condition_variable + void WaitForMap() + { + m_BufferMappedSignal.Wait(); + } + + void SignalMapped() + { + m_BufferMappedSignal.Trigger(); + } + + void SignalCopyScheduled() + { + m_CopyScheduledSignal.Trigger(); + } + + virtual void WaitForCopyScheduled()override final + { + m_CopyScheduledSignal.Wait(); + } + + bool DbgIsCopyScheduled() + { + return m_CopyScheduledSignal.IsTriggered(); + } + + bool DbgIsMapped() + { + return m_BufferMappedSignal.IsTriggered(); + } + + void Reset() + { + m_pData = nullptr; + m_RowStride = 0; + m_DepthStride = 0; + m_BufferMappedSignal.Reset(); + m_CopyScheduledSignal.Reset(); + } + + ID3D11Texture2D* GetStagingTex() { return m_pStagingTexture; } + private: + ThreadingTools::Signal m_BufferMappedSignal; + ThreadingTools::Signal m_CopyScheduledSignal; + CComPtr m_pStagingTexture; + }; + + struct TextureUploaderD3D11::InternalData + { + struct PendingBufferOperation + { + enum Operation + { + Map, + Copy, + MapAndCache + }operation; + RefCntAutoPtr pUploadBuffer; + CComPtr pd3d11NativeDstTexture; + UINT DstSubresource = 0; + + PendingBufferOperation(Operation op, UploadBufferD3D11* pBuff) : + operation(op), + pUploadBuffer(pBuff) + {} + PendingBufferOperation(Operation op, UploadBufferD3D11* pBuff, ID3D11Resource *pd3d11DstTex, UINT dstSubres) : + operation(op), + pUploadBuffer(pBuff), + pd3d11NativeDstTexture(pd3d11DstTex), + DstSubresource(dstSubres) + {} + }; + + InternalData(IRenderDevice *pDevice) + { + RefCntAutoPtr pDeviceD3D11(pDevice, IID_RenderDeviceD3D11); + m_pd3d11NativeDevice = pDeviceD3D11->GetD3D11Device(); + } + + CComPtr m_pd3d11NativeDevice; + + void SwapMapQueues() + { + std::lock_guard QueueLock(m_PendingOperationsMtx); + m_PendingOperations.swap(m_InWorkOperations); + } + + void EnqueCopy(UploadBufferD3D11 *pUploadBuffer, ID3D11Resource *pd3d11DstTex, UINT dstSubres) + { + std::lock_guard QueueLock(m_PendingOperationsMtx); + m_PendingOperations.emplace_back(PendingBufferOperation::Operation::Copy, pUploadBuffer, pd3d11DstTex, dstSubres); + } + + void EnqueMap(UploadBufferD3D11 *pUploadBuffer, PendingBufferOperation::Operation Op) + { + std::lock_guard QueueLock(m_PendingOperationsMtx); + m_PendingOperations.emplace_back(Op, pUploadBuffer); + } + + std::mutex m_PendingOperationsMtx; + std::vector< PendingBufferOperation > m_PendingOperations; + std::vector< PendingBufferOperation > m_InWorkOperations; + + std::mutex m_UploadBuffCacheMtx; + std::unordered_map< UploadBufferDesc, std::deque< RefCntAutoPtr > > m_UploadBufferCache; + }; + + TextureUploaderD3D11::TextureUploaderD3D11(IReferenceCounters *pRefCounters, IRenderDevice *pDevice, const TextureUploaderDesc Desc) : + TextureUploaderBase(pRefCounters, pDevice, Desc), + m_pInternalData(new InternalData(pDevice)) + { + } + + TextureUploaderD3D11::~TextureUploaderD3D11() + { + for (auto BuffQueueIt : m_pInternalData->m_UploadBufferCache) + { + if (BuffQueueIt.second.size()) + { + const auto &desc = BuffQueueIt.first; + auto &FmtInfo = m_pDevice->GetTextureFormatInfo(desc.Format); + LOG_INFO_MESSAGE("TextureUploaderD3D11: releasing ", BuffQueueIt.second.size(), ' ', desc.Width, 'x', desc.Height, 'x', desc.Depth, ' ', FmtInfo.Name, " staging texture(s) ") + } + } + } + + void TextureUploaderD3D11::RenderThreadUpdate(Diligent::IDeviceContext *pContext) + { + m_pInternalData->SwapMapQueues(); + if (!m_pInternalData->m_InWorkOperations.empty()) + { + RefCntAutoPtr pContextD3D11(pContext, IID_DeviceContextD3D11); + auto* pd3d11NativeCtx = pContextD3D11->GetD3D11DeviceContext(); + + for (auto &OperationInfo : m_pInternalData->m_InWorkOperations) + { + auto &pBuffer = OperationInfo.pUploadBuffer; + + switch (OperationInfo.operation) + { + case InternalData::PendingBufferOperation::MapAndCache: + case InternalData::PendingBufferOperation::Map: + { + D3D11_MAPPED_SUBRESOURCE MappedData; + auto hr = pd3d11NativeCtx->Map(pBuffer->GetStagingTex(), 0, D3D11_MAP_WRITE, D3D11_MAP_FLAG_DO_NOT_WAIT, &MappedData); + if (SUCCEEDED(hr)) + { + pBuffer->SetDataPtr(MappedData.pData, MappedData.RowPitch, MappedData.DepthPitch); + pBuffer->SignalMapped(); + if (OperationInfo.operation == InternalData::PendingBufferOperation::MapAndCache) + { + std::lock_guard CacheLock(m_pInternalData->m_UploadBuffCacheMtx); + auto &Cache = m_pInternalData->m_UploadBufferCache; + Cache[pBuffer->GetDesc()].emplace_back( std::move(pBuffer) ); + } + } + else + { + if (hr == DXGI_ERROR_WAS_STILL_DRAWING) + { + m_pInternalData->EnqueMap(pBuffer, OperationInfo.operation); + } + else + { + LOG_ERROR("Unknown DX error when mapping staging texture: ", hr) + } + } + } + break; + + case InternalData::PendingBufferOperation::Copy: + { + VERIFY(pBuffer->DbgIsMapped(), "Upload buffer must be copied only after it has been mapped"); + pd3d11NativeCtx->Unmap(pBuffer->GetStagingTex(), 0); + pd3d11NativeCtx->CopySubresourceRegion(OperationInfo.pd3d11NativeDstTexture, OperationInfo.DstSubresource, + 0, 0, 0, // DstX, DstY, DstZ + pBuffer->GetStagingTex(), + 0, // SrcSubresource + nullptr // pSrcBox + ); + pBuffer->SignalCopyScheduled(); + } + break; + } + } + m_pInternalData->m_InWorkOperations.clear(); + } + } + + void TextureUploaderD3D11::AllocateUploadBuffer(const UploadBufferDesc& Desc, bool IsRenderThread, IUploadBuffer **ppBuffer) + { + *ppBuffer = nullptr; + + { + std::lock_guard CacheLock(m_pInternalData->m_UploadBuffCacheMtx); + auto &Cache = m_pInternalData->m_UploadBufferCache; + if (!Cache.empty()) + { + auto DequeIt = Cache.find(Desc); + if (DequeIt != Cache.end()) + { + auto &Deque = DequeIt->second; + if (!Deque.empty()) + { + *ppBuffer = Deque.front().Detach(); + Deque.pop_front(); + } + } + } + } + + if( *ppBuffer == nullptr ) + { + D3D11_TEXTURE2D_DESC StagingTexDesc = + { + static_cast(Desc.Width), + static_cast(Desc.Height), + 1, // UINT MipLevels; + 1, // UINT ArraySize; + TexFormatToDXGI_Format(Desc.Format), + {1, 0}, // DXGI_SAMPLE_DESC SampleDesc; + D3D11_USAGE_STAGING, + 0, // UINT BindFlags; + D3D11_CPU_ACCESS_WRITE, // UINT CPUAccessFlags; + 0, // UINT MiscFlags; + }; + + CComPtr pStagingTex; + HRESULT hr = m_pInternalData->m_pd3d11NativeDevice->CreateTexture2D(&StagingTexDesc, nullptr, &pStagingTex); + if (FAILED(hr)) + { + LOG_ERROR_MESSAGE("Failed to allocate staging D3D11 texture") + return; + } + + LOG_INFO_MESSAGE("TextureUploaderD3D11: created ", Desc.Width, 'x', Desc.Height, ' ', m_pDevice->GetTextureFormatInfo(Desc.Format).Name, " staging texture") + + RefCntAutoPtr pUploadBuffer(MakeNewRCObj()(Desc, pStagingTex)); + m_pInternalData->EnqueMap(pUploadBuffer, InternalData::PendingBufferOperation::Map); + pUploadBuffer->WaitForMap(); + *ppBuffer = pUploadBuffer.Detach(); + } + } + + void TextureUploaderD3D11::ScheduleGPUCopy(Diligent::ITexture *pDstTexture, + Uint32 ArraySlice, + Uint32 MipLevel, + IUploadBuffer *pUploadBuffer) + { + auto *pUploadBufferD3D11 = ValidatedCast(pUploadBuffer); + RefCntAutoPtr pDstTexD3D11(pDstTexture, IID_TextureD3D11); + auto *pd3d11NativeDstTex = pDstTexD3D11->GetD3D11Texture(); + const auto &DstTexDesc = pDstTexture->GetDesc(); + UINT DstSubres = D3D11CalcSubresource(static_cast(MipLevel), static_cast(ArraySlice), static_cast(DstTexDesc.MipLevels)); + m_pInternalData->EnqueCopy(pUploadBufferD3D11, pd3d11NativeDstTex, DstSubres); + } + + void TextureUploaderD3D11::RecycleBuffer(IUploadBuffer *pUploadBuffer) + { + auto *pUploadBufferD3D11 = ValidatedCast(pUploadBuffer); + VERIFY(pUploadBufferD3D11->DbgIsCopyScheduled(), "Upload buffer must be recycled only after copy operation has been scheduled on the GPU"); + pUploadBufferD3D11->Reset(); + + m_pInternalData->EnqueMap(pUploadBufferD3D11, InternalData::PendingBufferOperation::MapAndCache); + } +} \ No newline at end of file diff --git a/Graphics/GraphicsTools/src/TextureUploaderD3D12.cpp b/Graphics/GraphicsTools/src/TextureUploaderD3D12.cpp new file mode 100644 index 00000000..2791d914 --- /dev/null +++ b/Graphics/GraphicsTools/src/TextureUploaderD3D12.cpp @@ -0,0 +1,274 @@ +/* Copyright 2015-2017 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 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * 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 "pch.h" + +#include +#include +#include +#include +#include + +#include "TextureUploaderD3D12.h" +#include "RenderDeviceD3D12.h" +#include "BufferD3D12.h" +#include "TextureD3D12.h" + +namespace Diligent +{ + + class UploadBufferD3D12 : public UploadBufferBase + { + public: + UploadBufferD3D12(IReferenceCounters *pRefCounters, + IRenderDeviceD3D12 *pRenderDeviceD3D12, + const UploadBufferDesc &Desc, + IBuffer *pStagingBuffer, + void *pData, + size_t RowStride, + size_t DepthStride) : + UploadBufferBase(pRefCounters, Desc), + m_pDeviceD3D12(pRenderDeviceD3D12), + m_pStagingBuffer(pStagingBuffer) + { + m_pData = pData; + m_RowStride = RowStride; + m_DepthStride = DepthStride; + } + + ~UploadBufferD3D12() + { + m_pStagingBuffer->Unmap(nullptr, MAP_WRITE, 0); + LOG_INFO_MESSAGE("Releasing staging buffer of size ", m_pStagingBuffer->GetDesc().uiSizeInBytes ) + } + + void SignalCopyScheduled() + { + m_CopyScheduledSignal.Trigger(); + } + + void Reset() + { + m_CopyScheduledSignal.Reset(); + } + + virtual void WaitForCopyScheduled()override final + { + m_CopyScheduledSignal.Wait(); + } + + IBuffer* GetStagingBuffer() { return m_pStagingBuffer; } + + bool DbgIsCopyScheduled()const { return m_CopyScheduledSignal.IsTriggered(); } + private: + + ThreadingTools::Signal m_CopyScheduledSignal; + + RefCntAutoPtr m_pStagingBuffer; + RefCntAutoPtr m_pDeviceD3D12; + }; + + struct TextureUploaderD3D12::InternalData + { + InternalData(IRenderDevice *pDevice) : + m_pDeviceD3D12(pDevice, IID_RenderDeviceD3D12) + { + m_pd3d12NativeDevice = m_pDeviceD3D12->GetD3D12Device(); + } + + CComPtr m_pd3d12NativeDevice; + RefCntAutoPtr m_pDeviceD3D12; + + void SwapMapQueues() + { + std::lock_guard QueueLock(m_PendingOperationsMtx); + m_PendingOperations.swap(m_InWorkOperations); + } + + void EnqueCopy(UploadBufferD3D12 *pUploadBuffer, ITextureD3D12 *pDstTex, Uint32 dstSlice, Uint32 dstMip) + { + std::lock_guard QueueLock(m_PendingOperationsMtx); + m_PendingOperations.emplace_back(PendingBufferOperation::Operation::Copy, pUploadBuffer, pDstTex, dstSlice, dstMip); + } + + std::mutex m_PendingOperationsMtx; + struct PendingBufferOperation + { + enum Operation + { + Copy + }operation; + RefCntAutoPtr pUploadBuffer; + RefCntAutoPtr pDstTexture; + Uint32 DstSlice = 0; + Uint32 DstMip = 0; + + PendingBufferOperation(Operation op, UploadBufferD3D12* pBuff) : + operation(op), + pUploadBuffer(pBuff) + {} + PendingBufferOperation(Operation op, UploadBufferD3D12* pBuff, ITextureD3D12 *pDstTex, Uint32 dstSlice, Uint32 dstMip) : + operation(op), + pUploadBuffer(pBuff), + pDstTexture(pDstTex), + DstSlice(dstSlice), + DstMip(dstMip) + {} + }; + std::vector< PendingBufferOperation > m_PendingOperations; + std::vector< PendingBufferOperation > m_InWorkOperations; + + std::mutex m_UploadBuffCacheMtx; + std::unordered_map< UploadBufferDesc, std::deque< std::pair > > > m_UploadBufferCache; + }; + + TextureUploaderD3D12::TextureUploaderD3D12(IReferenceCounters *pRefCounters, IRenderDevice *pDevice, const TextureUploaderDesc Desc) : + TextureUploaderBase(pRefCounters, pDevice, Desc), + m_pInternalData(new InternalData(pDevice)) + { + } + + TextureUploaderD3D12::~TextureUploaderD3D12() + { + for (auto BuffQueueIt : m_pInternalData->m_UploadBufferCache) + { + if (BuffQueueIt.second.size()) + { + const auto &desc = BuffQueueIt.first; + auto &FmtInfo = m_pDevice->GetTextureFormatInfo(desc.Format); + LOG_INFO_MESSAGE("TextureUploaderD3D12: releasing ", BuffQueueIt.second.size(), ' ', desc.Width, 'x', desc.Height, 'x', desc.Depth, ' ', FmtInfo.Name, " upload buffer(s) ") + } + } + } + + void TextureUploaderD3D12::RenderThreadUpdate(IDeviceContext *pContext) + { + m_pInternalData->SwapMapQueues(); + if (!m_pInternalData->m_InWorkOperations.empty()) + { + for (auto &OperationInfo : m_pInternalData->m_InWorkOperations) + { + auto &pBuffer = OperationInfo.pUploadBuffer; + + switch (OperationInfo.operation) + { + case InternalData::PendingBufferOperation::Copy: + { + TextureSubResData SubResData(pBuffer->GetStagingBuffer(), static_cast(pBuffer->GetRowStride())); + const auto &TexDesc = OperationInfo.pDstTexture->GetDesc(); + Box DstBox; + DstBox.MaxX = TexDesc.Width; + DstBox.MaxY = TexDesc.Height; + OperationInfo.pDstTexture->UpdateData(pContext, OperationInfo.DstMip, OperationInfo.DstSlice, DstBox, SubResData); + pBuffer->SignalCopyScheduled(); + } + break; + } + } + + m_pInternalData->m_InWorkOperations.clear(); + } + } + + void TextureUploaderD3D12::AllocateUploadBuffer(const UploadBufferDesc& Desc, bool IsRenderThread, IUploadBuffer **ppBuffer) + { + *ppBuffer = nullptr; + + { + std::lock_guard CacheLock(m_pInternalData->m_UploadBuffCacheMtx); + auto &Cache = m_pInternalData->m_UploadBufferCache; + if (!Cache.empty()) + { + auto DequeIt = Cache.find(Desc); + if (DequeIt != Cache.end()) + { + auto &Deque = DequeIt->second; + if (!Deque.empty()) + { + auto &FrontBuff = Deque.front(); + if (m_pInternalData->m_pDeviceD3D12->IsFenceSignaled(FrontBuff.first)) + { + *ppBuffer = FrontBuff.second.Detach(); + Deque.pop_front(); + } + } + } + } + } + + // No available buffer found in the cache + if(*ppBuffer == nullptr) + { + BufferDesc BuffDesc; + BuffDesc.Name = "Staging buffer for UploadBufferD3D12"; + BuffDesc.CPUAccessFlags = CPU_ACCESS_WRITE; + BuffDesc.Usage = USAGE_CPU_ACCESSIBLE; + + const auto &TexFmtInfo = m_pDevice->GetTextureFormatInfo(Desc.Format); + Uint32 RowStride = Desc.Width * TexFmtInfo.ComponentSize * TexFmtInfo.NumComponents; + static_assert((D3D12_TEXTURE_DATA_PITCH_ALIGNMENT & (D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1)) == 0, "Alginment is expected to be power of 2"); + Uint32 AlignmentMask = D3D12_TEXTURE_DATA_PITCH_ALIGNMENT-1; + RowStride = (RowStride + AlignmentMask) & (~AlignmentMask); + + BuffDesc.uiSizeInBytes = Desc.Height * RowStride; + RefCntAutoPtr pStagingBuffer; + m_pDevice->CreateBuffer(BuffDesc, BufferData(), &pStagingBuffer); + + PVoid CpuVirtualAddress = nullptr; + pStagingBuffer->Map(nullptr, MAP_WRITE, 0, CpuVirtualAddress); + if (CpuVirtualAddress == nullptr) + { + LOG_ERROR_MESSAGE("Failed to map upload buffer") + return; + } + + LOG_INFO_MESSAGE("Created staging buffer of size ", BuffDesc.uiSizeInBytes ) + + RefCntAutoPtr pUploadBuffer(MakeNewRCObj()(m_pInternalData->m_pDeviceD3D12, Desc, pStagingBuffer, CpuVirtualAddress, RowStride, 0)); + *ppBuffer = pUploadBuffer.Detach(); + } + } + + void TextureUploaderD3D12::ScheduleGPUCopy(ITexture *pDstTexture, + Uint32 ArraySlice, + Uint32 MipLevel, + IUploadBuffer *pUploadBuffer) + { + auto *pUploadBufferD3D12 = ValidatedCast(pUploadBuffer); + RefCntAutoPtr pDstTexD3D12(pDstTexture, IID_TextureD3D12); + m_pInternalData->EnqueCopy(pUploadBufferD3D12, pDstTexD3D12, ArraySlice, MipLevel); + } + + void TextureUploaderD3D12::RecycleBuffer(IUploadBuffer *pUploadBuffer) + { + auto *pUploadBufferD3D12 = ValidatedCast(pUploadBuffer); + VERIFY(pUploadBufferD3D12->DbgIsCopyScheduled(), "Upload buffer must be recycled only after copy operation has been scheduled on the GPU"); + pUploadBufferD3D12->Reset(); + + std::lock_guard CacheLock(m_pInternalData->m_UploadBuffCacheMtx); + auto &Cache = m_pInternalData->m_UploadBufferCache; + auto &Deque = Cache[pUploadBufferD3D12->GetDesc()]; + Uint64 FenceValue = m_pInternalData->m_pDeviceD3D12->GetNextFenceValue(); + Deque.emplace_back( FenceValue, pUploadBufferD3D12 ); + } +} diff --git a/Graphics/GraphicsTools/src/TextureUploaderGL.cpp b/Graphics/GraphicsTools/src/TextureUploaderGL.cpp new file mode 100644 index 00000000..2eee70f4 --- /dev/null +++ b/Graphics/GraphicsTools/src/TextureUploaderGL.cpp @@ -0,0 +1,271 @@ +/* Copyright 2015-2017 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 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS. + * + * 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 "pch.h" +#include +#include +#include +#include "TextureUploaderGL.h" + +namespace Diligent +{ + + class UploadBufferGL : public UploadBufferBase + { + public: + UploadBufferGL(IReferenceCounters *pRefCounters, const UploadBufferDesc &Desc) : + UploadBufferBase(pRefCounters, Desc) + {} + + void SetDataPtr(void *pData, size_t RowStride, size_t DepthStride) + { + m_pData = pData; + m_RowStride = RowStride; + m_DepthStride = DepthStride; + } + + // http://en.cppreference.com/w/cpp/thread/condition_variable + void WaitForMap() + { + m_BufferMappedSignal.Wait(); + } + + void SignalMapped() + { + m_BufferMappedSignal.Trigger(); + } + + void SignalCopyScheduled() + { + m_CopyScheduledSignal.Trigger(); + } + + virtual void WaitForCopyScheduled()override final + { + m_CopyScheduledSignal.Wait(); + } + + bool DbgIsCopyScheduled()const { return m_CopyScheduledSignal.IsTriggered(); } + + void Reset() + { + m_BufferMappedSignal.Reset(); + m_CopyScheduledSignal.Reset(); + m_pData = nullptr; + // Do not zero out strides + } + + private: + friend class TextureUploaderGL; + ThreadingTools::Signal m_BufferMappedSignal; + ThreadingTools::Signal m_CopyScheduledSignal; + RefCntAutoPtr m_pStagingBuffer; + }; + + struct TextureUploaderGL::InternalData + { + void SwapMapQueues() + { + std::lock_guard QueueLock(m_PendingOperationsMtx); + m_PendingOperations.swap(m_InWorkOperations); + } + + void EnqueCopy(UploadBufferGL *pUploadBuffer, ITexture *pDstTexture, Uint32 dstSlice, Uint32 dstMip) + { + std::lock_guard QueueLock(m_PendingOperationsMtx); + m_PendingOperations.emplace_back(PendingBufferOperation::Operation::Copy, pUploadBuffer, pDstTexture, dstSlice, dstMip); + } + + void EnqueMap(UploadBufferGL *pUploadBuffer) + { + std::lock_guard QueueLock(m_PendingOperationsMtx); + m_PendingOperations.emplace_back(PendingBufferOperation::Operation::Map, pUploadBuffer); + } + + + struct PendingBufferOperation + { + enum Operation + { + Map, + Copy + }operation; + RefCntAutoPtr pUploadBuffer; + RefCntAutoPtr pDstTexture; + Uint32 DstSlice = 0; + Uint32 DstMip = 0; + + PendingBufferOperation(Operation op, UploadBufferGL* pBuff) : + operation(op), + pUploadBuffer(pBuff) + {} + PendingBufferOperation(Operation op, UploadBufferGL* pBuff, ITexture *pDstTex, Uint32 dstSlice, Uint32 dstMip) : + operation(op), + pUploadBuffer(pBuff), + pDstTexture(pDstTex), + DstSlice(dstSlice), + DstMip(dstMip) + {} + }; + + std::mutex m_PendingOperationsMtx; + std::vector< PendingBufferOperation > m_PendingOperations; + std::vector< PendingBufferOperation > m_InWorkOperations; + + std::mutex m_UploadBuffCacheMtx; + std::unordered_map< UploadBufferDesc, std::deque > > m_UploadBufferCache; + }; + + TextureUploaderGL::TextureUploaderGL(IReferenceCounters *pRefCounters, IRenderDevice *pDevice, const TextureUploaderDesc Desc) : + TextureUploaderBase(pRefCounters, pDevice, Desc), + m_pInternalData(new InternalData()) + { + } + + TextureUploaderGL::~TextureUploaderGL() + { + for (auto BuffQueueIt : m_pInternalData->m_UploadBufferCache) + { + if (BuffQueueIt.second.size()) + { + const auto &desc = BuffQueueIt.first; + auto &FmtInfo = m_pDevice->GetTextureFormatInfo(desc.Format); + LOG_INFO_MESSAGE("TextureUploaderGL: releasing ", BuffQueueIt.second.size(), ' ', desc.Width, 'x', desc.Height, 'x', desc.Depth, ' ', FmtInfo.Name, " upload buffer(s) ") + } + } + } + + void TextureUploaderGL::RenderThreadUpdate(IDeviceContext *pContext) + { + m_pInternalData->SwapMapQueues(); + if (!m_pInternalData->m_InWorkOperations.empty()) + { + for (auto &OperationInfo : m_pInternalData->m_InWorkOperations) + { + auto &pBuffer = OperationInfo.pUploadBuffer; + + switch (OperationInfo.operation) + { + case InternalData::PendingBufferOperation::Map: + { + Uint32 RowStride = static_cast(pBuffer->GetRowStride()); + if (pBuffer->m_pStagingBuffer == nullptr) + { + const auto &Desc = pBuffer->GetDesc(); + BufferDesc BuffDesc; + BuffDesc.Name = "Staging buffer for UploadBufferGL"; + BuffDesc.CPUAccessFlags = CPU_ACCESS_WRITE; + BuffDesc.Usage = USAGE_CPU_ACCESSIBLE; + + const auto &TexFmtInfo = m_pDevice->GetTextureFormatInfo(Desc.Format); + RowStride = Desc.Width * TexFmtInfo.ComponentSize * TexFmtInfo.NumComponents; + const Uint32 Alignment = 16; + const Uint32 AlignmentMask = Alignment-1; + RowStride = (RowStride + AlignmentMask) & (~AlignmentMask); + + BuffDesc.uiSizeInBytes = Desc.Height * RowStride; + RefCntAutoPtr pStagingBuffer; + m_pDevice->CreateBuffer(BuffDesc, BufferData(), &pBuffer->m_pStagingBuffer); + } + + PVoid CpuAddress = nullptr; + pBuffer->m_pStagingBuffer->Map(pContext, MAP_WRITE, MAP_FLAG_DISCARD, CpuAddress); + pBuffer->SetDataPtr(CpuAddress, RowStride, 0); + + pBuffer->SignalMapped(); + } + break; + + case InternalData::PendingBufferOperation::Copy: + { + pBuffer->m_pStagingBuffer->Unmap(pContext, MAP_WRITE, MAP_FLAG_DISCARD); + TextureSubResData SubResData(pBuffer->m_pStagingBuffer, static_cast(pBuffer->GetRowStride())); + Box DstBox; + const auto &TexDesc = OperationInfo.pDstTexture->GetDesc(); + DstBox.MaxX = TexDesc.Width; + DstBox.MaxY = TexDesc.Height; + OperationInfo.pDstTexture->UpdateData(pContext, OperationInfo.DstMip, OperationInfo.DstSlice, DstBox, SubResData); + pBuffer->SignalCopyScheduled(); + } + break; + } + } + m_pInternalData->m_InWorkOperations.clear(); + } + } + + void TextureUploaderGL::AllocateUploadBuffer(const UploadBufferDesc& Desc, bool IsRenderThread, IUploadBuffer **ppBuffer) + { + *ppBuffer = nullptr; + RefCntAutoPtr pUploadBuffer; + + { + std::lock_guard CacheLock(m_pInternalData->m_UploadBuffCacheMtx); + auto &Cache = m_pInternalData->m_UploadBufferCache; + if (!Cache.empty()) + { + auto DequeIt = Cache.find(Desc); + if (DequeIt != Cache.end()) + { + auto &Deque = DequeIt->second; + if (!Deque.empty()) + { + pUploadBuffer.Attach(Deque.front().Detach()); + Deque.pop_front(); + } + } + } + } + + if( !pUploadBuffer ) + { + pUploadBuffer = MakeNewRCObj()(Desc); + LOG_INFO_MESSAGE("TextureUploaderGL: created upload buffer for ", Desc.Width, 'x', Desc.Height, 'x', Desc.Depth, ' ', m_pDevice->GetTextureFormatInfo(Desc.Format).Name, " texture" ) + } + + m_pInternalData->EnqueMap(pUploadBuffer); + pUploadBuffer->WaitForMap(); + *ppBuffer = pUploadBuffer.Detach(); + } + + void TextureUploaderGL::ScheduleGPUCopy(ITexture *pDstTexture, + Uint32 ArraySlice, + Uint32 MipLevel, + IUploadBuffer *pUploadBuffer) + { + auto *pUploadBufferGL = ValidatedCast(pUploadBuffer); + m_pInternalData->EnqueCopy(pUploadBufferGL, pDstTexture, ArraySlice, MipLevel); + } + + void TextureUploaderGL::RecycleBuffer(IUploadBuffer *pUploadBuffer) + { + auto *pUploadBufferGL = ValidatedCast(pUploadBuffer); + VERIFY(pUploadBufferGL->DbgIsCopyScheduled(), "Upload buffer must be recycled only after copy operation has been scheduled on the GPU"); + pUploadBufferGL->Reset(); + + std::lock_guard CacheLock(m_pInternalData->m_UploadBuffCacheMtx); + auto &Cache = m_pInternalData->m_UploadBufferCache; + auto &Deque = Cache[pUploadBufferGL->GetDesc()]; + Deque.emplace_back( pUploadBufferGL ); + } +} -- cgit v1.2.3