Diligent Engine  v.2.4.g
StreamingBuffer.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2019-2021 Diligent Graphics LLC
3  * Copyright 2015-2019 Egor Yusov
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * In no event and under no legal theory, whether in tort (including negligence),
18  * contract, or otherwise, unless required by applicable law (such as deliberate
19  * and grossly negligent acts) or agreed to in writing, shall any Contributor be
20  * liable for any damages, including any direct, indirect, special, incidental,
21  * or consequential damages of any character arising as a result of this License or
22  * out of the use or inability to use the software (including but not limited to damages
23  * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
24  * all other commercial damages or losses), even if such Contributor has been advised
25  * of the possibility of such damages.
26  */
27 
28 #pragma once
29 
30 #include <functional>
31 #include <vector>
32 #include <string>
33 
34 #include "../../GraphicsEngine/interface/RenderDevice.h"
35 #include "../../GraphicsEngine/interface/DeviceContext.h"
36 #include "../../GraphicsEngine/interface/Buffer.h"
37 #include "../../../Common/interface/RefCntAutoPtr.hpp"
38 #include "MapHelper.hpp"
39 
40 namespace Diligent
41 {
42 
44 {
45  IRenderDevice* pDevice = nullptr;
47  std::function<void(IBuffer*)> OnBufferResizeCallback = nullptr;
49  bool AllowPersistentMapping = false;
50 };
51 
53 {
54 public:
55  StreamingBuffer() noexcept
56  {}
57 
60  m_BufferSize{CI.BuffDesc.uiSizeInBytes},
61  m_OnBufferResizeCallback{CI.OnBufferResizeCallback},
62  m_MapInfo(CI.NumContexts)
63  {
64  VERIFY_EXPR(CI.pDevice != nullptr);
65  VERIFY_EXPR(CI.BuffDesc.Usage == USAGE_DYNAMIC);
66  CI.pDevice->CreateBuffer(CI.BuffDesc, nullptr, &m_pBuffer);
67  VERIFY_EXPR(m_pBuffer);
68  if (m_OnBufferResizeCallback)
69  m_OnBufferResizeCallback(m_pBuffer);
70  }
71 
72  StreamingBuffer(const StreamingBuffer&) = delete;
73  StreamingBuffer& operator=(const StreamingBuffer&) = delete;
74 
75  StreamingBuffer(StreamingBuffer&&) = default;
77 
79  {
80  for (const auto& mapInfo : m_MapInfo)
81  {
82  VERIFY(!mapInfo.m_MappedData, "Destroying streaming buffer that is still mapped");
83  }
84  }
85 
86  // Returns offset of the allocated region
87  Uint32 Map(IDeviceContext* pCtx, IRenderDevice* pDevice, Uint32 Size, size_t CtxNum = 0)
88  {
89  VERIFY_EXPR(Size > 0);
90 
91  auto& MapInfo = m_MapInfo[CtxNum];
92  // Check if there is enough space in the buffer
93  if (MapInfo.m_CurrOffset + Size > m_BufferSize)
94  {
95  // Unmap the buffer
96  Flush(CtxNum);
97  VERIFY_EXPR(MapInfo.m_CurrOffset == 0);
98 
99  if (Size > m_BufferSize)
100  {
101  while (m_BufferSize < Size)
102  m_BufferSize *= 2;
103 
104  auto BuffDesc = m_pBuffer->GetDesc();
105  BuffDesc.uiSizeInBytes = m_BufferSize;
106  // BuffDesc.Name becomes invalid after old buffer is released
107  std::string Name = BuffDesc.Name;
108  BuffDesc.Name = Name.c_str();
109 
110  m_pBuffer.Release();
111  pDevice->CreateBuffer(BuffDesc, nullptr, &m_pBuffer);
112  if (m_OnBufferResizeCallback)
113  m_OnBufferResizeCallback(m_pBuffer);
114 
115  LOG_INFO_MESSAGE("Extended streaming buffer '", BuffDesc.Name, "' to ", m_BufferSize, " bytes");
116  }
117  }
118 
119  if (!m_UsePersistentMap)
120  {
121  VERIFY(MapInfo.m_MappedData == nullptr, "Streaming buffer must be unmapped before it can be mapped next time when persistent mapping is not used");
122  }
123 
124  if (MapInfo.m_MappedData == nullptr)
125  {
126  // If current offset is zero, we are mapping the buffer for the first time after it has been Reseted. Use MAP_FLAG_DISCARD flag.
127  // Otherwise use MAP_FLAG_NO_OVERWRITE flag.
128  MapInfo.m_MappedData.Map(pCtx, m_pBuffer, MAP_WRITE, MapInfo.m_CurrOffset == 0 ? MAP_FLAG_DISCARD : MAP_FLAG_NO_OVERWRITE);
129  VERIFY_EXPR(MapInfo.m_MappedData);
130  }
131 
132  auto Offset = MapInfo.m_CurrOffset;
133  // Update offset
134  MapInfo.m_CurrOffset += Size;
135  return Offset;
136  }
137 
138  Uint32 Update(IDeviceContext* pCtx, IRenderDevice* pDevice, const void* pData, Uint32 Size, size_t CtxNum = 0)
139  {
140  VERIFY_EXPR(pData != nullptr);
141  auto Offset = Map(pCtx, pDevice, Size, CtxNum);
142  auto* pCPUAddress = reinterpret_cast<Uint8*>(GetMappedCPUAddress(CtxNum)) + Offset;
143  memcpy(pCPUAddress, pData, Size);
144  Unmap(CtxNum);
145 
146  return Offset;
147  }
148 
149  void Unmap(size_t CtxNum = 0)
150  {
151  if (!m_UsePersistentMap)
152  {
153  m_MapInfo[CtxNum].m_MappedData.Unmap();
154  }
155  }
156 
157  void Flush(size_t CtxNum = 0)
158  {
159  m_MapInfo[CtxNum].m_MappedData.Unmap();
160  m_MapInfo[CtxNum].m_CurrOffset = 0;
161  }
162 
163  void Reset()
164  {
165  for (Uint32 ctx = 0; ctx < m_MapInfo.size(); ++ctx)
166  Flush(ctx);
167  }
168 
169  IBuffer* GetBuffer() const { return m_pBuffer.RawPtr<IBuffer>(); }
170 
171  void* GetMappedCPUAddress(size_t CtxNum = 0)
172  {
173  return m_MapInfo[CtxNum].m_MappedData;
174  }
175 
176 private:
177  bool m_UsePersistentMap = false;
178 
179  Uint32 m_BufferSize = 0;
180 
181  RefCntAutoPtr<IBuffer> m_pBuffer;
182 
183  std::function<void(IBuffer*)> m_OnBufferResizeCallback;
184 
185  struct MapInfo
186  {
187  MapHelper<Uint8> m_MappedData;
188  Uint32 m_CurrOffset = 0;
189  };
190  // We need to keep track of mapped data for every context
191  std::vector<MapInfo> m_MapInfo;
192 };
193 
194 } // namespace Diligent
Diligent::IRenderDevice::CreateBuffer
virtual void METHOD() CreateBuffer(const BufferDesc &BuffDesc, const BufferData *pBuffData, IBuffer **ppBuffer)
Creates a new buffer object.
Diligent::StreamingBufferCreateInfo::BuffDesc
BufferDesc BuffDesc
Definition: StreamingBuffer.hpp:46
Diligent::StreamingBuffer::StreamingBuffer
StreamingBuffer() noexcept
Definition: StreamingBuffer.hpp:55
Diligent::StreamingBuffer::Map
Uint32 Map(IDeviceContext *pCtx, IRenderDevice *pDevice, Uint32 Size, size_t CtxNum=0)
Definition: StreamingBuffer.hpp:87
Diligent::StreamingBufferCreateInfo::AllowPersistentMapping
bool AllowPersistentMapping
Definition: StreamingBuffer.hpp:49
Diligent::MAP_FLAG_DISCARD
@ MAP_FLAG_DISCARD
Previous contents of the resource will be undefined. This flag is only compatible with MAP_WRITE D3D...
Definition: GraphicsTypes.h:241
Diligent::MAP_FLAG_NO_OVERWRITE
@ MAP_FLAG_NO_OVERWRITE
The system will not synchronize pending operations before mapping the buffer. It is responsibility of...
Definition: GraphicsTypes.h:247
Diligent::StreamingBufferCreateInfo::OnBufferResizeCallback
std::function< void(IBuffer *)> OnBufferResizeCallback
Definition: StreamingBuffer.hpp:47
Diligent::StreamingBufferCreateInfo
Definition: StreamingBuffer.hpp:43
Diligent::IRenderDevice::GetDeviceCaps
virtual const DeviceCaps &METHOD() GetDeviceCaps() const
Gets the device capabilities, see Diligent::DeviceCaps for details.
Diligent::USAGE_DYNAMIC
@ USAGE_DYNAMIC
A resource that can be read by the GPU and written at least once per frame by the CPU....
Definition: GraphicsTypes.h:161
Diligent::StreamingBuffer::Reset
void Reset()
Definition: StreamingBuffer.hpp:163
Diligent::StreamingBuffer::GetMappedCPUAddress
void * GetMappedCPUAddress(size_t CtxNum=0)
Definition: StreamingBuffer.hpp:171
Diligent::IBuffer
Buffer interface.
Definition: Buffer.h:187
Diligent::StreamingBufferCreateInfo::pDevice
IRenderDevice * pDevice
Definition: StreamingBuffer.hpp:45
Diligent::IRenderDevice
Render device interface.
Definition: RenderDevice.h:75
LOG_INFO_MESSAGE
#define LOG_INFO_MESSAGE(...)
Definition: Errors.hpp:124
Diligent::StreamingBuffer::GetBuffer
IBuffer * GetBuffer() const
Definition: StreamingBuffer.hpp:169
Diligent::DeviceCaps::IsVulkanDevice
bool IsVulkanDevice() const
Definition: GraphicsTypes.h:1872
Diligent::StreamingBuffer::operator=
StreamingBuffer & operator=(const StreamingBuffer &)=delete
Diligent::StreamingBufferCreateInfo::NumContexts
Uint32 NumContexts
Definition: StreamingBuffer.hpp:48
Diligent::RefCntAutoPtr
Template class that implements reference counting.
Definition: RefCntAutoPtr.hpp:73
Diligent::Uint32
uint32_t Uint32
32-bit unsigned integer
Definition: BasicTypes.h:51
Diligent::StreamingBuffer::Flush
void Flush(size_t CtxNum=0)
Definition: StreamingBuffer.hpp:157
Diligent::MAP_WRITE
@ MAP_WRITE
The resource is mapped for writing. D3D11 counterpart: D3D11_MAP_WRITE. OpenGL counterpart: GL_MAP_...
Definition: GraphicsTypes.h:214
Diligent::StreamingBuffer::Update
Uint32 Update(IDeviceContext *pCtx, IRenderDevice *pDevice, const void *pData, Uint32 Size, size_t CtxNum=0)
Definition: StreamingBuffer.hpp:138
Diligent::StreamingBuffer::StreamingBuffer
StreamingBuffer(const StreamingBufferCreateInfo &CI)
Definition: StreamingBuffer.hpp:58
Diligent::BufferDesc
Buffer description.
Definition: Buffer.h:74
Diligent::StreamingBuffer::Unmap
void Unmap(size_t CtxNum=0)
Definition: StreamingBuffer.hpp:149
MapHelper.hpp
Diligent::RENDER_DEVICE_TYPE_D3D12
@ RENDER_DEVICE_TYPE_D3D12
D3D12 device.
Definition: GraphicsTypes.h:1483
Diligent::IDeviceContext
Device context interface.
Definition: DeviceContext.h:1460
Diligent::Uint8
uint8_t Uint8
8-bit unsigned integer
Definition: BasicTypes.h:53
VERIFY_EXPR
#define VERIFY_EXPR(...)
Definition: DebugUtilities.hpp:79
VERIFY
#define VERIFY(...)
Definition: DebugUtilities.hpp:76
Diligent::StreamingBuffer::~StreamingBuffer
~StreamingBuffer()
Definition: StreamingBuffer.hpp:78
Diligent::MapHelper< Uint8 >
Diligent::DeviceCaps::DevType
enum RENDER_DEVICE_TYPE DevType
Device type. See Diligent::DeviceType.
Definition: GraphicsTypes.h:1836
Diligent
The library uses Direct3D-style math:
Definition: AdvancedMath.hpp:37
Diligent::StreamingBuffer
Definition: StreamingBuffer.hpp:52