Extra2D/include/renderer/instance_buffer.h

322 lines
8.4 KiB
C
Raw Normal View History

#pragma once
#include <renderer/rhi/rhi.h>
#include <renderer/rhi/rhi_types.h>
#include <types/math/vec2.h>
#include <types/math/color.h>
#include <types/math/mat4.h>
#include <vector>
#include <memory>
namespace extra2d {
/**
* @brief
*
*
* std140
*
*
* - 使 cos/sin
* - 便GPU访问
*/
struct InstanceData {
// 第一组 16 字节 - 变换数据
Vec2 position; // 位置偏移 (8 bytes)
float rotationCos; // 旋转角度余弦值 (4 bytes) - 预计算避免着色器三角函数
float rotationSin; // 旋转角度正弦值 (4 bytes) - 预计算避免着色器三角函数
// 第二组 16 字节 - 缩放和预留
Vec2 scale; // 缩放 (8 bytes)
float padding1[2]; // 填充到 16 字节对齐 (8 bytes)
// 第三组 16 字节 - 颜色
Color color; // 颜色 (16 bytes) - r, g, b, a
// 第四组 16 字节 - UV坐标
float uvX; // UV 起始 X (4 bytes)
float uvY; // UV 起始 Y (4 bytes)
float uvWidth; // UV 宽度 (4 bytes)
float uvHeight; // UV 高度 (4 bytes)
InstanceData()
: position(0.0f, 0.0f)
, rotationCos(1.0f) // cos(0) = 1
, rotationSin(0.0f) // sin(0) = 0
, scale(1.0f, 1.0f)
, padding1{0.0f, 0.0f}
, color(Color::White)
, uvX(0.0f)
, uvY(0.0f)
, uvWidth(1.0f)
, uvHeight(1.0f) {}
/**
* @brief cos/sin
* @param angle
*/
void setRotation(float angle) {
rotationCos = std::cos(angle);
rotationSin = std::sin(angle);
}
/**
* @brief atan2计算
* @return
*/
float getRotation() const {
return std::atan2(rotationSin, rotationCos);
}
};
static_assert(sizeof(InstanceData) == 64, "InstanceData size should be 64 bytes for std140 alignment");
/**
* @brief
*
* GPU缓冲区
*/
struct DirtyRange {
uint32_t start; // 起始实例索引
uint32_t count; // 实例数量
DirtyRange(uint32_t s = 0, uint32_t c = 0) : start(s), count(c) {}
bool isValid() const { return count > 0; }
uint32_t end() const { return start + count; }
// 检查是否与另一个区域重叠或相邻
bool canMerge(const DirtyRange& other) const {
return (start <= other.end() && other.start <= end()) ||
(end() + 1 >= other.start && other.end() + 1 >= start);
}
// 合并两个区域
void merge(const DirtyRange& other) {
uint32_t newStart = std::min(start, other.start);
uint32_t newEnd = std::max(end(), other.end());
start = newStart;
count = newEnd - newStart;
}
};
/**
* @brief
*
*
*
*
*
* - PCIe带宽占用
* - GPU上传次数
*/
class InstanceBuffer {
public:
/**
* @brief
*/
InstanceBuffer();
/**
* @brief
*/
~InstanceBuffer();
// 禁止拷贝
InstanceBuffer(const InstanceBuffer&) = delete;
InstanceBuffer& operator=(const InstanceBuffer&) = delete;
// 允许移动
InstanceBuffer(InstanceBuffer&& other) noexcept;
InstanceBuffer& operator=(InstanceBuffer&& other) noexcept;
/**
* @brief
* @param maxInstances
* @return
*/
bool initialize(uint32_t maxInstances);
/**
* @brief
*/
void shutdown();
/**
* @brief
* @param instances
* @param count
* @return
*/
bool updateInstances(const InstanceData* instances, uint32_t count);
/**
* @brief
* @param instances
* @param start
* @param count
* @return
*/
bool updateInstancesRange(const InstanceData* instances, uint32_t start, uint32_t count);
/**
* @brief
* @param instance
* @return
*/
uint32_t addInstance(const InstanceData& instance);
/**
* @brief updateGPU时更新
* @param start
* @param count
*/
void markDirty(uint32_t start, uint32_t count);
/**
* @brief
*/
void markAllDirty();
/**
* @brief GPU
* @return
*/
bool updateGPU();
/**
* @brief
*/
void clear();
/**
* @brief
* @return
*/
uint32_t getInstanceCount() const { return instanceCount_; }
/**
* @brief
* @return
*/
uint32_t getMaxInstances() const { return maxInstances_; }
/**
* @brief RHI
* @return
*/
BufferHandle getBufferHandle() const { return bufferHandle_; }
/**
* @brief RHI
* @return
*/
RHIBuffer* getRHIBuffer() const { return bufferHandle_.get(); }
/**
* @brief
* @return
*/
bool isValid() const { return bufferHandle_.isValid(); }
/**
* @brief
* @return
*/
uint32_t getDirtyRangeCount() const { return static_cast<uint32_t>(dirtyRanges_.size()); }
/**
* @brief
* @return
*/
bool hasDirtyData() const { return !dirtyRanges_.empty(); }
private:
BufferHandle bufferHandle_; // RHI 缓冲区句柄
uint32_t maxInstances_ = 0; // 最大实例数量
uint32_t instanceCount_ = 0; // 当前实例数量
std::vector<InstanceData> cpuBuffer_; // CPU 端缓冲区
std::vector<DirtyRange> dirtyRanges_; // 脏区域列表
// 最大脏区域数量,超过则合并为全量更新
static constexpr uint32_t MAX_DIRTY_RANGES = 8;
/**
* @brief
* @param range
*/
void addDirtyRange(const DirtyRange& range);
/**
* @brief
*/
void mergeAllDirtyRanges();
/**
* @brief
*/
void clearDirtyRanges();
};
/**
* @brief
*
*
*/
class InstanceBufferManager {
public:
/**
* @brief
*/
InstanceBufferManager();
/**
* @brief
*/
~InstanceBufferManager();
// 禁止拷贝
InstanceBufferManager(const InstanceBufferManager&) = delete;
InstanceBufferManager& operator=(const InstanceBufferManager&) = delete;
// 允许移动
InstanceBufferManager(InstanceBufferManager&& other) noexcept;
InstanceBufferManager& operator=(InstanceBufferManager&& other) noexcept;
/**
* @brief
* @return
*/
bool initialize();
/**
* @brief
*/
void shutdown();
/**
* @brief
* @param minSize
* @return
*/
InstanceBuffer* acquireBuffer(uint32_t minSize);
/**
* @brief
* @param buffer
*/
void releaseBuffer(InstanceBuffer* buffer);
/**
* @brief
*/
void reset();
private:
std::vector<std::unique_ptr<InstanceBuffer>> bufferPool_;
uint32_t currentBufferIndex_ = 0;
static constexpr uint32_t DEFAULT_BUFFER_SIZE = 1024;
};
} // namespace extra2d