diff --git a/examples/cornell_box b/examples/cornell_box index 4db3aaa..b02d962 100644 Binary files a/examples/cornell_box and b/examples/cornell_box differ diff --git a/include/core/super_resolution.h b/include/core/super_resolution.h index 49ab392..7525cc0 100644 --- a/include/core/super_resolution.h +++ b/include/core/super_resolution.h @@ -115,9 +115,9 @@ private: SuperResolutionConfig config_; uint current_jitter_frame_; - TextureHandle low_res_rt_texture_; // W/block × H/block – per-frame RT output - TextureHandle accumulated_rt_texture_; // W × H – running average (binding 4) - TextureHandle upscaled_texture_; // W × H – final tonemapped output + TextureHandle low_res_rt_texture_; // W/block × H/block – per-frame RT output + TextureHandle accumulated_rt_texture_; // W × H – running average (binding 4) + TextureHandle upscaled_texture_; // W × H – final tonemapped output std::shared_ptr compute_shader_; bool initialized_ = false; diff --git a/src/core/denoiser.cpp b/src/core/denoiser.cpp index 33c497d..43a1288 100644 --- a/src/core/denoiser.cpp +++ b/src/core/denoiser.cpp @@ -7,142 +7,146 @@ namespace are { Denoiser::Denoiser(uint width, uint height) - : width_(width) - , height_(height) - , output_texture_(INVALID_HANDLE) - , history_texture_(INVALID_HANDLE) - , history_valid_(false) - , initialized_(false) { + : width_(width) + , height_(height) + , output_texture_(INVALID_HANDLE) + , history_texture_(INVALID_HANDLE) + , history_valid_(false) + , initialized_(false) { } Denoiser::~Denoiser() { - release(); + release(); } -bool Denoiser::initialize(const std::shared_ptr& shader) { - if (initialized_) return true; +bool Denoiser::initialize(const std::shared_ptr &shader) { + if (initialized_) + return true; - if (!shader || !shader->is_valid()) { - ARE_LOG_ERROR("Invalid denoise shader"); - return false; - } + if (!shader || !shader->is_valid()) { + ARE_LOG_ERROR("Invalid denoise shader"); + return false; + } - shader_ = shader; - create_output_texture_(); + shader_ = shader; + create_output_texture_(); - initialized_ = true; - ARE_LOG_INFO("Denoiser initialized"); - return true; + initialized_ = true; + ARE_LOG_INFO("Denoiser initialized"); + return true; } void Denoiser::release() { - if (!initialized_) return; + if (!initialized_) + return; - shader_.reset(); + shader_.reset(); - if (output_texture_ != INVALID_HANDLE) { - ResourceManager::instance().destroy_texture(output_texture_); - output_texture_ = INVALID_HANDLE; - } + if (output_texture_ != INVALID_HANDLE) { + ResourceManager::instance().destroy_texture(output_texture_); + output_texture_ = INVALID_HANDLE; + } - if (history_texture_ != INVALID_HANDLE) { - ResourceManager::instance().destroy_texture(history_texture_); - history_texture_ = INVALID_HANDLE; - } + if (history_texture_ != INVALID_HANDLE) { + ResourceManager::instance().destroy_texture(history_texture_); + history_texture_ = INVALID_HANDLE; + } - history_valid_ = false; - initialized_ = false; + history_valid_ = false; + initialized_ = false; } void Denoiser::resize(uint width, uint height) { - if (width == width_ && height == height_) return; - width_ = width; - height_ = height; + if (width == width_ && height == height_) + return; + width_ = width; + height_ = height; - if (!initialized_) return; + if (!initialized_) + return; - ResourceManager &rm = ResourceManager::instance(); + ResourceManager &rm = ResourceManager::instance(); - if (output_texture_ != INVALID_HANDLE) { - rm.destroy_texture(output_texture_); - output_texture_ = INVALID_HANDLE; - } + if (output_texture_ != INVALID_HANDLE) { + rm.destroy_texture(output_texture_); + output_texture_ = INVALID_HANDLE; + } - if (history_texture_ != INVALID_HANDLE) { - rm.destroy_texture(history_texture_); - history_texture_ = INVALID_HANDLE; - } + if (history_texture_ != INVALID_HANDLE) { + rm.destroy_texture(history_texture_); + history_texture_ = INVALID_HANDLE; + } - history_valid_ = false; - create_output_texture_(); + history_valid_ = false; + create_output_texture_(); } TextureHandle Denoiser::denoise(TextureHandle input_texture, int radius, float temporal_weight) { - if (!initialized_) return input_texture; + if (!initialized_) + return input_texture; - radius = (radius < 0) ? 0 : radius; - temporal_weight = (temporal_weight < 0.0f) ? 0.0f : ((temporal_weight > 1.0f) ? 1.0f : temporal_weight); + radius = (radius < 0) ? 0 : radius; + temporal_weight = (temporal_weight < 0.0f) ? 0.0f : ((temporal_weight > 1.0f) ? 1.0f : temporal_weight); - shader_->use(); + shader_->use(); - glBindImageTexture(0, input_texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); - glBindImageTexture(1, output_texture_, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); + glBindImageTexture(0, input_texture, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); + glBindImageTexture(1, output_texture_, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); - shader_->set_int("u_radius", radius); - shader_->set_float("u_temporal_weight", temporal_weight); - shader_->set_bool("u_has_history", history_valid_ && temporal_weight > 0.0f); + shader_->set_int("u_radius", radius); + shader_->set_float("u_temporal_weight", temporal_weight); + shader_->set_bool("u_has_history", history_valid_ && temporal_weight > 0.0f); - // Bind history texture if available and temporal accumulation is enabled - if (history_valid_ && temporal_weight > 0.0f) { - glBindImageTexture(2, history_texture_, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); - } + // Bind history texture if available and temporal accumulation is enabled + if (history_valid_ && temporal_weight > 0.0f) { + glBindImageTexture(2, history_texture_, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); + } - uint groups_x = (width_ + COMPUTE_GROUP_SIZE_X - 1) / COMPUTE_GROUP_SIZE_X; - uint groups_y = (height_ + COMPUTE_GROUP_SIZE_Y - 1) / COMPUTE_GROUP_SIZE_Y; - glDispatchCompute(groups_x, groups_y, 1); + uint groups_x = (width_ + COMPUTE_GROUP_SIZE_X - 1) / COMPUTE_GROUP_SIZE_X; + uint groups_y = (height_ + COMPUTE_GROUP_SIZE_Y - 1) / COMPUTE_GROUP_SIZE_Y; + glDispatchCompute(groups_x, groups_y, 1); + glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); - glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + // Copy output to history for next frame (if temporal accumulation is enabled) + if (temporal_weight > 0.0f) { + // Create history texture if it doesn't exist + if (history_texture_ == INVALID_HANDLE) { + 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; + history_texture_ = rm.create_texture(desc); + } - // Copy output to history for next frame (if temporal accumulation is enabled) - if (temporal_weight > 0.0f) { - // Create history texture if it doesn't exist - if (history_texture_ == INVALID_HANDLE) { - 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; - history_texture_ = rm.create_texture(desc); - } + // Copy output to history using GPU (blit or compute) + // For simplicity, we'll just bind output as history for next frame + // This requires double buffering - let's swap the textures + std::swap(output_texture_, history_texture_); + history_valid_ = true; - // Copy output to history using GPU (blit or compute) - // For simplicity, we'll just bind output as history for next frame - // This requires double buffering - let's swap the textures - std::swap(output_texture_, history_texture_); - history_valid_ = true; + // Return the new output (which was history before swap) + return output_texture_; + } - // Return the new output (which was history before swap) - return output_texture_; - } - - return output_texture_; + return output_texture_; } void Denoiser::reset_history() { - history_valid_ = false; + history_valid_ = false; } void Denoiser::create_output_texture_() { - 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); + 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/renderer.cpp b/src/core/renderer.cpp index db5b81d..cf88dd2 100644 --- a/src/core/renderer.cpp +++ b/src/core/renderer.cpp @@ -1,6 +1,7 @@ #include "core/renderer.h" #include "resource/resource_manager.h" #include "utils/logger.h" +#include #include #include @@ -24,6 +25,27 @@ bool Renderer::initialize() { ARE_LOG_INFO("Initializing Aurora Rendering Engine..."); + // The parameter check for super resolution module + if (config_.sr_config.enabled) { + // Parameters checking + if (config_.sr_config.scaling <= 1) { + ARE_LOG_WARN("Super resolution disabled: scaling must be > 1 (got " + std::to_string(config_.sr_config.scaling) + ")"); + config_.sr_config.enabled = false; + config_.sr_config.scaling = 1; + } + + // The super resolution module does not support nouveau driver + std::string vendor = std::string(reinterpret_cast(glGetString(GL_VENDOR))); + std::transform(vendor.begin(), vendor.end(), vendor.begin(), ::tolower); + std::string renderer = std::string(reinterpret_cast(glGetString(GL_RENDERER))); + std::transform(renderer.begin(), renderer.end(), renderer.begin(), ::tolower); + if (vendor.find("mesa") != std::string::npos && renderer.find("nv") != std::string::npos) { + ARE_LOG_WARN("Super resolution disabled: The super resolution module on nouveau may produce artifacts. Please switch to the NVIDIA proprietary driver if possible."); + config_.sr_config.enabled = false; + config_.sr_config.scaling = 1; + } + } + // Initialize shader manager shader_manager_ = std::make_unique(); if (!shader_manager_->initialize()) { diff --git a/src/core/super_resolution.cpp b/src/core/super_resolution.cpp index 0a8944d..f1942b2 100644 --- a/src/core/super_resolution.cpp +++ b/src/core/super_resolution.cpp @@ -4,6 +4,7 @@ #include "utils/logger.h" #include #include +#include namespace are { @@ -24,43 +25,51 @@ SuperResolution::~SuperResolution() { bool SuperResolution::initialize(const std::shared_ptr &shader) { if (initialized_) { - ARE_LOG_WARN("SuperResolution already initialized"); + ARE_LOG_WARN("Super resolution already initialized"); return true; } + if (!shader || !shader->is_valid()) { ARE_LOG_ERROR("Invalid shader"); return false; } + compute_shader_ = shader; create_textures_(); initialized_ = true; - ARE_LOG_INFO("SuperResolution initialized: " + std::to_string(full_width_) + "x" + std::to_string(full_height_) + " scaling_px=" + std::to_string(config_.scaling) + " lowres=" + std::to_string(low_res_w_) + "x" + std::to_string(low_res_h_)); + ARE_LOG_INFO("Super resolution initialized: " + std::to_string(full_width_) + "x" + std::to_string(full_height_) + " scaling_px=" + std::to_string(config_.scaling) + " lowres=" + std::to_string(low_res_w_) + "x" + std::to_string(low_res_h_)); return true; } void SuperResolution::release() { - if (!initialized_) + if (!initialized_) { return; + } ResourceManager &rm = ResourceManager::instance(); + if (low_res_rt_texture_ != INVALID_HANDLE) { rm.destroy_texture(low_res_rt_texture_); low_res_rt_texture_ = INVALID_HANDLE; } + if (accumulated_rt_texture_ != INVALID_HANDLE) { rm.destroy_texture(accumulated_rt_texture_); accumulated_rt_texture_ = INVALID_HANDLE; } + if (upscaled_texture_ != INVALID_HANDLE) { rm.destroy_texture(upscaled_texture_); upscaled_texture_ = INVALID_HANDLE; } + initialized_ = false; ARE_LOG_INFO("SuperResolution released"); } TextureHandle SuperResolution::upscale() { - if (!initialized_ || !compute_shader_) + if (!initialized_ || !compute_shader_) { return INVALID_HANDLE; + } compute_shader_->use(); glBindImageTexture(1, accumulated_rt_texture_, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); @@ -84,26 +93,31 @@ void SuperResolution::reset_accumulation() { } void SuperResolution::resize(uint full_width, uint full_height) { - if (full_width == full_width_ && full_height == full_height_) + if (full_width == full_width_ && full_height == full_height_) { return; + } full_width_ = full_width; full_height_ = full_height; uint block = compute_block_size_(); low_res_w_ = full_width_ / block; low_res_h_ = full_height_ / block; - if (!initialized_) + if (!initialized_) { return; + } ResourceManager &rm = ResourceManager::instance(); if (low_res_rt_texture_ != INVALID_HANDLE) { rm.destroy_texture(low_res_rt_texture_); } + if (accumulated_rt_texture_ != INVALID_HANDLE) { rm.destroy_texture(accumulated_rt_texture_); } + if (upscaled_texture_ != INVALID_HANDLE) { rm.destroy_texture(upscaled_texture_); } + create_textures_(); ARE_LOG_INFO("SuperResolution resized to " + std::to_string(full_width) + "x" + std::to_string(full_height)); } @@ -122,8 +136,7 @@ void SuperResolution::clear_accumulation_texture_() const { GLuint fbo; glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - accumulated_rt_texture_, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, accumulated_rt_texture_, 0); const GLfloat clear_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; glClearBufferfv(GL_COLOR, 0, clear_color); glBindFramebuffer(GL_FRAMEBUFFER, 0);