diff --git a/TODO-List b/TODO-List new file mode 100644 index 0000000..3ce1c29 --- /dev/null +++ b/TODO-List @@ -0,0 +1,10 @@ +* 1. 修复全局光照导致的采样问题 +* 2. 重构代码,统一化结构、加入ResourceManager +* 2.1. 优化cpu-gpu交互效率 +2.2 修改shader文件结构 +3. 支持更多材质及pbr参数 +4. 添加HDRI支持 +5. 支持glTF 2.0模型加载 +6. 加入ReSITR优化收敛速度 +7. 添加基于PBR及简单机器学习模型的超分辨率采样 +8. 加入粒子系统 diff --git a/examples/cornell_box b/examples/cornell_box index 20a4b8b..bb88f13 100644 Binary files a/examples/cornell_box and b/examples/cornell_box differ diff --git a/examples/normal_map_cornell_box b/examples/normal_map_cornell_box index 2f925a7..a12afc5 100644 Binary files a/examples/normal_map_cornell_box and b/examples/normal_map_cornell_box differ diff --git a/include/basic/types.h b/include/basic/types.h index b145938..17d1c95 100644 --- a/include/basic/types.h +++ b/include/basic/types.h @@ -27,6 +27,7 @@ using TextureHandle = uint; using BufferHandle = uint; using ShaderHandle = uint; using FramebufferHandle = uint; +using VertexArrayHandle = uint; // Invalid handle constant constexpr uint INVALID_HANDLE = 0; diff --git a/include/core/gbuffer.h b/include/core/gbuffer.h index c4aebc5..f0fc691 100644 --- a/include/core/gbuffer.h +++ b/include/core/gbuffer.h @@ -74,15 +74,6 @@ private: TextureHandle depth_texture_; bool initialized_; - - /* - * @brief Create texture for G-Buffer attachment - * @param internal_format OpenGL internal format - * @param format OpenGL format - * @param type OpenGL type - * @return Texture handle - */ - TextureHandle create_texture_(uint internal_format, uint format, uint type); }; } // namespace are diff --git a/include/core/raytracer.h b/include/core/raytracer.h index c08176a..00d9a23 100644 --- a/include/core/raytracer.h +++ b/include/core/raytracer.h @@ -95,7 +95,6 @@ private: std::shared_ptr compute_shader_; TextureHandle accumulation_texture_; - BufferHandle scene_buffer_; BufferHandle material_buffer_; BufferHandle light_buffer_; diff --git a/include/core/renderer.h b/include/core/renderer.h index 2141d76..d32cef2 100644 --- a/include/core/renderer.h +++ b/include/core/renderer.h @@ -74,6 +74,8 @@ private: std::unique_ptr screen_blit_; std::unique_ptr denoiser_; + TextureHandle rt_output_texture_; + bool initialized_; uint frame_count_; }; diff --git a/include/resource/resource_manager.h b/include/resource/resource_manager.h new file mode 100644 index 0000000..a79f2c3 --- /dev/null +++ b/include/resource/resource_manager.h @@ -0,0 +1,128 @@ +#ifndef ARE_INCLUDE_RESOURCE_RESOURCE_MANAGER_H +#define ARE_INCLUDE_RESOURCE_RESOURCE_MANAGER_H + +#include "basic/types.h" +#include "resource/buffer.h" +#include "resource/texture.h" +#include +#include +#include + +namespace are { + +// Texture creation parameters +struct TextureDescription { + uint width = 1; + uint height = 1; + TextureFormat format = TextureFormat::RGBA8; + TextureFilter filter = TextureFilter::LINEAR; + TextureWrap wrap = TextureWrap::CLAMP_TO_EDGE; + bool generate_mipmaps = false; +}; + +// Buffer creation parameters +struct BufferDescription { + BufferType type = BufferType::VERTEX_BUFFER; + BufferUsage usage = BufferUsage::STATIC_DRAW; + size_t size = 0; + const void *data = nullptr; +}; + +// Texture array creation parameters +struct TextureArrayDescription { + uint width = 1; + uint height = 1; + TextureFormat format = TextureFormat::RGBA8; + TextureFilter filter = TextureFilter::LINEAR; + TextureWrap wrap = TextureWrap::REPEAT; + std::vector> textures; +}; + +// Framebuffer creation parameters +struct FramebufferDescription { + uint width = 1; + uint height = 1; + bool create_depth = true; + uint color_attachment_count = 0; +}; + +// GPU resource manager - centralized resource creation and lifecycle +class ResourceManager { +public: + static ResourceManager &instance(); + + // Initialization and release + bool initialize(); + void release(); + + // === Texture Management === + TextureHandle create_texture(const TextureDescription &desc); + TextureHandle create_texture(uint width, uint height, TextureFormat format); + TextureHandle create_texture(const std::string &path); + void destroy_texture(TextureHandle handle); + + // === Buffer Management === + BufferHandle create_buffer(const BufferDescription &desc); + void update_buffer(BufferHandle handle, size_t offset, size_t size, const void *data); + void destroy_buffer(BufferHandle handle); + + // === Framebuffer Management === + FramebufferHandle create_framebuffer(const FramebufferDescription &desc); + TextureHandle get_framebuffer_color_attachment(FramebufferHandle fbo, uint index); + TextureHandle get_framebuffer_depth_attachment(FramebufferHandle fbo); + void destroy_framebuffer(FramebufferHandle fbo); + + // === Texture Array Management === + TextureHandle create_texture_array(const TextureArrayDescription &desc); + void destroy_texture_array(TextureHandle handle); + + // === VAO Management === + VertexArrayHandle create_vertex_array(); + void destroy_vertex_array(VertexArrayHandle vao); + + // === Binding Management === + void bind_buffer(BufferHandle buffer, uint binding_point); + void bind_image_texture(TextureHandle texture, uint binding, bool read, bool write); + void bind_texture_to_unit(TextureHandle texture, uint unit); + + // === Query === + bool is_texture_valid(TextureHandle handle) const; + bool is_buffer_valid(BufferHandle handle) const; + bool is_framebuffer_valid(FramebufferHandle handle) const; + +private: + ResourceManager(); + ~ResourceManager(); + + struct TextureResource { + TextureHandle gl_handle; + uint width; + uint height; + TextureFormat format; + }; + + struct BufferResource { + BufferHandle gl_handle; + BufferType type; + BufferUsage usage; + size_t size; + }; + + struct FramebufferResource { + FramebufferHandle gl_handle; + uint width; + uint height; + std::vector color_attachments; + TextureHandle depth_attachment; + }; + + std::unordered_map textures_; + std::unordered_map buffers_; + std::unordered_map framebuffers_; + + bool initialized_; +}; + +} // namespace are + +#endif // ARE_INCLUDE_RESOURCE_RESOURCE_MANAGER_H diff --git a/include/resource/shader.h b/include/resource/shader.h index de69052..877b443 100644 --- a/include/resource/shader.h +++ b/include/resource/shader.h @@ -53,7 +53,7 @@ public: bool compile_compute(const std::string &compute_source); // Use/activate shader program - void use() const; // 改为const + void use() const; // Release shader resources void release(); @@ -63,63 +63,63 @@ public: * @param name Uniform name * @param value Value */ - void set_bool(const std::string &name, bool value) const; // 新增,const + void set_bool(const std::string &name, bool value) const; /* * @brief Set uniform integer * @param name Uniform name * @param value Value */ - void set_int(const std::string &name, int value) const; // 改为const + void set_int(const std::string &name, int value) const; /* * @brief Set uniform unsigned integer * @param name Uniform name * @param value Value */ - void set_uint(const std::string &name, uint value) const; // 改为const + void set_uint(const std::string &name, uint value) const; /* * @brief Set uniform float * @param name Uniform name * @param value Value */ - void set_float(const std::string &name, float value) const; // 改为const + void set_float(const std::string &name, float value) const; /* * @brief Set uniform vec2 * @param name Uniform name * @param value Value */ - void set_vec2(const std::string &name, const Vec2 &value) const; // 改为const + void set_vec2(const std::string &name, const Vec2 &value) const; /* * @brief Set uniform vec3 * @param name Uniform name * @param value Value */ - void set_vec3(const std::string &name, const Vec3 &value) const; // 改为const + void set_vec3(const std::string &name, const Vec3 &value) const; /* * @brief Set uniform vec4 * @param name Uniform name * @param value Value */ - void set_vec4(const std::string &name, const Vec4 &value) const; // 改为const + void set_vec4(const std::string &name, const Vec4 &value) const; /* * @brief Set uniform mat3 * @param name Uniform name * @param value Value */ - void set_mat3(const std::string &name, const Mat3 &value) const; // 改为const + void set_mat3(const std::string &name, const Mat3 &value) const; /* * @brief Set uniform mat4 * @param name Uniform name * @param value Value */ - void set_mat4(const std::string &name, const Mat4 &value) const; // 改为const + void set_mat4(const std::string &name, const Mat4 &value) const; /* * @brief Get shader program handle @@ -139,14 +139,14 @@ public: private: ShaderHandle handle_; - mutable std::unordered_map uniform_cache_; // 改为mutable + mutable std::unordered_map uniform_cache_; /* * @brief Get uniform location (with caching) * @param name Uniform name * @return Uniform location */ - int get_uniform_location_(const std::string &name) const; // 改为const + int get_uniform_location_(const std::string &name) const; /* * @brief Compile shader stage diff --git a/include/utils/logger.h b/include/utils/logger.h index 07faee1..5557a73 100644 --- a/include/utils/logger.h +++ b/include/utils/logger.h @@ -1,5 +1,5 @@ -#ifndef ARE_INCLUDE_CORE_LOGGER_H -#define ARE_INCLUDE_CORE_LOGGER_H +#ifndef ARE_INCLUDE_UTILS_LOGGER_H +#define ARE_INCLUDE_UTILS_LOGGER_H #include #include @@ -19,18 +19,18 @@ enum class LogLevel { // Thread-safe logging system class Logger { public: - /** + /* * @brief Initialize the logging system * @param min_level Minimum log level to display */ static void init(LogLevel min_level = LogLevel::ARE_LOG_INFO); - /** + /* * @brief Shutdown the logging system */ static void shutdown(); - /** + /* * @brief Log a message with file/function/line information * @param level Log severity level * @param file Source file name @@ -41,7 +41,7 @@ public: static void log(LogLevel level, const char *file, const char *func, int line, const std::string &message); - /** + /* * @brief Set minimum log level * @param level Minimum log level to display */ @@ -62,4 +62,4 @@ private: #define ARE_LOG_ERROR(msg) are::Logger::log(are::LogLevel::ARE_LOG_ERROR, __FILE__, __func__, __LINE__, msg) #define ARE_LOG_CRITICAL(msg) are::Logger::log(are::LogLevel::ARE_LOG_CRITICAL, __FILE__, __func__, __LINE__, msg) -#endif // ARE_INCLUDE_CORE_LOGGER_H +#endif // ARE_INCLUDE_UTILS_LOGGER_H diff --git a/src/core/denoiser.cpp b/src/core/denoiser.cpp index 1dbe047..e0b5824 100644 --- a/src/core/denoiser.cpp +++ b/src/core/denoiser.cpp @@ -1,5 +1,6 @@ #include "core/denoiser.h" #include "basic/constants.h" +#include "resource/resource_manager.h" #include "utils/logger.h" #include @@ -38,7 +39,7 @@ void Denoiser::release() { shader_.reset(); if (output_texture_ != INVALID_HANDLE) { - glDeleteTextures(1, &output_texture_); + ResourceManager::instance().destroy_texture(output_texture_); output_texture_ = INVALID_HANDLE; } @@ -53,7 +54,7 @@ void Denoiser::resize(uint width, uint height) { if (!initialized_) return; if (output_texture_ != INVALID_HANDLE) { - glDeleteTextures(1, &output_texture_); + ResourceManager::instance().destroy_texture(output_texture_); output_texture_ = INVALID_HANDLE; } create_output_texture_(); @@ -81,13 +82,14 @@ TextureHandle Denoiser::denoise(TextureHandle input_texture, int radius) { } void Denoiser::create_output_texture_() { - glGenTextures(1, &output_texture_); - glBindTexture(GL_TEXTURE_2D, output_texture_); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width_, height_, 0, GL_RGBA, GL_FLOAT, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + ResourceManager &rm = ResourceManager::instance(); + TextureDescription desc; + desc.width = width_; + desc.height = height_; + desc.format = TextureFormat::RGBA32F; + desc.filter = TextureFilter::NEAREST; + desc.wrap = TextureWrap::CLAMP_TO_EDGE; + output_texture_ = rm.create_texture(desc); } } // namespace are diff --git a/src/core/gbuffer.cpp b/src/core/gbuffer.cpp index 890652a..8895e39 100644 --- a/src/core/gbuffer.cpp +++ b/src/core/gbuffer.cpp @@ -1,4 +1,5 @@ #include "core/gbuffer.h" +#include "resource/resource_manager.h" #include "utils/logger.h" #include @@ -25,49 +26,58 @@ bool GBuffer::initialize() { return true; } + ResourceManager &rm = ResourceManager::instance(); + + // Create framebuffer glGenFramebuffers(1, &fbo_); glBindFramebuffer(GL_FRAMEBUFFER, fbo_); - textures_[GBUFFER_POSITION] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT); - textures_[GBUFFER_NORMAL] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT); - textures_[GBUFFER_ALBEDO] = create_texture_(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE); + // Create color attachments using ResourceManager + TextureDescription tex_desc; + tex_desc.width = width_; + tex_desc.height = height_; + tex_desc.filter = TextureFilter::NEAREST; + tex_desc.wrap = TextureWrap::CLAMP_TO_EDGE; - // New: material params (metallic, roughness, ior, type) - textures_[GBUFFER_MATERIAL] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT); + tex_desc.format = TextureFormat::RGBA32F; + textures_[GBUFFER_POSITION] = rm.create_texture(tex_desc); - // New: material id (integer) - textures_[GBUFFER_MATERIAL_ID] = create_texture_(GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT); + tex_desc.format = TextureFormat::RGBA32F; + textures_[GBUFFER_NORMAL] = rm.create_texture(tex_desc); - // New: texcoord + tangent (xy = texcoord, zw = tangent) - textures_[GBUFFER_TEXCOORD] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT); + tex_desc.format = TextureFormat::RGBA8; + textures_[GBUFFER_ALBEDO] = rm.create_texture(tex_desc); - // New: tangent (xyz = tangent, w = unused) - textures_[GBUFFER_TANGENT] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT); + tex_desc.format = TextureFormat::RGBA32F; + textures_[GBUFFER_MATERIAL] = rm.create_texture(tex_desc); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_POSITION, - GL_TEXTURE_2D, textures_[GBUFFER_POSITION], 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_NORMAL, - GL_TEXTURE_2D, textures_[GBUFFER_NORMAL], 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_ALBEDO, - GL_TEXTURE_2D, textures_[GBUFFER_ALBEDO], 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_MATERIAL, - GL_TEXTURE_2D, textures_[GBUFFER_MATERIAL], 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_MATERIAL_ID, - GL_TEXTURE_2D, textures_[GBUFFER_MATERIAL_ID], 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_TEXCOORD, - GL_TEXTURE_2D, textures_[GBUFFER_TEXCOORD], 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_TANGENT, - GL_TEXTURE_2D, textures_[GBUFFER_TANGENT], 0); + textures_[GBUFFER_MATERIAL_ID] = rm.create_texture(width_, height_, TextureFormat::R32F); + + tex_desc.format = TextureFormat::RGBA32F; + textures_[GBUFFER_TEXCOORD] = rm.create_texture(tex_desc); + + tex_desc.format = TextureFormat::RGBA32F; + textures_[GBUFFER_TANGENT] = rm.create_texture(tex_desc); + + // Attach color textures to framebuffer + for (int i = 0; i < GBUFFER_COUNT; ++i) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, + GL_TEXTURE_2D, textures_[i], 0); + } + + // Create depth texture using ResourceManager + TextureDescription depth_desc; + depth_desc.width = width_; + depth_desc.height = height_; + depth_desc.format = TextureFormat::DEPTH24_STENCIL8; + depth_desc.filter = TextureFilter::NEAREST; + depth_desc.wrap = TextureWrap::CLAMP_TO_EDGE; + depth_texture_ = rm.create_texture(depth_desc); - glGenTextures(1, &depth_texture_); - glBindTexture(GL_TEXTURE_2D, depth_texture_); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width_, height_, 0, - GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depth_texture_, 0); + // Set draw buffers GLenum draw_buffers[GBUFFER_COUNT] = { GL_COLOR_ATTACHMENT0 + GBUFFER_POSITION, GL_COLOR_ATTACHMENT0 + GBUFFER_NORMAL, @@ -96,6 +106,8 @@ void GBuffer::release() { if (!initialized_) return; + ResourceManager &rm = ResourceManager::instance(); + if (fbo_ != INVALID_HANDLE) { glDeleteFramebuffers(1, &fbo_); fbo_ = INVALID_HANDLE; @@ -103,13 +115,13 @@ void GBuffer::release() { for (int i = 0; i < GBUFFER_COUNT; ++i) { if (textures_[i] != INVALID_HANDLE) { - glDeleteTextures(1, &textures_[i]); + rm.destroy_texture(textures_[i]); textures_[i] = INVALID_HANDLE; } } if (depth_texture_ != INVALID_HANDLE) { - glDeleteTextures(1, &depth_texture_); + rm.destroy_texture(depth_texture_); depth_texture_ = INVALID_HANDLE; } @@ -117,18 +129,6 @@ void GBuffer::release() { ARE_LOG_INFO("GBuffer released"); } -TextureHandle GBuffer::create_texture_(uint internal_format, uint format, uint type) { - TextureHandle texture; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width_, height_, 0, format, type, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - return texture; -} - void GBuffer::render(const Scene &scene, const Shader &shader) { if (!initialized_) { ARE_LOG_ERROR("GBuffer not initialized"); diff --git a/src/core/raytracer.cpp b/src/core/raytracer.cpp index ad1f0fd..6cc4518 100644 --- a/src/core/raytracer.cpp +++ b/src/core/raytracer.cpp @@ -1,5 +1,6 @@ #include "core/raytracer.h" #include "basic/constants.h" +#include "resource/resource_manager.h" #include "utils/logger.h" #include @@ -22,7 +23,6 @@ RayTracer::RayTracer(uint width, uint height, const RayTracerConfig &config) , height_(height) , config_(config) , accumulation_texture_(INVALID_HANDLE) - , scene_buffer_(INVALID_HANDLE) , material_buffer_(INVALID_HANDLE) , light_buffer_(INVALID_HANDLE) , bvh_(nullptr) @@ -43,33 +43,27 @@ bool RayTracer::initialize(const std::shared_ptr &shader) { return true; } + ResourceManager &rm = ResourceManager::instance(); + compute_shader_ = shader; // Create accumulation texture - glGenTextures(1, &accumulation_texture_); - glBindTexture(GL_TEXTURE_2D, accumulation_texture_); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width_, height_, 0, GL_RGBA, GL_FLOAT, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + accumulation_texture_ = rm.create_texture(width_, height_, TextureFormat::RGBA32F); // Create shader storage buffers - glGenBuffers(1, &material_buffer_); - glGenBuffers(1, &light_buffer_); + BufferDescription ssbo_desc; + ssbo_desc.type = BufferType::SHADER_STORAGE_BUFFER; + ssbo_desc.usage = BufferUsage::DYNAMIC_DRAW; + ssbo_desc.size = 1; + ssbo_desc.data = nullptr; + material_buffer_ = rm.create_buffer(ssbo_desc); + light_buffer_ = rm.create_buffer(ssbo_desc); // Initialize texture arrays (empty for now) for (int i = 0; i < 6; i++) { texture_arrays_[i] = 0; texture_array_sizes_[i] = 0; - glGenTextures(1, &texture_arrays_[i]); - glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays_[i]); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT); } - glBindTexture(GL_TEXTURE_2D_ARRAY, 0); // Initialize BVH if enabled if (config_.use_bvh_) { @@ -85,26 +79,28 @@ void RayTracer::release() { if (!initialized_) return; + ResourceManager &rm = ResourceManager::instance(); + if (accumulation_texture_ != INVALID_HANDLE) { - glDeleteTextures(1, &accumulation_texture_); + rm.destroy_texture(accumulation_texture_); accumulation_texture_ = INVALID_HANDLE; } // Release texture arrays for (int i = 0; i < 6; i++) { if (texture_arrays_[i] != 0) { - glDeleteTextures(1, &texture_arrays_[i]); + rm.destroy_texture_array(texture_arrays_[i]); texture_arrays_[i] = 0; } } if (material_buffer_ != INVALID_HANDLE) { - glDeleteBuffers(1, &material_buffer_); + rm.destroy_buffer(material_buffer_); material_buffer_ = INVALID_HANDLE; } if (light_buffer_ != INVALID_HANDLE) { - glDeleteBuffers(1, &light_buffer_); + rm.destroy_buffer(light_buffer_); light_buffer_ = INVALID_HANDLE; } @@ -254,18 +250,14 @@ void RayTracer::resize(uint width, uint height) { height_ = height; if (initialized_) { + ResourceManager &rm = ResourceManager::instance(); + // Recreate accumulation texture if (accumulation_texture_ != INVALID_HANDLE) { - glDeleteTextures(1, &accumulation_texture_); + rm.destroy_texture(accumulation_texture_); } - glGenTextures(1, &accumulation_texture_); - glBindTexture(GL_TEXTURE_2D, accumulation_texture_); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width_, height_, 0, GL_RGBA, GL_FLOAT, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + accumulation_texture_ = rm.create_texture(width_, height_, TextureFormat::RGBA32F); reset_accumulation(); } @@ -439,8 +431,16 @@ void RayTracer::build_texture_arrays_(const Scene &scene) { } } + ResourceManager &rm = ResourceManager::instance(); + // Build arrays for each slot for (int slot = 0; slot < 6; slot++) { + // Destroy previous texture array if exists + if (texture_arrays_[slot] != 0) { + rm.destroy_texture_array(texture_arrays_[slot]); + texture_arrays_[slot] = 0; + } + if (textures[slot].empty()) { texture_array_sizes_[slot] = 0; continue; @@ -448,89 +448,25 @@ void RayTracer::build_texture_arrays_(const Scene &scene) { texture_array_sizes_[slot] = static_cast(textures[slot].size()); - // Get dimensions from first texture (assume all same size) - int width = textures[slot][0]->get_width(); - int height = textures[slot][0]->get_height(); + // Create texture array using ResourceManager + TextureArrayDescription desc; + desc.textures = textures[slot]; + desc.filter = TextureFilter::LINEAR; + desc.wrap = TextureWrap::REPEAT; - // Create texture array - glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays_[slot]); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, width, height, - static_cast(textures[slot].size()), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + texture_arrays_[slot] = rm.create_texture_array(desc); - // Copy each texture to array layer and set indices on materials + // Set texture index on all materials using each texture for (size_t i = 0; i < textures[slot].size(); i++) { - auto &tex = textures[slot][i]; - GLuint tex_handle = tex->get_handle(); - if (tex_handle != 0) { - // Get original texture format - TextureFormat orig_format = tex->get_format(); - int orig_width = tex->get_width(); - int orig_height = tex->get_height(); - - // Get the correct format for reading - GLenum orig_gl_format = GL_RGBA; - int channels = 4; - switch (orig_format) { - case TextureFormat::R8: - orig_gl_format = GL_RED; - channels = 1; - break; - case TextureFormat::RG8: - orig_gl_format = GL_RG; - channels = 2; - break; - case TextureFormat::RGB8: - orig_gl_format = GL_RGB; - channels = 3; - break; - case TextureFormat::RGBA8: - orig_gl_format = GL_RGBA; - channels = 4; - break; - default: - orig_gl_format = GL_RGBA; - channels = 4; - break; - } - - // Read texture data with correct format - std::vector orig_pixels(orig_width * orig_height * channels); - glBindTexture(GL_TEXTURE_2D, tex_handle); - glGetTexImage(GL_TEXTURE_2D, 0, orig_gl_format, GL_UNSIGNED_BYTE, orig_pixels.data()); - glBindTexture(GL_TEXTURE_2D, 0); - - // Convert to RGBA for texture array (always RGBA8) - std::vector pixels(orig_width * orig_height * 4, 255); - for (int y = 0; y < orig_height; y++) { - for (int x = 0; x < orig_width; x++) { - int src_idx = (y * orig_width + x) * channels; - int dst_idx = (y * orig_width + x) * 4; - pixels[dst_idx + 0] = orig_pixels[src_idx + 0]; - pixels[dst_idx + 1] = (channels >= 2) ? orig_pixels[src_idx + 1] : orig_pixels[src_idx + 0]; - pixels[dst_idx + 2] = (channels >= 3) ? orig_pixels[src_idx + 2] : orig_pixels[src_idx + 0]; - pixels[dst_idx + 3] = (channels >= 4) ? orig_pixels[src_idx + 3] : 255; - } - } - - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, static_cast(i), - width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); - - // Set texture index on all materials using this texture - // Index is i+1 because 0 means "no texture" in the shader - uint32_t array_index = static_cast(i) + 1; - for (const auto &mat : materials) { - if (mat->get_texture(static_cast(slot)).get() == tex.get()) { - mat->set_texture_index(static_cast(slot), array_index); - } + // Index is i+1 because 0 means "no texture" in the shader + uint32_t array_index = static_cast(i) + 1; + for (const auto &mat : materials) { + if (mat->get_texture(static_cast(slot)).get() == textures[slot][i].get()) { + mat->set_texture_index(static_cast(slot), array_index); } } } - - // Generate mipmaps - glGenerateMipmap(GL_TEXTURE_2D_ARRAY); } - - glBindTexture(GL_TEXTURE_2D_ARRAY, 0); } } // namespace are diff --git a/src/core/renderer.cpp b/src/core/renderer.cpp index 5ee3de2..022f6db 100644 --- a/src/core/renderer.cpp +++ b/src/core/renderer.cpp @@ -1,4 +1,5 @@ #include "core/renderer.h" +#include "resource/resource_manager.h" #include "utils/logger.h" #include #include @@ -7,6 +8,7 @@ namespace are { Renderer::Renderer(const RendererConfig &config) : config_(config) + , rt_output_texture_(INVALID_HANDLE) , initialized_(false) , frame_count_(0) { } @@ -68,10 +70,14 @@ bool Renderer::initialize() { ARE_LOG_ERROR("Failed to initialize denoiser"); return false; } - - initialized_ = true; - ARE_LOG_INFO("Aurora Rendering Engine initialized successfully"); - return true; + + // Create ray tracing output texture (reused every frame) + ResourceManager &rm = ResourceManager::instance(); + rt_output_texture_ = rm.create_texture(config_.width_, config_.height_, TextureFormat::RGBA32F); + + initialized_ = true; + ARE_LOG_INFO("Aurora Rendering Engine initialized successfully"); + return true; } void Renderer::shutdown() { @@ -80,30 +86,18 @@ void Renderer::shutdown() { ARE_LOG_INFO("Shutting down Aurora Rendering Engine..."); - if (screen_blit_) { - screen_blit_->release(); - screen_blit_.reset(); - } + ResourceManager &rm = ResourceManager::instance(); - if (raytracer_) { - raytracer_->release(); - raytracer_.reset(); + if (rt_output_texture_ != INVALID_HANDLE) { + rm.destroy_texture(rt_output_texture_); + rt_output_texture_ = INVALID_HANDLE; } - if (gbuffer_) { - gbuffer_->release(); - gbuffer_.reset(); - } - - if (shader_manager_) { - shader_manager_->release(); - shader_manager_.reset(); - } - - if (denoiser_) { - denoiser_->release(); - denoiser_.reset(); - } + screen_blit_.reset(); + raytracer_.reset(); + gbuffer_.reset(); + shader_manager_.reset(); + denoiser_.reset(); initialized_ = false; ARE_LOG_INFO("Aurora Rendering Engine shut down"); @@ -136,19 +130,8 @@ RenderStats Renderer::render(const Scene& scene, TextureHandle output_texture) { // Phase 2: Ray tracing pass auto raytrace_start = std::chrono::high_resolution_clock::now(); - // Create output texture if not provided - TextureHandle rt_output = output_texture; - bool created_temp_texture = false; - - if (rt_output == 0) { - glGenTextures(1, &rt_output); - glBindTexture(GL_TEXTURE_2D, rt_output); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, config_.width_, config_.height_, - 0, GL_RGBA, GL_FLOAT, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - created_temp_texture = true; - } + // Use output texture if provided, otherwise use internal texture + TextureHandle rt_output = (output_texture != 0) ? output_texture : rt_output_texture_; raytracer_->trace(scene, *gbuffer_, rt_output); @@ -163,9 +146,8 @@ RenderStats Renderer::render(const Scene& scene, TextureHandle output_texture) { } // Phase 4: Blit to screen if output is default framebuffer - if (created_temp_texture && output_texture == 0) { + if (output_texture == 0) { screen_blit_->blit_fullscreen(final_output); - glDeleteTextures(1, &rt_output); } // Calculate total frame time @@ -194,6 +176,14 @@ void Renderer::resize(uint width, uint height) { config_.height_ = height; if (initialized_) { + ResourceManager &rm = ResourceManager::instance(); + + // Recreate ray tracing output texture + if (rt_output_texture_ != INVALID_HANDLE) { + rm.destroy_texture(rt_output_texture_); + } + rt_output_texture_ = rm.create_texture(width, height, TextureFormat::RGBA32F); + gbuffer_->resize(width, height); raytracer_->resize(width, height); denoiser_->resize(width, height); diff --git a/src/core/screen_blit.cpp b/src/core/screen_blit.cpp index 54ddb2c..17815bd 100644 --- a/src/core/screen_blit.cpp +++ b/src/core/screen_blit.cpp @@ -1,4 +1,5 @@ #include "core/screen_blit.h" +#include "resource/resource_manager.h" #include "utils/logger.h" #include @@ -35,13 +36,15 @@ void ScreenBlit::release() { shader_.reset(); + ResourceManager &rm = ResourceManager::instance(); + if (vao_ != 0) { - glDeleteVertexArrays(1, &vao_); + rm.destroy_vertex_array(vao_); vao_ = 0; } if (vbo_ != 0) { - glDeleteBuffers(1, &vbo_); + rm.destroy_buffer(vbo_); vbo_ = 0; } @@ -96,12 +99,19 @@ void ScreenBlit::create_quad_() { -1.0f, 1.0f, 0.0f, 1.0f }; - glGenVertexArrays(1, &vao_); - glGenBuffers(1, &vbo_); + ResourceManager &rm = ResourceManager::instance(); + vao_ = rm.create_vertex_array(); glBindVertexArray(vao_); + + BufferDescription vbo_desc; + vbo_desc.type = BufferType::VERTEX_BUFFER; + vbo_desc.usage = BufferUsage::STATIC_DRAW; + vbo_desc.size = sizeof(vertices); + vbo_desc.data = vertices; + vbo_ = rm.create_buffer(vbo_desc); + glBindBuffer(GL_ARRAY_BUFFER, vbo_); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // Position attribute glEnableVertexAttribArray(0); diff --git a/src/core/shader_manager.cpp b/src/core/shader_manager.cpp index eb323d1..f22fa51 100644 --- a/src/core/shader_manager.cpp +++ b/src/core/shader_manager.cpp @@ -32,9 +32,6 @@ bool ShaderManager::initialize() { void ShaderManager::release() { if (!initialized_) return; - for (auto& pair : shader_cache_) { - if (pair.second) pair.second->release(); - } shader_cache_.clear(); gbuffer_shader_.reset(); @@ -110,7 +107,7 @@ bool ShaderManager::load_builtin_shaders_() { ARE_LOG_ERROR("Failed to load screen blit shader"); return false; } - shader_cache_["screen_blit"] = denoise_shader_; + shader_cache_["screen_blit"] = screen_blit_shader_; ARE_LOG_INFO("Screen blit shader loaded successfully"); // Load ray tracing shader diff --git a/src/resource/resource_manager.cpp b/src/resource/resource_manager.cpp new file mode 100644 index 0000000..f932bca --- /dev/null +++ b/src/resource/resource_manager.cpp @@ -0,0 +1,667 @@ +#include "resource/resource_manager.h" +#include "utils/logger.h" +#include + +namespace are { + +ResourceManager::ResourceManager() + : initialized_(false) { +} + +ResourceManager::~ResourceManager() { + release(); +} + +ResourceManager &ResourceManager::instance() { + static ResourceManager manager; + return manager; +} + +bool ResourceManager::initialize() { + if (initialized_) { + ARE_LOG_WARN("ResourceManager already initialized"); + return true; + } + + initialized_ = true; + ARE_LOG_INFO("ResourceManager initialized successfully"); + return true; +} + +void ResourceManager::release() { + if (!initialized_) + return; + + ARE_LOG_INFO("Releasing ResourceManager resources..."); + + // Release all textures + for (auto &[handle, resource] : textures_) { + glDeleteTextures(1, &resource.gl_handle); + } + textures_.clear(); + + // Release all buffers + for (auto &[handle, resource] : buffers_) { + glDeleteBuffers(1, &resource.gl_handle); + } + buffers_.clear(); + + // Release all framebuffers and their attachments + for (auto &[handle, resource] : framebuffers_) { + // Attachments are owned by textures_ map, already deleted + glDeleteFramebuffers(1, &resource.gl_handle); + } + framebuffers_.clear(); + + initialized_ = false; + ARE_LOG_INFO("ResourceManager released"); +} + +// === Texture Management === + +TextureHandle ResourceManager::create_texture(const TextureDescription &desc) { + TextureHandle handle; + glGenTextures(1, &handle); + glBindTexture(GL_TEXTURE_2D, handle); + + // Convert format to GL types + GLenum gl_internal_format = GL_RGBA8; + GLenum gl_format = GL_RGBA; + GLenum gl_type = GL_UNSIGNED_BYTE; + + switch (desc.format) { + case TextureFormat::R8: + gl_internal_format = GL_R8; + gl_format = GL_RED; + gl_type = GL_UNSIGNED_BYTE; + break; + case TextureFormat::RG8: + gl_internal_format = GL_RG8; + gl_format = GL_RG; + gl_type = GL_UNSIGNED_BYTE; + break; + case TextureFormat::RGB8: + gl_internal_format = GL_RGB8; + gl_format = GL_RGB; + gl_type = GL_UNSIGNED_BYTE; + break; + case TextureFormat::RGBA8: + gl_internal_format = GL_RGBA8; + gl_format = GL_RGBA; + gl_type = GL_UNSIGNED_BYTE; + break; + case TextureFormat::RGBA32F: + gl_internal_format = GL_RGBA32F; + gl_format = GL_RGBA; + gl_type = GL_FLOAT; + break; + case TextureFormat::R32F: + gl_internal_format = GL_R32F; + gl_format = GL_RED; + gl_type = GL_FLOAT; + break; + case TextureFormat::RG32F: + gl_internal_format = GL_RG32F; + gl_format = GL_RG; + gl_type = GL_FLOAT; + break; + case TextureFormat::DEPTH24_STENCIL8: + gl_internal_format = GL_DEPTH24_STENCIL8; + gl_format = GL_DEPTH_STENCIL; + gl_type = GL_UNSIGNED_INT_24_8; + break; + default: + gl_internal_format = GL_RGBA8; + gl_format = GL_RGBA; + gl_type = GL_UNSIGNED_BYTE; + break; + } + + glTexImage2D(GL_TEXTURE_2D, 0, gl_internal_format, desc.width, desc.height, + 0, gl_format, gl_type, nullptr); + + // Set filter + GLenum gl_min_filter = GL_LINEAR; + GLenum gl_mag_filter = GL_LINEAR; + + switch (desc.filter) { + case TextureFilter::NEAREST: + gl_min_filter = GL_NEAREST; + gl_mag_filter = GL_NEAREST; + break; + case TextureFilter::LINEAR: + gl_min_filter = GL_LINEAR; + gl_mag_filter = GL_LINEAR; + break; + case TextureFilter::NEAREST_MIPMAP_NEAREST: + gl_min_filter = GL_NEAREST_MIPMAP_NEAREST; + gl_mag_filter = GL_NEAREST; + break; + case TextureFilter::LINEAR_MIPMAP_NEAREST: + gl_min_filter = GL_LINEAR_MIPMAP_NEAREST; + gl_mag_filter = GL_LINEAR; + break; + case TextureFilter::NEAREST_MIPMAP_LINEAR: + gl_min_filter = GL_NEAREST_MIPMAP_LINEAR; + gl_mag_filter = GL_NEAREST; + break; + case TextureFilter::LINEAR_MIPMAP_LINEAR: + gl_min_filter = GL_LINEAR_MIPMAP_LINEAR; + gl_mag_filter = GL_LINEAR; + break; + default: + gl_min_filter = GL_LINEAR; + gl_mag_filter = GL_LINEAR; + break; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_min_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_mag_filter); + + // Set wrap + GLenum gl_wrap = GL_REPEAT; + switch (desc.wrap) { + case TextureWrap::REPEAT: + gl_wrap = GL_REPEAT; + break; + case TextureWrap::MIRRORED_REPEAT: + gl_wrap = GL_MIRRORED_REPEAT; + break; + case TextureWrap::CLAMP_TO_EDGE: + gl_wrap = GL_CLAMP_TO_EDGE; + break; + case TextureWrap::CLAMP_TO_BORDER: + gl_wrap = GL_CLAMP_TO_BORDER; + break; + default: + gl_wrap = GL_REPEAT; + break; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl_wrap); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl_wrap); + + // Generate mipmaps if requested + if (desc.generate_mipmaps) { + glGenerateMipmap(GL_TEXTURE_2D); + } + + glBindTexture(GL_TEXTURE_2D, 0); + + TextureResource resource; + resource.gl_handle = handle; + resource.width = desc.width; + resource.height = desc.height; + resource.format = desc.format; + textures_[handle] = resource; + + ARE_LOG_DEBUG("Texture created: " + std::to_string(handle)); + return handle; +} + +TextureHandle ResourceManager::create_texture(uint width, uint height, TextureFormat format) { + TextureDescription desc; + desc.width = width; + desc.height = height; + desc.format = format; + return create_texture(desc); +} + +TextureHandle ResourceManager::create_texture(const std::string &path) { + // Use Texture class for file loading (stb_image) + auto tex = std::make_shared(); + if (!tex->load_from_file(path, true)) { + ARE_LOG_ERROR("Failed to load texture: " + path); + return INVALID_HANDLE; + } + + TextureHandle handle = tex->get_handle(); + + // Register in manager (but don't own - Texture class manages lifetime) + TextureResource resource; + resource.gl_handle = handle; + resource.width = tex->get_width(); + resource.height = tex->get_height(); + resource.format = tex->get_format(); + textures_[handle] = resource; + + return handle; +} + +void ResourceManager::destroy_texture(TextureHandle handle) { + auto it = textures_.find(handle); + if (it == textures_.end()) { + ARE_LOG_WARN("Attempting to destroy unknown texture: " + std::to_string(handle)); + return; + } + + glDeleteTextures(1, &it->second.gl_handle); + textures_.erase(it); + ARE_LOG_DEBUG("Texture destroyed: " + std::to_string(handle)); +} + +// === Buffer Management === + +BufferHandle ResourceManager::create_buffer(const BufferDescription &desc) { + BufferHandle handle; + glGenBuffers(1, &handle); + + GLenum gl_type = GL_ARRAY_BUFFER; + switch (desc.type) { + case BufferType::VERTEX_BUFFER: + gl_type = GL_ARRAY_BUFFER; + break; + case BufferType::INDEX_BUFFER: + gl_type = GL_ELEMENT_ARRAY_BUFFER; + break; + case BufferType::UNIFORM_BUFFER: + gl_type = GL_UNIFORM_BUFFER; + break; + case BufferType::SHADER_STORAGE_BUFFER: + gl_type = GL_SHADER_STORAGE_BUFFER; + break; + default: + gl_type = GL_ARRAY_BUFFER; + break; + } + + GLenum gl_usage = GL_STATIC_DRAW; + switch (desc.usage) { + case BufferUsage::STATIC_DRAW: + gl_usage = GL_STATIC_DRAW; + break; + case BufferUsage::DYNAMIC_DRAW: + gl_usage = GL_DYNAMIC_DRAW; + break; + case BufferUsage::STREAM_DRAW: + gl_usage = GL_STREAM_DRAW; + break; + default: + gl_usage = GL_STATIC_DRAW; + break; + } + + glBindBuffer(gl_type, handle); + glBufferData(gl_type, desc.size, desc.data, gl_usage); + glBindBuffer(gl_type, 0); + + BufferResource resource; + resource.gl_handle = handle; + resource.type = desc.type; + resource.usage = desc.usage; + resource.size = desc.size; + buffers_[handle] = resource; + + ARE_LOG_DEBUG("Buffer created: " + std::to_string(handle) + " size: " + std::to_string(desc.size)); + return handle; +} + +void ResourceManager::update_buffer(BufferHandle handle, size_t offset, size_t size, const void *data) { + auto it = buffers_.find(handle); + if (it == buffers_.end()) { + ARE_LOG_ERROR("Attempting to update unknown buffer: " + std::to_string(handle)); + return; + } + + GLenum gl_type = GL_ARRAY_BUFFER; + switch (it->second.type) { + case BufferType::VERTEX_BUFFER: + gl_type = GL_ARRAY_BUFFER; + break; + case BufferType::INDEX_BUFFER: + gl_type = GL_ELEMENT_ARRAY_BUFFER; + break; + case BufferType::UNIFORM_BUFFER: + gl_type = GL_UNIFORM_BUFFER; + break; + case BufferType::SHADER_STORAGE_BUFFER: + gl_type = GL_SHADER_STORAGE_BUFFER; + break; + default: + gl_type = GL_ARRAY_BUFFER; + break; + } + + glBindBuffer(gl_type, handle); + glBufferSubData(gl_type, offset, size, data); + glBindBuffer(gl_type, 0); +} + +void ResourceManager::destroy_buffer(BufferHandle handle) { + auto it = buffers_.find(handle); + if (it == buffers_.end()) { + ARE_LOG_WARN("Attempting to destroy unknown buffer: " + std::to_string(handle)); + return; + } + + glDeleteBuffers(1, &it->second.gl_handle); + buffers_.erase(it); + ARE_LOG_DEBUG("Buffer destroyed: " + std::to_string(handle)); +} + +// === Framebuffer Management === + +FramebufferHandle ResourceManager::create_framebuffer(const FramebufferDescription &desc) { + FramebufferHandle fbo; + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + FramebufferResource resource; + resource.gl_handle = fbo; + resource.width = desc.width; + resource.height = desc.height; + + // Create color attachments + for (uint i = 0; i < desc.color_attachment_count; ++i) { + TextureDescription tex_desc; + tex_desc.width = desc.width; + tex_desc.height = desc.height; + tex_desc.format = TextureFormat::RGBA32F; + tex_desc.filter = TextureFilter::NEAREST; + tex_desc.wrap = TextureWrap::CLAMP_TO_EDGE; + + TextureHandle color_tex = create_texture(tex_desc); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, + GL_TEXTURE_2D, color_tex, 0); + + resource.color_attachments.push_back(color_tex); + } + + // Create depth attachment if requested + if (desc.create_depth) { + TextureDescription depth_desc; + depth_desc.width = desc.width; + depth_desc.height = desc.height; + depth_desc.format = TextureFormat::DEPTH24_STENCIL8; + depth_desc.filter = TextureFilter::NEAREST; + depth_desc.wrap = TextureWrap::CLAMP_TO_EDGE; + + TextureHandle depth_tex = create_texture(depth_desc); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + GL_TEXTURE_2D, depth_tex, 0); + + resource.depth_attachment = depth_tex; + } + + // Set draw buffers if color attachments exist + if (desc.color_attachment_count > 0) { + std::vector draw_buffers(desc.color_attachment_count); + for (uint i = 0; i < desc.color_attachment_count; ++i) { + draw_buffers[i] = GL_COLOR_ATTACHMENT0 + i; + } + glDrawBuffers(desc.color_attachment_count, draw_buffers.data()); + } + + // Check completeness + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + ARE_LOG_ERROR("Framebuffer is not complete!"); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + destroy_framebuffer(fbo); + return INVALID_HANDLE; + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + framebuffers_[fbo] = resource; + + ARE_LOG_DEBUG("Framebuffer created: " + std::to_string(fbo)); + return fbo; +} + +TextureHandle ResourceManager::get_framebuffer_color_attachment(FramebufferHandle fbo, uint index) { + auto it = framebuffers_.find(fbo); + if (it == framebuffers_.end()) { + ARE_LOG_ERROR("Invalid framebuffer handle: " + std::to_string(fbo)); + return INVALID_HANDLE; + } + + if (index >= it->second.color_attachments.size()) { + ARE_LOG_ERROR("Color attachment index out of range: " + std::to_string(index)); + return INVALID_HANDLE; + } + + return it->second.color_attachments[index]; +} + +TextureHandle ResourceManager::get_framebuffer_depth_attachment(FramebufferHandle fbo) { + auto it = framebuffers_.find(fbo); + if (it == framebuffers_.end()) { + ARE_LOG_ERROR("Invalid framebuffer handle: " + std::to_string(fbo)); + return INVALID_HANDLE; + } + + return it->second.depth_attachment; +} + +void ResourceManager::destroy_framebuffer(FramebufferHandle fbo) { + auto it = framebuffers_.find(fbo); + if (it == framebuffers_.end()) { + ARE_LOG_WARN("Attempting to destroy unknown framebuffer: " + std::to_string(fbo)); + return; + } + + // Destroy color attachments + for (auto &color_tex : it->second.color_attachments) { + destroy_texture(color_tex); + } + + // Destroy depth attachment + if (it->second.depth_attachment != INVALID_HANDLE) { + destroy_texture(it->second.depth_attachment); + } + + glDeleteFramebuffers(1, &it->second.gl_handle); + framebuffers_.erase(it); + ARE_LOG_DEBUG("Framebuffer destroyed: " + std::to_string(fbo)); +} + +// === Texture Array Management === + +TextureHandle ResourceManager::create_texture_array(const TextureArrayDescription &desc) { + if (desc.textures.empty()) { + ARE_LOG_WARN("Creating empty texture array"); + return INVALID_HANDLE; + } + + // Get dimensions from first texture + int tex_width = desc.textures[0]->get_width(); + int tex_height = desc.textures[0]->get_height(); + + // Create texture array + GLuint tex_array; + glGenTextures(1, &tex_array); + glBindTexture(GL_TEXTURE_2D_ARRAY, tex_array); + + // Allocate storage + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, tex_width, tex_height, + static_cast(desc.textures.size()), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + + // Copy each texture to array layer + for (size_t i = 0; i < desc.textures.size(); ++i) { + auto &tex = desc.textures[i]; + GLuint tex_handle = tex->get_handle(); + + if (tex_handle == 0) + continue; + + TextureFormat orig_format = tex->get_format(); + int orig_width = tex->get_width(); + int orig_height = tex->get_height(); + + // Get format for reading + GLenum orig_gl_format = GL_RGBA; + int channels = 4; + switch (orig_format) { + case TextureFormat::R8: + orig_gl_format = GL_RED; + channels = 1; + break; + case TextureFormat::RG8: + orig_gl_format = GL_RG; + channels = 2; + break; + case TextureFormat::RGB8: + orig_gl_format = GL_RGB; + channels = 3; + break; + case TextureFormat::RGBA8: + orig_gl_format = GL_RGBA; + channels = 4; + break; + default: + orig_gl_format = GL_RGBA; + channels = 4; + break; + } + + // Read texture data + std::vector orig_pixels(orig_width * orig_height * channels); + glBindTexture(GL_TEXTURE_2D, tex_handle); + glGetTexImage(GL_TEXTURE_2D, 0, orig_gl_format, GL_UNSIGNED_BYTE, orig_pixels.data()); + glBindTexture(GL_TEXTURE_2D, 0); + + // Convert to RGBA + std::vector pixels(orig_width * orig_height * 4, 255); + for (int y = 0; y < orig_height; ++y) { + for (int x = 0; x < orig_width; ++x) { + int src_idx = (y * orig_width + x) * channels; + int dst_idx = (y * orig_width + x) * 4; + pixels[dst_idx + 0] = orig_pixels[src_idx + 0]; + pixels[dst_idx + 1] = (channels >= 2) ? orig_pixels[src_idx + 1] : orig_pixels[src_idx + 0]; + pixels[dst_idx + 2] = (channels >= 3) ? orig_pixels[src_idx + 2] : orig_pixels[src_idx + 0]; + pixels[dst_idx + 3] = (channels >= 4) ? orig_pixels[src_idx + 3] : 255; + } + } + + // Upload to array layer + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, static_cast(i), + tex_width, tex_height, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); + } + + // Set filter + GLenum gl_min_filter = GL_LINEAR; + GLenum gl_mag_filter = GL_LINEAR; + switch (desc.filter) { + case TextureFilter::NEAREST: + gl_min_filter = GL_NEAREST; + gl_mag_filter = GL_NEAREST; + break; + case TextureFilter::LINEAR: + gl_min_filter = GL_LINEAR; + gl_mag_filter = GL_LINEAR; + break; + default: + gl_min_filter = GL_LINEAR; + gl_mag_filter = GL_LINEAR; + break; + } + + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, gl_min_filter); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, gl_mag_filter); + + // Set wrap + GLenum gl_wrap = GL_REPEAT; + switch (desc.wrap) { + case TextureWrap::REPEAT: + gl_wrap = GL_REPEAT; + break; + case TextureWrap::CLAMP_TO_EDGE: + gl_wrap = GL_CLAMP_TO_EDGE; + break; + default: + gl_wrap = GL_REPEAT; + break; + } + + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, gl_wrap); + glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, gl_wrap); + + glGenerateMipmap(GL_TEXTURE_2D_ARRAY); + + glBindTexture(GL_TEXTURE_2D_ARRAY, 0); + + TextureResource resource; + resource.gl_handle = tex_array; + resource.width = tex_width; + resource.height = tex_height; + resource.format = TextureFormat::RGBA8; + textures_[tex_array] = resource; + + ARE_LOG_DEBUG("Texture array created: " + std::to_string(tex_array) + " layers: " + std::to_string(desc.textures.size())); + return tex_array; +} + +void ResourceManager::destroy_texture_array(TextureHandle handle) { + destroy_texture(handle); +} + +// === VAO Management === + +VertexArrayHandle ResourceManager::create_vertex_array() { + VertexArrayHandle vao; + glGenVertexArrays(1, &vao); + ARE_LOG_DEBUG("Vertex array created: " + std::to_string(vao)); + return vao; +} + +void ResourceManager::destroy_vertex_array(VertexArrayHandle vao) { + glDeleteVertexArrays(1, &vao); + ARE_LOG_DEBUG("Vertex array destroyed: " + std::to_string(vao)); +} + +// === Binding Management === + +void ResourceManager::bind_buffer(BufferHandle buffer, uint binding_point) { + auto it = buffers_.find(buffer); + if (it == buffers_.end()) { + ARE_LOG_ERROR("Attempting to bind unknown buffer: " + std::to_string(buffer)); + return; + } + + GLenum gl_type = GL_ARRAY_BUFFER; + switch (it->second.type) { + case BufferType::UNIFORM_BUFFER: + gl_type = GL_UNIFORM_BUFFER; + break; + case BufferType::SHADER_STORAGE_BUFFER: + gl_type = GL_SHADER_STORAGE_BUFFER; + break; + default: + ARE_LOG_ERROR("Buffer type not supported for bind_buffer"); + return; + } + + glBindBufferBase(gl_type, binding_point, buffer); +} + +void ResourceManager::bind_image_texture(TextureHandle texture, uint binding, bool read, bool write) { + GLenum access = GL_READ_ONLY; + if (read && write) { + access = GL_READ_WRITE; + } else if (write) { + access = GL_WRITE_ONLY; + } + + glBindImageTexture(binding, texture, 0, GL_FALSE, 0, access, GL_RGBA32F); +} + +void ResourceManager::bind_texture_to_unit(TextureHandle texture, uint unit) { + glActiveTexture(GL_TEXTURE0 + unit); + glBindTexture(GL_TEXTURE_2D, texture); +} + +// === Query === + +bool ResourceManager::is_texture_valid(TextureHandle handle) const { + return textures_.find(handle) != textures_.end(); +} + +bool ResourceManager::is_buffer_valid(BufferHandle handle) const { + return buffers_.find(handle) != buffers_.end(); +} + +bool ResourceManager::is_framebuffer_valid(FramebufferHandle handle) const { + return framebuffers_.find(handle) != framebuffers_.end(); +} + +} // namespace are diff --git a/src/resource/shader.cpp b/src/resource/shader.cpp index 2e40a3c..6928c54 100644 --- a/src/resource/shader.cpp +++ b/src/resource/shader.cpp @@ -1,6 +1,6 @@ #include "resource/shader.h" #include "utils/logger.h" -#include "basic/math.h" // 修改为math.h +#include "basic/math.h" #include #include #include @@ -19,7 +19,7 @@ Shader::Shader(Shader&& other) noexcept } Shader::~Shader() { - // Don't auto-release, let user control lifetime + release(); } Shader& Shader::operator=(Shader&& other) noexcept { @@ -88,7 +88,7 @@ bool Shader::compile_compute(const std::string& compute_source) { return success; } -void Shader::use() const { // 改为const +void Shader::use() const { if (handle_ != INVALID_HANDLE) { glUseProgram(handle_); } @@ -102,50 +102,50 @@ void Shader::release() { uniform_cache_.clear(); } -void Shader::set_bool(const std::string& name, bool value) const { // 新增 +void Shader::set_bool(const std::string& name, bool value) const { glUniform1i(get_uniform_location_(name), static_cast(value)); } -void Shader::set_int(const std::string& name, int value) const { // 改为const +void Shader::set_int(const std::string& name, int value) const { glUniform1i(get_uniform_location_(name), value); } -void Shader::set_uint(const std::string& name, uint value) const { // 改为const +void Shader::set_uint(const std::string& name, uint value) const { glUniform1ui(get_uniform_location_(name), value); } -void Shader::set_float(const std::string& name, float value) const { // 改为const +void Shader::set_float(const std::string& name, float value) const { glUniform1f(get_uniform_location_(name), value); } -void Shader::set_vec2(const std::string& name, const Vec2& value) const { // 改为const +void Shader::set_vec2(const std::string& name, const Vec2& value) const { glUniform2fv(get_uniform_location_(name), 1, &value[0]); } -void Shader::set_vec3(const std::string& name, const Vec3& value) const { // 改为const +void Shader::set_vec3(const std::string& name, const Vec3& value) const { glUniform3fv(get_uniform_location_(name), 1, &value[0]); } -void Shader::set_vec4(const std::string& name, const Vec4& value) const { // 改为const +void Shader::set_vec4(const std::string& name, const Vec4& value) const { glUniform4fv(get_uniform_location_(name), 1, &value[0]); } -void Shader::set_mat3(const std::string& name, const Mat3& value) const { // 改为const +void Shader::set_mat3(const std::string& name, const Mat3& value) const { glUniformMatrix3fv(get_uniform_location_(name), 1, GL_FALSE, &value[0][0]); } -void Shader::set_mat4(const std::string& name, const Mat4& value) const { // 改为const +void Shader::set_mat4(const std::string& name, const Mat4& value) const { glUniformMatrix4fv(get_uniform_location_(name), 1, GL_FALSE, MathUtils::value_ptr(value)); } -int Shader::get_uniform_location_(const std::string& name) const { // 改为const +int Shader::get_uniform_location_(const std::string& name) const { auto it = uniform_cache_.find(name); if (it != uniform_cache_.end()) { return it->second; } int location = glGetUniformLocation(handle_, name.c_str()); - uniform_cache_[name] = location; // mutable允许修改 + uniform_cache_[name] = location; if (location == -1) { ARE_LOG_WARN("Uniform '" + name + "' not found in shader"); diff --git a/src/scene/mesh.cpp b/src/scene/mesh.cpp index 032fe19..fd16aa4 100644 --- a/src/scene/mesh.cpp +++ b/src/scene/mesh.cpp @@ -1,4 +1,5 @@ #include "scene/mesh.h" +#include "resource/resource_manager.h" #include "utils/logger.h" #include #include @@ -52,21 +53,29 @@ bool Mesh::upload_to_gpu() { return false; } + ResourceManager &rm = ResourceManager::instance(); + // Generate VAO - glGenVertexArrays(1, &vao_); + vao_ = rm.create_vertex_array(); glBindVertexArray(vao_); // Generate and upload VBO - glGenBuffers(1, &vbo_); + BufferDescription vbo_desc; + vbo_desc.type = BufferType::VERTEX_BUFFER; + vbo_desc.usage = BufferUsage::STATIC_DRAW; + vbo_desc.size = vertices_.size() * sizeof(Vertex); + vbo_desc.data = vertices_.data(); + vbo_ = rm.create_buffer(vbo_desc); glBindBuffer(GL_ARRAY_BUFFER, vbo_); - glBufferData(GL_ARRAY_BUFFER, vertices_.size() * sizeof(Vertex), - vertices_.data(), GL_STATIC_DRAW); // Generate and upload EBO - glGenBuffers(1, &ebo_); + BufferDescription ebo_desc; + ebo_desc.type = BufferType::INDEX_BUFFER; + ebo_desc.usage = BufferUsage::STATIC_DRAW; + ebo_desc.size = indices_.size() * sizeof(uint); + ebo_desc.data = indices_.data(); + ebo_ = rm.create_buffer(ebo_desc); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_.size() * sizeof(uint), - indices_.data(), GL_STATIC_DRAW); // Set vertex attributes // Location 0: Position @@ -100,18 +109,20 @@ void Mesh::release_gpu_resources() { if (!uploaded_) return; + ResourceManager &rm = ResourceManager::instance(); + if (vao_ != 0) { - glDeleteVertexArrays(1, &vao_); + rm.destroy_vertex_array(vao_); vao_ = 0; } if (vbo_ != 0) { - glDeleteBuffers(1, &vbo_); + rm.destroy_buffer(vbo_); vbo_ = 0; } if (ebo_ != 0) { - glDeleteBuffers(1, &ebo_); + rm.destroy_buffer(ebo_); ebo_ = 0; }