Fix&Add: 禁Buffer/Texture类拷贝,添加Materials/Lights->GPU按需上传功能
parent
b8ae9808a8
commit
dbe0bd3385
Binary file not shown.
|
|
@ -90,6 +90,9 @@ private:
|
||||||
Buffer bvh_triangle_buffer_; // 添加
|
Buffer bvh_triangle_buffer_; // 添加
|
||||||
bool bvh_built_; // 添加
|
bool bvh_built_; // 添加
|
||||||
|
|
||||||
|
uint materials_hash_;
|
||||||
|
uint lights_hash_;
|
||||||
|
|
||||||
uint frame_count_;
|
uint frame_count_;
|
||||||
bool initialized_;
|
bool initialized_;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,12 @@ public:
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
Buffer();
|
Buffer();
|
||||||
|
|
||||||
|
Buffer(const Buffer&) = delete;
|
||||||
|
Buffer& operator=(const Buffer&) = delete;
|
||||||
|
|
||||||
|
Buffer(Buffer&& other) noexcept;
|
||||||
|
Buffer& operator=(Buffer&& other) noexcept;
|
||||||
|
|
||||||
/// @brief Destructor
|
/// @brief Destructor
|
||||||
~Buffer();
|
~Buffer();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,12 @@ public:
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
Texture();
|
Texture();
|
||||||
|
|
||||||
|
Texture(const Texture&) = delete;
|
||||||
|
Texture& operator=(const Texture&) = delete;
|
||||||
|
|
||||||
|
Texture(Texture&& other) noexcept;
|
||||||
|
Texture& operator=(Texture&& other) noexcept;
|
||||||
|
|
||||||
/// @brief Destructor
|
/// @brief Destructor
|
||||||
~Texture();
|
~Texture();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,18 @@
|
||||||
|
|
||||||
namespace are {
|
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)
|
RayTracer::RayTracer(uint width, uint height, const RayTracerConfig &config)
|
||||||
: width_(width)
|
: width_(width)
|
||||||
, height_(height)
|
, height_(height)
|
||||||
|
|
@ -15,6 +27,8 @@ RayTracer::RayTracer(uint width, uint height, const RayTracerConfig &config)
|
||||||
, light_buffer_(INVALID_HANDLE)
|
, light_buffer_(INVALID_HANDLE)
|
||||||
, bvh_(nullptr)
|
, bvh_(nullptr)
|
||||||
, bvh_built_(false)
|
, bvh_built_(false)
|
||||||
|
, materials_hash_(0u)
|
||||||
|
, lights_hash_(0u)
|
||||||
, frame_count_(0)
|
, frame_count_(0)
|
||||||
, initialized_(false) {
|
, initialized_(false) {
|
||||||
}
|
}
|
||||||
|
|
@ -104,6 +118,7 @@ bool RayTracer::rebuild_bvh(const Scene &scene) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bvh_built_ = true;
|
bvh_built_ = true;
|
||||||
|
reset_accumulation();
|
||||||
Logger::info("BVH built and uploaded successfully");
|
Logger::info("BVH built and uploaded successfully");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -227,7 +242,7 @@ void RayTracer::set_config(const RayTracerConfig &config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayTracer::upload_scene_data_(const Scene &scene) {
|
void RayTracer::upload_scene_data_(const Scene &scene) {
|
||||||
// Upload materials
|
// Upload materials (on change only)
|
||||||
const auto &materials = scene.get_materials();
|
const auto &materials = scene.get_materials();
|
||||||
if (!materials.empty()) {
|
if (!materials.empty()) {
|
||||||
struct MaterialData {
|
struct MaterialData {
|
||||||
|
|
@ -244,7 +259,7 @@ void RayTracer::upload_scene_data_(const Scene &scene) {
|
||||||
material_data.reserve(materials.size());
|
material_data.reserve(materials.size());
|
||||||
|
|
||||||
for (const auto &mat : materials) {
|
for (const auto &mat : materials) {
|
||||||
MaterialData data;
|
MaterialData data {};
|
||||||
data.albedo = mat->get_albedo();
|
data.albedo = mat->get_albedo();
|
||||||
data.metallic = mat->get_metallic();
|
data.metallic = mat->get_metallic();
|
||||||
data.emission = mat->get_emission();
|
data.emission = mat->get_emission();
|
||||||
|
|
@ -254,14 +269,26 @@ void RayTracer::upload_scene_data_(const Scene &scene) {
|
||||||
material_data.push_back(data);
|
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_);
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, material_buffer_);
|
||||||
glBufferData(GL_SHADER_STORAGE_BUFFER,
|
glBufferData(GL_SHADER_STORAGE_BUFFER,
|
||||||
material_data.size() * sizeof(MaterialData),
|
material_data.size() * sizeof(MaterialData),
|
||||||
material_data.data(), GL_DYNAMIC_DRAW);
|
material_data.data(), GL_DYNAMIC_DRAW);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, material_buffer_);
|
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();
|
const auto &lights = scene.get_lights();
|
||||||
if (!lights.empty()) {
|
if (!lights.empty()) {
|
||||||
struct LightData {
|
struct LightData {
|
||||||
|
|
@ -279,7 +306,7 @@ void RayTracer::upload_scene_data_(const Scene &scene) {
|
||||||
light_data.reserve(lights.size());
|
light_data.reserve(lights.size());
|
||||||
|
|
||||||
for (const auto &light : lights) {
|
for (const auto &light : lights) {
|
||||||
LightData data;
|
LightData data {};
|
||||||
data.position = light->get_position();
|
data.position = light->get_position();
|
||||||
data.type = static_cast<int>(light->get_type());
|
data.type = static_cast<int>(light->get_type());
|
||||||
data.direction = light->get_direction();
|
data.direction = light->get_direction();
|
||||||
|
|
@ -290,11 +317,22 @@ void RayTracer::upload_scene_data_(const Scene &scene) {
|
||||||
light_data.push_back(data);
|
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_);
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, light_buffer_);
|
||||||
glBufferData(GL_SHADER_STORAGE_BUFFER,
|
glBufferData(GL_SHADER_STORAGE_BUFFER,
|
||||||
light_data.size() * sizeof(LightData),
|
light_data.size() * sizeof(LightData),
|
||||||
light_data.data(), GL_DYNAMIC_DRAW);
|
light_data.data(), GL_DYNAMIC_DRAW);
|
||||||
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, light_buffer_);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,31 @@ Buffer::Buffer()
|
||||||
, usage_(BufferUsage::STATIC_DRAW) {
|
, 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() {
|
Buffer::~Buffer() {
|
||||||
// Don't auto-release, let user control lifetime
|
release();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::create(BufferType type, size_t size, const void* data, BufferUsage usage) {
|
bool Buffer::create(BufferType type, size_t size, const void* data, BufferUsage usage) {
|
||||||
|
|
|
||||||
|
|
@ -104,8 +104,37 @@ Texture::Texture()
|
||||||
, has_mipmaps_(false) {
|
, 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() {
|
Texture::~Texture() {
|
||||||
// Don't auto-release, let user control lifetime
|
release();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Texture::load_from_file(const std::string& path, bool generate_mipmaps) {
|
bool Texture::load_from_file(const std::string& path, bool generate_mipmaps) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue