This commit is contained in:
daiqingshuang
2025-12-27 12:15:45 +08:00
parent 5a8d62f841
commit fd125b495b
15 changed files with 365 additions and 185 deletions

View File

@@ -5,24 +5,27 @@
// ============================================================================
// ============================================================================
// Push Constants(双阶段布局
// Push Constants (简化布局)
// ============================================================================
//
// 布局说明 (128 bytes):
// [0-15] Header: scale + translate (顶点着色器使用)
// [16-51] 顶点阶段 Custom: effect_rect(16) + original_effect_rect(16) + intensity(4) (顶点着色器使用)
// [52-127] 片元阶段 Custom: 效果参数 (本着色器使用)
// [0-15] Header: scale + translate
// [16-31] effect_rect (vec4)
// [32-47] original_effect_rect (vec4)
// [48-51] intensity (float)
//
// 注意:顶点和片元着色器共享相同的 Push Constants 布局
// ============================================================================
layout(push_constant) uniform PushConstants {
// Header (16 bytes) [offset 0-15] - 可选声明,片元着色器可能不使用
// Header (16 bytes) [offset 0-15]
vec2 scale; ///< 缩放因子 (2/width, 2/height)
vec2 translate; ///< 平移因子 (-1, -1)
// === 片元阶段专用参数 (从 offset 52 开始) ===
// 注意:跳过顶点阶段的 effect_rect(16) + original_effect_rect(16) + intensity(4) = 36 bytes [offset 16-51]
layout(offset = 52) float intensity; ///< [52-55] 效果强度
// 用户自定义数据 (112 bytes) [offset 16-127]
vec4 effect_rect; ///< [16-31] 效果区域 [x, y, width, height]
vec4 original_effect_rect; ///< [32-47] 原始效果区域 [x, y, width, height]
float intensity; ///< [48-51] 效果强度
// 可扩展更多用户数据...
} pc;
@@ -34,8 +37,9 @@ layout(set = 0, binding = 1) uniform BlurParams {
vec2 direction; ///< 模糊方向(用于分离式模糊)
} blur;
// 来自顶点着色器(使用 post_process 模式的标准顶点着色器)
layout(location = 0) in vec2 v_uv;
// 来自顶点着色器
layout(location = 0) in vec2 v_uv; ///< 控件局部 UV [0,1]
layout(location = 1) in vec2 v_screen_uv; ///< 屏幕空间 UV用于采样源纹理
// 输出
layout(location = 0) out vec4 frag_color;
@@ -53,8 +57,8 @@ void main() {
vec2 tex_size = vec2(textureSize(u_source_texture, 0));
vec2 texel_size = 1.0 / tex_size;
// 使用 v_uv 计算源纹理坐标v_uv 范围 [0,1]viewport_size 转换为纹理坐标
vec2 source_uv = v_uv;
// 使用 v_screen_uv 采样源纹理backdrop 模式
vec2 source_uv = v_screen_uv;
vec4 result = vec4(0.0);
float total_weight = 0.0;

View File

@@ -1,29 +1,23 @@
#version 450 core
// ============================================================================
// 通用输入
// ============================================================================
// ============================================================================
// Push Constants双阶段布局
// Push Constants (简化布局)
// ============================================================================
//
// 布局说明 (128 bytes):
// [0-15] Header: scale + translate (顶点着色器使用)
// [16-51] 顶点阶段 Custom: effect_rect(16) + original_effect_rect(16) + intensity(4) (顶点着色器使用)
// [52-127] 片元阶段 Custom: 效果参数 (本着色器使用)
// [0-15] Header: scale + translate
// [16-19] intensity (float)
//
// 注意:顶点和片元着色器共享相同的 Push Constants 布局
// ============================================================================
layout(push_constant) uniform PushConstants {
// Header (16 bytes) [offset 0-15] - 可选声明,片元着色器可能不使用
vec2 scale; ///< 缩放因子 (2/width, 2/height)
vec2 translate; ///< 平移因子 (-1, -1)
// Header (16 bytes) [offset 0-15]
vec2 scale; ///< 缩放因子
vec2 translate; ///< 平移因子
// === 片元阶段专用参数 (从 offset 52 开始) ===
// 注意:跳过顶点阶段的 effect_rect(16) + original_effect_rect(16) + intensity(4) = 36 bytes [offset 16-51]
layout(offset = 52) float intensity; ///< [52-55] 效果强度
vec2 viewport_size; ///< [56-63] 视口大小(用于 UV 计算)
// 用户自定义数据 (112 bytes) [offset 16-127]
float intensity; ///< [16-19] 效果强度
// 可扩展更多用户数据...
} pc;
@@ -32,8 +26,9 @@ layout(set = 0, binding = 1) uniform ChromaticAberrationParams {
vec2 offset; ///< RGB 通道偏移
} ca;
layout(location = 0) in vec2 v_uv;
layout(location = 1) in vec2 v_screen_pos;
// 来自顶点着色器
layout(location = 0) in vec2 v_uv; ///< 控件局部 UV [0,1]
layout(location = 1) in vec2 v_screen_uv; ///< 屏幕空间 UV用于采样源纹理
layout(location = 0) out vec4 frag_color;
@@ -42,8 +37,10 @@ layout(location = 0) out vec4 frag_color;
// ============================================================================
void main() {
vec2 source_uv = v_screen_pos / pc.viewport_size;
vec2 texel_size = 1.0 / pc.viewport_size;
// 使用 v_screen_uv 采样源纹理backdrop 模式)
vec2 source_uv = v_screen_uv;
vec2 tex_size = vec2(textureSize(u_source_texture, 0));
vec2 texel_size = 1.0 / tex_size;
// 计算偏移(从中心向外增强)
vec2 center = vec2(0.5);

View File

@@ -1,29 +1,23 @@
#version 450 core
// ============================================================================
// 通用输入
// ============================================================================
// ============================================================================
// Push Constants双阶段布局
// Push Constants (简化布局)
// ============================================================================
//
// 布局说明 (128 bytes):
// [0-15] Header: scale + translate (顶点着色器使用)
// [16-51] 顶点阶段 Custom: effect_rect(16) + original_effect_rect(16) + intensity(4) (顶点着色器使用)
// [52-127] 片元阶段 Custom: 效果参数 (本着色器使用)
// [0-15] Header: scale + translate
// [16-19] intensity (float)
//
// 注意:顶点和片元着色器共享相同的 Push Constants 布局
// ============================================================================
layout(push_constant) uniform PushConstants {
// Header (16 bytes) [offset 0-15] - 可选声明,片元着色器可能不使用
vec2 scale; ///< 缩放因子 (2/width, 2/height)
vec2 translate; ///< 平移因子 (-1, -1)
// Header (16 bytes) [offset 0-15]
vec2 scale; ///< 缩放因子
vec2 translate; ///< 平移因子
// === 片元阶段专用参数 (从 offset 52 开始) ===
// 注意:跳过顶点阶段的 effect_rect(16) + original_effect_rect(16) + intensity(4) = 36 bytes [offset 16-51]
layout(offset = 52) float intensity; ///< [52-55] 效果强度
vec2 viewport_size; ///< [56-63] 视口大小(用于 UV 计算)
// 用户自定义数据 (112 bytes) [offset 16-127]
float intensity; ///< [16-19] 效果强度
// 可扩展更多用户数据...
} pc;
@@ -35,8 +29,9 @@ layout(set = 0, binding = 1) uniform ColorAdjustParams {
float gamma; ///< 伽马 [0.1, 3]
} color;
layout(location = 0) in vec2 v_uv;
layout(location = 1) in vec2 v_screen_pos;
// 来自顶点着色器
layout(location = 0) in vec2 v_uv; ///< 控件局部 UV [0,1]
layout(location = 1) in vec2 v_screen_uv; ///< 屏幕空间 UV用于采样源纹理
layout(location = 0) out vec4 frag_color;
@@ -45,7 +40,8 @@ layout(location = 0) out vec4 frag_color;
// ============================================================================
void main() {
vec2 source_uv = v_screen_pos / pc.viewport_size;
// 使用 v_screen_uv 采样源纹理backdrop 模式)
vec2 source_uv = v_screen_uv;
vec4 original = texture(u_source_texture, source_uv);
vec3 c = original.rgb;

View File

@@ -1,29 +1,23 @@
#version 450 core
// ============================================================================
// 通用输入
// ============================================================================
// ============================================================================
// Push Constants双阶段布局
// Push Constants (简化布局)
// ============================================================================
//
// 布局说明 (128 bytes):
// [0-15] Header: scale + translate (顶点着色器使用)
// [16-51] 顶点阶段 Custom: effect_rect(16) + original_effect_rect(16) + intensity(4) (顶点着色器使用)
// [52-127] 片元阶段 Custom: 效果参数 (本着色器使用)
// [0-15] Header: scale + translate
// [16-19] intensity (float)
//
// 注意:顶点和片元着色器共享相同的 Push Constants 布局
// ============================================================================
layout(push_constant) uniform PushConstants {
// Header (16 bytes) [offset 0-15] - 可选声明,片元着色器可能不使用
vec2 scale; ///< 缩放因子 (2/width, 2/height)
vec2 translate; ///< 平移因子 (-1, -1)
// Header (16 bytes) [offset 0-15]
vec2 scale; ///< 缩放因子
vec2 translate; ///< 平移因子
// === 片元阶段专用参数 (从 offset 52 开始) ===
// 注意:跳过顶点阶段的 effect_rect(16) + original_effect_rect(16) + intensity(4) = 36 bytes [offset 16-51]
layout(offset = 52) float intensity; ///< [52-55] 效果强度
vec2 viewport_size; ///< [56-63] 视口大小(用于 UV 计算)
// 用户自定义数据 (112 bytes) [offset 16-127]
float intensity; ///< [16-19] 效果强度
// 可扩展更多用户数据...
} pc;
@@ -33,8 +27,9 @@ layout(set = 0, binding = 1) uniform ColorTintParams {
int blend_mode; ///< 混合模式
} tint;
layout(location = 0) in vec2 v_uv;
layout(location = 1) in vec2 v_screen_pos;
// 来自顶点着色器
layout(location = 0) in vec2 v_uv; ///< 控件局部 UV [0,1]
layout(location = 1) in vec2 v_screen_uv; ///< 屏幕空间 UV用于采样源纹理
layout(location = 0) out vec4 frag_color;
@@ -67,7 +62,8 @@ vec3 blend_overlay(vec3 base, vec3 blend) {
}
void main() {
vec2 source_uv = v_screen_pos / pc.viewport_size;
// 使用 v_screen_uv 采样源纹理backdrop 模式)
vec2 source_uv = v_screen_uv;
vec4 original = texture(u_source_texture, source_uv);
vec3 result = original.rgb;

View File

@@ -1,30 +1,25 @@
#version 450 core
// ============================================================================
// 通用输入
// ============================================================================
// ============================================================================
// Push Constants双阶段布局
// Push Constants (简化布局)
// ============================================================================
//
// 布局说明 (128 bytes):
// [0-15] Header: scale + translate (顶点着色器使用)
// [16-51] 顶点阶段 Custom: effect_rect(16) + original_effect_rect(16) + intensity(4) (顶点着色器使用)
// [52-127] 片元阶段 Custom: 效果参数 (本着色器使用)
// [0-15] Header: scale + translate
// [16-19] intensity (float)
// [20-23] time (float) - 用于动画噪点
//
// 注意:顶点和片元着色器共享相同的 Push Constants 布局
// ============================================================================
layout(push_constant) uniform PushConstants {
// Header (16 bytes) [offset 0-15] - 可选声明,片元着色器可能不使用
vec2 scale; ///< 缩放因子 (2/width, 2/height)
vec2 translate; ///< 平移因子 (-1, -1)
// Header (16 bytes) [offset 0-15]
vec2 scale; ///< 缩放因子
vec2 translate; ///< 平移因子
// === 片元阶段专用参数 (从 offset 52 开始) ===
// 注意:跳过顶点阶段的 effect_rect(16) + original_effect_rect(16) + intensity(4) = 36 bytes [offset 16-51]
layout(offset = 52) float intensity; ///< [52-55] 效果强度
vec2 viewport_size; ///< [56-63] 视口大小(用于 UV 计算)
float time; ///< [64-67] 时间(用于动画噪点)
// 用户自定义数据 (112 bytes) [offset 16-127]
float intensity; ///< [16-19] 效果强度
float time; ///< [20-23] 时间(用于动画噪点)
// 可扩展更多用户数据...
} pc;
@@ -35,8 +30,9 @@ layout(set = 0, binding = 1) uniform NoiseParams {
int animated; ///< 是否动画
} noise;
layout(location = 0) in vec2 v_uv;
layout(location = 1) in vec2 v_screen_pos;
// 来自顶点着色器
layout(location = 0) in vec2 v_uv; ///< 控件局部 UV [0,1]
layout(location = 1) in vec2 v_screen_uv; ///< 屏幕空间 UV用于采样源纹理
layout(location = 0) out vec4 frag_color;
@@ -50,11 +46,14 @@ float random(vec2 st) {
}
void main() {
vec2 source_uv = v_screen_pos / pc.viewport_size;
// 使用 v_screen_uv 采样源纹理backdrop 模式)
vec2 source_uv = v_screen_uv;
vec4 original = texture(u_source_texture, source_uv);
// 计算噪点坐标
vec2 noise_uv = v_screen_pos / noise.grain_size;
// 计算噪点坐标(使用 v_uv 局部坐标计算噪点)
vec2 tex_size = vec2(textureSize(u_source_texture, 0));
vec2 pixel_pos = v_screen_uv * tex_size;
vec2 noise_uv = pixel_pos / noise.grain_size;
// 如果启用动画,添加时间偏移
float time_offset = noise.animated != 0 ? pc.time : 0.0;

View File

@@ -1,29 +1,23 @@
#version 450 core
// ============================================================================
// 通用输入
// ============================================================================
// ============================================================================
// Push Constants双阶段布局
// Push Constants (简化布局)
// ============================================================================
//
// 布局说明 (128 bytes):
// [0-15] Header: scale + translate (顶点着色器使用)
// [16-51] 顶点阶段 Custom: effect_rect(16) + original_effect_rect(16) + intensity(4) (顶点着色器使用)
// [52-127] 片元阶段 Custom: 效果参数 (本着色器使用)
// [0-15] Header: scale + translate
// [16-19] intensity (float)
//
// 注意:顶点和片元着色器共享相同的 Push Constants 布局
// ============================================================================
layout(push_constant) uniform PushConstants {
// Header (16 bytes) [offset 0-15] - 可选声明,片元着色器可能不使用
vec2 scale; ///< 缩放因子 (2/width, 2/height)
vec2 translate; ///< 平移因子 (-1, -1)
// Header (16 bytes) [offset 0-15]
vec2 scale; ///< 缩放因子
vec2 translate; ///< 平移因子
// === 片元阶段专用参数 (从 offset 52 开始) ===
// 注意:跳过顶点阶段的 effect_rect(16) + original_effect_rect(16) + intensity(4) = 36 bytes [offset 16-51]
layout(offset = 52) float intensity; ///< [52-55] 效果强度
vec2 viewport_size; ///< [56-63] 视口大小(用于 UV 计算)
// 用户自定义数据 (112 bytes) [offset 16-127]
float intensity; ///< [16-19] 效果强度
// 可扩展更多用户数据...
} pc;
@@ -34,8 +28,9 @@ layout(set = 0, binding = 1) uniform VignetteParams {
vec4 tint_color; ///< 暗角颜色
} vignette;
layout(location = 0) in vec2 v_uv;
layout(location = 1) in vec2 v_screen_pos;
// 来自顶点着色器
layout(location = 0) in vec2 v_uv; ///< 控件局部 UV [0,1]
layout(location = 1) in vec2 v_screen_uv; ///< 屏幕空间 UV用于采样源纹理
layout(location = 0) out vec4 frag_color;
@@ -44,7 +39,8 @@ layout(location = 0) out vec4 frag_color;
// ============================================================================
void main() {
vec2 source_uv = v_screen_pos / pc.viewport_size;
// 使用 v_screen_uv 采样源纹理backdrop 模式)
vec2 source_uv = v_screen_uv;
vec4 original = texture(u_source_texture, source_uv);
// 计算到中心的距离(归一化)

View File

@@ -12,6 +12,11 @@
* 1: 右上 (1,0)
* 2: 左下 (0,1)
* 3: 右下 (1,1)
*
* 变换说明:
* C++ 端预先计算 scale/translate 以包含控件位置和大小信息:
* scale = vec2(widget_width * 2 / viewport_width, widget_height * 2 / viewport_height)
* translate = vec2(-1 + widget_x * 2 / viewport_width, -1 + widget_y * 2 / viewport_height)
*/
// ============================================================================
@@ -20,20 +25,20 @@
layout(push_constant) uniform PushConstants {
// 基础变换 (16 bytes) [offset 0-15]
vec2 scale; ///< 缩放因子 (2/width, 2/height)
vec2 translate; ///< 平移因子 (-1, -1)
// 已预计算包含控件位置和大小信息
vec2 scale; ///< 缩放因子 (widget_size * 2 / viewport_size)
vec2 translate; ///< 平移因子 (-1 + widget_pos * 2 / viewport_size)
// 用户自定义数据 (112 bytes) [offset 16-127]
vec2 widget_pos; ///< 控件位置: x, y
vec2 widget_size; ///< 控件尺寸: width, height
// 可扩展更多用户数据...
// 可由片元着色器自由使用...
} pc;
// ============================================================================
// 输出到片段着色器(标准化接口)
// ============================================================================
layout(location = 0) out vec2 v_uv; ///< [0,1] 标准化 UV 坐标
layout(location = 0) out vec2 v_uv; ///< [0,1] 标准化 UV 坐标(控件局部)
layout(location = 1) out vec2 v_screen_uv; ///< [0,1] 屏幕空间 UV用于采样源纹理/backdrop
// ============================================================================
// 常量定义
@@ -61,13 +66,14 @@ void main() {
// 获取标准化局部坐标 [0,1]
vec2 local_pos = QUAD_POSITIONS[quad_vertex];
// 计算屏幕空间位置用于 NDC 转换
vec2 screen_pos = pc.widget_pos + local_pos * pc.widget_size;
// 输出 UV 坐标(与局部坐标相同)
// 输出局部 UV 坐标(用于效果计算)
v_uv = local_pos;
// 换到 NDC使用简化的 scale/translate 变换
vec2 ndc = screen_pos * pc.scale + pc.translate;
// 直接变换到 NDCscale/translate 已预计算包含控件位置和大小
vec2 ndc = local_pos * pc.scale + pc.translate;
gl_Position = vec4(ndc, 0.0, 1.0);
// 输出屏幕空间 UV用于采样源纹理/backdrop
// NDC [-1, 1] -> UV [0, 1]
v_screen_uv = (ndc + 1.0) * 0.5;
}

View File

@@ -18,27 +18,25 @@
*/
// ============================================================================
// Push Constants(双阶段布局
// Push Constants (简化布局)
// ============================================================================
//
// 布局说明 (128 bytes):
// [0-15] Header: scale + translate (顶点着色器使用)
// [16-31] 顶点阶段 Custom: widget_pos + widget_size (顶点着色器使用)
// [32-127] 片元阶段 Custom: 效果参数 (本着色器使用)
// [0-15] Header: scale + translate (顶点着色器使用,已预计算控件位置/大小)
// [16-127] 用户自定义数据: 效果参数 (本着色器使用)
//
// ============================================================================
layout(push_constant) uniform PushConstants {
// Header (16 bytes) [offset 0-15] - 可选声明,片元着色器可能不使用
vec2 scale; ///< 缩放因子 (2/width, 2/height)
vec2 translate; ///< 平移因子 (-1, -1)
// Header (16 bytes) [offset 0-15]
vec2 scale; ///< 缩放因子 (已预计算包含控件信息)
vec2 translate; ///< 平移因子 (已预计算包含控件信息)
// === 片元阶段专用参数 (从 offset 32 开始) ===
// 注意:跳过顶点阶段的 widget_pos(8) + widget_size(8) = 16 bytes [offset 16-31]
layout(offset = 32) float intensity; ///< [32-35] 故障强度
float scan_line_freq; ///< [36-39] 扫描线频率
float noise_amount; ///< [40-43] 噪声量
float time; ///< [44-47] 时间(用于动画效果)
// 用户自定义数据 (112 bytes) [offset 16-127]
float intensity; ///< [16-19] 故障强度
float scan_line_freq; ///< [20-23] 扫描线频率
float noise_amount; ///< [24-27] 噪声量
float time; ///< [28-31] 时间(用于动画效果)
// 可扩展更多用户数据...
} pc;

View File

@@ -18,28 +18,26 @@
*/
// ============================================================================
// Push Constants(双阶段布局
// Push Constants (简化布局)
// ============================================================================
//
// 布局说明 (128 bytes):
// [0-15] Header: scale + translate (顶点着色器使用)
// [16-31] 顶点阶段 Custom: widget_pos + widget_size (顶点着色器使用)
// [32-127] 片元阶段 Custom: 效果参数 (本着色器使用)
// [0-15] Header: scale + translate (顶点着色器使用,已预计算控件位置/大小)
// [16-127] 用户自定义数据: 效果参数 (本着色器使用)
//
// ============================================================================
layout(push_constant) uniform PushConstants {
// Header (16 bytes) [offset 0-15] - 可选声明,片元着色器可能不使用
vec2 scale; ///< 缩放因子 (2/width, 2/height)
vec2 translate; ///< 平移因子 (-1, -1)
// Header (16 bytes) [offset 0-15]
vec2 scale; ///< 缩放因子 (已预计算包含控件信息)
vec2 translate; ///< 平移因子 (已预计算包含控件信息)
// === 片元阶段专用参数 (从 offset 32 开始) ===
// 注意:跳过顶点阶段的 widget_pos(8) + widget_size(8) = 16 bytes [offset 16-31]
layout(offset = 32) vec4 base_color; ///< [32-47] 次色/结束颜色 (r, g, b, a)
float frequency; ///< [48-51] 波浪频率
float amplitude; ///< [52-55] 波浪振幅
float speed; ///< [56-59] 波浪速度
float time; ///< [60-63] 时间(用于动画效果)
// 用户自定义数据 (112 bytes) [offset 16-127]
vec4 base_color; ///< [16-31] 次色/结束颜色 (r, g, b, a)
float frequency; ///< [32-35] 波浪频率
float amplitude; ///< [36-39] 波浪振幅
float speed; ///< [40-43] 波浪速度
float time; ///< [44-47] 时间(用于动画效果)
// 可扩展更多用户数据...
} pc;

View File

@@ -310,6 +310,9 @@ namespace mirage {
// 渲染实现
// ============================================================================
// [DEBUG] 静态变量用于首帧诊断
static bool first_frame_logged = false;
auto render_pipeline::render_window_impl(
window_render_context& window,
const render_tree& tree,
@@ -333,6 +336,11 @@ namespace mirage {
// 获取窗口独立的帧索引用于窗口相关资源fence、命令缓冲、描述符池
uint32_t frame_index = window.get_current_frame();
// [DEBUG] 首帧诊断日志
if (!first_frame_logged) {
std::cout << "[DEBUG-首帧] render_window_impl 开始, frame_index=" << frame_index << std::endl;
}
// 1. 等待帧栅栏(使用窗口独立的帧栅栏)
if (!window.wait_for_frame(frame_index)) {
@@ -367,6 +375,12 @@ namespace mirage {
return std::unexpected(render_error::image_acquisition_failed);
}
uint32_t image_index = *maybe_image_index;
// [DEBUG] 首帧诊断日志
if (!first_frame_logged) {
std::cout << "[DEBUG-首帧] acquire_next_image 成功, image_index=" << image_index
<< ", swapchain_image_count=" << window.get_swapchain().get_image_count() << std::endl;
}
// 重置帧栅栏(使用窗口独立的帧栅栏)
window.reset_frame_fence(frame_index);
@@ -516,6 +530,13 @@ namespace mirage {
.linear_sampler = shared_resources_->get_blit_sampler()
};
// [DEBUG] 首帧渲染树诊断
if (!first_frame_logged) {
std::cout << "[DEBUG-TREE] 渲染树空=" << (tree.empty() ? "true" : "false")
<< ", viewport_size: " << viewport_size.x() << "x" << viewport_size.y()
<< ", use_full_render: " << (use_full_render ? "true" : "false") << std::endl;
}
auto* tree_executor = shared_resources_->get_tree_executor();
tree_executor->execute(tree, exec_ctx);
@@ -578,7 +599,20 @@ namespace mirage {
}
// 23. Present
// [DEBUG] 首帧诊断日志
if (!first_frame_logged) {
std::cout << "[DEBUG-首帧] 即将 Present, image_index=" << image_index
<< ", frame_index=" << frame_index << std::endl;
}
auto present_result = window.present(device_.get_present_queue(), image_index);
// [DEBUG] 首帧诊断日志
if (!first_frame_logged) {
std::cout << "[DEBUG-首帧] Present 完成, result=" << vk::to_string(present_result) << std::endl;
first_frame_logged = true;
}
if (present_result == vk::Result::eErrorOutOfDateKHR ||
present_result == vk::Result::eSuboptimalKHR) {
return std::unexpected(render_error::swapchain_out_of_date);
@@ -597,6 +631,9 @@ namespace mirage {
// Blit 到 Swapchain
// ============================================================================
// [DEBUG] 静态变量用于 blit 诊断
static bool blit_first_frame_logged = false;
void render_pipeline::blit_to_swapchain(
frame_context<swapchain_pass_tag>& ctx,
window_render_context& window,
@@ -610,6 +647,15 @@ namespace mirage {
// 设置视口和裁剪
auto extent = window.get_extent();
// [DEBUG] 首帧 blit 诊断
if (!blit_first_frame_logged) {
auto& offscreen = window.get_offscreen();
auto offscreen_extent = offscreen.extent();
std::cout << "[DEBUG-BLIT] 首帧 blit - window extent: " << extent.width << "x" << extent.height
<< ", offscreen extent: " << offscreen_extent.width << "x" << offscreen_extent.height
<< ", offscreen state: " << static_cast<int>(offscreen.current_state()) << std::endl;
}
vk::Viewport viewport{};
viewport.x = 0.0f;
@@ -666,6 +712,12 @@ namespace mirage {
}
}
// [DEBUG] 首帧 blit 完成
if (!blit_first_frame_logged) {
std::cout << "[DEBUG-BLIT] 首帧 blit draw 完成" << std::endl;
blit_first_frame_logged = true;
}
// 绘制全屏三角形
cmd.draw(3, 1, 0, 0);
}

View File

@@ -185,11 +185,14 @@ namespace mirage {
return false;
}
swapchain_ = std::make_unique<swapchain>(std::move(swapchain_result.value()));
std::cout << "[DEBUG-WRC] 首次创建 swapchain 完成, 请求尺寸: " << width << "x" << height << std::endl;
}
// 获取实际的 swapchain 尺寸
// 注意如果窗口最小化extent 可能为 (0, 0)
auto actual_extent = swapchain_->get_extent();
std::cout << "[DEBUG-WRC] swapchain 实际尺寸: " << actual_extent.width << "x" << actual_extent.height << std::endl;
if (actual_extent.width == 0 || actual_extent.height == 0) {
// 窗口最小化,跳过资源创建,视为成功
return true;
@@ -223,15 +226,16 @@ namespace mirage {
}
else {
// 首次创建离屏目标(必须启用深度/模板缓冲以匹配渲染器管线的 RenderPass
offscreen_ = std::make_unique<offscreen_target>(
*device_, *res_mgr_,
offscreen_target::config{
.enable_depth_stencil = true,
.depth_stencil_format = vk::Format::eD24UnormS8Uint
}
);
offscreen_->initialize(actual_extent.width, actual_extent.height);
}
offscreen_ = std::make_unique<offscreen_target>(
*device_, *res_mgr_,
offscreen_target::config{
.enable_depth_stencil = true,
.depth_stencil_format = vk::Format::eD24UnormS8Uint
}
);
offscreen_->initialize(actual_extent.width, actual_extent.height);
std::cout << "[DEBUG-WRC] 首次创建 offscreen target, 尺寸: " << actual_extent.width << "x" << actual_extent.height << std::endl;
}
// 创建 blit 描述符(如果尚未创建)
if (blit_descriptor_sets_.empty() && blit_desc_layout_) {
@@ -252,6 +256,13 @@ namespace mirage {
// 重置图像状态
reset_all_image_states();
// [修复] 首次创建时预初始化所有 swapchain 图像
// 在三缓冲模式下,窗口系统可能显示未被渲染的图像导致黑屏
// 通过预先 clear 所有图像来解决此问题
if (swapchain_) {
prewarm_swapchain_images();
}
return true;
}
@@ -886,4 +897,101 @@ namespace mirage {
surface_ = nullptr;
}
// ============================================================================
// 预热 swapchain 图像(解决三缓冲首帧黑屏问题)
// ============================================================================
auto window_render_context::prewarm_swapchain_images() -> void {
if (!device_ || !swapchain_ || !res_mgr_ || command_buffers_.empty()) {
return;
}
auto device_handle = device_->get_handle();
auto image_count = swapchain_->get_image_count();
auto extent = swapchain_->get_extent();
std::cout << "[WINDOW_RENDER_CONTEXT] 预热 " << image_count << " 张 swapchain 图像..." << std::endl;
// 获取 RenderPass使用 clear 模式,因为它接受 undefined 布局)
vk::RenderPass render_pass = get_swapchain_render_pass(true);
// 为每张图像执行一次 clear 操作
for (uint32_t i = 0; i < image_count; ++i) {
// 分配一个临时命令缓冲
vk::CommandBufferAllocateInfo alloc_info{};
alloc_info.commandPool = command_pool_.get();
alloc_info.level = vk::CommandBufferLevel::ePrimary;
alloc_info.commandBufferCount = 1;
auto [alloc_result, cmd_buffers] = device_handle.allocateCommandBuffers(alloc_info);
if (alloc_result != vk::Result::eSuccess || cmd_buffers.empty()) {
std::cerr << "[WINDOW_RENDER_CONTEXT] 预热失败:无法分配命令缓冲" << std::endl;
return;
}
auto cmd = cmd_buffers[0];
// 开始录制
vk::CommandBufferBeginInfo begin_info{};
begin_info.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit;
if (cmd.begin(begin_info) != vk::Result::eSuccess) {
device_handle.freeCommandBuffers(command_pool_.get(), cmd);
continue;
}
// 开始 RenderPass这会自动处理 undefined -> color attachment 的布局转换)
vk::RenderPassBeginInfo rp_begin{};
rp_begin.renderPass = render_pass;
rp_begin.framebuffer = framebuffers_[i].get();
rp_begin.renderArea.offset = vk::Offset2D{0, 0};
rp_begin.renderArea.extent = extent;
// 使用透明黑色 clear与正常渲染一致
vk::ClearValue clear_value{};
clear_value.color = vk::ClearColorValue{std::array<float, 4>{0.0f, 0.0f, 0.0f, 0.0f}};
rp_begin.clearValueCount = 1;
rp_begin.pClearValues = &clear_value;
cmd.beginRenderPass(rp_begin, vk::SubpassContents::eInline);
cmd.endRenderPass();
// 结束录制
if (cmd.end() != vk::Result::eSuccess) {
device_handle.freeCommandBuffers(command_pool_.get(), cmd);
continue;
}
// 创建临时 fence 用于同步
vk::FenceCreateInfo fence_info{};
auto [fence_result, fence] = device_handle.createFence(fence_info);
if (fence_result != vk::Result::eSuccess) {
device_handle.freeCommandBuffers(command_pool_.get(), cmd);
continue;
}
// 提交命令
vk::SubmitInfo submit_info{};
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &cmd;
auto submit_result = device_->get_graphics_queue().submit(1, &submit_info, fence);
if (submit_result != vk::Result::eSuccess) {
device_handle.destroyFence(fence);
device_handle.freeCommandBuffers(command_pool_.get(), cmd);
continue;
}
// 等待完成
(void)device_handle.waitForFences(1, &fence, VK_TRUE, UINT64_MAX);
// 清理
device_handle.destroyFence(fence);
device_handle.freeCommandBuffers(command_pool_.get(), cmd);
// 标记图像已初始化
mark_image_initialized(i);
}
std::cout << "[WINDOW_RENDER_CONTEXT] 预热完成" << std::endl;
}
} // namespace mirage

View File

@@ -299,6 +299,9 @@ namespace mirage {
/// 销毁 swapchain 相关资源Framebuffer、RenderPass
auto destroy_swapchain_resources() -> void;
/// 预热 swapchain 图像(解决三缓冲首帧黑屏问题)
auto prewarm_swapchain_images() -> void;
// =====================================================================
// 成员变量

View File

@@ -320,10 +320,32 @@ namespace mirage {
// ========================================
// Header [0-15]: scale + translate (16 字节)
// ========================================
// NDC = position * scale + translate
// 对于使用程序化四边形的模式procedural 和 post_process预计算包含控件位置和大小的 scale/translate
// scale = (widget_width * 2 / viewport_width, widget_height * 2 / viewport_height)
// translate = (-1 + widget_x * 2 / viewport_width, -1 + widget_y * 2 / viewport_height)
//
// 对于 custom_geometry 模式,使用标准的全局变换:
// scale = (2/width, 2/height)
// translate = (-1, -1)
pc->header = create_push_constants_header(viewport_size_.x(), viewport_size_.y());
if (command.render_mode == custom_shader_render_mode::procedural ||
command.render_mode == custom_shader_render_mode::post_process ||
command.render_mode == custom_shader_render_mode::mask) {
// 程序化四边形模式:预计算控件的 NDC 变换
// 顶点着色器将使用 local_pos * scale + translate 来生成 NDC
float scale_x = command.size.x() * 2.0f / viewport_size_.x();
float scale_y = command.size.y() * 2.0f / viewport_size_.y();
float translate_x = -1.0f + command.position.x() * 2.0f / viewport_size_.x();
float translate_y = -1.0f + command.position.y() * 2.0f / viewport_size_.y();
pc->header.scale[0] = scale_x;
pc->header.scale[1] = scale_y;
pc->header.translate[0] = translate_x;
pc->header.translate[1] = translate_y;
}
else {
// custom_geometry 模式:使用标准的全局变换(顶点数据已包含屏幕坐标)
pc->header = create_push_constants_header(viewport_size_.x(), viewport_size_.y());
}
// ========================================
// Custom [16-127]: 用户自定义数据 (112 字节)
@@ -340,11 +362,8 @@ namespace mirage {
}
else {
// ========================================
// 单一模式(向后兼容)
// 简化模式:用户数据直接从 offset 16 开始
// ========================================
// 布局:
// [16-31]: 几何信息 (widget_pos + widget_size) - 16 字节,顶点着色器必需
// [32-127]: 用户自定义数据 - 96 字节
fill_legacy_push_constants(command, pc);
}
}
@@ -353,26 +372,17 @@ namespace mirage {
const custom_shader_widget_command& command,
custom_shader_push_constants* pc) const {
// ========================================
// 单一模式布局(向后兼容)
// [16-31]: 几何信息 (widget_pos + widget_size) - 16 字节
// [32-127]: 用户自定义数据 - 96 字节
// 简化布局:用户数据直接从 offset 16 开始
// [16-127]: 用户自定义数据 - 112 字节
// ========================================
// 注意widget_pos 和 widget_size 已通过 scale/translate 预计算
// 不再需要在 custom_data 中传递几何信息
// 1. 填充几何信息(顶点着色器 custom_shader_quad_procedural.vert.glsl 必需)
float* geo_data = reinterpret_cast<float*>(pc->custom_data);
geo_data[0] = command.position.x(); // widget_pos.x at offset 16
geo_data[1] = command.position.y(); // widget_pos.y at offset 20
geo_data[2] = command.size.x(); // widget_size.x at offset 24
geo_data[3] = command.size.y(); // widget_size.y at offset 28
// 2. 复制用户数据(从 offset 32 开始,留出 16 字节给几何信息)
constexpr size_t GEO_INFO_SIZE = 16; // widget_pos(8) + widget_size(8)
constexpr size_t USER_DATA_OFFSET = GEO_INFO_SIZE;
constexpr size_t MAX_USER_DATA_SIZE = PUSH_CONSTANT_CUSTOM_MAX_SIZE - GEO_INFO_SIZE; // 96 bytes
// 直接复制用户数据到 offset 16
if (command.push_constant_data && command.push_constant_size > 0) {
size_t copy_size = std::min(static_cast<size_t>(command.push_constant_size), MAX_USER_DATA_SIZE);
std::memcpy(pc->custom_data + USER_DATA_OFFSET, command.push_constant_data, copy_size);
size_t copy_size = std::min(static_cast<size_t>(command.push_constant_size),
static_cast<size_t>(PUSH_CONSTANT_CUSTOM_MAX_SIZE));
std::memcpy(pc->custom_data, command.push_constant_data, copy_size);
}
}

View File

@@ -265,14 +265,12 @@ namespace mirage {
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
return capabilities.currentExtent;
}
else {
vk::Extent2D actual_extent = {width, height};
actual_extent.width = std::clamp(actual_extent.width, capabilities.minImageExtent.width,
capabilities.maxImageExtent.width);
actual_extent.height = std::clamp(actual_extent.height, capabilities.minImageExtent.height,
capabilities.maxImageExtent.height);
return actual_extent;
}
vk::Extent2D actual_extent = {width, height};
actual_extent.width = std::clamp(actual_extent.width, capabilities.minImageExtent.width,
capabilities.maxImageExtent.width);
actual_extent.height = std::clamp(actual_extent.height, capabilities.minImageExtent.height,
capabilities.maxImageExtent.height);
return actual_extent;
}
auto swapchain::create(

View File

@@ -111,6 +111,9 @@ namespace mirage {
auto fb_size = window_->get_framebuffer_size();
current_width_ = static_cast<uint32_t>(fb_size.x());
current_height_ = static_cast<uint32_t>(fb_size.y());
std::cout << "[DEBUG-INIT] 窗口配置尺寸: " << config.width << "x" << config.height
<< ", 帧缓冲尺寸: " << fb_size.x() << "x" << fb_size.y() << std::endl;
// ========================================================================
// 3. 注册窗口到渲染管线
@@ -284,6 +287,9 @@ namespace mirage {
}
}
// [DEBUG] 静态变量用于首帧诊断
static bool render_first_frame_logged = false;
void render_window::render() {
auto* coordinator = context_provider_.get_thread_coordinator();
if (!coordinator || !root_widget_) {
@@ -291,6 +297,12 @@ namespace mirage {
<< ", root_widget=" << root_widget_.get() << std::endl;
return;
}
// [DEBUG] 首帧诊断日志
if (!render_first_frame_logged) {
std::cout << "[DEBUG-RENDER] 首帧渲染 - current_size: " << current_width_ << "x" << current_height_
<< std::endl;
}
// 检查是否真的需要渲染(基于脏控件计数)
// 只有当有脏控件、或有待处理字形、或需要完全重绘时才提交帧
@@ -314,6 +326,13 @@ namespace mirage {
// 统一使用多线程模式提交帧(传递 shared_ptr 确保布局期间有效)
coordinator->submit_frame(win_id, root_widget_, viewport_size);
// [DEBUG] 首帧诊断日志
if (!render_first_frame_logged) {
std::cout << "[DEBUG-RENDER] 提交帧完成 - viewport_size: " << viewport_size.x() << "x" << viewport_size.y()
<< std::endl;
render_first_frame_logged = true;
}
// 提交后重置完全重绘标记
needs_full_redraw_ = false;