fix: 修复超分scaling=1时黑屏问题,确认超分模块在nouveau驱动环境下无法正确运行问题

- 添加参数检查,当scaling<=1时自动关闭超分并WARN
- 添加运行环境提示,当渲染器处于nouveau驱动环境中时自动关闭超分并WARN
main
ternaryop8479 2026-05-23 00:25:29 +08:00
parent 9259bb9c6f
commit 5bb7d461a4
5 changed files with 144 additions and 105 deletions

Binary file not shown.

View File

@ -115,9 +115,9 @@ private:
SuperResolutionConfig config_; SuperResolutionConfig config_;
uint current_jitter_frame_; uint current_jitter_frame_;
TextureHandle low_res_rt_texture_; // W/block × H/block per-frame RT 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 accumulated_rt_texture_; // W × H running average (binding 4)
TextureHandle upscaled_texture_; // W × H final tonemapped output TextureHandle upscaled_texture_; // W × H final tonemapped output
std::shared_ptr<Shader> compute_shader_; std::shared_ptr<Shader> compute_shader_;
bool initialized_ = false; bool initialized_ = false;

View File

@ -7,142 +7,146 @@
namespace are { namespace are {
Denoiser::Denoiser(uint width, uint height) Denoiser::Denoiser(uint width, uint height)
: width_(width) : width_(width)
, height_(height) , height_(height)
, output_texture_(INVALID_HANDLE) , output_texture_(INVALID_HANDLE)
, history_texture_(INVALID_HANDLE) , history_texture_(INVALID_HANDLE)
, history_valid_(false) , history_valid_(false)
, initialized_(false) { , initialized_(false) {
} }
Denoiser::~Denoiser() { Denoiser::~Denoiser() {
release(); release();
} }
bool Denoiser::initialize(const std::shared_ptr<Shader>& shader) { bool Denoiser::initialize(const std::shared_ptr<Shader> &shader) {
if (initialized_) return true; if (initialized_)
return true;
if (!shader || !shader->is_valid()) { if (!shader || !shader->is_valid()) {
ARE_LOG_ERROR("Invalid denoise shader"); ARE_LOG_ERROR("Invalid denoise shader");
return false; return false;
} }
shader_ = shader; shader_ = shader;
create_output_texture_(); create_output_texture_();
initialized_ = true; initialized_ = true;
ARE_LOG_INFO("Denoiser initialized"); ARE_LOG_INFO("Denoiser initialized");
return true; return true;
} }
void Denoiser::release() { void Denoiser::release() {
if (!initialized_) return; if (!initialized_)
return;
shader_.reset(); shader_.reset();
if (output_texture_ != INVALID_HANDLE) { if (output_texture_ != INVALID_HANDLE) {
ResourceManager::instance().destroy_texture(output_texture_); ResourceManager::instance().destroy_texture(output_texture_);
output_texture_ = INVALID_HANDLE; output_texture_ = INVALID_HANDLE;
} }
if (history_texture_ != INVALID_HANDLE) { if (history_texture_ != INVALID_HANDLE) {
ResourceManager::instance().destroy_texture(history_texture_); ResourceManager::instance().destroy_texture(history_texture_);
history_texture_ = INVALID_HANDLE; history_texture_ = INVALID_HANDLE;
} }
history_valid_ = false; history_valid_ = false;
initialized_ = false; initialized_ = false;
} }
void Denoiser::resize(uint width, uint height) { void Denoiser::resize(uint width, uint height) {
if (width == width_ && height == height_) return; if (width == width_ && height == height_)
width_ = width; return;
height_ = height; width_ = width;
height_ = height;
if (!initialized_) return; if (!initialized_)
return;
ResourceManager &rm = ResourceManager::instance(); ResourceManager &rm = ResourceManager::instance();
if (output_texture_ != INVALID_HANDLE) { if (output_texture_ != INVALID_HANDLE) {
rm.destroy_texture(output_texture_); rm.destroy_texture(output_texture_);
output_texture_ = INVALID_HANDLE; output_texture_ = INVALID_HANDLE;
} }
if (history_texture_ != INVALID_HANDLE) { if (history_texture_ != INVALID_HANDLE) {
rm.destroy_texture(history_texture_); rm.destroy_texture(history_texture_);
history_texture_ = INVALID_HANDLE; history_texture_ = INVALID_HANDLE;
} }
history_valid_ = false; history_valid_ = false;
create_output_texture_(); create_output_texture_();
} }
TextureHandle Denoiser::denoise(TextureHandle input_texture, int radius, float temporal_weight) { 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; radius = (radius < 0) ? 0 : radius;
temporal_weight = (temporal_weight < 0.0f) ? 0.0f : ((temporal_weight > 1.0f) ? 1.0f : temporal_weight); 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(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(1, output_texture_, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
shader_->set_int("u_radius", radius); shader_->set_int("u_radius", radius);
shader_->set_float("u_temporal_weight", temporal_weight); shader_->set_float("u_temporal_weight", temporal_weight);
shader_->set_bool("u_has_history", history_valid_ && temporal_weight > 0.0f); shader_->set_bool("u_has_history", history_valid_ && temporal_weight > 0.0f);
// Bind history texture if available and temporal accumulation is enabled // Bind history texture if available and temporal accumulation is enabled
if (history_valid_ && temporal_weight > 0.0f) { if (history_valid_ && temporal_weight > 0.0f) {
glBindImageTexture(2, history_texture_, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); 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_x = (width_ + COMPUTE_GROUP_SIZE_X - 1) / COMPUTE_GROUP_SIZE_X;
uint groups_y = (height_ + COMPUTE_GROUP_SIZE_Y - 1) / COMPUTE_GROUP_SIZE_Y; uint groups_y = (height_ + COMPUTE_GROUP_SIZE_Y - 1) / COMPUTE_GROUP_SIZE_Y;
glDispatchCompute(groups_x, groups_y, 1); 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) // Copy output to history using GPU (blit or compute)
if (temporal_weight > 0.0f) { // For simplicity, we'll just bind output as history for next frame
// Create history texture if it doesn't exist // This requires double buffering - let's swap the textures
if (history_texture_ == INVALID_HANDLE) { std::swap(output_texture_, history_texture_);
ResourceManager &rm = ResourceManager::instance(); history_valid_ = true;
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) // Return the new output (which was history before swap)
// For simplicity, we'll just bind output as history for next frame return output_texture_;
// 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 output_texture_;
}
return output_texture_;
} }
void Denoiser::reset_history() { void Denoiser::reset_history() {
history_valid_ = false; history_valid_ = false;
} }
void Denoiser::create_output_texture_() { void Denoiser::create_output_texture_() {
ResourceManager &rm = ResourceManager::instance(); ResourceManager &rm = ResourceManager::instance();
TextureDescription desc; TextureDescription desc;
desc.width = width_; desc.width = width_;
desc.height = height_; desc.height = height_;
desc.format = TextureFormat::RGBA32F; desc.format = TextureFormat::RGBA32F;
desc.filter = TextureFilter::NEAREST; desc.filter = TextureFilter::NEAREST;
desc.wrap = TextureWrap::CLAMP_TO_EDGE; desc.wrap = TextureWrap::CLAMP_TO_EDGE;
output_texture_ = rm.create_texture(desc); output_texture_ = rm.create_texture(desc);
} }
} // namespace are } // namespace are

View File

@ -1,6 +1,7 @@
#include "core/renderer.h" #include "core/renderer.h"
#include "resource/resource_manager.h" #include "resource/resource_manager.h"
#include "utils/logger.h" #include "utils/logger.h"
#include <algorithm>
#include <chrono> #include <chrono>
#include <glad/glad.h> #include <glad/glad.h>
@ -24,6 +25,27 @@ bool Renderer::initialize() {
ARE_LOG_INFO("Initializing Aurora Rendering Engine..."); 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<const char *>(glGetString(GL_VENDOR)));
std::transform(vendor.begin(), vendor.end(), vendor.begin(), ::tolower);
std::string renderer = std::string(reinterpret_cast<const char *>(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 // Initialize shader manager
shader_manager_ = std::make_unique<ShaderManager>(); shader_manager_ = std::make_unique<ShaderManager>();
if (!shader_manager_->initialize()) { if (!shader_manager_->initialize()) {

View File

@ -4,6 +4,7 @@
#include "utils/logger.h" #include "utils/logger.h"
#include <cmath> #include <cmath>
#include <glad/glad.h> #include <glad/glad.h>
#include <string>
namespace are { namespace are {
@ -24,43 +25,51 @@ SuperResolution::~SuperResolution() {
bool SuperResolution::initialize(const std::shared_ptr<Shader> &shader) { bool SuperResolution::initialize(const std::shared_ptr<Shader> &shader) {
if (initialized_) { if (initialized_) {
ARE_LOG_WARN("SuperResolution already initialized"); ARE_LOG_WARN("Super resolution already initialized");
return true; return true;
} }
if (!shader || !shader->is_valid()) { if (!shader || !shader->is_valid()) {
ARE_LOG_ERROR("Invalid shader"); ARE_LOG_ERROR("Invalid shader");
return false; return false;
} }
compute_shader_ = shader; compute_shader_ = shader;
create_textures_(); create_textures_();
initialized_ = true; 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; return true;
} }
void SuperResolution::release() { void SuperResolution::release() {
if (!initialized_) if (!initialized_) {
return; return;
}
ResourceManager &rm = ResourceManager::instance(); ResourceManager &rm = ResourceManager::instance();
if (low_res_rt_texture_ != INVALID_HANDLE) { if (low_res_rt_texture_ != INVALID_HANDLE) {
rm.destroy_texture(low_res_rt_texture_); rm.destroy_texture(low_res_rt_texture_);
low_res_rt_texture_ = INVALID_HANDLE; low_res_rt_texture_ = INVALID_HANDLE;
} }
if (accumulated_rt_texture_ != INVALID_HANDLE) { if (accumulated_rt_texture_ != INVALID_HANDLE) {
rm.destroy_texture(accumulated_rt_texture_); rm.destroy_texture(accumulated_rt_texture_);
accumulated_rt_texture_ = INVALID_HANDLE; accumulated_rt_texture_ = INVALID_HANDLE;
} }
if (upscaled_texture_ != INVALID_HANDLE) { if (upscaled_texture_ != INVALID_HANDLE) {
rm.destroy_texture(upscaled_texture_); rm.destroy_texture(upscaled_texture_);
upscaled_texture_ = INVALID_HANDLE; upscaled_texture_ = INVALID_HANDLE;
} }
initialized_ = false; initialized_ = false;
ARE_LOG_INFO("SuperResolution released"); ARE_LOG_INFO("SuperResolution released");
} }
TextureHandle SuperResolution::upscale() { TextureHandle SuperResolution::upscale() {
if (!initialized_ || !compute_shader_) if (!initialized_ || !compute_shader_) {
return INVALID_HANDLE; return INVALID_HANDLE;
}
compute_shader_->use(); compute_shader_->use();
glBindImageTexture(1, accumulated_rt_texture_, 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA32F); 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) { 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; return;
}
full_width_ = full_width; full_width_ = full_width;
full_height_ = full_height; full_height_ = full_height;
uint block = compute_block_size_(); uint block = compute_block_size_();
low_res_w_ = full_width_ / block; low_res_w_ = full_width_ / block;
low_res_h_ = full_height_ / block; low_res_h_ = full_height_ / block;
if (!initialized_) if (!initialized_) {
return; return;
}
ResourceManager &rm = ResourceManager::instance(); ResourceManager &rm = ResourceManager::instance();
if (low_res_rt_texture_ != INVALID_HANDLE) { if (low_res_rt_texture_ != INVALID_HANDLE) {
rm.destroy_texture(low_res_rt_texture_); rm.destroy_texture(low_res_rt_texture_);
} }
if (accumulated_rt_texture_ != INVALID_HANDLE) { if (accumulated_rt_texture_ != INVALID_HANDLE) {
rm.destroy_texture(accumulated_rt_texture_); rm.destroy_texture(accumulated_rt_texture_);
} }
if (upscaled_texture_ != INVALID_HANDLE) { if (upscaled_texture_ != INVALID_HANDLE) {
rm.destroy_texture(upscaled_texture_); rm.destroy_texture(upscaled_texture_);
} }
create_textures_(); create_textures_();
ARE_LOG_INFO("SuperResolution resized to " + std::to_string(full_width) + "x" + std::to_string(full_height)); 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; GLuint fbo;
glGenFramebuffers(1, &fbo); glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, accumulated_rt_texture_, 0);
accumulated_rt_texture_, 0);
const GLfloat clear_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; const GLfloat clear_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
glClearBufferfv(GL_COLOR, 0, clear_color); glClearBufferfv(GL_COLOR, 0, clear_color);
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);