diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2020-12-06 20:29:43 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2020-12-06 20:29:43 +0000 |
| commit | a33f6de479bc0d662a41ddf1cf758bacb59aa09b (patch) | |
| tree | 3533e1bef1113c5b386256a27bfd9550652a8629 /Graphics/GraphicsTools | |
| parent | DynamicAtlasManager: fixed dtor to allow moved-out objects (diff) | |
| download | DiligentCore-a33f6de479bc0d662a41ddf1cf758bacb59aa09b.tar.gz DiligentCore-a33f6de479bc0d662a41ddf1cf758bacb59aa09b.zip | |
GraphicsTools: added DynamicBuffer class
Diffstat (limited to 'Graphics/GraphicsTools')
| -rw-r--r-- | Graphics/GraphicsTools/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | Graphics/GraphicsTools/interface/DynamicBuffer.hpp | 142 | ||||
| -rw-r--r-- | Graphics/GraphicsTools/src/DynamicBuffer.cpp | 112 |
3 files changed, 256 insertions, 0 deletions
diff --git a/Graphics/GraphicsTools/CMakeLists.txt b/Graphics/GraphicsTools/CMakeLists.txt index 7d806761..1bc9c9e7 100644 --- a/Graphics/GraphicsTools/CMakeLists.txt +++ b/Graphics/GraphicsTools/CMakeLists.txt @@ -4,6 +4,7 @@ project(Diligent-GraphicsTools CXX) set(INTERFACE interface/CommonlyUsedStates.h + interface/DynamicBuffer.hpp interface/DurationQueryHelper.hpp interface/GraphicsUtilities.h interface/MapHelper.hpp @@ -18,6 +19,7 @@ set(INTERFACE set(SOURCE src/DurationQueryHelper.cpp + src/DynamicBuffer.cpp src/GraphicsUtilities.cpp src/ScopedQueryHelper.cpp src/ScreenCapture.cpp diff --git a/Graphics/GraphicsTools/interface/DynamicBuffer.hpp b/Graphics/GraphicsTools/interface/DynamicBuffer.hpp new file mode 100644 index 00000000..86615ca8 --- /dev/null +++ b/Graphics/GraphicsTools/interface/DynamicBuffer.hpp @@ -0,0 +1,142 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#pragma once + +/// \file +/// Declaration of a DynamicBuffer class + +#include "../../GraphicsEngine/interface/RenderDevice.h" +#include "../../GraphicsEngine/interface/DeviceContext.h" +#include "../../GraphicsEngine/interface/Buffer.h" +#include "../../../Common/interface/RefCntAutoPtr.hpp" + +namespace Diligent +{ + +/// Dynamically resizable buffer +class DynamicBuffer +{ +public: + /// Initialies the dynamic buffer. + + /// \param[in] pDevice - Render device that will be used to create the buffer. + /// This parameter may be null (see remarks). + /// \param[in] Desc - Buffer description. + /// + /// \remarks If pDevice is null, internal buffer creation will be postponed + /// until GetBuffer() or Resize() is called. + DynamicBuffer(IRenderDevice* pDevice, const BufferDesc& Desc); + + // clang-format off + DynamicBuffer (const DynamicBuffer&) = delete; + DynamicBuffer& operator=(const DynamicBuffer&) = delete; + DynamicBuffer ( DynamicBuffer&&) = default; + DynamicBuffer& operator=( DynamicBuffer&&) = default; + // clang-format on + + + /// Resizes the buffer to the new size. + + /// \param[in] pDevice - Render device that will be used create a new internal buffer. + /// This parameter may be null (see remarks). + /// \param[in] pContext - Device context that will be used to copy existing contents + /// to the new buffer. This parameter may be null (see remarks). + /// \param[in] NewSize - New buffer size. Can be zero. + /// \return Pointer to the new buffer. + /// + /// \remarks The method operation depends on which of pDevice and pContext parameters + /// are not null: + /// - Both pDevice and pContext are not null: internal buffer is created + /// and existing contents is copied. GetBuffer() may be called with + /// both pDevice and pContext being null. + /// - pDevice is not null, pContext is null: internal buffer is created, + /// but existing contents is not copied. An application must provide non-null + /// device context when calling GetBuffer(). + /// - Both pDevice and pContext are null: internal buffer is not created. + /// An application must provide non-null device and device context when calling + /// GetBuffer(). + /// + /// If NewSize is zero, internal buffer will be released. + IBuffer* Resize(IRenderDevice* pDevice, + IDeviceContext* pContext, + Uint32 NewSize); + + + /// Returns the pointer to the buffer object, initializing it if necessary. + + /// \param[in] pDevice - Render device that will be used to create the new buffer, + /// if necessary (see remarks). + /// \param[in] pContext - Device context that will be used to copy existing + /// buffer contents, if necessary (see remarks). + /// \return The pointer to the buffer object. + /// + /// \remarks If the buffer has been resized, but internal buffer object has not been + /// initialized, pDevice and pContext must not be null. + /// + /// If buffer does not need to be updated (PendingUpdate() returns false), + /// both pDevice and pContext may be null. + IBuffer* GetBuffer(IRenderDevice* pDevice, + IDeviceContext* pContext); + + + /// Returns true if the buffer buffer must be updated before use (e.g. it has been resized, + /// but internal buffer has not been initialized or updated). + /// When update is not pending, GetBuffer() may be called with null device and context. + bool PendingUpdate() const + { + return (m_Desc.uiSizeInBytes > 0) && (!m_pBuffer || m_pStaleBuffer); + } + + + /// Returns the buffer description. + const BufferDesc& GetDesc() + { + return m_Desc; + } + + + /// Returns dynamic buffer version. + /// The version is incremented every time a new internal buffer is created. + Uint32 GetVersion() const + { + return m_Version; + } + +private: + void CommitResize(IRenderDevice* pDevice, + IDeviceContext* pContext); + + BufferDesc m_Desc; + const std::string m_Name; + Uint32 m_Version = 0; + + RefCntAutoPtr<IBuffer> m_pBuffer; + RefCntAutoPtr<IBuffer> m_pStaleBuffer; +}; + +} // namespace Diligent diff --git a/Graphics/GraphicsTools/src/DynamicBuffer.cpp b/Graphics/GraphicsTools/src/DynamicBuffer.cpp new file mode 100644 index 00000000..1932716f --- /dev/null +++ b/Graphics/GraphicsTools/src/DynamicBuffer.cpp @@ -0,0 +1,112 @@ +/* + * Copyright 2019-2020 Diligent Graphics LLC + * Copyright 2015-2019 Egor Yusov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * In no event and under no legal theory, whether in tort (including negligence), + * contract, or otherwise, unless required by applicable law (such as deliberate + * and grossly negligent acts) or agreed to in writing, shall any Contributor be + * liable for any damages, including any direct, indirect, special, incidental, + * or consequential damages of any character arising as a result of this License or + * out of the use or inability to use the software (including but not limited to damages + * for loss of goodwill, work stoppage, computer failure or malfunction, or any and + * all other commercial damages or losses), even if such Contributor has been advised + * of the possibility of such damages. + */ + +#include "DynamicBuffer.hpp" + +#include <algorithm> + +#include "DebugUtilities.hpp" + +namespace Diligent +{ + +DynamicBuffer::DynamicBuffer(IRenderDevice* pDevice, const BufferDesc& Desc) : + m_Desc{Desc}, + m_Name{Desc.Name != nullptr ? Desc.Name : "Dynamic buffer"} +{ + m_Desc.Name = m_Name.c_str(); + if (m_Desc.uiSizeInBytes > 0 && pDevice != nullptr) + { + pDevice->CreateBuffer(Desc, nullptr, &m_pBuffer); + VERIFY_EXPR(m_pBuffer); + } +} + +void DynamicBuffer::CommitResize(IRenderDevice* pDevice, + IDeviceContext* pContext) +{ + if (!m_pBuffer && m_Desc.uiSizeInBytes > 0 && pDevice != nullptr) + { + pDevice->CreateBuffer(m_Desc, nullptr, &m_pBuffer); + VERIFY_EXPR(m_pBuffer); + ++m_Version; + } + + if (m_pStaleBuffer && m_pBuffer && pContext != nullptr) + { + auto CopySize = std::min(m_Desc.uiSizeInBytes, m_pStaleBuffer->GetDesc().uiSizeInBytes); + pContext->CopyBuffer(m_pStaleBuffer, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION, + m_pBuffer, 0, CopySize, RESOURCE_STATE_TRANSITION_MODE_TRANSITION); + m_pStaleBuffer.Release(); + } +} + +IBuffer* DynamicBuffer::Resize(IRenderDevice* pDevice, + IDeviceContext* pContext, + Uint32 NewSize) +{ + if (m_Desc.uiSizeInBytes != NewSize) + { + if (!m_pStaleBuffer) + m_pStaleBuffer = std::move(m_pBuffer); + else + { + DEV_CHECK_ERR(!m_pBuffer || NewSize == 0, + "There is a non-null stale buffer. This likely indicates that " + "Resize() has been called multiple times with different sizes, " + "but copy has not been committed by providing non-null device " + "context to either Resize() or GetBuffer()"); + } + + m_Desc.uiSizeInBytes = NewSize; + + if (m_Desc.uiSizeInBytes == 0) + { + m_pStaleBuffer.Release(); + m_pBuffer.Release(); + } + } + + CommitResize(pDevice, pContext); + + return m_pBuffer; +} + +IBuffer* DynamicBuffer::GetBuffer(IRenderDevice* pDevice, + IDeviceContext* pContext) +{ + DEV_CHECK_ERR(m_pBuffer || m_Desc.uiSizeInBytes == 0 || pDevice != nullptr, + "A new buffer must be created, but pDevice is null. Use PendingUpdate() to check if the buffer must be updated."); + DEV_CHECK_ERR(!m_pStaleBuffer || pContext != nullptr, + "An existing contents of the buffer must be copied to the new buffer, but pContext is null. " + "Use PendingUpdate() to check if the buffer must be updated."); + CommitResize(pDevice, pContext); + + return m_pBuffer; +} + +} // namespace Diligent |
