Files
FlaxEngine/Source/Engine/Graphics/DynamicBuffer.h

225 lines
6.8 KiB
C++

// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Core/Collections/Array.h"
#include "GPUBuffer.h"
/// <summary>
/// Dynamic GPU buffer that allows to update and use GPU data (index/vertex/other) during single frame (supports dynamic resizing).
/// </summary>
class FLAXENGINE_API DynamicBuffer
{
protected:
GPUBuffer* _buffer;
String _name;
uint32 _stride;
public:
NON_COPYABLE(DynamicBuffer);
/// <summary>
/// Init
/// </summary>
/// <param name="initialCapacity">Initial capacity of the buffer (in bytes)</param>
/// <param name="stride">Stride in bytes</param>
/// <param name="name">Buffer name</param>
DynamicBuffer(uint32 initialCapacity, uint32 stride, const String& name);
/// <summary>
/// Destructor
/// </summary>
virtual ~DynamicBuffer();
public:
/// <summary>
/// GPU usage of the resource. Use Dynamic for resources that can be updated multiple timers per-frame.
/// </summary>
GPUResourceUsage Usage = GPUResourceUsage::Dynamic;
/// <summary>
/// The data container (raw bytes storage).
/// </summary>
Array<byte> Data;
/// <summary>
/// Gets buffer (can be null due to 'late init' feature).
/// </summary>
FORCE_INLINE GPUBuffer* GetBuffer() const
{
return _buffer;
}
/// <summary>
/// Clear data (begin for writing)
/// </summary>
FORCE_INLINE void Clear()
{
Data.Clear();
}
/// <summary>
/// Write bytes to the buffer
/// </summary>
/// <param name="data">Data to write</param>
template<typename T>
FORCE_INLINE void Write(const T& data)
{
Data.Add((byte*)&data, sizeof(T));
}
/// <summary>
/// Write bytes to the buffer
/// </summary>
/// <param name="bytes">Pointer to data to write</param>
/// <param name="size">Amount of data to write (in bytes)</param>
FORCE_INLINE void Write(const void* bytes, int32 size)
{
Data.Add((const byte*)bytes, size);
}
/// <summary>
/// Allocates bytes in the buffer by resizing the buffer for new memory and returns the pointer to the start of the allocated space.
/// </summary>
/// <param name="size">Amount of data to allocate (in bytes)</param>
FORCE_INLINE byte* WriteReserve(int32 size)
{
const int32 start = Data.Count();
Data.AddUninitialized(size);
return Data.Get() + start;
}
/// <summary>
/// Allocates bytes in the buffer by resizing the buffer for new memory and returns the pointer to the start of the allocated space.
/// </summary>
/// <param name="count">Amount of items to allocate</param>
template<typename T>
FORCE_INLINE T* WriteReserve(int32 count)
{
return (T*)WriteReserve(count * sizeof(T));
}
/// <summary>
/// Unlock buffer and flush data with a buffer (it will be ready for an immediate draw).
/// </summary>
void Flush()
{
Flush(nullptr);
}
/// <summary>
/// Unlock buffer and flush data with a buffer (it will be ready for a during next frame draw).
/// </summary>
/// <param name="context">The GPU command list context to use for data uploading.</param>
void Flush(class GPUContext* context);
/// <summary>
/// Disposes the buffer resource and clears the used memory.
/// </summary>
void Dispose();
protected:
virtual void InitDesc(GPUBufferDescription& desc, int32 numElements) = 0;
};
/// <summary>
/// Dynamic vertex buffer that allows to render any vertices during single frame (supports dynamic resizing)
/// </summary>
class FLAXENGINE_API DynamicVertexBuffer : public DynamicBuffer
{
private:
GPUVertexLayout* _layout;
public:
/// <summary>
/// Init
/// </summary>
/// <param name="initialCapacity">Initial capacity of the buffer (in bytes)</param>
/// <param name="stride">Stride in bytes</param>
/// <param name="name">Buffer name</param>
/// <param name="layout">The vertex buffer layout.</param>
DynamicVertexBuffer(uint32 initialCapacity, uint32 stride, const String& name = String::Empty, GPUVertexLayout* layout = nullptr)
: DynamicBuffer(initialCapacity, stride, name)
, _layout(layout)
{
}
// Gets the vertex buffer layout.
GPUVertexLayout* GetLayout() const;
// Sets the vertex buffer layout.
void SetLayout(GPUVertexLayout* layout);
protected:
// [DynamicBuffer]
void InitDesc(GPUBufferDescription& desc, int32 numElements) override;
};
/// <summary>
/// Dynamic index buffer that allows to render any indices during single frame (supports dynamic resizing)
/// </summary>
class FLAXENGINE_API DynamicIndexBuffer : public DynamicBuffer
{
public:
/// <summary>
/// Init
/// </summary>
/// <param name="initialCapacity">Initial capacity of the buffer (in bytes)</param>
/// <param name="stride">Stride in bytes</param>
/// <param name="name">Buffer name</param>
DynamicIndexBuffer(uint32 initialCapacity, uint32 stride, const String& name = String::Empty)
: DynamicBuffer(initialCapacity, stride, name)
{
}
protected:
// [DynamicBuffer]
void InitDesc(GPUBufferDescription& desc, int32 numElements) override;
};
/// <summary>
/// Dynamic structured buffer that allows to upload data to the GPU from CPU (supports dynamic resizing).
/// </summary>
class FLAXENGINE_API DynamicStructuredBuffer : public DynamicBuffer
{
private:
bool _isUnorderedAccess;
public:
/// <summary>
/// Init
/// </summary>
/// <param name="initialCapacity">Initial capacity of the buffer (in bytes).</param>
/// <param name="stride">Stride in bytes.</param>
/// <param name="isUnorderedAccess">True if unordered access usage.</param>
/// <param name="name">Buffer name.</param>
DynamicStructuredBuffer(uint32 initialCapacity, uint32 stride, bool isUnorderedAccess = false, const String& name = String::Empty);
protected:
// [DynamicBuffer]
void InitDesc(GPUBufferDescription& desc, int32 numElements) override;
};
/// <summary>
/// Dynamic Typed buffer that allows to upload data to the GPU from CPU (supports dynamic resizing).
/// </summary>
class FLAXENGINE_API DynamicTypedBuffer : public DynamicBuffer
{
private:
PixelFormat _format;
bool _isUnorderedAccess;
public:
/// <summary>
/// Init
/// </summary>
/// <param name="initialCapacity">Initial capacity of the buffer (in bytes).</param>
/// <param name="format">Format of the data.</param>
/// <param name="isUnorderedAccess">True if unordered access usage.</param>
/// <param name="name">Buffer name.</param>
DynamicTypedBuffer(uint32 initialCapacity, PixelFormat format, bool isUnorderedAccess = false, const String& name = String::Empty);
protected:
// [DynamicBuffer]
void InitDesc(GPUBufferDescription& desc, int32 numElements) override;
};