feat: 添加ResourceManager统一管理资源

- 注释规范化
- 修复shader_cache_引用错误
- 简化shader_manager.cpp release函数
- 添加ResourceManager用于资源管理
master
ternaryop8479 2026-03-28 09:00:21 +08:00
parent 917281d8f4
commit 687a79b526
19 changed files with 1005 additions and 261 deletions

10
TODO-List Normal file
View File

@ -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. 加入粒子系统

Binary file not shown.

Binary file not shown.

View File

@ -27,6 +27,7 @@ using TextureHandle = uint;
using BufferHandle = uint; using BufferHandle = uint;
using ShaderHandle = uint; using ShaderHandle = uint;
using FramebufferHandle = uint; using FramebufferHandle = uint;
using VertexArrayHandle = uint;
// Invalid handle constant // Invalid handle constant
constexpr uint INVALID_HANDLE = 0; constexpr uint INVALID_HANDLE = 0;

View File

@ -74,15 +74,6 @@ private:
TextureHandle depth_texture_; TextureHandle depth_texture_;
bool initialized_; 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 } // namespace are

View File

@ -95,7 +95,6 @@ private:
std::shared_ptr<Shader> compute_shader_; std::shared_ptr<Shader> compute_shader_;
TextureHandle accumulation_texture_; TextureHandle accumulation_texture_;
BufferHandle scene_buffer_;
BufferHandle material_buffer_; BufferHandle material_buffer_;
BufferHandle light_buffer_; BufferHandle light_buffer_;

View File

@ -74,6 +74,8 @@ private:
std::unique_ptr<ScreenBlit> screen_blit_; std::unique_ptr<ScreenBlit> screen_blit_;
std::unique_ptr<Denoiser> denoiser_; std::unique_ptr<Denoiser> denoiser_;
TextureHandle rt_output_texture_;
bool initialized_; bool initialized_;
uint frame_count_; uint frame_count_;
}; };

View File

@ -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 <memory>
#include <unordered_map>
#include <vector>
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<std::shared_ptr<Texture>> 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<TextureHandle> color_attachments;
TextureHandle depth_attachment;
};
std::unordered_map<TextureHandle, TextureResource> textures_;
std::unordered_map<BufferHandle, BufferResource> buffers_;
std::unordered_map<FramebufferHandle, FramebufferResource> framebuffers_;
bool initialized_;
};
} // namespace are
#endif // ARE_INCLUDE_RESOURCE_RESOURCE_MANAGER_H

View File

@ -53,7 +53,7 @@ public:
bool compile_compute(const std::string &compute_source); bool compile_compute(const std::string &compute_source);
// Use/activate shader program // Use/activate shader program
void use() const; // 改为const void use() const;
// Release shader resources // Release shader resources
void release(); void release();
@ -63,63 +63,63 @@ public:
* @param name Uniform name * @param name Uniform name
* @param value Value * @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 * @brief Set uniform integer
* @param name Uniform name * @param name Uniform name
* @param value Value * @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 * @brief Set uniform unsigned integer
* @param name Uniform name * @param name Uniform name
* @param value Value * @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 * @brief Set uniform float
* @param name Uniform name * @param name Uniform name
* @param value Value * @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 * @brief Set uniform vec2
* @param name Uniform name * @param name Uniform name
* @param value Value * @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 * @brief Set uniform vec3
* @param name Uniform name * @param name Uniform name
* @param value Value * @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 * @brief Set uniform vec4
* @param name Uniform name * @param name Uniform name
* @param value Value * @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 * @brief Set uniform mat3
* @param name Uniform name * @param name Uniform name
* @param value Value * @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 * @brief Set uniform mat4
* @param name Uniform name * @param name Uniform name
* @param value Value * @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 * @brief Get shader program handle
@ -139,14 +139,14 @@ public:
private: private:
ShaderHandle handle_; ShaderHandle handle_;
mutable std::unordered_map<std::string, int> uniform_cache_; // 改为mutable mutable std::unordered_map<std::string, int> uniform_cache_;
/* /*
* @brief Get uniform location (with caching) * @brief Get uniform location (with caching)
* @param name Uniform name * @param name Uniform name
* @return Uniform location * @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 * @brief Compile shader stage

View File

@ -1,5 +1,5 @@
#ifndef ARE_INCLUDE_CORE_LOGGER_H #ifndef ARE_INCLUDE_UTILS_LOGGER_H
#define ARE_INCLUDE_CORE_LOGGER_H #define ARE_INCLUDE_UTILS_LOGGER_H
#include <memory> #include <memory>
#include <string> #include <string>
@ -19,18 +19,18 @@ enum class LogLevel {
// Thread-safe logging system // Thread-safe logging system
class Logger { class Logger {
public: public:
/** /*
* @brief Initialize the logging system * @brief Initialize the logging system
* @param min_level Minimum log level to display * @param min_level Minimum log level to display
*/ */
static void init(LogLevel min_level = LogLevel::ARE_LOG_INFO); static void init(LogLevel min_level = LogLevel::ARE_LOG_INFO);
/** /*
* @brief Shutdown the logging system * @brief Shutdown the logging system
*/ */
static void shutdown(); static void shutdown();
/** /*
* @brief Log a message with file/function/line information * @brief Log a message with file/function/line information
* @param level Log severity level * @param level Log severity level
* @param file Source file name * @param file Source file name
@ -41,7 +41,7 @@ public:
static void log(LogLevel level, const char *file, const char *func, static void log(LogLevel level, const char *file, const char *func,
int line, const std::string &message); int line, const std::string &message);
/** /*
* @brief Set minimum log level * @brief Set minimum log level
* @param level Minimum log level to display * @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_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) #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

View File

@ -1,5 +1,6 @@
#include "core/denoiser.h" #include "core/denoiser.h"
#include "basic/constants.h" #include "basic/constants.h"
#include "resource/resource_manager.h"
#include "utils/logger.h" #include "utils/logger.h"
#include <glad/glad.h> #include <glad/glad.h>
@ -38,7 +39,7 @@ void Denoiser::release() {
shader_.reset(); shader_.reset();
if (output_texture_ != INVALID_HANDLE) { if (output_texture_ != INVALID_HANDLE) {
glDeleteTextures(1, &output_texture_); ResourceManager::instance().destroy_texture(output_texture_);
output_texture_ = INVALID_HANDLE; output_texture_ = INVALID_HANDLE;
} }
@ -53,7 +54,7 @@ void Denoiser::resize(uint width, uint height) {
if (!initialized_) return; if (!initialized_) return;
if (output_texture_ != INVALID_HANDLE) { if (output_texture_ != INVALID_HANDLE) {
glDeleteTextures(1, &output_texture_); ResourceManager::instance().destroy_texture(output_texture_);
output_texture_ = INVALID_HANDLE; output_texture_ = INVALID_HANDLE;
} }
create_output_texture_(); create_output_texture_();
@ -81,13 +82,14 @@ TextureHandle Denoiser::denoise(TextureHandle input_texture, int radius) {
} }
void Denoiser::create_output_texture_() { void Denoiser::create_output_texture_() {
glGenTextures(1, &output_texture_); ResourceManager &rm = ResourceManager::instance();
glBindTexture(GL_TEXTURE_2D, output_texture_); TextureDescription desc;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width_, height_, 0, GL_RGBA, GL_FLOAT, nullptr); desc.width = width_;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); desc.height = height_;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); desc.format = TextureFormat::RGBA32F;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); desc.filter = TextureFilter::NEAREST;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); desc.wrap = TextureWrap::CLAMP_TO_EDGE;
output_texture_ = rm.create_texture(desc);
} }
} // namespace are } // namespace are

View File

@ -1,4 +1,5 @@
#include "core/gbuffer.h" #include "core/gbuffer.h"
#include "resource/resource_manager.h"
#include "utils/logger.h" #include "utils/logger.h"
#include <glad/glad.h> #include <glad/glad.h>
@ -25,49 +26,58 @@ bool GBuffer::initialize() {
return true; return true;
} }
ResourceManager &rm = ResourceManager::instance();
// Create framebuffer
glGenFramebuffers(1, &fbo_); glGenFramebuffers(1, &fbo_);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_); glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
textures_[GBUFFER_POSITION] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT); // Create color attachments using ResourceManager
textures_[GBUFFER_NORMAL] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT); TextureDescription tex_desc;
textures_[GBUFFER_ALBEDO] = create_texture_(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE); 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) tex_desc.format = TextureFormat::RGBA32F;
textures_[GBUFFER_MATERIAL] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT); textures_[GBUFFER_POSITION] = rm.create_texture(tex_desc);
// New: material id (integer) tex_desc.format = TextureFormat::RGBA32F;
textures_[GBUFFER_MATERIAL_ID] = create_texture_(GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT); textures_[GBUFFER_NORMAL] = rm.create_texture(tex_desc);
// New: texcoord + tangent (xy = texcoord, zw = tangent) tex_desc.format = TextureFormat::RGBA8;
textures_[GBUFFER_TEXCOORD] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT); textures_[GBUFFER_ALBEDO] = rm.create_texture(tex_desc);
// New: tangent (xyz = tangent, w = unused) tex_desc.format = TextureFormat::RGBA32F;
textures_[GBUFFER_TANGENT] = create_texture_(GL_RGBA32F, GL_RGBA, GL_FLOAT); textures_[GBUFFER_MATERIAL] = rm.create_texture(tex_desc);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_POSITION, textures_[GBUFFER_MATERIAL_ID] = rm.create_texture(width_, height_, TextureFormat::R32F);
GL_TEXTURE_2D, textures_[GBUFFER_POSITION], 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_NORMAL, tex_desc.format = TextureFormat::RGBA32F;
GL_TEXTURE_2D, textures_[GBUFFER_NORMAL], 0); textures_[GBUFFER_TEXCOORD] = rm.create_texture(tex_desc);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_ALBEDO,
GL_TEXTURE_2D, textures_[GBUFFER_ALBEDO], 0); tex_desc.format = TextureFormat::RGBA32F;
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_MATERIAL, textures_[GBUFFER_TANGENT] = rm.create_texture(tex_desc);
GL_TEXTURE_2D, textures_[GBUFFER_MATERIAL], 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_MATERIAL_ID, // Attach color textures to framebuffer
GL_TEXTURE_2D, textures_[GBUFFER_MATERIAL_ID], 0); for (int i = 0; i < GBUFFER_COUNT; ++i) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_TEXCOORD, glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
GL_TEXTURE_2D, textures_[GBUFFER_TEXCOORD], 0); GL_TEXTURE_2D, textures_[i], 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBUFFER_TANGENT, }
GL_TEXTURE_2D, textures_[GBUFFER_TANGENT], 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, glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_TEXTURE_2D, depth_texture_, 0); GL_TEXTURE_2D, depth_texture_, 0);
// Set draw buffers
GLenum draw_buffers[GBUFFER_COUNT] = { GLenum draw_buffers[GBUFFER_COUNT] = {
GL_COLOR_ATTACHMENT0 + GBUFFER_POSITION, GL_COLOR_ATTACHMENT0 + GBUFFER_POSITION,
GL_COLOR_ATTACHMENT0 + GBUFFER_NORMAL, GL_COLOR_ATTACHMENT0 + GBUFFER_NORMAL,
@ -96,6 +106,8 @@ void GBuffer::release() {
if (!initialized_) if (!initialized_)
return; return;
ResourceManager &rm = ResourceManager::instance();
if (fbo_ != INVALID_HANDLE) { if (fbo_ != INVALID_HANDLE) {
glDeleteFramebuffers(1, &fbo_); glDeleteFramebuffers(1, &fbo_);
fbo_ = INVALID_HANDLE; fbo_ = INVALID_HANDLE;
@ -103,13 +115,13 @@ void GBuffer::release() {
for (int i = 0; i < GBUFFER_COUNT; ++i) { for (int i = 0; i < GBUFFER_COUNT; ++i) {
if (textures_[i] != INVALID_HANDLE) { if (textures_[i] != INVALID_HANDLE) {
glDeleteTextures(1, &textures_[i]); rm.destroy_texture(textures_[i]);
textures_[i] = INVALID_HANDLE; textures_[i] = INVALID_HANDLE;
} }
} }
if (depth_texture_ != INVALID_HANDLE) { if (depth_texture_ != INVALID_HANDLE) {
glDeleteTextures(1, &depth_texture_); rm.destroy_texture(depth_texture_);
depth_texture_ = INVALID_HANDLE; depth_texture_ = INVALID_HANDLE;
} }
@ -117,18 +129,6 @@ void GBuffer::release() {
ARE_LOG_INFO("GBuffer released"); 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) { void GBuffer::render(const Scene &scene, const Shader &shader) {
if (!initialized_) { if (!initialized_) {
ARE_LOG_ERROR("GBuffer not initialized"); ARE_LOG_ERROR("GBuffer not initialized");

View File

@ -1,5 +1,6 @@
#include "core/raytracer.h" #include "core/raytracer.h"
#include "basic/constants.h" #include "basic/constants.h"
#include "resource/resource_manager.h"
#include "utils/logger.h" #include "utils/logger.h"
#include <glad/glad.h> #include <glad/glad.h>
@ -22,7 +23,6 @@ RayTracer::RayTracer(uint width, uint height, const RayTracerConfig &config)
, height_(height) , height_(height)
, config_(config) , config_(config)
, accumulation_texture_(INVALID_HANDLE) , accumulation_texture_(INVALID_HANDLE)
, scene_buffer_(INVALID_HANDLE)
, material_buffer_(INVALID_HANDLE) , material_buffer_(INVALID_HANDLE)
, light_buffer_(INVALID_HANDLE) , light_buffer_(INVALID_HANDLE)
, bvh_(nullptr) , bvh_(nullptr)
@ -43,33 +43,27 @@ bool RayTracer::initialize(const std::shared_ptr<Shader> &shader) {
return true; return true;
} }
ResourceManager &rm = ResourceManager::instance();
compute_shader_ = shader; compute_shader_ = shader;
// Create accumulation texture // Create accumulation texture
glGenTextures(1, &accumulation_texture_); accumulation_texture_ = rm.create_texture(width_, height_, TextureFormat::RGBA32F);
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);
// Create shader storage buffers // Create shader storage buffers
glGenBuffers(1, &material_buffer_); BufferDescription ssbo_desc;
glGenBuffers(1, &light_buffer_); 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) // Initialize texture arrays (empty for now)
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
texture_arrays_[i] = 0; texture_arrays_[i] = 0;
texture_array_sizes_[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 // Initialize BVH if enabled
if (config_.use_bvh_) { if (config_.use_bvh_) {
@ -85,26 +79,28 @@ void RayTracer::release() {
if (!initialized_) if (!initialized_)
return; return;
ResourceManager &rm = ResourceManager::instance();
if (accumulation_texture_ != INVALID_HANDLE) { if (accumulation_texture_ != INVALID_HANDLE) {
glDeleteTextures(1, &accumulation_texture_); rm.destroy_texture(accumulation_texture_);
accumulation_texture_ = INVALID_HANDLE; accumulation_texture_ = INVALID_HANDLE;
} }
// Release texture arrays // Release texture arrays
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
if (texture_arrays_[i] != 0) { if (texture_arrays_[i] != 0) {
glDeleteTextures(1, &texture_arrays_[i]); rm.destroy_texture_array(texture_arrays_[i]);
texture_arrays_[i] = 0; texture_arrays_[i] = 0;
} }
} }
if (material_buffer_ != INVALID_HANDLE) { if (material_buffer_ != INVALID_HANDLE) {
glDeleteBuffers(1, &material_buffer_); rm.destroy_buffer(material_buffer_);
material_buffer_ = INVALID_HANDLE; material_buffer_ = INVALID_HANDLE;
} }
if (light_buffer_ != INVALID_HANDLE) { if (light_buffer_ != INVALID_HANDLE) {
glDeleteBuffers(1, &light_buffer_); rm.destroy_buffer(light_buffer_);
light_buffer_ = INVALID_HANDLE; light_buffer_ = INVALID_HANDLE;
} }
@ -254,18 +250,14 @@ void RayTracer::resize(uint width, uint height) {
height_ = height; height_ = height;
if (initialized_) { if (initialized_) {
ResourceManager &rm = ResourceManager::instance();
// Recreate accumulation texture // Recreate accumulation texture
if (accumulation_texture_ != INVALID_HANDLE) { if (accumulation_texture_ != INVALID_HANDLE) {
glDeleteTextures(1, &accumulation_texture_); rm.destroy_texture(accumulation_texture_);
} }
glGenTextures(1, &accumulation_texture_); accumulation_texture_ = rm.create_texture(width_, height_, TextureFormat::RGBA32F);
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);
reset_accumulation(); reset_accumulation();
} }
@ -439,8 +431,16 @@ void RayTracer::build_texture_arrays_(const Scene &scene) {
} }
} }
ResourceManager &rm = ResourceManager::instance();
// Build arrays for each slot // Build arrays for each slot
for (int slot = 0; slot < 6; 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()) { if (textures[slot].empty()) {
texture_array_sizes_[slot] = 0; texture_array_sizes_[slot] = 0;
continue; continue;
@ -448,89 +448,25 @@ void RayTracer::build_texture_arrays_(const Scene &scene) {
texture_array_sizes_[slot] = static_cast<uint>(textures[slot].size()); texture_array_sizes_[slot] = static_cast<uint>(textures[slot].size());
// Get dimensions from first texture (assume all same size) // Create texture array using ResourceManager
int width = textures[slot][0]->get_width(); TextureArrayDescription desc;
int height = textures[slot][0]->get_height(); desc.textures = textures[slot];
desc.filter = TextureFilter::LINEAR;
desc.wrap = TextureWrap::REPEAT;
// Create texture array texture_arrays_[slot] = rm.create_texture_array(desc);
glBindTexture(GL_TEXTURE_2D_ARRAY, texture_arrays_[slot]);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, width, height,
static_cast<int>(textures[slot].size()), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
// 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++) { for (size_t i = 0; i < textures[slot].size(); i++) {
auto &tex = textures[slot][i]; // Index is i+1 because 0 means "no texture" in the shader
GLuint tex_handle = tex->get_handle(); uint32_t array_index = static_cast<uint32_t>(i) + 1;
if (tex_handle != 0) { for (const auto &mat : materials) {
// Get original texture format if (mat->get_texture(static_cast<TextureSlot>(slot)).get() == textures[slot][i].get()) {
TextureFormat orig_format = tex->get_format(); mat->set_texture_index(static_cast<TextureSlot>(slot), array_index);
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<uint8_t> 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<uint8_t> 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<int>(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<uint32_t>(i) + 1;
for (const auto &mat : materials) {
if (mat->get_texture(static_cast<TextureSlot>(slot)).get() == tex.get()) {
mat->set_texture_index(static_cast<TextureSlot>(slot), array_index);
}
} }
} }
} }
// Generate mipmaps
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
} }
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
} }
} // namespace are } // namespace are

View File

@ -1,4 +1,5 @@
#include "core/renderer.h" #include "core/renderer.h"
#include "resource/resource_manager.h"
#include "utils/logger.h" #include "utils/logger.h"
#include <chrono> #include <chrono>
#include <glad/glad.h> #include <glad/glad.h>
@ -7,6 +8,7 @@ namespace are {
Renderer::Renderer(const RendererConfig &config) Renderer::Renderer(const RendererConfig &config)
: config_(config) : config_(config)
, rt_output_texture_(INVALID_HANDLE)
, initialized_(false) , initialized_(false)
, frame_count_(0) { , frame_count_(0) {
} }
@ -68,10 +70,14 @@ bool Renderer::initialize() {
ARE_LOG_ERROR("Failed to initialize denoiser"); ARE_LOG_ERROR("Failed to initialize denoiser");
return false; return false;
} }
initialized_ = true; // Create ray tracing output texture (reused every frame)
ARE_LOG_INFO("Aurora Rendering Engine initialized successfully"); ResourceManager &rm = ResourceManager::instance();
return true; 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() { void Renderer::shutdown() {
@ -80,30 +86,18 @@ void Renderer::shutdown() {
ARE_LOG_INFO("Shutting down Aurora Rendering Engine..."); ARE_LOG_INFO("Shutting down Aurora Rendering Engine...");
if (screen_blit_) { ResourceManager &rm = ResourceManager::instance();
screen_blit_->release();
screen_blit_.reset();
}
if (raytracer_) { if (rt_output_texture_ != INVALID_HANDLE) {
raytracer_->release(); rm.destroy_texture(rt_output_texture_);
raytracer_.reset(); rt_output_texture_ = INVALID_HANDLE;
} }
if (gbuffer_) { screen_blit_.reset();
gbuffer_->release(); raytracer_.reset();
gbuffer_.reset(); gbuffer_.reset();
} shader_manager_.reset();
denoiser_.reset();
if (shader_manager_) {
shader_manager_->release();
shader_manager_.reset();
}
if (denoiser_) {
denoiser_->release();
denoiser_.reset();
}
initialized_ = false; initialized_ = false;
ARE_LOG_INFO("Aurora Rendering Engine shut down"); 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 // Phase 2: Ray tracing pass
auto raytrace_start = std::chrono::high_resolution_clock::now(); auto raytrace_start = std::chrono::high_resolution_clock::now();
// Create output texture if not provided // Use output texture if provided, otherwise use internal texture
TextureHandle rt_output = output_texture; TextureHandle rt_output = (output_texture != 0) ? output_texture : rt_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;
}
raytracer_->trace(scene, *gbuffer_, rt_output); 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 // 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); screen_blit_->blit_fullscreen(final_output);
glDeleteTextures(1, &rt_output);
} }
// Calculate total frame time // Calculate total frame time
@ -194,6 +176,14 @@ void Renderer::resize(uint width, uint height) {
config_.height_ = height; config_.height_ = height;
if (initialized_) { 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); gbuffer_->resize(width, height);
raytracer_->resize(width, height); raytracer_->resize(width, height);
denoiser_->resize(width, height); denoiser_->resize(width, height);

View File

@ -1,4 +1,5 @@
#include "core/screen_blit.h" #include "core/screen_blit.h"
#include "resource/resource_manager.h"
#include "utils/logger.h" #include "utils/logger.h"
#include <glad/glad.h> #include <glad/glad.h>
@ -35,13 +36,15 @@ void ScreenBlit::release() {
shader_.reset(); shader_.reset();
ResourceManager &rm = ResourceManager::instance();
if (vao_ != 0) { if (vao_ != 0) {
glDeleteVertexArrays(1, &vao_); rm.destroy_vertex_array(vao_);
vao_ = 0; vao_ = 0;
} }
if (vbo_ != 0) { if (vbo_ != 0) {
glDeleteBuffers(1, &vbo_); rm.destroy_buffer(vbo_);
vbo_ = 0; vbo_ = 0;
} }
@ -96,12 +99,19 @@ void ScreenBlit::create_quad_() {
-1.0f, 1.0f, 0.0f, 1.0f -1.0f, 1.0f, 0.0f, 1.0f
}; };
glGenVertexArrays(1, &vao_); ResourceManager &rm = ResourceManager::instance();
glGenBuffers(1, &vbo_);
vao_ = rm.create_vertex_array();
glBindVertexArray(vao_); 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_); glBindBuffer(GL_ARRAY_BUFFER, vbo_);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Position attribute // Position attribute
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);

View File

@ -32,9 +32,6 @@ bool ShaderManager::initialize() {
void ShaderManager::release() { void ShaderManager::release() {
if (!initialized_) return; if (!initialized_) return;
for (auto& pair : shader_cache_) {
if (pair.second) pair.second->release();
}
shader_cache_.clear(); shader_cache_.clear();
gbuffer_shader_.reset(); gbuffer_shader_.reset();
@ -110,7 +107,7 @@ bool ShaderManager::load_builtin_shaders_() {
ARE_LOG_ERROR("Failed to load screen blit shader"); ARE_LOG_ERROR("Failed to load screen blit shader");
return false; return false;
} }
shader_cache_["screen_blit"] = denoise_shader_; shader_cache_["screen_blit"] = screen_blit_shader_;
ARE_LOG_INFO("Screen blit shader loaded successfully"); ARE_LOG_INFO("Screen blit shader loaded successfully");
// Load ray tracing shader // Load ray tracing shader

View File

@ -0,0 +1,667 @@
#include "resource/resource_manager.h"
#include "utils/logger.h"
#include <glad/glad.h>
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<Texture>();
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<GLenum> 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<int>(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<uint8_t> 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<uint8_t> 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<int>(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

View File

@ -1,6 +1,6 @@
#include "resource/shader.h" #include "resource/shader.h"
#include "utils/logger.h" #include "utils/logger.h"
#include "basic/math.h" // 修改为math.h #include "basic/math.h"
#include <glad/glad.h> #include <glad/glad.h>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
@ -19,7 +19,7 @@ Shader::Shader(Shader&& other) noexcept
} }
Shader::~Shader() { Shader::~Shader() {
// Don't auto-release, let user control lifetime release();
} }
Shader& Shader::operator=(Shader&& other) noexcept { Shader& Shader::operator=(Shader&& other) noexcept {
@ -88,7 +88,7 @@ bool Shader::compile_compute(const std::string& compute_source) {
return success; return success;
} }
void Shader::use() const { // 改为const void Shader::use() const {
if (handle_ != INVALID_HANDLE) { if (handle_ != INVALID_HANDLE) {
glUseProgram(handle_); glUseProgram(handle_);
} }
@ -102,50 +102,50 @@ void Shader::release() {
uniform_cache_.clear(); 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<int>(value)); glUniform1i(get_uniform_location_(name), static_cast<int>(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); 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); 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); 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]); 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]); 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]); 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]); 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)); 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); auto it = uniform_cache_.find(name);
if (it != uniform_cache_.end()) { if (it != uniform_cache_.end()) {
return it->second; return it->second;
} }
int location = glGetUniformLocation(handle_, name.c_str()); int location = glGetUniformLocation(handle_, name.c_str());
uniform_cache_[name] = location; // mutable允许修改 uniform_cache_[name] = location;
if (location == -1) { if (location == -1) {
ARE_LOG_WARN("Uniform '" + name + "' not found in shader"); ARE_LOG_WARN("Uniform '" + name + "' not found in shader");

View File

@ -1,4 +1,5 @@
#include "scene/mesh.h" #include "scene/mesh.h"
#include "resource/resource_manager.h"
#include "utils/logger.h" #include "utils/logger.h"
#include <algorithm> #include <algorithm>
#include <glad/glad.h> #include <glad/glad.h>
@ -52,21 +53,29 @@ bool Mesh::upload_to_gpu() {
return false; return false;
} }
ResourceManager &rm = ResourceManager::instance();
// Generate VAO // Generate VAO
glGenVertexArrays(1, &vao_); vao_ = rm.create_vertex_array();
glBindVertexArray(vao_); glBindVertexArray(vao_);
// Generate and upload VBO // 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_); glBindBuffer(GL_ARRAY_BUFFER, vbo_);
glBufferData(GL_ARRAY_BUFFER, vertices_.size() * sizeof(Vertex),
vertices_.data(), GL_STATIC_DRAW);
// Generate and upload EBO // 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_); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_.size() * sizeof(uint),
indices_.data(), GL_STATIC_DRAW);
// Set vertex attributes // Set vertex attributes
// Location 0: Position // Location 0: Position
@ -100,18 +109,20 @@ void Mesh::release_gpu_resources() {
if (!uploaded_) if (!uploaded_)
return; return;
ResourceManager &rm = ResourceManager::instance();
if (vao_ != 0) { if (vao_ != 0) {
glDeleteVertexArrays(1, &vao_); rm.destroy_vertex_array(vao_);
vao_ = 0; vao_ = 0;
} }
if (vbo_ != 0) { if (vbo_ != 0) {
glDeleteBuffers(1, &vbo_); rm.destroy_buffer(vbo_);
vbo_ = 0; vbo_ = 0;
} }
if (ebo_ != 0) { if (ebo_ != 0) {
glDeleteBuffers(1, &ebo_); rm.destroy_buffer(ebo_);
ebo_ = 0; ebo_ = 0;
} }