NAP
gpubuffer.h
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4 
5 #pragma once
6 
7 // Local Includes
8 #include "fillpolicy.h"
9 #include "formatutils.h"
10 #include "renderutils.h"
11 #include "bufferdata.h"
12 
13 // External Includes
14 #include <nap/resourceptr.h>
15 #include <glm/glm.hpp>
16 #include <nap/logger.h>
17 #include <vulkan/vulkan_core.h>
18 #include <utility/dllexport.h>
19 #include <nap/signalslot.h>
20 #include <vector>
21 #include <utility/errorstate.h>
22 
23 namespace nap
24 {
25  class RenderService;
26  class Core;
27 
41  enum class EMemoryUsage : uint
42  {
43  Static,
44  DynamicRead,
46  };
47 
48 
50  // GPU Buffer
52 
64  class NAPAPI GPUBuffer : public Resource
65  {
66  friend class RenderService;
67  RTTI_ENABLE(Resource)
68  public:
75  GPUBuffer(Core& core);
76 
84  GPUBuffer(Core& core, EMemoryUsage usage);
85 
86  // Queues buffers for destruction
87  virtual ~GPUBuffer();
88 
92  virtual VkBuffer getBuffer() const;
93 
97  virtual const BufferData& getBufferData() const;
98 
102  virtual bool init(utility::ErrorState& errorState) override;
103 
107  virtual uint getCount() const = 0;
108 
112  virtual size_t getSize() const = 0;
113 
117  virtual uint32 getElementSize() const = 0;
118 
122  virtual VkBufferUsageFlags getBufferUsageFlags() const { return mUsageFlags; }
123 
129  void ensureUsage(VkBufferUsageFlags usage) { mUsageFlags |= usage; }
130 
135  virtual bool isInitialized() const = 0;
136 
141  void asyncGetData(std::function<void(const void*, size_t)> copyFunction);
142 
147 
149 
150  protected:
157  bool allocateInternal(size_t size, utility::ErrorState& errorState);
158 
167  bool setDataInternal(const void* data, size_t size, size_t reservedSize, utility::ErrorState& errorState);
168 
172  void requestClear();
173 
174  RenderService* mRenderService = nullptr;
175  std::vector<BufferData> mRenderBuffers;
176  std::vector<BufferData> mStagingBuffers;
177  uint32 mSize = 0;
178 
179  int mCurrentRenderBufferIndex = 0;
180  int mCurrentStagingBufferIndex = 0;
181  std::vector<int> mDownloadStagingBufferIndices;
182 
183  private:
184  using BufferReadCallback = std::function<void(void* data, size_t sizeInBytes)>;
185 
186  // Called when usage = static
187  bool setDataInternalStatic(const void* data, size_t size, utility::ErrorState& errorState);
188 
189  // Called when usage = dynamic write
190  bool setDataInternalDynamic(const void* data, size_t size, size_t reservedSize, utility::ErrorState& errorState);
191 
192  // Uploads data from the staging buffer into GPU buffer. Automatically called by the render service at the appropriate time.
193  // Only occurs when 'usage' = 'static'. Dynamic data shares GPU / CPU memory and is updated immediately.
194  void upload(VkCommandBuffer commandBuffer);
195 
196  // Downloads data from GPU buffer to staging buffer
197  void download(VkCommandBuffer commandBuffer);
198 
199  // Clears the buffer to zero
200  void clear(VkCommandBuffer commandBuffer);
201 
202  // Called by the render service when download is ready
203  void notifyDownloadReady(int frameIndex);
204 
205  // Clears queued texture downloads
206  void clearDownloads();
207 
208  std::vector<BufferReadCallback> mReadCallbacks;
209  VkBufferUsageFlags mUsageFlags = 0;
210  };
211 
212 
214  // GPUBufferNumeric
216 
222  class NAPAPI GPUBufferNumeric : public GPUBuffer
223  {
224  RTTI_ENABLE(GPUBuffer)
225  public:
231  GPUBufferNumeric(Core& core, VkFormat format, uint32 elementSize) :
232  GPUBuffer(core), mFormat(format), mElementSize(elementSize)
233  { }
234 
241  GPUBufferNumeric(Core& core, VkFormat format, uint32 elementSize, EMemoryUsage usage) :
242  GPUBuffer(core, usage), mFormat(format), mElementSize(elementSize)
243  { }
244 
248  virtual uint getCount() const override { return mCount; }
249 
253  virtual uint32 getElementSize() const override { return mElementSize; };
254 
258  virtual size_t getSize() const override { return mCount * mElementSize; };
259 
263  virtual VkFormat getFormat() const { return mFormat; }
264 
269  virtual void setCount(uint32 count) { mCount = count; }
270 
280  virtual bool setData(const void* data, size_t elementCount, size_t reservedElementCount, utility::ErrorState& errorState);
281 
282  uint32 mCount = 0;
283 
284  private:
285  VkFormat mFormat = VK_FORMAT_UNDEFINED;
286  uint32 mElementSize = 0;
287  };
288 
289 
291  // Numeric GPU Buffer
293 
307  template<typename T>
309  {
310  RTTI_ENABLE(GPUBufferNumeric)
311  public:
317  GPUBufferNumeric(core, getVulkanFormat(RTTI_OF(T)), sizeof(T))
318  { }
319 
328  TypedGPUBufferNumeric(Core& core, EMemoryUsage usage, bool storage) :
329  GPUBufferNumeric(core, getVulkanFormat(RTTI_OF(T)), sizeof(T), usage), mStorage(storage)
330  { }
331 
339  virtual bool init(utility::ErrorState& errorState) override;
340 
348  bool setData(const std::vector<T>& data, utility::ErrorState& errorState);
349 
353  virtual bool isInitialized() const override { return mInitialized; };
354 
355  bool mClear = false;
357 
358  private:
359  bool mStorage = true;
360  bool mInitialized = false;
361  };
362 
363 
365  // Vertex Buffers
367 
386  template<typename T>
388  {
389  RTTI_ENABLE(TypedGPUBufferNumeric<T>)
390  public:
396  TypedGPUBufferNumeric<T>(core)
397  { }
398 
407  VertexBuffer(Core& core, EMemoryUsage usage, bool storage) :
408  TypedGPUBufferNumeric<T>(core, usage, storage)
409  { }
410 
416  virtual bool init(utility::ErrorState& errorState) override;
417  };
418 
419 
421  // Index Buffer
423 
441  class NAPAPI IndexBuffer : public TypedGPUBufferNumeric<uint>
442  {
443  RTTI_ENABLE(TypedGPUBufferNumeric<uint>)
444  public:
445  // Constructor
447 
456  IndexBuffer(Core & core, EMemoryUsage usage, bool storage) :
457  TypedGPUBufferNumeric<uint>(core, usage, storage) { }
458 
464  virtual bool init(utility::ErrorState & errorState) override;
465  };
466 
467 
469  // GPU numeric buffer type definitions
471 
472  // General purpose GPU buffers
480 
481  // Vertex GPU buffers
488 
489 
491  // Template Definitions
493 
494  template<typename T>
496  {
497  // Ensure storage bit is set if requested
498  VkBufferUsageFlags req_usage = mStorage ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : 0;
499  this->ensureUsage(req_usage);
500 
501  // Initialize Base
502  if (!GPUBufferNumeric::init(errorState))
503  return false;
504 
505  if (!errorState.check(mMemoryUsage != EMemoryUsage::DynamicWrite || mCount >= 0,
506  "Cannot allocate a non-DynamicWrite buffer with zero elements."))
507  return false;
508 
509  // Calculate buffer size
510  uint32 buffer_size = mCount * sizeof(T);
511 
512  // Allocate buffer memory
513  if (!allocateInternal(buffer_size, errorState))
514  return false;
515 
516  // Upload data when a buffer fill policy is available
517  if (mFillPolicy != nullptr)
518  {
519  if (mMemoryUsage != EMemoryUsage::DynamicRead)
520  {
521  // Create a staging buffer to upload
522  auto staging_buffer = std::make_unique<T[]>(mCount);
523  mFillPolicy->fill(mCount, staging_buffer.get());
524 
525  // Prepare staging buffer upload
526  if (!setDataInternal(staging_buffer.get(), buffer_size, buffer_size, errorState))
527  return false;
528  }
529  else
530  {
531  // Warn user that buffers cannot be filled when their usage is set to DynamicRead
532  nap::Logger::warn(utility::stringFormat("%s: The configured fill policy was ignored as the buffer usage is DynamicRead", mID.c_str()).c_str());
533  }
534  }
535 
536  // Optionally clear - does not count as an upload
537  else if (mClear)
538  {
540  }
541 
542  mInitialized = true;
543  return true;
544  }
545 
546  template<typename T>
547  bool TypedGPUBufferNumeric<T>::setData(const std::vector<T>& data, utility::ErrorState& errorState)
548  {
549  if (!setDataInternal(data.data(), data.size() * sizeof(T), data.capacity() * sizeof(T), errorState))
550  return false;
551 
552  // Update count
553  mCount = data.size();
554  return true;
555  }
556 
557  template<typename T>
559  {
560  this->ensureUsage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
561  return TypedGPUBufferNumeric<T>::init(errorState);
562  }
563 }
nap::uint
unsigned int uint
Definition: numeric.h:23
nap::TypedGPUBufferNumeric::init
virtual bool init(utility::ErrorState &errorState) override
Definition: gpubuffer.h:495
nap::IndexBuffer
Definition: gpubuffer.h:441
nap::GPUBuffer::bufferChanged
nap::Signal bufferChanged
Definition: gpubuffer.h:146
nap::IndexBuffer::IndexBuffer
IndexBuffer(Core &core)
Definition: gpubuffer.h:446
nap::TypedGPUBufferNumeric::TypedGPUBufferNumeric
TypedGPUBufferNumeric(Core &core)
Definition: gpubuffer.h:316
nap::VertexBuffer::VertexBuffer
VertexBuffer(Core &core)
Definition: gpubuffer.h:395
nap::GPUBufferNumeric::getCount
virtual uint getCount() const override
Definition: gpubuffer.h:248
nap::EMemoryUsage::Static
@ Static
Buffer data is uploaded only once from the CPU to the GPU.
nap::EMemoryUsage::DynamicRead
@ DynamicRead
Buffer data is uploaded only once from the CPU to the GPU, and frequently read from GPU to CPU.
nap::utility::ErrorState::check
bool check(bool successCondition, T &&errorMessage)
Definition: errorstate.h:36
nap::VertexBuffer::VertexBuffer
VertexBuffer(Core &core, EMemoryUsage usage, bool storage)
Definition: gpubuffer.h:407
nap::GPUBufferNumeric
Definition: gpubuffer.h:222
nap::TypedGPUBufferNumeric::mClear
bool mClear
Property: 'Clear' If no fill policy is set, performs an initial clear-to-zero transfer operation on t...
Definition: gpubuffer.h:355
nap::GPUBuffer::requestClear
void requestClear()
nap::rtti::ObjectPtr
Definition: objectptr.h:154
nap::EMemoryUsage
EMemoryUsage
Definition: gpubuffer.h:41
nap::getVulkanFormat
NAPAPI VkFormat getVulkanFormat(nap::rtti::TypeInfo type)
nap::GPUBuffer::mRenderBuffers
std::vector< BufferData > mRenderBuffers
Render accessible buffers.
Definition: gpubuffer.h:175
nap::utility::ErrorState
Definition: errorstate.h:19
nap::IndexBuffer::IndexBuffer
IndexBuffer(Core &core, EMemoryUsage usage, bool storage)
Definition: gpubuffer.h:456
nap::TypedGPUBufferNumeric::TypedGPUBufferNumeric
TypedGPUBufferNumeric(Core &core, EMemoryUsage usage, bool storage)
Definition: gpubuffer.h:328
nap::GPUBuffer::init
virtual bool init(utility::ErrorState &errorState) override
nap::uint32
uint32_t uint32
Definition: numeric.h:20
nap::TypedGPUBufferNumeric::setData
bool setData(const std::vector< T > &data, utility::ErrorState &errorState)
Definition: gpubuffer.h:547
nap::GPUBufferNumeric::getFormat
virtual VkFormat getFormat() const
Definition: gpubuffer.h:263
nap::TypedGPUBufferNumeric::isInitialized
virtual bool isInitialized() const override
Definition: gpubuffer.h:353
nap::GPUBufferNumeric::setCount
virtual void setCount(uint32 count)
Definition: gpubuffer.h:269
nap::Signal
Definition: signalslot.h:28
nap::GPUBuffer::mDownloadStagingBufferIndices
std::vector< int > mDownloadStagingBufferIndices
Staging buffer indices associated with a frameindex.
Definition: gpubuffer.h:181
nap::VertexBuffer::init
virtual bool init(utility::ErrorState &errorState) override
Definition: gpubuffer.h:558
nap::RenderService
Definition: renderservice.h:275
nap::GPUBuffer::mStagingBuffers
std::vector< BufferData > mStagingBuffers
Staging buffers, used when uploading or downloading data.
Definition: gpubuffer.h:176
nap::Core
Definition: core.h:82
nap::EMemoryUsage::DynamicWrite
@ DynamicWrite
Buffer data is updated more than once from the CPU to the GPU.
nap::GPUBuffer::ensureUsage
void ensureUsage(VkBufferUsageFlags usage)
Definition: gpubuffer.h:129
nap::BufferData
Definition: bufferdata.h:22
nap::GPUBufferNumeric::getElementSize
virtual uint32 getElementSize() const override
Definition: gpubuffer.h:253
nap
Definition: templateapp.h:17
nap::GPUBuffer
Definition: gpubuffer.h:64
nap::TypedGPUBufferNumeric
Definition: gpubuffer.h:308
nap::GPUBuffer::getBufferUsageFlags
virtual VkBufferUsageFlags getBufferUsageFlags() const
Definition: gpubuffer.h:122
nap::Resource
Definition: resource.h:19
nap::VertexBuffer
Definition: gpubuffer.h:387
nap::GPUBufferNumeric::getSize
virtual size_t getSize() const override
Definition: gpubuffer.h:258
nap::GPUBufferNumeric::GPUBufferNumeric
GPUBufferNumeric(Core &core, VkFormat format, uint32 elementSize, EMemoryUsage usage)
Definition: gpubuffer.h:241
nap::TypedGPUBufferNumeric::mFillPolicy
ResourcePtr< FillPolicy< T > > mFillPolicy
Property: 'FillPolicy' Optional fill policy to fill the buffer with on initialization.
Definition: gpubuffer.h:356
nap::GPUBufferNumeric::GPUBufferNumeric
GPUBufferNumeric(Core &core, VkFormat format, uint32 elementSize)
Definition: gpubuffer.h:231