Fix&Add: 禁Buffer/Texture类拷贝,添加Materials/Lights->GPU按需上传功能

master
ternaryop8479 2026-02-11 12:12:38 +08:00
parent b8ae9808a8
commit dbe0bd3385
7 changed files with 122 additions and 17 deletions

Binary file not shown.

View File

@ -90,6 +90,9 @@ private:
Buffer bvh_triangle_buffer_; // 添加
bool bvh_built_; // 添加
uint materials_hash_;
uint lights_hash_;
uint frame_count_;
bool initialized_;

View File

@ -26,6 +26,12 @@ public:
/// @brief Constructor
Buffer();
Buffer(const Buffer&) = delete;
Buffer& operator=(const Buffer&) = delete;
Buffer(Buffer&& other) noexcept;
Buffer& operator=(Buffer&& other) noexcept;
/// @brief Destructor
~Buffer();

View File

@ -47,6 +47,12 @@ public:
/// @brief Constructor
Texture();
Texture(const Texture&) = delete;
Texture& operator=(const Texture&) = delete;
Texture(Texture&& other) noexcept;
Texture& operator=(Texture&& other) noexcept;
/// @brief Destructor
~Texture();

View File

@ -5,6 +5,18 @@
namespace are {
namespace {
uint fnv1a_hash_bytes(const void *data, size_t size) {
const uint8_t *bytes = static_cast<const uint8_t *>(data);
uint h = 2166136261u;
for (size_t i = 0; i < size; ++i) {
h ^= bytes[i];
h *= 16777619u;
}
return h;
}
} // namespace
RayTracer::RayTracer(uint width, uint height, const RayTracerConfig &config)
: width_(width)
, height_(height)
@ -15,6 +27,8 @@ RayTracer::RayTracer(uint width, uint height, const RayTracerConfig &config)
, light_buffer_(INVALID_HANDLE)
, bvh_(nullptr)
, bvh_built_(false)
, materials_hash_(0u)
, lights_hash_(0u)
, frame_count_(0)
, initialized_(false) {
}
@ -104,6 +118,7 @@ bool RayTracer::rebuild_bvh(const Scene &scene) {
}
bvh_built_ = true;
reset_accumulation();
Logger::info("BVH built and uploaded successfully");
return true;
}
@ -227,7 +242,7 @@ void RayTracer::set_config(const RayTracerConfig &config) {
}
void RayTracer::upload_scene_data_(const Scene &scene) {
// Upload materials
// Upload materials (on change only)
const auto &materials = scene.get_materials();
if (!materials.empty()) {
struct MaterialData {
@ -244,7 +259,7 @@ void RayTracer::upload_scene_data_(const Scene &scene) {
material_data.reserve(materials.size());
for (const auto &mat : materials) {
MaterialData data;
MaterialData data {};
data.albedo = mat->get_albedo();
data.metallic = mat->get_metallic();
data.emission = mat->get_emission();
@ -254,14 +269,26 @@ void RayTracer::upload_scene_data_(const Scene &scene) {
material_data.push_back(data);
}
uint h = fnv1a_hash_bytes(material_data.data(), material_data.size() * sizeof(MaterialData));
if (h != materials_hash_) {
materials_hash_ = h;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, material_buffer_);
glBufferData(GL_SHADER_STORAGE_BUFFER,
material_data.size() * sizeof(MaterialData),
material_data.data(), GL_DYNAMIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, material_buffer_);
reset_accumulation(); // materials changed => invalidate accumulation
} else {
// Still ensure bound (in case other code changed bindings)
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, material_buffer_);
}
} else {
materials_hash_ = 0u;
}
// Upload lights
// Upload lights (on change only)
const auto &lights = scene.get_lights();
if (!lights.empty()) {
struct LightData {
@ -279,7 +306,7 @@ void RayTracer::upload_scene_data_(const Scene &scene) {
light_data.reserve(lights.size());
for (const auto &light : lights) {
LightData data;
LightData data {};
data.position = light->get_position();
data.type = static_cast<int>(light->get_type());
data.direction = light->get_direction();
@ -290,11 +317,22 @@ void RayTracer::upload_scene_data_(const Scene &scene) {
light_data.push_back(data);
}
uint h = fnv1a_hash_bytes(light_data.data(), light_data.size() * sizeof(LightData));
if (h != lights_hash_) {
lights_hash_ = h;
glBindBuffer(GL_SHADER_STORAGE_BUFFER, light_buffer_);
glBufferData(GL_SHADER_STORAGE_BUFFER,
light_data.size() * sizeof(LightData),
light_data.data(), GL_DYNAMIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, light_buffer_);
reset_accumulation(); // lights changed => invalidate accumulation
} else {
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, light_buffer_);
}
} else {
lights_hash_ = 0u;
}
}

View File

@ -32,8 +32,31 @@ Buffer::Buffer()
, usage_(BufferUsage::STATIC_DRAW) {
}
Buffer::Buffer(Buffer&& other) noexcept
: handle_(other.handle_)
, type_(other.type_)
, size_(other.size_)
, usage_(other.usage_) {
other.handle_ = INVALID_HANDLE;
other.size_ = 0;
}
Buffer& Buffer::operator=(Buffer&& other) noexcept {
if (this == &other) return *this;
release();
handle_ = other.handle_;
type_ = other.type_;
size_ = other.size_;
usage_ = other.usage_;
other.handle_ = INVALID_HANDLE;
other.size_ = 0;
return *this;
}
Buffer::~Buffer() {
// Don't auto-release, let user control lifetime
release();
}
bool Buffer::create(BufferType type, size_t size, const void* data, BufferUsage usage) {

View File

@ -104,8 +104,37 @@ Texture::Texture()
, has_mipmaps_(false) {
}
Texture::Texture(Texture&& other) noexcept
: handle_(other.handle_)
, width_(other.width_)
, height_(other.height_)
, format_(other.format_)
, has_mipmaps_(other.has_mipmaps_) {
other.handle_ = INVALID_HANDLE;
other.width_ = 0;
other.height_ = 0;
other.has_mipmaps_ = false;
}
Texture& Texture::operator=(Texture&& other) noexcept {
if (this == &other) return *this;
release();
handle_ = other.handle_;
width_ = other.width_;
height_ = other.height_;
format_ = other.format_;
has_mipmaps_ = other.has_mipmaps_;
other.handle_ = INVALID_HANDLE;
other.width_ = 0;
other.height_ = 0;
other.has_mipmaps_ = false;
return *this;
}
Texture::~Texture() {
// Don't auto-release, let user control lifetime
release();
}
bool Texture::load_from_file(const std::string& path, bool generate_mipmaps) {