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