Diligent Engine API Reference
BufferBase.h
1 /* Copyright 2015-2018 Egor Yusov
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
12  *
13  * In no event and under no legal theory, whether in tort (including negligence),
14  * contract, or otherwise, unless required by applicable law (such as deliberate
15  * and grossly negligent acts) or agreed to in writing, shall any Contributor be
16  * liable for any damages, including any direct, indirect, special, incidental,
17  * or consequential damages of any character arising as a result of this License or
18  * out of the use or inability to use the software (including but not limited to damages
19  * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
20  * all other commercial damages or losses), even if such Contributor has been advised
21  * of the possibility of such damages.
22  */
23 
24 #pragma once
25 
28 
29 #include "Buffer.h"
30 #include "DeviceObjectBase.h"
31 #include "GraphicsAccessories.h"
32 #include "STDAllocator.h"
33 #include <memory>
34 
35 namespace Diligent
36 {
37 
39 
45 template<class BaseInterface, class BufferViewImplType, class TBuffViewObjAllocator>
46 class BufferBase : public DeviceObjectBase < BaseInterface, BufferDesc>
47 {
48 public:
50 
58  BufferBase( IReferenceCounters *pRefCounters,
59  TBuffViewObjAllocator &BuffViewObjAllocator,
60  IRenderDevice *pDevice,
61  const BufferDesc& BuffDesc,
62  bool bIsDeviceInternal) :
63  TDeviceObjectBase( pRefCounters, pDevice, BuffDesc, bIsDeviceInternal),
64 #ifdef _DEBUG
65  m_dbgBuffViewAllocator(BuffViewObjAllocator),
66 #endif
67  m_pDefaultUAV(nullptr, STDDeleter<BufferViewImplType, TBuffViewObjAllocator>(BuffViewObjAllocator) ),
68  m_pDefaultSRV(nullptr, STDDeleter<BufferViewImplType, TBuffViewObjAllocator>(BuffViewObjAllocator) )
69  {
70 #define VERIFY_BUFFER(Expr, ...) VERIFY(Expr, "Buffer \"", this->m_Desc.Name ? this->m_Desc.Name : "", "\": ", ##__VA_ARGS__)
71 
72 #ifdef _DEBUG
73  Uint32 AllowedBindFlags =
77  const Char* strAllowedBindFlags =
78  "BIND_VERTEX_BUFFER (1), BIND_INDEX_BUFFER (2), BIND_UNIFORM_BUFFER (4), "
79  "BIND_SHADER_RESOURCE (8), BIND_STREAM_OUTPUT (16), BIND_UNORDERED_ACCESS (128), "
80  "BIND_INDIRECT_DRAW_ARGS (256)";
81 
82  VERIFY_BUFFER( (BuffDesc.BindFlags & ~AllowedBindFlags) == 0, "Incorrect bind flags specified (", BuffDesc.BindFlags & ~AllowedBindFlags, "). Only the following flags are allowed:\n", strAllowedBindFlags );
83 #endif
84 
85  if( (this->m_Desc.BindFlags & BIND_UNORDERED_ACCESS) ||
86  (this->m_Desc.BindFlags & BIND_SHADER_RESOURCE) )
87  {
88  VERIFY_BUFFER( this->m_Desc.Mode > BUFFER_MODE_UNDEFINED && this->m_Desc.Mode < BUFFER_MODE_NUM_MODES, "Buffer mode (", this->m_Desc.Mode, ") is not correct" );
89  if( this->m_Desc.Mode == BUFFER_MODE_STRUCTURED )
90  {
91  VERIFY_BUFFER( this->m_Desc.ElementByteStride != 0, "Element stride cannot be zero for structured buffer" );
92  }
93 
94  if( this->m_Desc.Mode == BUFFER_MODE_FORMATTED )
95  {
96  VERIFY_BUFFER( this->m_Desc.Format.ValueType != VT_UNDEFINED, "Value type is not specified for a formatted buffer" );
97  VERIFY_BUFFER( this->m_Desc.Format.NumComponents != 0, "Num components cannot be zero in a formatted buffer" );
98  if( this->m_Desc.ElementByteStride == 0 )
99  this->m_Desc.ElementByteStride = static_cast<Uint32>(GetValueSize( this->m_Desc.Format.ValueType )) * this->m_Desc.Format.NumComponents;
100  }
101  }
102  }
103 
104  IMPLEMENT_QUERY_INTERFACE_IN_PLACE( IID_Buffer, TDeviceObjectBase )
105 
106 
107  virtual void UpdateData( IDeviceContext *pContext, Uint32 Offset, Uint32 Size, const PVoid pData )override = 0;
108 
110  virtual void CopyData( IDeviceContext *pContext, IBuffer *pSrcBuffer, Uint32 SrcOffset, Uint32 DstOffset, Uint32 Size )override = 0;
111 
113  virtual void Map( IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapFlags, PVoid &pMappedData )override;
114 
116  virtual void Unmap( IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapFlags )override = 0;
117 
120  virtual void CreateView( const struct BufferViewDesc &ViewDesc, IBufferView **ppView )override;
121 
123  virtual IBufferView* GetDefaultView( BUFFER_VIEW_TYPE ViewType )override;
124 
126 
132  void CreateDefaultViews();
133 
134 protected:
135 
137  virtual void CreateViewInternal( const struct BufferViewDesc &ViewDesc, IBufferView **ppView, bool bIsDefaultView ) = 0;
138 
140  void CorrectBufferViewDesc( struct BufferViewDesc &ViewDesc );
141 
142 #ifdef _DEBUG
143  TBuffViewObjAllocator &m_dbgBuffViewAllocator;
144 #endif
145 
147  std::unique_ptr<BufferViewImplType, STDDeleter<BufferViewImplType, TBuffViewObjAllocator> > m_pDefaultUAV;
148 
150  std::unique_ptr<BufferViewImplType, STDDeleter<BufferViewImplType, TBuffViewObjAllocator> > m_pDefaultSRV;
151 };
152 
153 template<class BaseInterface, class BufferViewImplType, class TBuffViewObjAllocator>
154 void BufferBase<BaseInterface, BufferViewImplType, TBuffViewObjAllocator> :: UpdateData( IDeviceContext *pContext, Uint32 Offset, Uint32 Size, const PVoid pData )
155 {
156  VERIFY_BUFFER( this->m_Desc.Usage == USAGE_DEFAULT, "Only default usage buffers can be updated with UpdateData()" );
157  VERIFY_BUFFER( Offset < this->m_Desc.uiSizeInBytes, "Offset (", Offset, ") exceeds the buffer size (", this->m_Desc.uiSizeInBytes, ")" );
158  VERIFY_BUFFER( Size + Offset <= this->m_Desc.uiSizeInBytes, "Update region [", Offset, ",", Size + Offset, ") is out of buffer bounds [0,",this->m_Desc.uiSizeInBytes,")" );
159 }
160 
161 template<class BaseInterface, class BufferViewImplType, class TBuffViewObjAllocator>
162 void BufferBase<BaseInterface, BufferViewImplType, TBuffViewObjAllocator> :: CopyData( IDeviceContext *pContext, IBuffer *pSrcBuffer, Uint32 SrcOffset, Uint32 DstOffset, Uint32 Size )
163 {
164  VERIFY_BUFFER( DstOffset + Size <= this->m_Desc.uiSizeInBytes, "Destination range [", DstOffset, ",", DstOffset + Size, ") is out of buffer bounds [0,",this->m_Desc.uiSizeInBytes,")" );
165  VERIFY_BUFFER( SrcOffset + Size <= pSrcBuffer->GetDesc().uiSizeInBytes, "Source range [", SrcOffset, ",", SrcOffset + Size, ") is out of buffer bounds [0,",this->m_Desc.uiSizeInBytes,")" );
166 }
167 
168 
169 template<class BaseInterface, class BufferViewImplType, class TBuffViewObjAllocator>
170 void BufferBase<BaseInterface, BufferViewImplType, TBuffViewObjAllocator> :: Map( IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapFlags, PVoid &pMappedData )
171 {
172  switch( MapType )
173  {
174  case MAP_READ:
175  VERIFY_BUFFER( this->m_Desc.Usage == USAGE_CPU_ACCESSIBLE, "Only buffers with usage USAGE_CPU_ACCESSIBLE can be read from" );
176  VERIFY_BUFFER( (this->m_Desc.CPUAccessFlags & CPU_ACCESS_READ), "Buffer being mapped for reading was not created with CPU_ACCESS_READ flag" );
177  VERIFY_BUFFER( (MapFlags & MAP_FLAG_DISCARD) == 0, "MAP_FLAG_DISCARD is not valid when mapping buffer for reading" );
178  break;
179 
180  case MAP_WRITE:
181  VERIFY_BUFFER( this->m_Desc.Usage == USAGE_DYNAMIC || this->m_Desc.Usage == USAGE_CPU_ACCESSIBLE, "Only buffers with usage USAGE_CPU_ACCESSIBLE or USAGE_DYNAMIC can be mapped for writing" );
182  VERIFY_BUFFER( (this->m_Desc.CPUAccessFlags & CPU_ACCESS_WRITE), "Buffer being mapped for writing was not created with CPU_ACCESS_WRITE flag" );
183  break;
184 
185  case MAP_READ_WRITE:
186  VERIFY_BUFFER( this->m_Desc.Usage == USAGE_CPU_ACCESSIBLE, "Only buffers with usage USAGE_CPU_ACCESSIBLE can be mapped for reading and writing" );
187  VERIFY_BUFFER( (this->m_Desc.CPUAccessFlags & CPU_ACCESS_WRITE), "Buffer being mapped for reading & writing was not created with CPU_ACCESS_WRITE flag" );
188  VERIFY_BUFFER( (this->m_Desc.CPUAccessFlags & CPU_ACCESS_READ), "Buffer being mapped for reading & writing was not created with CPU_ACCESS_READ flag" );
189  VERIFY_BUFFER( (MapFlags & MAP_FLAG_DISCARD) == 0, "MAP_FLAG_DISCARD is not valid when mapping buffer for reading and writing" );
190  break;
191 
192  default: UNEXPECTED( "Unknown map type" );
193  }
194 
195  if (this->m_Desc.Usage == USAGE_DYNAMIC)
196  {
197  VERIFY((MapFlags & MAP_FLAG_DISCARD) != 0 && MapType == MAP_WRITE, "Dynamic buffers can only be mapped for writing with discard flag");
198  }
199 
200  if ( (MapFlags & MAP_FLAG_DISCARD) != 0 )
201  {
202  VERIFY_BUFFER( this->m_Desc.Usage == USAGE_DYNAMIC || this->m_Desc.Usage == USAGE_CPU_ACCESSIBLE, "Only dynamic and staging buffers can be mapped with discard flag" );
203  VERIFY_BUFFER( MapType == MAP_WRITE, "MAP_FLAG_DISCARD is only valid when mapping buffer for writing" );
204  }
205 }
206 
207 template<class BaseInterface, class BufferViewImplType, class TBuffViewObjAllocator>
209 {
210 
211 }
212 
213 
214 template<class BaseInterface, class BufferViewImplType, class TBuffViewObjAllocator>
216 {
217  CreateViewInternal( ViewDesc, ppView, false );
218 }
219 
220 
221 template<class BaseInterface, class BufferViewImplType, class TBuffViewObjAllocator>
223 {
224  if( ViewDesc.ByteWidth == 0 )
225  ViewDesc.ByteWidth = this->m_Desc.uiSizeInBytes;
226  if( ViewDesc.ByteOffset + ViewDesc.ByteWidth > this->m_Desc.uiSizeInBytes )
227  LOG_ERROR_AND_THROW( "Buffer view range [", ViewDesc.ByteOffset, ", ", ViewDesc.ByteOffset + ViewDesc.ByteWidth, ") is out of the buffer boundaries [0, ", this->m_Desc.uiSizeInBytes, ")." );
228  if( (this->m_Desc.BindFlags & BIND_UNORDERED_ACCESS) ||
229  (this->m_Desc.BindFlags & BIND_SHADER_RESOURCE) )
230  {
231  VERIFY( this->m_Desc.ElementByteStride != 0, "Element byte stride is zero" );
232  if( (ViewDesc.ByteOffset % this->m_Desc.ElementByteStride) != 0 )
233  LOG_ERROR_AND_THROW( "Buffer view byte offset (", ViewDesc.ByteOffset, ") is not multiple of element byte stride (", this->m_Desc.ElementByteStride, ")." );
234  if( (ViewDesc.ByteWidth % this->m_Desc.ElementByteStride) != 0 )
235  LOG_ERROR_AND_THROW( "Buffer view byte width (", ViewDesc.ByteWidth, ") is not multiple of element byte stride (", this->m_Desc.ElementByteStride, ")." );
236  }
237 }
238 
239 template<class BaseInterface, class BufferViewImplType, class TBuffViewObjAllocator>
241 {
242  switch( ViewType )
243  {
244  case BUFFER_VIEW_SHADER_RESOURCE: return m_pDefaultSRV.get();
245  case BUFFER_VIEW_UNORDERED_ACCESS: return m_pDefaultUAV.get();
246  default: UNEXPECTED( "Unknown view type" ); return nullptr;
247  }
248 }
249 
250 template<class BaseInterface, class BufferViewImplType, class TBuffViewObjAllocator>
252 {
253  if( this->m_Desc.BindFlags & BIND_UNORDERED_ACCESS )
254  {
255  BufferViewDesc ViewDesc;
257  IBufferView *pUAV = nullptr;
258  CreateViewInternal( ViewDesc, &pUAV, true );
259  m_pDefaultUAV.reset( static_cast<BufferViewImplType*>(pUAV) );
260  VERIFY( m_pDefaultUAV->GetDesc().ViewType == BUFFER_VIEW_UNORDERED_ACCESS, "Unexpected view type" );
261  }
262 
263  if( this->m_Desc.BindFlags & BIND_SHADER_RESOURCE )
264  {
265  BufferViewDesc ViewDesc;
267  IBufferView* pSRV = nullptr;
268  CreateViewInternal( ViewDesc, &pSRV, true );
269  m_pDefaultSRV.reset( static_cast<BufferViewImplType*>(pSRV) );
270  VERIFY( m_pDefaultSRV->GetDesc().ViewType == BUFFER_VIEW_SHADER_RESOURCE, "Unexpected view type" );
271  }
272 }
273 
274 }
void CorrectBufferViewDesc(struct BufferViewDesc &ViewDesc)
Corrects buffer view description and validates view parameters.
Definition: BufferBase.h:222
BUFFER_VIEW_TYPE ViewType
View type. See Diligent::BUFFER_VIEW_TYPE for details.
Definition: BufferView.h:42
void CreateDefaultViews()
Creates default buffer views.
Definition: BufferBase.h:251
Buffer view description.
Definition: BufferView.h:39
Helper value storing the total number of modes in the enumeration.
Definition: Buffer.h:53
Render device interface.
Definition: RenderDevice.h:55
Undefined type.
Definition: GraphicsTypes.h:41
A buffer or a texture can be bound as a shader resource.
Definition: GraphicsTypes.h:68
virtual IBufferView * GetDefaultView(BUFFER_VIEW_TYPE ViewType) override
Implementation of IBuffer::GetDefaultView().
Definition: BufferBase.h:240
BUFFER_MODE Mode
Buffer mode.
Definition: Buffer.h:78
Namespace for the OpenGL implementation of the graphics engine.
Definition: BufferD3D11Impl.h:34
A buffer view will define an unordered access view that will be used for unordered read/write operati...
Definition: GraphicsTypes.h:230
virtual void CreateView(const struct BufferViewDesc &ViewDesc, IBufferView **ppView) override
Implementation of IBuffer::CreateView(); calls CreateViewInternal() virtual function that creates buf...
Definition: BufferBase.h:215
Uint32 ElementByteStride
Buffer element stride, in bytes. For a structured buffer (BufferDesc::Mode equals Diligent::BUFFER_MO...
Definition: Buffer.h:131
Uint32 ByteOffset
Offset in bytes from the beginnig of the buffer to the start of the buffer region referenced by the v...
Definition: BufferView.h:46
A buffer can be bound as an index buffer.
Definition: GraphicsTypes.h:65
Template class implementing base functionality for a buffer object.
Definition: BufferBase.h:46
Undefined mode.
Definition: Buffer.h:44
Previous contents of the resource will be undefined. This flag is only compatible with MAP_WRITE D3D...
Definition: GraphicsTypes.h:158
Structured buffer.
Definition: Buffer.h:50
BufferBase(IReferenceCounters *pRefCounters, TBuffViewObjAllocator &BuffViewObjAllocator, IRenderDevice *pDevice, const BufferDesc &BuffDesc, bool bIsDeviceInternal)
Definition: BufferBase.h:58
virtual void Unmap(IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapFlags) override=0
Base implementation of IBuffer::Unmap()
Definition: BufferBase.h:208
A buffer can be bound as a vertex buffer.
Definition: GraphicsTypes.h:64
Buffer interface.
Definition: Buffer.h:200
Formated buffer.
Definition: Buffer.h:47
Device context interface.
Definition: DeviceContext.h:443
A buffer can be bound as the source buffer for indirect draw commands.
Definition: GraphicsTypes.h:74
A resource can be mapped for reading.
Definition: GraphicsTypes.h:114
A resource that requires read and write access by the GPU and can also be occasionally written by the...
Definition: GraphicsTypes.h:95
Buffer description.
Definition: Buffer.h:57
virtual void CreateViewInternal(const struct BufferViewDesc &ViewDesc, IBufferView **ppView, bool bIsDefaultView)=0
Pure virtual function that creates buffer view for the specific engine implementation.
virtual void UpdateData(IDeviceContext *pContext, Uint32 Offset, Uint32 Size, const PVoid pData) override=0
Base implementation of IBuffer::UpdateData(); validates input parameters.
Definition: BufferBase.h:154
Resource is mapped for writing. D3D11 counterpart: D3D11_MAP_WRITE. OpenGL counterpart: GL_MAP_WRIT...
Definition: GraphicsTypes.h:133
VALUE_TYPE ValueType
Type of components. For a formatted buffer, this value cannot be VT_UNDEFINED.
Definition: Buffer.h:84
A resource that facilitates transferring data from GPU to CPU. D3D11 Counterpart: D3D11_USAGE_STAGI...
Definition: GraphicsTypes.h:103
Resource is mapped for reading. D3D11 counterpart: D3D11_MAP_READ. OpenGL counterpart: GL_MAP_READ_...
Definition: GraphicsTypes.h:129
BufferDesc m_Desc
Object description.
Definition: DeviceObjectBase.h:138
A buffer or a texture can be bound as an unordered access view.
Definition: GraphicsTypes.h:73
virtual void Map(IDeviceContext *pContext, MAP_TYPE MapType, Uint32 MapFlags, PVoid &pMappedData) override
Base implementation of IBuffer::Map(); validates input parameters.
Definition: BufferBase.h:170
Uint32 ByteWidth
Size in bytes of the referenced buffer region.
Definition: BufferView.h:49
A buffer can be bound as a target for stream output stage.
Definition: GraphicsTypes.h:70
A buffer view will define a shader resource view that will be used as the source for the shader read ...
Definition: GraphicsTypes.h:226
virtual void CopyData(IDeviceContext *pContext, IBuffer *pSrcBuffer, Uint32 SrcOffset, Uint32 DstOffset, Uint32 Size) override=0
Base implementation of IBuffer::CopyData(); validates input parameters.
Definition: BufferBase.h:162
A buffer can be bound as a uniform buffer.
Definition: GraphicsTypes.h:66
std::unique_ptr< BufferViewImplType, STDDeleter< BufferViewImplType, TBuffViewObjAllocator > > m_pDefaultUAV
Default UAV addressing the entire buffer.
Definition: BufferBase.h:147
A resource can be mapped for writing.
Definition: GraphicsTypes.h:115
std::unique_ptr< BufferViewImplType, STDDeleter< BufferViewImplType, TBuffViewObjAllocator > > m_pDefaultSRV
Default SRV addressing the entire buffer.
Definition: BufferBase.h:150
Uint32 NumComponents
Number of components. Allowed values: 1, 2, 3, 4. For a formatted buffer, this value cannot be 0...
Definition: Buffer.h:88
BufferFormat Format
Buffer format.
Definition: Buffer.h:124
Uint32 BindFlags
Buffer bind flags, see Diligent::BIND_FLAGS for details.
Definition: Buffer.h:68
Resource is mapped for reading and writing. D3D11 counterpart: D3D11_MAP_READ_WRITE. OpenGL counterpart: GL_MAP_WRITE_BIT | GL_MAP_READ_BIT.
Definition: GraphicsTypes.h:137
Buffer view interface.
Definition: BufferView.h:91
Template class implementing base functionality for a device object.
Definition: DeviceObjectBase.h:42
MAP_TYPE
Resource mapping type.
Definition: GraphicsTypes.h:125
A resource that can be read by the GPU and written at least once per frame by the CPU...
Definition: GraphicsTypes.h:99
BUFFER_VIEW_TYPE
Buffer view type.
Definition: GraphicsTypes.h:219