添加着色器绑定代码使用方式检查
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
||||
[submodule "nvapi/sdk"]
|
||||
path = nvapi/sdk
|
||||
url = https://github.com/NVIDIA/nvapi.git
|
||||
[submodule "nvapi/sdk/nvapi"]
|
||||
path = nvapi/sdk/nvapi
|
||||
url = https://github.com/NVIDIA/nvapi.git
|
||||
|
||||
1043
plans/push_constant_base_static_check_design.md
Normal file
1043
plans/push_constant_base_static_check_design.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,92 +0,0 @@
|
||||
#version 450 core
|
||||
|
||||
/**
|
||||
* @brief 高斯模糊效果片段着色器
|
||||
*
|
||||
* 实现单次 pass 的高斯模糊效果。
|
||||
* 注意:当前实现采用单次 pass 的简化模糊(非分离式),
|
||||
* 分离式模糊需要两次渲染 pass(水平+垂直)以获得更好的性能和质量。
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// Uniform Buffer
|
||||
// ============================================================================
|
||||
|
||||
layout(set = 0, binding = 0) uniform BlurParams {
|
||||
float radius; ///< 模糊半径(像素)
|
||||
float intensity; ///< 效果强度 [0, 1]
|
||||
vec2 direction; ///< 模糊方向(用于分离式模糊)
|
||||
int padding; ///< 对齐填充
|
||||
} params;
|
||||
|
||||
// ============================================================================
|
||||
// 输入
|
||||
// ============================================================================
|
||||
|
||||
layout(location = 0) in vec2 v_uv; ///< 标准化 UV 坐标 [0, 1]
|
||||
|
||||
// ============================================================================
|
||||
// 纹理采样(后处理模式)
|
||||
// ============================================================================
|
||||
|
||||
layout(set = 0, binding = 1) uniform sampler2D source_texture;
|
||||
|
||||
// ============================================================================
|
||||
// 输出
|
||||
// ============================================================================
|
||||
|
||||
layout(location = 0) out vec4 out_color; ///< 最终颜色输出
|
||||
|
||||
// ============================================================================
|
||||
// 辅助函数
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 高斯权重计算
|
||||
* @param x 距离中心的偏移量
|
||||
* @param sigma 标准差
|
||||
* @return 高斯权重值
|
||||
*/
|
||||
float gaussian(float x, float sigma) {
|
||||
return exp(-(x * x) / (2.0 * sigma * sigma));
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 主函数
|
||||
// ============================================================================
|
||||
|
||||
void main() {
|
||||
vec2 uv = v_uv;
|
||||
|
||||
// 获取纹理尺寸和像素大小
|
||||
vec2 tex_size = vec2(textureSize(source_texture, 0));
|
||||
vec2 texel_size = 1.0 / tex_size;
|
||||
|
||||
// 采样源纹理
|
||||
vec4 original = texture(source_texture, uv);
|
||||
|
||||
// 计算高斯模糊 sigma(使用 3σ 原则)
|
||||
float sigma = params.radius / 3.0;
|
||||
|
||||
// 计算采样范围
|
||||
int half_samples = int(params.radius);
|
||||
|
||||
// 限制采样次数以防性能过低
|
||||
if (half_samples > 32) half_samples = 32;
|
||||
|
||||
// 单次 pass 简化模糊(仅使用一个方向)
|
||||
vec4 result = vec4(0.0);
|
||||
float total_weight = 0.0;
|
||||
|
||||
for (int i = -half_samples; i <= half_samples; ++i) {
|
||||
float weight = gaussian(float(i), sigma);
|
||||
vec2 offset = params.direction * float(i) * texel_size;
|
||||
result += texture(source_texture, uv + offset) * weight;
|
||||
total_weight += weight;
|
||||
}
|
||||
|
||||
vec4 blurred = result / total_weight;
|
||||
|
||||
// 根据强度混合原始颜色和模糊效果
|
||||
out_color = mix(original, blurred, params.intensity);
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
#version 450 core
|
||||
|
||||
/**
|
||||
* @brief 色差效果片段着色器
|
||||
*
|
||||
* 实现 RGB 通道分离偏移效果,模拟透镜色散特性。
|
||||
* 用于后处理模式,对源纹理应用效果。
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// Uniform Buffer
|
||||
// ============================================================================
|
||||
|
||||
layout(set = 0, binding = 0) uniform ChromaticAberrationParams {
|
||||
vec2 offset; ///< RGB 通道偏移量(归一化坐标)
|
||||
float intensity; ///< 效果强度 [0, 1]
|
||||
float padding[2]; ///< 对齐填充
|
||||
} params;
|
||||
|
||||
// ============================================================================
|
||||
// 输入
|
||||
// ============================================================================
|
||||
|
||||
layout(location = 0) in vec2 v_uv; ///< 标准化 UV 坐标 [0, 1]
|
||||
|
||||
// ============================================================================
|
||||
// 纹理采样(后处理模式)
|
||||
// ============================================================================
|
||||
|
||||
layout(set = 0, binding = 1) uniform sampler2D source_texture;
|
||||
|
||||
// ============================================================================
|
||||
// 输出
|
||||
// ============================================================================
|
||||
|
||||
layout(location = 0) out vec4 out_color; ///< 最终颜色输出
|
||||
|
||||
// ============================================================================
|
||||
// 主函数
|
||||
// ============================================================================
|
||||
|
||||
void main() {
|
||||
vec2 uv = v_uv;
|
||||
|
||||
// 计算从中心到当前像素的方向和距离
|
||||
vec2 center = vec2(0.5);
|
||||
vec2 dir = normalize(uv - center);
|
||||
float dist = length(uv - center);
|
||||
|
||||
// 计算偏移(从中心向外增强)
|
||||
vec2 offset_scaled = params.offset * dist * params.intensity;
|
||||
|
||||
// 分离采样 RGB 通道
|
||||
// R 通道向外偏移,B 通道向内偏移
|
||||
float r = texture(source_texture, uv + dir * offset_scaled).r;
|
||||
float g = texture(source_texture, uv).g;
|
||||
float b = texture(source_texture, uv - dir * offset_scaled).b;
|
||||
|
||||
// 保持原始 alpha
|
||||
float a = texture(source_texture, uv).a;
|
||||
|
||||
out_color = vec4(r, g, b, a);
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
#version 450 core
|
||||
|
||||
/**
|
||||
* @brief 颜色调整片段着色器
|
||||
*
|
||||
* 实现亮度、对比度、饱和度和伽马调整效果。
|
||||
* 用于后处理模式,对源纹理应用效果。
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// Uniform Buffer
|
||||
// ============================================================================
|
||||
|
||||
layout(set = 0, binding = 0) uniform ColorAdjustParams {
|
||||
float brightness; ///< 亮度 [-1, 1]
|
||||
float contrast; ///< 对比度 [0, 2]
|
||||
float saturation; ///< 饱和度 [0, 2]
|
||||
float gamma; ///< 伽马 [0.1, 3]
|
||||
} params;
|
||||
|
||||
// ============================================================================
|
||||
// 输入
|
||||
// ============================================================================
|
||||
|
||||
layout(location = 0) in vec2 v_uv; ///< 标准化 UV 坐标 [0, 1]
|
||||
|
||||
// ============================================================================
|
||||
// 纹理采样(后处理模式)
|
||||
// ============================================================================
|
||||
|
||||
layout(set = 0, binding = 1) uniform sampler2D source_texture;
|
||||
|
||||
// ============================================================================
|
||||
// 输出
|
||||
// ============================================================================
|
||||
|
||||
layout(location = 0) out vec4 out_color; ///< 最终颜色输出
|
||||
|
||||
// ============================================================================
|
||||
// 主函数
|
||||
// ============================================================================
|
||||
|
||||
void main() {
|
||||
vec2 uv = v_uv;
|
||||
|
||||
// 采样源纹理
|
||||
vec4 original = texture(source_texture, uv);
|
||||
vec3 c = original.rgb;
|
||||
|
||||
// 亮度调整
|
||||
c += params.brightness;
|
||||
|
||||
// 对比度调整
|
||||
c = (c - 0.5) * params.contrast + 0.5;
|
||||
|
||||
// 饱和度调整
|
||||
float luminance = dot(c, vec3(0.299, 0.587, 0.114));
|
||||
c = mix(vec3(luminance), c, params.saturation);
|
||||
|
||||
// 伽马校正
|
||||
c = pow(max(c, vec3(0.0)), vec3(1.0 / params.gamma));
|
||||
|
||||
// 保持 alpha
|
||||
out_color = vec4(c, original.a);
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
#version 450 core
|
||||
|
||||
/**
|
||||
* @brief 色调映射片段着色器
|
||||
*
|
||||
* 实现多种混合模式的色调映射效果。
|
||||
* 用于后处理模式,对源纹理应用效果。
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// Uniform Buffer
|
||||
// ============================================================================
|
||||
|
||||
layout(set = 0, binding = 0) uniform ColorTintParams {
|
||||
vec4 tint_color; ///< 色调颜色 [r, g, b, a]
|
||||
int blend_mode; ///< 混合模式 (0=normal, 1=additive, 2=multiply, 3=screen, 4=overlay)
|
||||
float intensity; ///< 效果强度 [0, 1]
|
||||
float padding; ///< 对齐填充
|
||||
} params;
|
||||
|
||||
// ============================================================================
|
||||
// 输入
|
||||
// ============================================================================
|
||||
|
||||
layout(location = 0) in vec2 v_uv; ///< 标准化 UV 坐标 [0, 1]
|
||||
|
||||
// ============================================================================
|
||||
// 纹理采样(后处理模式)
|
||||
// ============================================================================
|
||||
|
||||
layout(set = 0, binding = 1) uniform sampler2D source_texture;
|
||||
|
||||
// ============================================================================
|
||||
// 输出
|
||||
// ============================================================================
|
||||
|
||||
layout(location = 0) out vec4 out_color; ///< 最终颜色输出
|
||||
|
||||
// ============================================================================
|
||||
// 混合函数
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 正常混合
|
||||
*/
|
||||
vec3 blend_normal(vec3 base, vec3 blend) {
|
||||
return blend;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 加法混合
|
||||
*/
|
||||
vec3 blend_additive(vec3 base, vec3 blend) {
|
||||
return base + blend;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 正片叠底混合
|
||||
*/
|
||||
vec3 blend_multiply(vec3 base, vec3 blend) {
|
||||
return base * blend;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 滤色混合
|
||||
*/
|
||||
vec3 blend_screen(vec3 base, vec3 blend) {
|
||||
return 1.0 - (1.0 - base) * (1.0 - blend);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 叠加混合
|
||||
*/
|
||||
vec3 blend_overlay(vec3 base, vec3 blend) {
|
||||
return mix(
|
||||
2.0 * base * blend,
|
||||
1.0 - 2.0 * (1.0 - base) * (1.0 - blend),
|
||||
step(0.5, base)
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 主函数
|
||||
// ============================================================================
|
||||
|
||||
void main() {
|
||||
vec2 uv = v_uv;
|
||||
|
||||
// 采样源纹理
|
||||
vec4 original = texture(source_texture, uv);
|
||||
vec3 result = original.rgb;
|
||||
vec3 tint_rgb = params.tint_color.rgb;
|
||||
float tint_alpha = params.tint_color.a * params.intensity;
|
||||
|
||||
// 根据混合模式处理
|
||||
switch (params.blend_mode) {
|
||||
case 0: // Normal
|
||||
result = mix(result, tint_rgb, tint_alpha);
|
||||
break;
|
||||
case 1: // Additive
|
||||
result = blend_additive(result, tint_rgb * tint_alpha);
|
||||
break;
|
||||
case 2: // Multiply
|
||||
result = mix(result, blend_multiply(result, tint_rgb), tint_alpha);
|
||||
break;
|
||||
case 3: // Screen
|
||||
result = mix(result, blend_screen(result, tint_rgb), tint_alpha);
|
||||
break;
|
||||
case 4: // Overlay
|
||||
result = mix(result, blend_overlay(result, tint_rgb), tint_alpha);
|
||||
break;
|
||||
default:
|
||||
result = mix(result, tint_rgb, tint_alpha);
|
||||
break;
|
||||
}
|
||||
|
||||
// 保持 alpha
|
||||
out_color = vec4(result, original.a);
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
#version 450 core
|
||||
|
||||
/**
|
||||
* @brief 噪点效果片段着色器
|
||||
*
|
||||
* 实现电影胶片噪点效果,可选择静态或动态(动画)噪点。
|
||||
* 用于后处理模式,对源纹理应用效果。
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// Uniform Buffer
|
||||
// ============================================================================
|
||||
|
||||
layout(set = 0, binding = 0) uniform NoiseParams {
|
||||
float amount; ///< 噪点强度 [0, 1]
|
||||
float grain_size; ///< 颗粒大小 [0.5, 5.0]
|
||||
int animated; ///< 是否启用动画
|
||||
float time; ///< 时间参数(用于动画)
|
||||
} params;
|
||||
|
||||
// ============================================================================
|
||||
// 输入
|
||||
// ============================================================================
|
||||
|
||||
layout(location = 0) in vec2 v_uv; ///< 标准化 UV 坐标 [0, 1]
|
||||
|
||||
// ============================================================================
|
||||
// 纹理采样(后处理模式)
|
||||
// ============================================================================
|
||||
|
||||
layout(set = 0, binding = 1) uniform sampler2D source_texture;
|
||||
|
||||
// ============================================================================
|
||||
// 输出
|
||||
// ============================================================================
|
||||
|
||||
layout(location = 0) out vec4 out_color; ///< 最终颜色输出
|
||||
|
||||
// ============================================================================
|
||||
// 辅助函数
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 简单的伪随机数生成器
|
||||
* @param st 二维输入坐标
|
||||
* @return 归一化的随机值 [0, 1]
|
||||
*/
|
||||
float random(vec2 st) {
|
||||
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 主函数
|
||||
// ============================================================================
|
||||
|
||||
void main() {
|
||||
vec2 uv = v_uv;
|
||||
|
||||
// 采样源纹理
|
||||
vec4 original = texture(source_texture, uv);
|
||||
|
||||
// 计算噪点坐标(根据颗粒大小缩放)
|
||||
vec2 noise_uv = uv / params.grain_size;
|
||||
|
||||
// 如果启用动画,添加时间偏移使噪点动态变化
|
||||
float time_offset = (params.animated != 0) ? params.time : 0.0;
|
||||
|
||||
// 生成噪点 [0, 1]
|
||||
float noise = random(noise_uv + time_offset);
|
||||
|
||||
// 混合噪点 - 使用叠加模式
|
||||
// 噪点值减去 0.5 使其范围变为 [-0.5, 0.5]
|
||||
vec3 noise_color = vec3(noise);
|
||||
vec3 result = original.rgb + (noise_color - 0.5) * params.amount;
|
||||
|
||||
// 根据强度混合原始颜色和噪点效果
|
||||
out_color = mix(original, vec4(result, original.a), 1.0);
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
#version 450 core
|
||||
|
||||
/**
|
||||
* @brief 暗角效果片段着色器
|
||||
*
|
||||
* 实现屏幕边缘暗角效果,模拟镜头光学特性。
|
||||
* 用于后处理模式,对源纹理应用效果。
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
// Uniform Buffer
|
||||
// ============================================================================
|
||||
|
||||
layout(set = 0, binding = 0) uniform VignetteParams {
|
||||
float radius; ///< 暗角半径 [0, 1]
|
||||
float softness; ///< 边缘柔和度 [0, 1]
|
||||
float intensity; ///< 效果强度 [0, 1]
|
||||
float padding; ///< 对齐填充
|
||||
vec4 tint_color; ///< 暗角颜色 [r, g, b, a]
|
||||
} params;
|
||||
|
||||
// ============================================================================
|
||||
// 输入
|
||||
// ============================================================================
|
||||
|
||||
layout(location = 0) in vec2 v_uv; ///< 标准化 UV 坐标 [0, 1]
|
||||
|
||||
// ============================================================================
|
||||
// 纹理采样(后处理模式)
|
||||
// ============================================================================
|
||||
|
||||
layout(set = 0, binding = 1) uniform sampler2D source_texture;
|
||||
|
||||
// ============================================================================
|
||||
// 输出
|
||||
// ============================================================================
|
||||
|
||||
layout(location = 0) out vec4 out_color; ///< 最终颜色输出
|
||||
|
||||
// ============================================================================
|
||||
// 主函数
|
||||
// ============================================================================
|
||||
|
||||
void main() {
|
||||
vec2 uv = v_uv;
|
||||
|
||||
// 采样源纹理
|
||||
vec4 original = texture(source_texture, uv);
|
||||
|
||||
// 计算到中心的距离(归一化到 [0, 1])
|
||||
vec2 center = vec2(0.5);
|
||||
float dist = length(uv - center) * 2.0; // [0, sqrt(2)]
|
||||
|
||||
// 计算暗角强度(smoothstep 实现柔和边缘)
|
||||
float vignette_factor = smoothstep(params.radius, params.radius + params.softness, dist);
|
||||
|
||||
// 应用暗角颜色
|
||||
vec4 vignetted = mix(original, params.tint_color, vignette_factor);
|
||||
|
||||
// 根据强度混合原始颜色和暗角效果
|
||||
out_color = mix(original, vignetted, params.intensity);
|
||||
}
|
||||
120
src/render/push_constant_traits.h
Normal file
120
src/render/push_constant_traits.h
Normal file
@@ -0,0 +1,120 @@
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
|
||||
namespace mirage {
|
||||
/**
|
||||
* @brief Concept: 验证布局是否包含 projection 成员
|
||||
*/
|
||||
template <typename Layout>
|
||||
concept has_projection_member = requires {
|
||||
{ Layout::has_projection } -> std::convertible_to<bool>;
|
||||
requires Layout::has_projection;
|
||||
{ Layout::projection_offset } -> std::convertible_to<size_t>;
|
||||
{ Layout::projection_size } -> std::convertible_to<size_t>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Concept: 验证布局是否包含 viewport_size 成员
|
||||
*/
|
||||
template <typename Layout>
|
||||
concept has_viewport_size_member = requires {
|
||||
{ Layout::has_viewport_size } -> std::convertible_to<bool>;
|
||||
requires Layout::has_viewport_size;
|
||||
{ Layout::viewport_size_offset } -> std::convertible_to<size_t>;
|
||||
{ Layout::viewport_size_size } -> std::convertible_to<size_t>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Concept: 验证布局是否包含 time 成员
|
||||
*/
|
||||
template <typename Layout>
|
||||
concept has_time_member = requires {
|
||||
{ Layout::has_time } -> std::convertible_to<bool>;
|
||||
requires Layout::has_time;
|
||||
{ Layout::time_offset } -> std::convertible_to<size_t>;
|
||||
{ Layout::time_size } -> std::convertible_to<size_t>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Concept: 验证是否为标准 Push Constant 基础布局
|
||||
*
|
||||
* 标准布局要求:
|
||||
* - projection: offset=0, size=64
|
||||
* - viewport_size: offset=64, size=8
|
||||
* - time: offset=72, size=4
|
||||
* - total_size=80
|
||||
*/
|
||||
template <typename Layout>
|
||||
concept standard_push_constant_base_layout =
|
||||
has_projection_member<Layout> &&
|
||||
has_viewport_size_member<Layout> &&
|
||||
has_time_member<Layout> &&
|
||||
requires {
|
||||
{ Layout::is_standard_layout } -> std::convertible_to<bool>;
|
||||
requires Layout::is_standard_layout;
|
||||
{ Layout::total_size } -> std::convertible_to<size_t>;
|
||||
requires Layout::total_size == 80;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Concept: 仅包含 projection 的布局(用于仅顶点着色器)
|
||||
*/
|
||||
template <typename Layout>
|
||||
concept projection_only_layout =
|
||||
has_projection_member<Layout> &&
|
||||
requires {
|
||||
requires Layout::projection_offset == 0;
|
||||
requires Layout::projection_size == 64;
|
||||
} &&
|
||||
(!has_viewport_size_member<Layout> || !Layout::has_viewport_size) &&
|
||||
(!has_time_member<Layout> || !Layout::has_time);
|
||||
|
||||
/**
|
||||
* @brief 编译期布局验证器
|
||||
*/
|
||||
template <typename Layout>
|
||||
struct push_constant_layout_validator {
|
||||
static constexpr bool has_projection =
|
||||
requires { { Layout::has_projection } -> std::convertible_to<bool>; } && Layout::has_projection;
|
||||
|
||||
static constexpr bool has_viewport_size =
|
||||
requires { { Layout::has_viewport_size } -> std::convertible_to<bool>; } && Layout::has_viewport_size;
|
||||
|
||||
static constexpr bool has_time =
|
||||
requires { { Layout::has_time } -> std::convertible_to<bool>; } && Layout::has_time;
|
||||
|
||||
static constexpr bool is_standard = standard_push_constant_base_layout<Layout>;
|
||||
|
||||
static constexpr bool is_projection_only = projection_only_layout<Layout>;
|
||||
|
||||
// 验证projection偏移量是否正确(如果存在)
|
||||
static constexpr bool projection_offset_valid =
|
||||
!has_projection || Layout::projection_offset == 0;
|
||||
|
||||
// 验证viewport_size偏移量是否正确(如果存在)
|
||||
static constexpr bool viewport_size_offset_valid =
|
||||
!has_viewport_size || Layout::viewport_size_offset == 64;
|
||||
|
||||
// 验证time偏移量是否正确(如果存在)
|
||||
static constexpr bool time_offset_valid =
|
||||
!has_time || Layout::time_offset == 72;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 用于约束需要标准布局的着色器规格
|
||||
*/
|
||||
template <typename ShaderSpec>
|
||||
concept shader_with_standard_push_constant = requires {
|
||||
typename ShaderSpec::push_constant_base_layout;
|
||||
} && standard_push_constant_base_layout<typename ShaderSpec::push_constant_base_layout>;
|
||||
|
||||
/**
|
||||
* @brief 用于约束需要projection的着色器规格
|
||||
*/
|
||||
template <typename ShaderSpec>
|
||||
concept shader_with_projection = requires {
|
||||
typename ShaderSpec::push_constant_base_layout;
|
||||
} && has_projection_member<typename ShaderSpec::push_constant_base_layout>;
|
||||
} // namespace mirage
|
||||
@@ -601,70 +601,69 @@ namespace mirage {
|
||||
// 基本信息
|
||||
// ========================================================================
|
||||
|
||||
uint32_t shader_id; ///< 着色器唯一标识(用于 Pipeline 缓存)
|
||||
vec2f_t position; ///< 控件位置(左上角)
|
||||
vec2f_t size; ///< 控件大小
|
||||
render_order order; ///< 渲染顺序和裁剪信息
|
||||
uint32_t shader_id; ///< 着色器唯一标识(用于 Pipeline 缓存)
|
||||
vec2f_t position; ///< 控件位置(左上角)
|
||||
vec2f_t size; ///< 控件大小
|
||||
render_order order; ///< 渲染顺序和裁剪信息
|
||||
|
||||
// ========================================================================
|
||||
// 着色器配置
|
||||
// ========================================================================
|
||||
|
||||
std::span<const uint32_t> vert_spirv; ///< 顶点着色器 SPIR-V
|
||||
std::span<const uint32_t> frag_spirv; ///< 片段着色器 SPIR-V
|
||||
std::span<const ui::shader_binding_info> bindings; ///< 描述符绑定信息
|
||||
std::span<const uint32_t> vert_spirv; ///< 顶点着色器 SPIR-V
|
||||
std::span<const uint32_t> frag_spirv; ///< 片段着色器 SPIR-V
|
||||
std::span<const shader_binding_info> bindings; ///< 描述符绑定信息
|
||||
|
||||
// ========================================================================
|
||||
// 渲染模式
|
||||
// ========================================================================
|
||||
|
||||
ui::custom_shader_render_mode render_mode; ///< 渲染模式
|
||||
uint32_t source_texture; ///< 源纹理 ID(post_process 模式)
|
||||
custom_shader_render_mode render_mode; ///< 渲染模式
|
||||
uint32_t source_texture; ///< 源纹理 ID(post_process 模式)
|
||||
|
||||
// ========================================================================
|
||||
// 参数数据
|
||||
// ========================================================================
|
||||
|
||||
const void* params_data; ///< 参数数据指针(UBO 内容)
|
||||
size_t params_size; ///< 参数数据大小
|
||||
bool params_dirty; ///< 参数是否需要更新
|
||||
const void* params_data; ///< 参数数据指针(UBO 内容)
|
||||
size_t params_size; ///< 参数数据大小
|
||||
bool params_dirty; ///< 参数是否需要更新
|
||||
|
||||
// ========================================================================
|
||||
// Push Constants 效果参数
|
||||
// ========================================================================
|
||||
|
||||
const void* push_constant_effect_data; ///< 效果参数数据指针(Push Constants 内容)
|
||||
size_t push_constant_effect_size; ///< 效果参数数据大小(字节)
|
||||
bool push_constant_effect_dirty; ///< 效果参数是否需要更新
|
||||
|
||||
// ========================================================================
|
||||
// 顶点数据(custom_geometry 模式)
|
||||
// ========================================================================
|
||||
|
||||
std::optional<ui::vertex_buffer_config> vertex_config; ///< 顶点缓冲配置
|
||||
std::optional<ui::index_buffer_config> index_config; ///< 索引缓冲配置
|
||||
bool vertices_dirty; ///< 顶点是否需要更新
|
||||
|
||||
// ========================================================================
|
||||
// 子控件渲染(post_process 模式)
|
||||
// ========================================================================
|
||||
|
||||
/// @brief 子控件渲染命令(当 render_mode == post_process 且无源纹理时)
|
||||
/// @note 渲染器会先将子控件渲染到临时目标,再应用着色器
|
||||
std::vector<render_command_t> child_commands;
|
||||
aabb2d_t child_bounds;
|
||||
std::optional<custom_vertex_buffer_config> vertex_config; ///< 顶点缓冲配置
|
||||
std::optional<index_buffer_config> index_config; ///< 索引缓冲配置
|
||||
bool vertices_dirty; ///< 顶点是否需要更新
|
||||
|
||||
/// @brief 默认构造函数
|
||||
custom_shader_widget_command()
|
||||
: shader_id(0)
|
||||
, position(vec2f_t::Zero())
|
||||
, size(vec2f_t::Zero())
|
||||
, order()
|
||||
, vert_spirv()
|
||||
, frag_spirv()
|
||||
, bindings()
|
||||
, render_mode(ui::custom_shader_render_mode::procedural)
|
||||
, source_texture(0)
|
||||
, params_data(nullptr)
|
||||
, params_size(0)
|
||||
, params_dirty(true)
|
||||
, vertex_config(std::nullopt)
|
||||
, index_config(std::nullopt)
|
||||
, vertices_dirty(false)
|
||||
, child_commands()
|
||||
, child_bounds(aabb2d_t::Zero()) {
|
||||
custom_shader_widget_command() : shader_id(0)
|
||||
, position(vec2f_t::Zero())
|
||||
, size(vec2f_t::Zero())
|
||||
, order()
|
||||
, vert_spirv()
|
||||
, frag_spirv()
|
||||
, bindings()
|
||||
, render_mode(custom_shader_render_mode::procedural)
|
||||
, source_texture(0)
|
||||
, params_data(nullptr)
|
||||
, params_size(0)
|
||||
, params_dirty(true)
|
||||
, push_constant_effect_data(nullptr)
|
||||
, push_constant_effect_size(0)
|
||||
, push_constant_effect_dirty(false)
|
||||
, vertex_config(std::nullopt)
|
||||
, index_config(std::nullopt)
|
||||
, vertices_dirty(false) {
|
||||
}
|
||||
};
|
||||
|
||||
@@ -678,6 +677,6 @@ namespace mirage {
|
||||
post_effect_command_t,
|
||||
mask_begin_command,
|
||||
mask_end_command,
|
||||
custom_shader_widget_command // 新增
|
||||
custom_shader_widget_command // 新增
|
||||
>;
|
||||
} // namespace mirage
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,167 +12,165 @@
|
||||
#include "ui/widgets/custom_shader/custom_shader_widget_types.h"
|
||||
#include <memory>
|
||||
|
||||
#include "render/vulkan/typed_buffer.h"
|
||||
|
||||
namespace mirage {
|
||||
// 前向声明
|
||||
struct custom_shader_buffers;
|
||||
|
||||
// 前向声明
|
||||
struct custom_shader_buffers;
|
||||
/// @brief 程序化四边形 Push Constants
|
||||
/// @details 用于 procedural 模式,通过 push constant 传递矩形信息
|
||||
struct procedural_quad_push_constants {
|
||||
vec4f_t rect; ///< x, y, width, height (16 bytes)
|
||||
vec4f_t color; ///< RGBA (16 bytes)
|
||||
};
|
||||
|
||||
/// @brief 程序化四边形 Push Constants
|
||||
/// @details 用于 procedural 模式,通过 push constant 传递矩形信息
|
||||
struct procedural_quad_push_constants {
|
||||
glm::vec4 rect; ///< x, y, width, height
|
||||
glm::vec4 color; ///< RGBA
|
||||
float corner_radius; ///< 圆角半径
|
||||
float padding[3]; ///< 对齐填充(16字节对齐)
|
||||
};
|
||||
static_assert(sizeof(procedural_quad_push_constants) == 32,
|
||||
"procedural_quad_push_constants must be 32 bytes");
|
||||
static_assert(sizeof(procedural_quad_push_constants) % 16 == 0,
|
||||
"procedural_quad_push_constants must be 16-byte aligned");
|
||||
|
||||
static_assert(sizeof(procedural_quad_push_constants) == 32,
|
||||
"procedural_quad_push_constants must be 32 bytes");
|
||||
static_assert(sizeof(procedural_quad_push_constants) % 16 == 0,
|
||||
"procedural_quad_push_constants must be 16-byte aligned");
|
||||
/// @brief 自定义着色器控件渲染器
|
||||
///
|
||||
/// 负责渲染 custom_shader_widget_command,支持三种渲染模式:
|
||||
/// - **程序化渲染**:使用无顶点缓冲区的四边形
|
||||
/// - **后处理模式**:先渲染子控件到临时目标,再应用着色器
|
||||
/// - **自定义几何**:使用用户提供的顶点数据
|
||||
///
|
||||
/// 与 shader_resource_manager 配合进行 Pipeline 缓存和资源管理。
|
||||
class custom_shader_widget_renderer {
|
||||
public:
|
||||
/// @brief 构造函数
|
||||
/// @param device 逻辑设备
|
||||
/// @param res_mgr 资源管理器
|
||||
/// @param shader_res_mgr 着色器资源管理器
|
||||
custom_shader_widget_renderer(
|
||||
logical_device& device,
|
||||
resource_manager& res_mgr,
|
||||
shader_resource_manager& shader_res_mgr
|
||||
);
|
||||
|
||||
/// @brief 自定义着色器控件渲染器
|
||||
///
|
||||
/// 负责渲染 custom_shader_widget_command,支持三种渲染模式:
|
||||
/// - **程序化渲染**:使用无顶点缓冲区的四边形
|
||||
/// - **后处理模式**:先渲染子控件到临时目标,再应用着色器
|
||||
/// - **自定义几何**:使用用户提供的顶点数据
|
||||
///
|
||||
/// 与 shader_resource_manager 配合进行 Pipeline 缓存和资源管理。
|
||||
class custom_shader_widget_renderer {
|
||||
public:
|
||||
/// @brief 构造函数
|
||||
/// @param device 逻辑设备
|
||||
/// @param res_mgr 资源管理器
|
||||
/// @param shader_res_mgr 着色器资源管理器
|
||||
custom_shader_widget_renderer(
|
||||
logical_device& device,
|
||||
resource_manager& res_mgr,
|
||||
shader_resource_manager& shader_res_mgr
|
||||
);
|
||||
~custom_shader_widget_renderer();
|
||||
|
||||
~custom_shader_widget_renderer();
|
||||
// 禁止拷贝
|
||||
custom_shader_widget_renderer(const custom_shader_widget_renderer&) = delete;
|
||||
custom_shader_widget_renderer& operator=(const custom_shader_widget_renderer&) = delete;
|
||||
|
||||
// 禁止拷贝
|
||||
custom_shader_widget_renderer(const custom_shader_widget_renderer&) = delete;
|
||||
custom_shader_widget_renderer& operator=(const custom_shader_widget_renderer&) = delete;
|
||||
/// @brief 初始化渲染器
|
||||
/// @param render_pass 渲染通道
|
||||
void initialize(vk::RenderPass render_pass);
|
||||
|
||||
/// @brief 初始化渲染器
|
||||
/// @param render_pass 渲染通道
|
||||
void initialize(vk::RenderPass render_pass);
|
||||
/// @brief 设置视口大小
|
||||
/// @param viewport_size 视口大小
|
||||
void set_viewport(const vec2f_t& viewport_size);
|
||||
|
||||
/// @brief 设置视口大小
|
||||
/// @param viewport_size 视口大小
|
||||
void set_viewport(const vec2f_t& viewport_size);
|
||||
/// @brief 设置目标池(用于 post_process 模式的临时目标)
|
||||
void set_target_pool(unified_target_pool* pool);
|
||||
|
||||
/// @brief 设置目标池(用于 post_process 模式的临时目标)
|
||||
void set_target_pool(unified_target_pool* pool);
|
||||
// ========================================================================
|
||||
// 类型安全渲染接口
|
||||
// ========================================================================
|
||||
|
||||
// ========================================================================
|
||||
// 类型安全渲染接口
|
||||
// ========================================================================
|
||||
/// @brief 渲染自定义着色器控件(离屏 Pass)
|
||||
/// @tparam State 当前 Pass 状态
|
||||
/// @param ctx 帧上下文
|
||||
/// @param command 渲染命令
|
||||
/// @param buffers 外部顶点缓冲区(可选,用于标准 ui_vertex)
|
||||
/// @param descriptor_pool 描述符池
|
||||
template <active_pass_state_tag State>
|
||||
void render(
|
||||
frame_context<State>& ctx,
|
||||
const custom_shader_widget_command& command,
|
||||
custom_shader_buffers* buffers,
|
||||
vk::DescriptorPool descriptor_pool
|
||||
) {
|
||||
render_impl(ctx.cmd(), command, buffers, descriptor_pool);
|
||||
}
|
||||
|
||||
/// @brief 渲染自定义着色器控件(离屏 Pass)
|
||||
/// @tparam State 当前 Pass 状态
|
||||
/// @param ctx 帧上下文
|
||||
/// @param command 渲染命令
|
||||
/// @param buffers 外部顶点缓冲区(可选,用于标准 ui_vertex)
|
||||
/// @param descriptor_pool 描述符池
|
||||
template <active_pass_state_tag State>
|
||||
void render(
|
||||
frame_context<State>& ctx,
|
||||
const custom_shader_widget_command& command,
|
||||
custom_shader_buffers* buffers,
|
||||
vk::DescriptorPool descriptor_pool
|
||||
) {
|
||||
render_impl(ctx.cmd(), command, buffers, descriptor_pool);
|
||||
}
|
||||
// ========================================================================
|
||||
// 低级接口
|
||||
// ========================================================================
|
||||
|
||||
// ========================================================================
|
||||
// 低级接口
|
||||
// ========================================================================
|
||||
/// @brief 渲染实现
|
||||
void render_impl(
|
||||
vk::CommandBuffer cmd,
|
||||
const custom_shader_widget_command& command,
|
||||
custom_shader_buffers* buffers,
|
||||
vk::DescriptorPool descriptor_pool
|
||||
);
|
||||
|
||||
/// @brief 渲染实现
|
||||
void render_impl(
|
||||
vk::CommandBuffer cmd,
|
||||
const custom_shader_widget_command& command,
|
||||
custom_shader_buffers* buffers,
|
||||
vk::DescriptorPool descriptor_pool
|
||||
);
|
||||
/// @brief 设置 Stencil 参考值
|
||||
void set_stencil_ref(uint8_t ref);
|
||||
|
||||
/// @brief 设置 Stencil 参考值
|
||||
void set_stencil_ref(uint8_t ref);
|
||||
/// @brief 获取 Stencil 参考值
|
||||
[[nodiscard]] auto get_stencil_ref() const -> uint8_t;
|
||||
|
||||
/// @brief 获取 Stencil 参考值
|
||||
[[nodiscard]] auto get_stencil_ref() const -> uint8_t;
|
||||
/// @brief 清理资源
|
||||
void cleanup();
|
||||
|
||||
/// @brief 清理资源
|
||||
void cleanup();
|
||||
private:
|
||||
logical_device& device_;
|
||||
resource_manager& res_mgr_;
|
||||
shader_resource_manager& shader_res_mgr_;
|
||||
unified_target_pool* target_pool_ = nullptr;
|
||||
|
||||
private:
|
||||
logical_device& device_;
|
||||
resource_manager& res_mgr_;
|
||||
shader_resource_manager& shader_res_mgr_;
|
||||
unified_target_pool* target_pool_ = nullptr;
|
||||
vk::RenderPass render_pass_;
|
||||
vec2f_t viewport_size_{0, 0};
|
||||
uint8_t stencil_ref_ = 0;
|
||||
|
||||
vk::RenderPass render_pass_;
|
||||
vec2f_t viewport_size_{0, 0};
|
||||
uint8_t stencil_ref_ = 0;
|
||||
// 默认顶点着色器 SPIR-V(从编译的头文件引入)
|
||||
std::span<const uint32_t> default_vert_spirv_;
|
||||
std::span<const uint32_t> procedural_vert_spirv_;
|
||||
|
||||
// 默认顶点着色器 SPIR-V(从编译的头文件引入)
|
||||
std::span<const uint32_t> default_vert_spirv_;
|
||||
std::span<const uint32_t> procedural_vert_spirv_;
|
||||
// 程序化四边形顶点缓冲(用于 custom_geometry 模式)
|
||||
device_handle_t<vk::Buffer> procedural_quad_buffer_;
|
||||
device_handle_t<vk::Buffer> procedural_quad_index_buffer_;
|
||||
VkDeviceSize procedural_quad_vertex_offset_ = 0;
|
||||
VkDeviceSize procedural_quad_index_offset_ = 0;
|
||||
|
||||
// 程序化四边形顶点缓冲(用于 custom_geometry 模式)
|
||||
device_handle_t<vk::Buffer> procedural_quad_buffer_;
|
||||
device_handle_t<vk::Buffer> procedural_quad_index_buffer_;
|
||||
VkDeviceSize procedural_quad_vertex_offset_ = 0;
|
||||
VkDeviceSize procedural_quad_index_offset_ = 0;
|
||||
// 内部方法
|
||||
void create_procedural_quad_buffer();
|
||||
|
||||
// 内部方法
|
||||
void create_procedural_quad_buffer();
|
||||
void render_procedural(
|
||||
vk::CommandBuffer cmd,
|
||||
const custom_shader_widget_command& command,
|
||||
vk::DescriptorPool descriptor_pool
|
||||
);
|
||||
|
||||
void render_procedural(
|
||||
vk::CommandBuffer cmd,
|
||||
const custom_shader_widget_command& command,
|
||||
vk::DescriptorPool descriptor_pool
|
||||
);
|
||||
void render_post_process(
|
||||
vk::CommandBuffer cmd,
|
||||
const custom_shader_widget_command& command,
|
||||
custom_shader_buffers* buffers,
|
||||
vk::DescriptorPool descriptor_pool
|
||||
);
|
||||
|
||||
void render_post_process(
|
||||
vk::CommandBuffer cmd,
|
||||
const custom_shader_widget_command& command,
|
||||
custom_shader_buffers* buffers,
|
||||
vk::DescriptorPool descriptor_pool
|
||||
);
|
||||
void render_custom_geometry(
|
||||
vk::CommandBuffer cmd,
|
||||
const custom_shader_widget_command& command,
|
||||
vk::DescriptorPool descriptor_pool
|
||||
);
|
||||
|
||||
void render_custom_geometry(
|
||||
vk::CommandBuffer cmd,
|
||||
const custom_shader_widget_command& command,
|
||||
vk::DescriptorPool descriptor_pool
|
||||
);
|
||||
auto setup_pipeline_and_descriptors(
|
||||
vk::CommandBuffer cmd,
|
||||
const custom_shader_widget_command& command,
|
||||
vk::DescriptorPool descriptor_pool,
|
||||
vk::ImageView source_texture_view = VK_NULL_HANDLE
|
||||
) -> std::tuple<vk::Pipeline, vk::PipelineLayout, vk::DescriptorSet>;
|
||||
|
||||
auto setup_pipeline_and_descriptors(
|
||||
vk::CommandBuffer cmd,
|
||||
const custom_shader_widget_command& command,
|
||||
vk::DescriptorPool descriptor_pool,
|
||||
vk::ImageView source_texture_view = VK_NULL_HANDLE
|
||||
) -> std::tuple<vk::Pipeline, vk::PipelineLayout, vk::DescriptorSet>;
|
||||
void push_constants(
|
||||
vk::CommandBuffer cmd,
|
||||
vk::PipelineLayout layout,
|
||||
const custom_shader_widget_command& command
|
||||
);
|
||||
};
|
||||
|
||||
void push_constants(
|
||||
vk::CommandBuffer cmd,
|
||||
vk::PipelineLayout layout,
|
||||
const custom_shader_widget_command& command
|
||||
);
|
||||
};
|
||||
/// @brief 自定义着色器控件的顶点缓冲区
|
||||
/// @details 由 per_window_vertex_buffers 管理
|
||||
struct custom_shader_buffers {
|
||||
typed_buffer_owned<ui_vertex> vertices;
|
||||
typed_buffer_owned<uint32_t> indices;
|
||||
|
||||
/// @brief 自定义着色器控件的顶点缓冲区
|
||||
/// @details 由 per_window_vertex_buffers 管理
|
||||
struct custom_shader_buffers {
|
||||
typed_buffer_owned<ui_vertex> vertices;
|
||||
typed_buffer_owned<uint32_t> indices;
|
||||
|
||||
size_t vertex_count = 0;
|
||||
size_t index_count = 0;
|
||||
};
|
||||
|
||||
} // namespace mirage
|
||||
size_t vertex_count = 0;
|
||||
size_t index_count = 0;
|
||||
};
|
||||
} // namespace mirage
|
||||
|
||||
@@ -2,38 +2,84 @@
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "render/push_constant_traits.h"
|
||||
|
||||
namespace mirage {
|
||||
/**
|
||||
* @brief Push Constants 结构
|
||||
* @brief Push Constants 基础部分(由渲染器自动管理)
|
||||
*
|
||||
* 用于传递全局渲染参数到着色器。
|
||||
* 使用 Push Constants 替代 Uniform Buffer 以提高频繁更新数据的性能。
|
||||
* 所有后处理着色器共享的基础参数,包括投影矩阵、视口大小和时间。
|
||||
* 此部分由渲染器自动填充,大小固定为 80 字节。
|
||||
*
|
||||
* 对应 GLSL 布局:
|
||||
* @code
|
||||
* layout(push_constant) uniform Constants {
|
||||
* mat4 projection;
|
||||
* vec2 viewport_size;
|
||||
* vec2 screen_resolution;
|
||||
* float time;
|
||||
* // padding 由编译器自动处理
|
||||
* } constants;
|
||||
* layout(push_constant) uniform PushConstants {
|
||||
* mat4 projection; // 偏移 0, 大小 64
|
||||
* vec2 viewport_size; // 偏移 64, 大小 8
|
||||
* float time; // 偏移 72, 大小 4
|
||||
* float _pad0; // 偏移 76, 大小 4
|
||||
* } pc;
|
||||
* @endcode
|
||||
*/
|
||||
struct push_constants {
|
||||
struct push_constants_base {
|
||||
float projection[16]; ///< 正交投影矩阵(列主序,符合 GLSL mat4 布局)
|
||||
float viewport_size[2]; ///< 视口大小 (width, height)
|
||||
float screen_resolution[2]; ///< 屏幕分辨率 (width, height),用于像素对齐
|
||||
float time; ///< 时间(秒),用于动画效果
|
||||
float padding[3]; ///< 对齐填充,确保结构体大小为 16 字节的倍数
|
||||
float _pad0; ///< 对齐填充
|
||||
};
|
||||
|
||||
// 静态断言确保结构体大小符合 std430/std140 对齐要求
|
||||
static_assert(sizeof(push_constants) == (16 + 2 + 2 + 1 + 3) * sizeof(float),
|
||||
"push_constants size must be 96 bytes");
|
||||
static_assert(sizeof(push_constants) % 16 == 0,
|
||||
"push_constants must be 16-byte aligned");
|
||||
static_assert(sizeof(push_constants_base) == 80, "push_constants_base must be exactly 80 bytes");
|
||||
|
||||
/// @brief Push Constants 基础部分结束偏移量(效果部分开始偏移)
|
||||
inline constexpr size_t PUSH_CONSTANT_BASE_OFFSET = 80;
|
||||
|
||||
/**
|
||||
* @brief Push Constants 标准基础部分期望布局
|
||||
*
|
||||
* 所有使用标准基础部分的着色器必须匹配此布局。
|
||||
* 此结构体用于编译期验证着色器声明的 push_constant 布局与 C++ 端定义的一致性。
|
||||
*
|
||||
* 期望布局:
|
||||
* - projection: 偏移 0, 大小 64
|
||||
* - viewport_size: 偏移 64, 大小 8
|
||||
* - time: 偏移 72, 大小 4
|
||||
* - _pad0: 偏移 76, 大小 4
|
||||
* - total_size: 80
|
||||
*/
|
||||
struct expected_push_constant_base_layout {
|
||||
static constexpr bool has_projection = true;
|
||||
static constexpr bool has_viewport_size = true;
|
||||
static constexpr bool has_time = true;
|
||||
static constexpr bool has_pad0 = true;
|
||||
|
||||
static constexpr size_t projection_offset = 0;
|
||||
static constexpr size_t viewport_size_offset = 64;
|
||||
static constexpr size_t time_offset = 72;
|
||||
static constexpr size_t pad0_offset = 76;
|
||||
|
||||
static constexpr size_t projection_size = 64;
|
||||
static constexpr size_t viewport_size_size = 8;
|
||||
static constexpr size_t time_size = 4;
|
||||
static constexpr size_t pad0_size = 4;
|
||||
|
||||
static constexpr size_t total_size = 80;
|
||||
};
|
||||
|
||||
// 验证 push_constants_base 与期望布局一致
|
||||
static_assert(offsetof(push_constants_base, projection) ==
|
||||
expected_push_constant_base_layout::projection_offset,
|
||||
"push_constants_base::projection offset mismatch");
|
||||
static_assert(offsetof(push_constants_base, viewport_size) ==
|
||||
expected_push_constant_base_layout::viewport_size_offset,
|
||||
"push_constants_base::viewport_size offset mismatch");
|
||||
static_assert(offsetof(push_constants_base, time) ==
|
||||
expected_push_constant_base_layout::time_offset,
|
||||
"push_constants_base::time offset mismatch");
|
||||
static_assert(offsetof(push_constants_base, _pad0) ==
|
||||
expected_push_constant_base_layout::pad0_offset,
|
||||
"push_constants_base::_pad0 offset mismatch");
|
||||
|
||||
/**
|
||||
* @brief 创建正交投影矩阵
|
||||
@@ -59,6 +105,61 @@ namespace mirage {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建 Push Constants 基础部分
|
||||
*
|
||||
* @param width 视口宽度
|
||||
* @param height 视口高度
|
||||
* @param time 当前时间(秒)
|
||||
* @return 初始化的 push_constants_base 结构
|
||||
*/
|
||||
inline auto create_push_constants_base(float width, float height, float time = 0.0f)
|
||||
-> push_constants_base {
|
||||
const auto proj = create_ortho_projection(width, height);
|
||||
|
||||
push_constants_base base{};
|
||||
std::memcpy(base.projection, proj.data(), sizeof(proj));
|
||||
base.viewport_size[0] = width;
|
||||
base.viewport_size[1] = height;
|
||||
base.time = time;
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Push Constants 结构(旧版,保留兼容性)
|
||||
*
|
||||
* 用于传递全局渲染参数到着色器。
|
||||
* 使用 Push Constants 替代 Uniform Buffer 以提高频繁更新数据的性能。
|
||||
*
|
||||
* 对应 GLSL 布局:
|
||||
* @code
|
||||
* layout(push_constant) uniform Constants {
|
||||
* mat4 projection;
|
||||
* vec2 viewport_size;
|
||||
* vec2 screen_resolution;
|
||||
* float time;
|
||||
* // padding 由编译器自动处理
|
||||
* } constants;
|
||||
* @endcode
|
||||
*/
|
||||
struct push_constants {
|
||||
float projection[16]; ///< 正交投影矩阵(列主序,符合 GLSL mat4 布局)
|
||||
float viewport_size[2]; ///< 视口大小 (width, height)
|
||||
float screen_resolution[2]; ///< 屏幕分辨率 (width, height),用于像素对齐
|
||||
float time; ///< 时间(秒),用于动画效果
|
||||
float padding[3]; ///< 对齐填充,确保结构体大小为 16 字节的倍数
|
||||
};
|
||||
|
||||
// 静态断言确保结构体大小符合 std430/std140 对齐要求
|
||||
|
||||
static_assert(sizeof(push_constants) == (16 + 2 + 2 + 1 + 3) * sizeof(float),
|
||||
"push_constants size must be 96 bytes");
|
||||
|
||||
|
||||
static_assert(sizeof(push_constants) % 16 == 0,
|
||||
"push_constants must be 16-byte aligned");
|
||||
|
||||
|
||||
/**
|
||||
* @brief 创建默认的全局 uniform 数据
|
||||
*
|
||||
@@ -73,14 +174,39 @@ namespace mirage {
|
||||
for (size_t i = 0; i < 16; ++i) {
|
||||
constants.projection[i] = proj[i];
|
||||
}
|
||||
constants.viewport_size[0] = width;
|
||||
constants.viewport_size[1] = height;
|
||||
constants.screen_resolution[0] = width; // 默认屏幕分辨率等于视口大小
|
||||
constants.viewport_size[0] = width;
|
||||
constants.viewport_size[1] = height;
|
||||
constants.screen_resolution[0] = width; // 默认屏幕分辨率等于视口大小
|
||||
constants.screen_resolution[1] = height;
|
||||
constants.time = time;
|
||||
constants.padding[0] = 0.0f;
|
||||
constants.padding[1] = 0.0f;
|
||||
constants.padding[2] = 0.0f;
|
||||
constants.time = time;
|
||||
constants.padding[0] = 0.0f;
|
||||
constants.padding[1] = 0.0f;
|
||||
constants.padding[2] = 0.0f;
|
||||
return constants;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 验证生成的布局与实际结构的一致性
|
||||
*
|
||||
* @tparam Layout 布局类型(由代码生成器生成)
|
||||
* @return 如果布局是标准的,返回 true;否则返回 false
|
||||
*
|
||||
* 使用方法:
|
||||
* @code
|
||||
* // 在生成的头文件中使用:
|
||||
* static_assert(validate_push_constants_base_layout<blur_push_constant_base_layout>(),
|
||||
* "Blur push constant base layout mismatch");
|
||||
* @endcode
|
||||
*/
|
||||
template <typename Layout>
|
||||
constexpr bool validate_push_constants_base_layout() {
|
||||
if constexpr (standard_push_constant_base_layout<Layout>) {
|
||||
static_assert(Layout::projection_offset == offsetof(push_constants_base, projection));
|
||||
static_assert(Layout::viewport_size_offset == offsetof(push_constants_base, viewport_size));
|
||||
static_assert(Layout::time_offset == offsetof(push_constants_base, time));
|
||||
static_assert(Layout::total_size == sizeof(push_constants_base));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace mirage
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace mirage {
|
||||
auto create_pipeline_internal(
|
||||
const logical_device& device,
|
||||
vk::ShaderModule shader_module,
|
||||
std::span<const binding_info> bindings
|
||||
std::span<const shader_binding_info> bindings
|
||||
) -> expected_t<compute_pipeline, vk::Result> {
|
||||
vk::Device vk_device = device.get_handle();
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace mirage {
|
||||
}
|
||||
|
||||
auto compute_pipeline::create(const logical_device& device, const std::string& shader_path,
|
||||
std::span<const binding_info> bindings) -> expected_t<compute_pipeline, vk::Result> {
|
||||
std::span<const shader_binding_info> bindings) -> expected_t<compute_pipeline, vk::Result> {
|
||||
auto module_ret = graphics_pipeline::load_shader_module(device, shader_path);
|
||||
if (!module_ret)
|
||||
return std::unexpected(module_ret.error());
|
||||
@@ -138,7 +138,7 @@ namespace mirage {
|
||||
}
|
||||
|
||||
auto compute_pipeline::create_from_spv(const logical_device& device, std::span<const uint32_t> spv_code,
|
||||
std::span<const binding_info> bindings) -> expected_t<
|
||||
std::span<const shader_binding_info> bindings) -> expected_t<
|
||||
compute_pipeline, vk::Result> {
|
||||
auto module_ret = graphics_pipeline::load_shader_module_from_memory(device, spv_code);
|
||||
if (!module_ret)
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace mirage {
|
||||
public:
|
||||
// Constructors / Factory
|
||||
static auto create(const logical_device& device, const std::string& shader_path,
|
||||
std::span<const binding_info> bindings = {}) -> expected_t<compute_pipeline, vk::Result>;
|
||||
std::span<const shader_binding_info> bindings = {}) -> expected_t<compute_pipeline, vk::Result>;
|
||||
static auto create_from_spv(const logical_device& device, std::span<const uint32_t> spv_code,
|
||||
std::span<const binding_info> bindings = {}) -> expected_t<
|
||||
std::span<const shader_binding_info> bindings = {}) -> expected_t<
|
||||
compute_pipeline, vk::Result>;
|
||||
|
||||
// Interface
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "render/vulkan/descriptor_manager.h"
|
||||
#include <vma/vk_mem_alloc.h>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace mirage {
|
||||
/**
|
||||
@@ -268,6 +269,34 @@ namespace mirage {
|
||||
*/
|
||||
[[nodiscard]] auto get_device() const noexcept -> vk::Device { return device_; }
|
||||
|
||||
/**
|
||||
* @brief 获取 Vulkan 物理设备
|
||||
* @return Vulkan 物理设备句柄
|
||||
*/
|
||||
[[nodiscard]] auto get_physical_device() const noexcept -> vk::PhysicalDevice {
|
||||
return physical_device_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 查找符合要求的内存类型
|
||||
*
|
||||
* @param type_bits 内存类型位掩码
|
||||
* @param properties 内存属性标志
|
||||
* @return 内存类型索引
|
||||
*/
|
||||
[[nodiscard]] auto find_memory_type(uint32_t type_bits, vk::MemoryPropertyFlags properties) const
|
||||
-> uint32_t {
|
||||
vk::PhysicalDeviceMemoryProperties mem_properties;
|
||||
physical_device_.getMemoryProperties(&mem_properties);
|
||||
|
||||
for (uint32_t i = 0; i < mem_properties.memoryTypeCount; i++) {
|
||||
if ((type_bits & (1 << i)) && (mem_properties.memoryTypes[i].propertyFlags & properties)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error("Failed to find suitable memory type");
|
||||
}
|
||||
private:
|
||||
// ========================================================================
|
||||
// 核心成员
|
||||
|
||||
@@ -35,7 +35,7 @@ void shader_resource_manager::initialize(vk::RenderPass render_pass, uint32_t fr
|
||||
// 获取 Uniform Buffer 对齐要求
|
||||
VkPhysicalDeviceProperties properties;
|
||||
vkGetPhysicalDeviceProperties(
|
||||
res_mgr_.get_device().get_handle().get<vk::PhysicalDevice>(),
|
||||
res_mgr_.get_physical_device(),
|
||||
&properties
|
||||
);
|
||||
min_uniform_buffer_offset_alignment_ = properties.limits.minUniformBufferOffsetAlignment;
|
||||
@@ -101,9 +101,16 @@ void shader_resource_manager::create_per_frame_uniform_buffer(uint32_t frame_ind
|
||||
}
|
||||
|
||||
void shader_resource_manager::create_pipeline_layout() {
|
||||
// 创建空的 Pipeline Layout(不使用 push constants 或 desc sets)
|
||||
// Descriptor Set Layout 由各 Pipeline 单独管理
|
||||
// 创建共享的 Pipeline Layout,支持完整的 Push Constants(128 字节)
|
||||
// 基础部分 80 字节 + 效果部分 48 字节
|
||||
vk::PushConstantRange push_constant_range{
|
||||
vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
|
||||
0, // 偏移
|
||||
128 // 大小(基础80 + 效果48,最大保证大小)
|
||||
};
|
||||
|
||||
vk::PipelineLayoutCreateInfo create_info{};
|
||||
create_info.setPushConstantRanges(push_constant_range);
|
||||
|
||||
auto [result, layout] = device_.createPipelineLayout(create_info);
|
||||
if (result == vk::Result::eSuccess) {
|
||||
@@ -155,8 +162,8 @@ auto shader_resource_manager::get_or_create_pipeline(
|
||||
std::span<const uint32_t> vert_spirv,
|
||||
std::span<const uint32_t> frag_spirv,
|
||||
std::span<const shader_binding_info> bindings,
|
||||
std::span<const VkVertexInputBindingDescription> vertex_bindings,
|
||||
std::span<const VkVertexInputAttributeDescription> vertex_attributes,
|
||||
std::span<const vk::VertexInputBindingDescription> vertex_bindings,
|
||||
std::span<const vk::VertexInputAttributeDescription> vertex_attributes,
|
||||
VkRenderPass render_pass
|
||||
) -> vk::Pipeline {
|
||||
std::lock_guard lock(pipeline_mutex_);
|
||||
@@ -279,27 +286,23 @@ auto shader_resource_manager::create_pipeline(
|
||||
device_handle_t<vk::ShaderModule> vert_module,
|
||||
device_handle_t<vk::ShaderModule> frag_module,
|
||||
vk::DescriptorSetLayout desc_layout,
|
||||
std::span<const VkVertexInputBindingDescription> vertex_bindings,
|
||||
std::span<const VkVertexInputAttributeDescription> vertex_attributes,
|
||||
std::span<const vk::VertexInputBindingDescription> vertex_bindings,
|
||||
std::span<const vk::VertexInputAttributeDescription> vertex_attributes,
|
||||
VkRenderPass render_pass
|
||||
) -> pipeline_resources_t {
|
||||
pipeline_resources_t resources;
|
||||
|
||||
// Shader Stage
|
||||
std::array shader_stages = {
|
||||
vk::PipelineShaderStageCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = vk::ShaderStageFlagBits::eVertex,
|
||||
.module = vert_module.get(),
|
||||
.pName = "main"
|
||||
},
|
||||
vk::PipelineShaderStageCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = vk::ShaderStageFlagBits::eFragment,
|
||||
.module = frag_module.get(),
|
||||
.pName = "main"
|
||||
}
|
||||
};
|
||||
vk::PipelineShaderStageCreateInfo vertex_stage_info{};
|
||||
vertex_stage_info.setModule(vert_module);
|
||||
vertex_stage_info.setStage(vk::ShaderStageFlagBits::eVertex);
|
||||
vertex_stage_info.setPName("main");
|
||||
vk::PipelineShaderStageCreateInfo fragment_stage_info{};
|
||||
fragment_stage_info.setModule(frag_module);
|
||||
fragment_stage_info.setStage(vk::ShaderStageFlagBits::eFragment);
|
||||
fragment_stage_info.setPName("main");
|
||||
|
||||
std::array shader_stages = {vertex_stage_info, fragment_stage_info};
|
||||
|
||||
// Vertex Input
|
||||
vk::PipelineVertexInputStateCreateInfo vertex_input_info{};
|
||||
@@ -318,7 +321,8 @@ auto shader_resource_manager::create_pipeline(
|
||||
viewport.maxDepth = 1.0f;
|
||||
|
||||
vk::Rect2D scissor{};
|
||||
scissor.extent = {1, 1};
|
||||
scissor.extent.setHeight(1);
|
||||
scissor.extent.setWidth(1);
|
||||
|
||||
vk::PipelineViewportStateCreateInfo viewport_info{};
|
||||
viewport_info.setViewports(viewport);
|
||||
@@ -354,9 +358,16 @@ auto shader_resource_manager::create_pipeline(
|
||||
vk::PipelineColorBlendStateCreateInfo color_blend_info{};
|
||||
color_blend_info.setAttachments(color_blend_attachment);
|
||||
|
||||
// Pipeline Layout
|
||||
// Pipeline Layout(支持完整的 Push Constants)
|
||||
vk::PushConstantRange push_constant_range{
|
||||
vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
|
||||
0, // 偏移
|
||||
128 // 大小(基础80 + 效果48,最大保证大小)
|
||||
};
|
||||
|
||||
vk::PipelineLayoutCreateInfo pipeline_layout_info{};
|
||||
pipeline_layout_info.setSetLayouts(desc_layout);
|
||||
pipeline_layout_info.setPushConstantRanges(push_constant_range);
|
||||
|
||||
auto [layout_result, pipeline_layout] = device_.createPipelineLayout(pipeline_layout_info);
|
||||
if (layout_result != vk::Result::eSuccess) {
|
||||
@@ -377,7 +388,7 @@ auto shader_resource_manager::create_pipeline(
|
||||
pipeline_info.renderPass = render_pass;
|
||||
pipeline_info.subpass = 0;
|
||||
|
||||
auto [pipeline_result, pipeline] = device_.createGraphicsPipelines(
|
||||
auto [pipeline_result, pipeline] = device_.createGraphicsPipeline(
|
||||
VK_NULL_HANDLE,
|
||||
pipeline_info
|
||||
);
|
||||
@@ -405,8 +416,8 @@ auto shader_resource_manager::create_pipeline(
|
||||
}
|
||||
|
||||
auto shader_resource_manager::compute_vertex_layout_hash(
|
||||
std::span<const VkVertexInputBindingDescription> bindings,
|
||||
std::span<const VkVertexInputAttributeDescription> attributes
|
||||
std::span<const vk::VertexInputBindingDescription> bindings,
|
||||
std::span<const vk::VertexInputAttributeDescription> attributes
|
||||
) -> std::size_t {
|
||||
std::size_t h = 0;
|
||||
|
||||
@@ -450,13 +461,12 @@ auto shader_resource_manager::get_or_create_descriptor_set_layout(
|
||||
vk_bindings.reserve(bindings.size());
|
||||
|
||||
for (const auto& b : bindings) {
|
||||
vk_bindings.push_back(vk::DescriptorSetLayoutBinding{
|
||||
.binding = b.binding,
|
||||
.descriptorType = b.type,
|
||||
.descriptorCount = b.count,
|
||||
.stageFlags = b.stage,
|
||||
.pImmutableSamplers = nullptr
|
||||
});
|
||||
vk::DescriptorSetLayoutBinding layout_binding{};
|
||||
layout_binding.setBinding(b.binding);
|
||||
layout_binding.setDescriptorType(b.type);
|
||||
layout_binding.setDescriptorCount(b.count);
|
||||
layout_binding.setStageFlags(b.stage);
|
||||
vk_bindings.push_back(layout_binding);
|
||||
}
|
||||
|
||||
// 创建 Layout
|
||||
@@ -513,14 +523,12 @@ void shader_resource_manager::update_uniform_buffer_descriptor(
|
||||
size
|
||||
};
|
||||
|
||||
vk::WriteDescriptorSet write{
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = set,
|
||||
.dstBinding = binding,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eUniformBuffer,
|
||||
.pBufferInfo = &buffer_info
|
||||
};
|
||||
vk::WriteDescriptorSet write{};
|
||||
write.setDstSet(set);
|
||||
write.setDstBinding(binding);
|
||||
write.setDescriptorCount(1);
|
||||
write.setDescriptorType(vk::DescriptorType::eUniformBuffer);
|
||||
write.setPBufferInfo(&buffer_info);
|
||||
|
||||
device_.updateDescriptorSets(write, nullptr);
|
||||
}
|
||||
@@ -537,14 +545,12 @@ void shader_resource_manager::update_sampler_descriptor(
|
||||
vk::ImageLayout::eShaderReadOnlyOptimal
|
||||
};
|
||||
|
||||
vk::WriteDescriptorSet write{
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.dstSet = set,
|
||||
.dstBinding = binding,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||
.pImageInfo = &image_info
|
||||
};
|
||||
vk::WriteDescriptorSet write{};
|
||||
write.setDstSet(set);
|
||||
write.setDstBinding(binding);
|
||||
write.setDescriptorCount(1);
|
||||
write.setDescriptorType(vk::DescriptorType::eCombinedImageSampler);
|
||||
write.setPImageInfo(&image_info);
|
||||
|
||||
device_.updateDescriptorSets(write, nullptr);
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ struct layout_cache_key {
|
||||
|
||||
[[nodiscard]] auto operator==(const layout_cache_key& other) const noexcept -> bool {
|
||||
return bindings.size() == other.bindings.size() &&
|
||||
std::equal(bindings.begin(), bindings.end(), other.bindings.begin());
|
||||
std::ranges::equal(bindings, other.bindings);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -124,7 +124,7 @@ struct layout_cache_key_hash {
|
||||
h ^= std::hash<uint32_t>{}(b.binding + 0x9e3779b9 + (h << 6) + (h >> 2));
|
||||
h ^= std::hash<int>{}(static_cast<int>(b.type) + 0x9e3779b9 + (h << 6) + (h >> 2));
|
||||
h ^= std::hash<uint32_t>{}(b.count + 0x9e3779b9 + (h << 6) + (h >> 2));
|
||||
h ^= std::hash<int>{}(static_cast<int>(b.stage) + 0x9e3779b9 + (h << 6) + (h >> 2));
|
||||
h ^= std::hash<int>{}(static_cast<VkShaderStageFlags>(b.stage) + 0x9e3779b9 + (h << 6) + (h >> 2));
|
||||
}
|
||||
return h;
|
||||
}
|
||||
@@ -216,8 +216,8 @@ public:
|
||||
std::span<const uint32_t> vert_spirv,
|
||||
std::span<const uint32_t> frag_spirv,
|
||||
std::span<const shader_binding_info> bindings,
|
||||
std::span<const VkVertexInputBindingDescription> vertex_bindings,
|
||||
std::span<const VkVertexInputAttributeDescription> vertex_attributes,
|
||||
std::span<const vk::VertexInputBindingDescription> vertex_bindings,
|
||||
std::span<const vk::VertexInputAttributeDescription> vertex_attributes,
|
||||
VkRenderPass render_pass
|
||||
) -> vk::Pipeline;
|
||||
|
||||
@@ -382,6 +382,20 @@ public:
|
||||
*/
|
||||
void cleanup();
|
||||
|
||||
// ========================================================================
|
||||
// 公共辅助方法
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 计算顶点布局哈希
|
||||
* @param bindings 顶点绑定描述
|
||||
* @param attributes 顶点属性描述
|
||||
* @return 哈希值
|
||||
*/
|
||||
[[nodiscard]] static auto compute_vertex_layout_hash(
|
||||
std::span<const vk::VertexInputBindingDescription> bindings,
|
||||
std::span<const vk::VertexInputAttributeDescription> attributes
|
||||
) -> std::size_t;
|
||||
private:
|
||||
// ========================================================================
|
||||
// 私有方法
|
||||
@@ -410,8 +424,8 @@ private:
|
||||
device_handle_t<vk::ShaderModule> vert_module,
|
||||
device_handle_t<vk::ShaderModule> frag_module,
|
||||
vk::DescriptorSetLayout desc_layout,
|
||||
std::span<const VkVertexInputBindingDescription> vertex_bindings,
|
||||
std::span<const VkVertexInputAttributeDescription> vertex_attributes,
|
||||
std::span<const vk::VertexInputBindingDescription> vertex_bindings,
|
||||
std::span<const vk::VertexInputAttributeDescription> vertex_attributes,
|
||||
VkRenderPass render_pass
|
||||
) -> pipeline_resources_t;
|
||||
|
||||
@@ -438,17 +452,6 @@ private:
|
||||
*/
|
||||
void create_per_frame_uniform_buffer(uint32_t frame_index, size_t capacity);
|
||||
|
||||
/**
|
||||
* @brief 计算顶点布局哈希
|
||||
* @param bindings 顶点绑定描述
|
||||
* @param attributes 顶点属性描述
|
||||
* @return 哈希值
|
||||
*/
|
||||
[[nodiscard]] static auto compute_vertex_layout_hash(
|
||||
std::span<const VkVertexInputBindingDescription> bindings,
|
||||
std::span<const VkVertexInputAttributeDescription> attributes
|
||||
) -> std::size_t;
|
||||
|
||||
// ========================================================================
|
||||
// 成员变量
|
||||
// ========================================================================
|
||||
|
||||
@@ -36,5 +36,12 @@ namespace mirage {
|
||||
vk::DescriptorType type; ///< 描述符类型
|
||||
uint32_t count; ///< 描述符数量
|
||||
vk::ShaderStageFlags stage; ///< 着色器阶段
|
||||
|
||||
bool operator==(const shader_binding_info& other) const {
|
||||
return binding == other.binding &&
|
||||
type == other.type &&
|
||||
count == other.count &&
|
||||
stage == other.stage;
|
||||
}
|
||||
};
|
||||
} // namespace mirage
|
||||
|
||||
@@ -5,216 +5,216 @@
|
||||
#include <type_traits>
|
||||
|
||||
namespace mirage {
|
||||
/// @brief 自定义着色器控件模板基类
|
||||
///
|
||||
/// @tparam ParamsT 着色器参数结构体类型(由着色器工具自动生成)
|
||||
/// @tparam VertexT 顶点类型(默认使用 ui_vertex)
|
||||
///
|
||||
/// 用户通过继承此类创建自定义着色器控件。ParamsT 类型应由着色器工具
|
||||
/// 从 GLSL UBO 定义自动生成,确保 C++ 和着色器之间的类型安全。
|
||||
///
|
||||
/// 支持三种渲染模式:
|
||||
/// - **程序化渲染**:使用着色器生成内容(无子控件,无源纹理)
|
||||
/// - **后处理模式**:对子控件渲染结果或指定纹理应用着色器效果
|
||||
/// - **自定义几何模式**:使用自定义顶点着色器和顶点缓冲
|
||||
///
|
||||
/// @example
|
||||
/// ```cpp
|
||||
/// // 使用工具生成的类型
|
||||
/// #include "gen/shaders/gradient.h"
|
||||
///
|
||||
/// class gradient_widget : public custom_shader_widget<shaders::GradientParams> {
|
||||
/// public:
|
||||
/// gradient_widget() {
|
||||
/// params().start_color = {1, 0, 0, 1};
|
||||
/// params().end_color = {0, 0, 1, 1};
|
||||
/// }
|
||||
///
|
||||
/// auto& colors(const vec4f_t& start, const vec4f_t& end) {
|
||||
/// params().start_color = start;
|
||||
/// params().end_color = end;
|
||||
/// mark_params_dirty();
|
||||
/// return *this;
|
||||
/// }
|
||||
///
|
||||
/// protected:
|
||||
/// auto get_shader_id() const noexcept -> uint32_t override {
|
||||
/// return hash_compile_time("gradient_widget");
|
||||
/// }
|
||||
///
|
||||
/// auto get_fragment_shader_spirv() const -> std::span<const uint32_t> override {
|
||||
/// return shaders::gradient_frag_spirv;
|
||||
/// }
|
||||
///
|
||||
/// auto get_bindings() const -> std::span<const shader_binding_info> override {
|
||||
/// return shaders::gradient_bindings;
|
||||
/// }
|
||||
///
|
||||
/// auto get_render_mode() const noexcept -> custom_shader_render_mode override {
|
||||
/// return custom_shader_render_mode::procedural;
|
||||
/// }
|
||||
/// };
|
||||
/// ```
|
||||
template <typename ParamsT, typename VertexT = ui_vertex>
|
||||
class custom_shader_widget : public custom_shader_widget_base {
|
||||
public:
|
||||
using params_type = ParamsT;
|
||||
using vertex_type = VertexT;
|
||||
|
||||
/// @brief 自定义着色器控件模板基类
|
||||
///
|
||||
/// @tparam ParamsT 着色器参数结构体类型(由着色器工具自动生成)
|
||||
/// @tparam VertexT 顶点类型(默认使用 ui_vertex)
|
||||
///
|
||||
/// 用户通过继承此类创建自定义着色器控件。ParamsT 类型应由着色器工具
|
||||
/// 从 GLSL UBO 定义自动生成,确保 C++ 和着色器之间的类型安全。
|
||||
///
|
||||
/// 支持三种渲染模式:
|
||||
/// - **程序化渲染**:使用着色器生成内容(无子控件,无源纹理)
|
||||
/// - **后处理模式**:对子控件渲染结果或指定纹理应用着色器效果
|
||||
/// - **自定义几何模式**:使用自定义顶点着色器和顶点缓冲
|
||||
///
|
||||
/// @example
|
||||
/// ```cpp
|
||||
/// // 使用工具生成的类型
|
||||
/// #include "gen/shaders/gradient.h"
|
||||
///
|
||||
/// class gradient_widget : public custom_shader_widget<shaders::GradientParams> {
|
||||
/// public:
|
||||
/// gradient_widget() {
|
||||
/// params().start_color = {1, 0, 0, 1};
|
||||
/// params().end_color = {0, 0, 1, 1};
|
||||
/// }
|
||||
///
|
||||
/// auto& colors(const vec4f_t& start, const vec4f_t& end) {
|
||||
/// params().start_color = start;
|
||||
/// params().end_color = end;
|
||||
/// mark_params_dirty();
|
||||
/// return *this;
|
||||
/// }
|
||||
///
|
||||
/// protected:
|
||||
/// auto get_shader_id() const noexcept -> uint32_t override {
|
||||
/// return hash_compile_time("gradient_widget");
|
||||
/// }
|
||||
///
|
||||
/// auto get_fragment_shader_spirv() const -> std::span<const uint32_t> override {
|
||||
/// return shaders::gradient_frag_spirv;
|
||||
/// }
|
||||
///
|
||||
/// auto get_bindings() const -> std::span<const shader_binding_info> override {
|
||||
/// return shaders::gradient_bindings;
|
||||
/// }
|
||||
///
|
||||
/// auto get_render_mode() const noexcept -> custom_shader_render_mode override {
|
||||
/// return custom_shader_render_mode::procedural;
|
||||
/// }
|
||||
/// };
|
||||
/// ```
|
||||
template <typename ParamsT, typename VertexT = ui_vertex>
|
||||
class custom_shader_widget : public custom_shader_widget_base {
|
||||
public:
|
||||
using params_type = ParamsT;
|
||||
using vertex_type = VertexT;
|
||||
// 静态断言:确保 ParamsT 满足要求
|
||||
static_assert(std::is_standard_layout_v<ParamsT>,
|
||||
"ParamsT must be standard layout for GPU compatibility");
|
||||
static_assert(alignof(ParamsT) <= 16,
|
||||
"ParamsT alignment must not exceed 16 bytes");
|
||||
|
||||
// 静态断言:确保 ParamsT 满足要求
|
||||
static_assert(std::is_standard_layout_v<ParamsT>,
|
||||
"ParamsT must be standard layout for GPU compatibility");
|
||||
static_assert(alignof(ParamsT) <= 16,
|
||||
"ParamsT alignment must not exceed 16 bytes");
|
||||
custom_shader_widget() = default;
|
||||
~custom_shader_widget() override = default;
|
||||
|
||||
custom_shader_widget() = default;
|
||||
~custom_shader_widget() override = default;
|
||||
// ========================================================================
|
||||
// 参数访问
|
||||
// ========================================================================
|
||||
|
||||
// ========================================================================
|
||||
// 参数访问
|
||||
// ========================================================================
|
||||
/// @brief 获取参数的可变引用
|
||||
/// @note 修改后需要调用 mark_params_dirty()
|
||||
[[nodiscard]] auto params() noexcept -> ParamsT& { return params_; }
|
||||
|
||||
/// @brief 获取参数的可变引用
|
||||
/// @note 修改后需要调用 mark_params_dirty()
|
||||
[[nodiscard]] auto params() noexcept -> ParamsT& { return params_; }
|
||||
/// @brief 获取参数的只读引用
|
||||
[[nodiscard]] auto params() const noexcept -> const ParamsT& { return params_; }
|
||||
|
||||
/// @brief 获取参数的只读引用
|
||||
[[nodiscard]] auto params() const noexcept -> const ParamsT& { return params_; }
|
||||
/// @brief 标记参数已修改
|
||||
void mark_params_dirty() {
|
||||
params_dirty_ = true;
|
||||
mark_render_dirty_internal();
|
||||
}
|
||||
|
||||
/// @brief 标记参数已修改
|
||||
void mark_params_dirty() {
|
||||
params_dirty_ = true;
|
||||
mark_render_dirty_internal();
|
||||
}
|
||||
protected:
|
||||
// ========================================================================
|
||||
// 实现基类纯虚函数
|
||||
// ========================================================================
|
||||
|
||||
protected:
|
||||
// ========================================================================
|
||||
// 实现基类纯虚函数
|
||||
// ========================================================================
|
||||
[[nodiscard]] auto get_params_data() const
|
||||
-> std::pair<const void*, size_t> override {
|
||||
return {¶ms_, sizeof(ParamsT)};
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_params_data() const
|
||||
-> std::pair<const void*, size_t> override {
|
||||
return {¶ms_, sizeof(ParamsT)};
|
||||
}
|
||||
[[nodiscard]] auto is_params_dirty() const noexcept -> bool override {
|
||||
return params_dirty_;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto is_params_dirty() const noexcept -> bool override {
|
||||
return params_dirty_;
|
||||
}
|
||||
void clear_params_dirty() override {
|
||||
params_dirty_ = false;
|
||||
}
|
||||
|
||||
void clear_params_dirty() override {
|
||||
params_dirty_ = false;
|
||||
}
|
||||
// ========================================================================
|
||||
// 自定义顶点支持
|
||||
// ========================================================================
|
||||
|
||||
// ========================================================================
|
||||
// 自定义顶点支持
|
||||
// ========================================================================
|
||||
/// @brief 标记顶点数据已修改
|
||||
void mark_vertices_dirty() {
|
||||
vertices_dirty_ = true;
|
||||
mark_render_dirty_internal();
|
||||
}
|
||||
|
||||
/// @brief 标记顶点数据已修改
|
||||
void mark_vertices_dirty() {
|
||||
vertices_dirty_ = true;
|
||||
mark_render_dirty_internal();
|
||||
}
|
||||
[[nodiscard]] auto is_vertices_dirty() const noexcept -> bool override {
|
||||
return vertices_dirty_;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto is_vertices_dirty() const noexcept -> bool override {
|
||||
return vertices_dirty_;
|
||||
}
|
||||
void clear_vertices_dirty() override {
|
||||
vertices_dirty_ = false;
|
||||
}
|
||||
|
||||
void clear_vertices_dirty() override {
|
||||
vertices_dirty_ = false;
|
||||
}
|
||||
// ========================================================================
|
||||
// 顶点数据管理(仅 custom_geometry 模式使用)
|
||||
// ========================================================================
|
||||
|
||||
// ========================================================================
|
||||
// 顶点数据管理(仅 custom_geometry 模式使用)
|
||||
// ========================================================================
|
||||
/// @brief 获取顶点数据
|
||||
[[nodiscard]] auto get_vertices() const noexcept -> const std::vector<VertexT>& {
|
||||
return vertices_;
|
||||
}
|
||||
|
||||
/// @brief 获取顶点数据
|
||||
[[nodiscard]] auto get_vertices() const noexcept -> const std::vector<VertexT>& {
|
||||
return vertices_;
|
||||
}
|
||||
/// @brief 获取顶点数据(可修改)
|
||||
[[nodiscard]] auto get_vertices() noexcept -> std::vector<VertexT>& {
|
||||
return vertices_;
|
||||
}
|
||||
|
||||
/// @brief 获取顶点数据(可修改)
|
||||
[[nodiscard]] auto get_vertices() noexcept -> std::vector<VertexT>& {
|
||||
return vertices_;
|
||||
}
|
||||
/// @brief 设置顶点数据
|
||||
void set_vertices(std::vector<VertexT> vertices) {
|
||||
vertices_ = std::move(vertices);
|
||||
mark_vertices_dirty();
|
||||
}
|
||||
|
||||
/// @brief 设置顶点数据
|
||||
void set_vertices(std::vector<VertexT> vertices) {
|
||||
vertices_ = std::move(vertices);
|
||||
mark_vertices_dirty();
|
||||
}
|
||||
/// @brief 获取索引数据
|
||||
[[nodiscard]] auto get_indices() const noexcept -> const std::vector<uint32_t>& {
|
||||
return indices_;
|
||||
}
|
||||
|
||||
/// @brief 获取索引数据
|
||||
[[nodiscard]] auto get_indices() const noexcept -> const std::vector<uint32_t>& {
|
||||
return indices_;
|
||||
}
|
||||
/// @brief 设置索引数据
|
||||
void set_indices(std::vector<uint32_t> indices) {
|
||||
indices_ = std::move(indices);
|
||||
mark_vertices_dirty();
|
||||
}
|
||||
|
||||
/// @brief 设置索引数据
|
||||
void set_indices(std::vector<uint32_t> indices) {
|
||||
indices_ = std::move(indices);
|
||||
mark_vertices_dirty();
|
||||
}
|
||||
/// @brief 获取顶点缓冲配置
|
||||
[[nodiscard]] auto get_vertex_buffer_config() const
|
||||
-> std::optional<custom_vertex_buffer_config> override {
|
||||
if (vertices_.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/// @brief 获取顶点缓冲配置
|
||||
[[nodiscard]] auto get_vertex_buffer_config() const
|
||||
-> std::optional<vertex_buffer_config> override {
|
||||
if (vertices_.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return custom_vertex_buffer_config{
|
||||
.data = vertices_.data(),
|
||||
.data_size = vertices_.size() * sizeof(VertexT),
|
||||
.vertex_count = vertices_.size(),
|
||||
.binding = get_vertex_binding_description(),
|
||||
.attributes = get_vertex_attribute_descriptions()
|
||||
};
|
||||
}
|
||||
|
||||
return vertex_buffer_config{
|
||||
.data = vertices_.data(),
|
||||
.data_size = vertices_.size() * sizeof(VertexT),
|
||||
.vertex_count = vertices_.size(),
|
||||
.binding = get_vertex_binding_description(),
|
||||
.attributes = get_vertex_attribute_descriptions()
|
||||
};
|
||||
}
|
||||
/// @brief 获取索引缓冲配置
|
||||
[[nodiscard]] auto get_index_buffer_config() const
|
||||
-> std::optional<index_buffer_config> override {
|
||||
if (indices_.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/// @brief 获取索引缓冲配置
|
||||
[[nodiscard]] auto get_index_buffer_config() const
|
||||
-> std::optional<index_buffer_config> override {
|
||||
if (indices_.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return index_buffer_config{
|
||||
.data = indices_.data(),
|
||||
.index_count = indices_.size()
|
||||
};
|
||||
}
|
||||
|
||||
return index_buffer_config{
|
||||
.data = indices_.data(),
|
||||
.index_count = indices_.size()
|
||||
};
|
||||
}
|
||||
/// @brief 获取顶点绑定描述(可重写)
|
||||
[[nodiscard]] virtual auto get_vertex_binding_description() const
|
||||
-> vk::VertexInputBindingDescription {
|
||||
if constexpr (requires { VertexT::get_binding_description(); }) {
|
||||
return VertexT::get_binding_description();
|
||||
}
|
||||
else {
|
||||
return vk::VertexInputBindingDescription{
|
||||
0, sizeof(VertexT), vk::VertexInputRate::eVertex
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 获取顶点绑定描述(可重写)
|
||||
[[nodiscard]] virtual auto get_vertex_binding_description() const
|
||||
-> vk::VertexInputBindingDescription {
|
||||
if constexpr (requires { VertexT::get_binding_description(); }) {
|
||||
return VertexT::get_binding_description();
|
||||
} else {
|
||||
return vk::VertexInputBindingDescription{
|
||||
0, sizeof(VertexT), vk::VertexInputRate::eVertex
|
||||
};
|
||||
}
|
||||
}
|
||||
/// @brief 获取顶点属性描述(可重写)
|
||||
[[nodiscard]] virtual auto get_vertex_attribute_descriptions() const
|
||||
-> std::vector<vk::VertexInputAttributeDescription> {
|
||||
if constexpr (requires { VertexT::get_attribute_descriptions(); }) {
|
||||
auto attrs = VertexT::get_attribute_descriptions();
|
||||
return std::vector<vk::VertexInputAttributeDescription>(
|
||||
attrs.begin(), attrs.end());
|
||||
}
|
||||
else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 获取顶点属性描述(可重写)
|
||||
[[nodiscard]] virtual auto get_vertex_attribute_descriptions() const
|
||||
-> std::vector<vk::VertexInputAttributeDescription> {
|
||||
if constexpr (requires { VertexT::get_attribute_descriptions(); }) {
|
||||
auto attrs = VertexT::get_attribute_descriptions();
|
||||
return std::vector<vk::VertexInputAttributeDescription>(
|
||||
attrs.begin(), attrs.end());
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
private:
|
||||
ParamsT params_{};
|
||||
bool params_dirty_ = true;
|
||||
bool vertices_dirty_ = false;
|
||||
|
||||
private:
|
||||
ParamsT params_{};
|
||||
bool params_dirty_ = true;
|
||||
bool vertices_dirty_ = false;
|
||||
|
||||
std::vector<VertexT> vertices_;
|
||||
std::vector<uint32_t> indices_;
|
||||
};
|
||||
|
||||
} // namespace mirage
|
||||
std::vector<VertexT> vertices_;
|
||||
std::vector<uint32_t> indices_;
|
||||
};
|
||||
} // namespace mirage
|
||||
|
||||
@@ -3,179 +3,176 @@
|
||||
#include "render/render_command.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mirage::ui {
|
||||
namespace mirage {
|
||||
struct custom_shader_widget_base::impl {
|
||||
impl() = default;
|
||||
};
|
||||
|
||||
struct custom_shader_widget_base::impl {
|
||||
impl() = default;
|
||||
};
|
||||
custom_shader_widget_base::custom_shader_widget_base() : impl_(std::make_unique<impl>()) {
|
||||
}
|
||||
|
||||
custom_shader_widget_base::custom_shader_widget_base()
|
||||
: impl_(std::make_unique<impl>()) {
|
||||
}
|
||||
custom_shader_widget_base::~custom_shader_widget_base() = default;
|
||||
|
||||
custom_shader_widget_base::~custom_shader_widget_base() = default;
|
||||
void custom_shader_widget_base::init(const std::shared_ptr<widget_context>& ctx) {
|
||||
single_child_widget_base::init(ctx);
|
||||
}
|
||||
|
||||
void custom_shader_widget_base::init(const std::shared_ptr<widget_context>& ctx) {
|
||||
single_child_widget_base::init(ctx);
|
||||
}
|
||||
void custom_shader_widget_base::tick(float dt) {
|
||||
single_child_widget_base::tick(dt);
|
||||
|
||||
void custom_shader_widget_base::tick(float dt) {
|
||||
single_child_widget_base::tick(dt);
|
||||
// 更新时间
|
||||
time_ += dt;
|
||||
|
||||
// 更新时间
|
||||
time_ += dt;
|
||||
// 如果需要每帧更新,标记脏状态
|
||||
if (is_animated()) {
|
||||
mark_render_dirty_internal();
|
||||
}
|
||||
}
|
||||
|
||||
// 如果需要每帧更新,标记脏状态
|
||||
if (is_animated()) {
|
||||
mark_render_dirty_internal();
|
||||
}
|
||||
}
|
||||
auto custom_shader_widget_base::do_measure(const vec2f_t& available_size) const -> vec2f_t {
|
||||
// 如果设置了固定大小,直接返回
|
||||
if (fixed_size_.x() > 0 || fixed_size_.y() > 0) {
|
||||
return fixed_size_;
|
||||
}
|
||||
|
||||
auto custom_shader_widget_base::do_measure(const vec2f_t& available_size) const -> vec2f_t {
|
||||
// 如果设置了固定大小,直接返回
|
||||
if (fixed_size_.x() > 0 || fixed_size_.y() > 0) {
|
||||
return fixed_size_;
|
||||
}
|
||||
// 尝试使用子控件的大小
|
||||
auto child = get_child();
|
||||
if (child) {
|
||||
return child->measure(available_size);
|
||||
}
|
||||
|
||||
// 尝试使用子控件的大小
|
||||
auto child = get_child();
|
||||
if (child) {
|
||||
return child->measure(available_size);
|
||||
}
|
||||
// 如果没有子控件且没有设置固定大小,使用可用空间
|
||||
return available_size;
|
||||
}
|
||||
|
||||
// 如果没有子控件且没有设置固定大小,使用可用空间
|
||||
return available_size;
|
||||
}
|
||||
void custom_shader_widget_base::arrange(const layout_state& state) {
|
||||
// 使用 layout_write_context 更新状态
|
||||
if (auto ctx = get_context()) {
|
||||
auto write_ctx = ctx->state_store().begin_layout_update(
|
||||
ctx->current_frame()
|
||||
);
|
||||
write_ctx.update_layout(get_widget_id(), state);
|
||||
write_ctx.commit();
|
||||
}
|
||||
|
||||
void custom_shader_widget_base::arrange(const layout_state& state) {
|
||||
// 使用 layout_write_context 更新状态
|
||||
if (auto ctx = get_context()) {
|
||||
auto write_ctx = ctx->state_store().begin_layout_update(
|
||||
ctx->current_frame()
|
||||
);
|
||||
write_ctx.update_layout(get_widget_id(), state);
|
||||
write_ctx.commit();
|
||||
}
|
||||
// 排列子控件
|
||||
auto child = get_child();
|
||||
if (child) {
|
||||
child->arrange(state);
|
||||
}
|
||||
}
|
||||
|
||||
// 排列子控件
|
||||
auto child = get_child();
|
||||
if (child) {
|
||||
child->arrange(state);
|
||||
}
|
||||
}
|
||||
int32_t custom_shader_widget_base::build_render_command(
|
||||
render_collector& collector,
|
||||
int32_t z_order
|
||||
) const {
|
||||
// 获取布局状态
|
||||
auto layout_state_opt = get_layout_state();
|
||||
if (!layout_state_opt) {
|
||||
return z_order;
|
||||
}
|
||||
|
||||
int32_t custom_shader_widget_base::build_render_command(
|
||||
render_collector& collector,
|
||||
int32_t z_order
|
||||
) const {
|
||||
// 获取布局状态
|
||||
auto layout_state_opt = get_layout_state();
|
||||
if (!layout_state_opt) {
|
||||
return z_order;
|
||||
}
|
||||
const auto& state = layout_state_opt.value();
|
||||
|
||||
const auto& state = layout_state_opt.value();
|
||||
// 检查是否应该渲染
|
||||
if (!should_render()) {
|
||||
return z_order;
|
||||
}
|
||||
|
||||
// 检查是否应该渲染
|
||||
if (!should_render()) {
|
||||
return z_order;
|
||||
}
|
||||
// 获取渲染模式
|
||||
auto render_mode = get_render_mode();
|
||||
|
||||
// 获取渲染模式
|
||||
auto render_mode = get_render_mode();
|
||||
// TODO: post_process 模式需要特殊处理
|
||||
// post_process 模式不是先绘制子控件,而是影响当前控件下的内容
|
||||
// 这需要在渲染器层面支持,需要后续实现 shader_resource_manager 和
|
||||
// custom_shader_widget_renderer 后再完善
|
||||
|
||||
// TODO: post_process 模式需要特殊处理
|
||||
// post_process 模式不是先绘制子控件,而是影响当前控件下的内容
|
||||
// 这需要在渲染器层面支持,需要后续实现 shader_resource_manager 和
|
||||
// custom_shader_widget_renderer 后再完善
|
||||
// 对于 procedural 和 custom_geometry 模式,直接构建渲染命令
|
||||
// 对于 post_process 模式,暂时使用占位符,后续完善
|
||||
|
||||
// 对于 procedural 和 custom_geometry 模式,直接构建渲染命令
|
||||
// 对于 post_process 模式,暂时使用占位符,后续完善
|
||||
if (render_mode == custom_shader_render_mode::post_process) {
|
||||
// post_process 模式:需要在渲染时先渲染子内容,再应用着色器效果
|
||||
// TODO: 需要实现完整的 post_process 支持
|
||||
// 包括:
|
||||
// 1. 创建临时渲染目标 (offscreen target)
|
||||
// 2. 先渲染子内容到临时目标
|
||||
// 3. 应用着色器效果(采样临时目标)
|
||||
// 4. 释放临时目标
|
||||
|
||||
if (render_mode == custom_shader_render_mode::post_process) {
|
||||
// post_process 模式:需要在渲染时先渲染子内容,再应用着色器效果
|
||||
// TODO: 需要实现完整的 post_process 支持
|
||||
// 包括:
|
||||
// 1. 创建临时渲染目标 (offscreen target)
|
||||
// 2. 先渲染子内容到临时目标
|
||||
// 3. 应用着色器效果(采样临时目标)
|
||||
// 4. 释放临时目标
|
||||
// 暂时提交一个占位符命令
|
||||
shader_uniform_map uniforms;
|
||||
uniforms["_render_mode"] = static_cast<uint32_t>(render_mode);
|
||||
|
||||
// 暂时提交一个占位符命令
|
||||
shader_uniform_map uniforms;
|
||||
uniforms["_render_mode"] = static_cast<uint32_t>(render_mode);
|
||||
custom_shader_effect effect(
|
||||
state.global_pos(),
|
||||
state.size(),
|
||||
get_shader_id(),
|
||||
std::move(uniforms),
|
||||
1.0f
|
||||
);
|
||||
effect.source = sample_source::previous_content;
|
||||
effect.order = render_order::at(z_order, state.get_global_aabb());
|
||||
|
||||
custom_shader_effect effect(
|
||||
vec2f_t(state.offset().x(), state.offset().y()),
|
||||
vec2f_t(state.size().x(), state.size().y()),
|
||||
get_shader_id(),
|
||||
std::move(uniforms),
|
||||
1.0f
|
||||
);
|
||||
effect.source = sample_source::previous_content;
|
||||
effect.order = render_order::at(z_order, state.clip_rect());
|
||||
collector.submit_post_effect(std::move(effect));
|
||||
}
|
||||
else {
|
||||
// procedural 或 custom_geometry 模式
|
||||
custom_shader_widget_command cmd;
|
||||
|
||||
collector.submit_post_effect(std::move(effect));
|
||||
}
|
||||
else {
|
||||
// procedural 或 custom_geometry 模式
|
||||
custom_shader_widget_command cmd;
|
||||
// 基本信息
|
||||
cmd.shader_id = get_shader_id();
|
||||
cmd.position = state.global_pos();
|
||||
cmd.size = state.size();
|
||||
cmd.order = render_order::at(z_order, state.get_global_aabb());
|
||||
|
||||
// 基本信息
|
||||
cmd.shader_id = get_shader_id();
|
||||
cmd.position = vec2f_t(state.offset().x(), state.offset().y());
|
||||
cmd.size = vec2f_t(state.size().x(), state.size().y());
|
||||
cmd.order = render_order::at(z_order, state.clip_rect());
|
||||
// 着色器配置
|
||||
cmd.vert_spirv = get_vertex_shader_spirv();
|
||||
cmd.frag_spirv = get_fragment_shader_spirv();
|
||||
cmd.bindings = get_bindings();
|
||||
|
||||
// 着色器配置
|
||||
cmd.vert_spirv = get_vertex_shader_spirv();
|
||||
cmd.frag_spirv = get_fragment_shader_spirv();
|
||||
cmd.bindings = get_bindings();
|
||||
// 渲染模式
|
||||
cmd.render_mode = render_mode;
|
||||
cmd.source_texture = get_source_texture_id();
|
||||
|
||||
// 渲染模式
|
||||
cmd.render_mode = render_mode;
|
||||
cmd.source_texture = get_source_texture_id();
|
||||
// 参数数据
|
||||
auto params_pair = get_params_data();
|
||||
cmd.params_data = params_pair.first;
|
||||
cmd.params_size = params_pair.second;
|
||||
cmd.params_dirty = is_params_dirty();
|
||||
|
||||
// 参数数据
|
||||
auto params_pair = get_params_data();
|
||||
cmd.params_data = params_pair.first;
|
||||
cmd.params_size = params_pair.second;
|
||||
cmd.params_dirty = is_params_dirty();
|
||||
// 顶点数据(custom_geometry 模式)
|
||||
cmd.vertex_config = get_vertex_buffer_config();
|
||||
cmd.index_config = get_index_buffer_config();
|
||||
cmd.vertices_dirty = is_vertices_dirty();
|
||||
|
||||
// 顶点数据(custom_geometry 模式)
|
||||
cmd.vertex_config = get_vertex_buffer_config();
|
||||
cmd.index_config = get_index_buffer_config();
|
||||
cmd.vertices_dirty = is_vertices_dirty();
|
||||
// 提交命令 - 使用占位符 custom_shader_effect,实际命令在渲染器中构建
|
||||
custom_shader_effect effect(
|
||||
cmd.position,
|
||||
cmd.size,
|
||||
cmd.shader_id,
|
||||
{},
|
||||
1.0f
|
||||
);
|
||||
effect.order = cmd.order;
|
||||
|
||||
// 提交命令 - 使用占位符 custom_shader_effect,实际命令在渲染器中构建
|
||||
custom_shader_effect effect(
|
||||
cmd.position,
|
||||
cmd.size,
|
||||
cmd.shader_id,
|
||||
{},
|
||||
1.0f
|
||||
);
|
||||
effect.order = cmd.order;
|
||||
collector.submit_post_effect(std::move(effect));
|
||||
}
|
||||
|
||||
collector.submit_post_effect(std::move(effect));
|
||||
}
|
||||
return z_order + 1;
|
||||
}
|
||||
|
||||
return z_order + 1;
|
||||
}
|
||||
void custom_shader_widget_base::set_fixed_size(const vec2f_t& size) {
|
||||
fixed_size_ = size;
|
||||
mark_measure_dirty();
|
||||
}
|
||||
|
||||
void custom_shader_widget_base::set_fixed_size(const vec2f_t& size) {
|
||||
fixed_size_ = size;
|
||||
mark_measure_dirty();
|
||||
}
|
||||
void custom_shader_widget_base::mark_render_dirty_internal() {
|
||||
mark_render_dirty();
|
||||
}
|
||||
|
||||
void custom_shader_widget_base::mark_render_dirty_internal() {
|
||||
mark_render_dirty();
|
||||
}
|
||||
|
||||
auto custom_shader_widget_base::get_vertex_shader_spirv() const
|
||||
-> std::span<const uint32_t> {
|
||||
// 默认返回空 span,由渲染器使用默认顶点着色器
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace mirage::ui
|
||||
auto custom_shader_widget_base::get_vertex_shader_spirv() const
|
||||
-> std::span<const uint32_t> {
|
||||
// 默认返回空 span,由渲染器使用默认顶点着色器
|
||||
return {};
|
||||
}
|
||||
} // namespace mirage
|
||||
|
||||
@@ -75,6 +75,25 @@ protected:
|
||||
/// @brief 清除参数脏标记
|
||||
virtual void clear_params_dirty() = 0;
|
||||
|
||||
// ========================================================================
|
||||
// Push Constants 效果参数相关(可选重写)
|
||||
// ========================================================================
|
||||
|
||||
/// @brief 获取 Push Constants 效果参数数据指针和大小
|
||||
/// @return {数据指针, 数据大小},如果没有 Push Constants 则返回 {nullptr, 0}
|
||||
[[nodiscard]] virtual auto get_push_constant_effect_data() const
|
||||
-> std::pair<const void*, size_t> {
|
||||
return {nullptr, 0};
|
||||
}
|
||||
|
||||
/// @brief Push Constants 效果参数是否已修改
|
||||
[[nodiscard]] virtual auto is_push_constant_effect_dirty() const noexcept -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief 清除 Push Constants 效果参数脏标记
|
||||
virtual void clear_push_constant_effect_dirty() {}
|
||||
|
||||
// ========================================================================
|
||||
// 子类可选重写的虚函数
|
||||
// ========================================================================
|
||||
@@ -107,7 +126,7 @@ protected:
|
||||
|
||||
/// @brief 获取顶点缓冲配置
|
||||
[[nodiscard]] virtual auto get_vertex_buffer_config() const
|
||||
-> std::optional<vertex_buffer_config> {
|
||||
-> std::optional<custom_vertex_buffer_config> {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,9 @@ namespace mirage {
|
||||
custom_geometry ///< 自定义几何(使用自定义顶点和顶点着色器)
|
||||
};
|
||||
|
||||
/// @brief 顶点缓冲配置
|
||||
struct vertex_buffer_config {
|
||||
/// @brief 顶点缓冲配置(用于自定义着色器控件)
|
||||
/// @note 使用 custom_vertex_buffer_config 以避免与 mirage::vertex_buffer_config 冲突
|
||||
struct custom_vertex_buffer_config {
|
||||
const void* data; ///< 顶点数据指针
|
||||
size_t data_size; ///< 数据大小(字节)
|
||||
size_t vertex_count; ///< 顶点数量
|
||||
@@ -40,4 +41,4 @@ namespace mirage {
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
} // namespace mirage::ui
|
||||
} // namespace mirage
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "ui/widgets/custom_shader/custom_shader_widget.h"
|
||||
#include <glm/vec2.hpp>
|
||||
#include "ui/widgets/custom_shader/shader_spec_widget.h"
|
||||
#include "blur_vert_frag.h"
|
||||
|
||||
namespace mirage::ui {
|
||||
namespace mirage {
|
||||
|
||||
/// @brief 高斯模糊效果控件
|
||||
///
|
||||
@@ -13,7 +13,7 @@ namespace mirage::ui {
|
||||
///
|
||||
/// @par 参数说明
|
||||
/// - radius: 模糊半径(像素),控制模糊程度
|
||||
/// - intensity: 效果强度 [0.0, 1.0],控制模糊效果的明显程度
|
||||
/// - samples: 采样次数,控制模糊质量
|
||||
/// - direction: 模糊方向,用于分离式模糊(当前单 pass 实现中可忽略)
|
||||
///
|
||||
/// @par 使用示例
|
||||
@@ -22,25 +22,22 @@ namespace mirage::ui {
|
||||
/// auto blur = create_widget<blur_widget>();
|
||||
/// blur->set_size({200, 100});
|
||||
/// blur->set_radius(5.0f);
|
||||
/// blur->set_intensity(0.8f);
|
||||
/// blur->set_samples(32);
|
||||
/// blur->set_direction(glm::vec2{1.0f, 0.0f}); // 水平模糊
|
||||
/// @endcode
|
||||
class blur_widget : public custom_shader_widget<blur_widget::BlurParams> {
|
||||
class blur_widget : public shader_spec_widget<shaders::blur_shader_spec<>> {
|
||||
public:
|
||||
/// @brief 模糊效果参数结构体
|
||||
/// @note 对应 shader 中的 BlurParams UBO
|
||||
/// @note 结构体大小为 24 字节,符合 std140 布局对齐要求
|
||||
struct BlurParams {
|
||||
float radius{5.0f}; ///< 模糊半径(像素)
|
||||
float intensity{1.0f}; ///< 效果强度 [0, 1]
|
||||
alignas(8) glm::vec2 direction{ ///< 模糊方向(用于分离式模糊)
|
||||
1.0f, 0.0f
|
||||
};
|
||||
};
|
||||
blur_widget() {
|
||||
// Uniform Buffer 参数默认值
|
||||
params().radius = 5.0f;
|
||||
params().samples = 16;
|
||||
params().direction = vec2f_t{1.0f, 0.0f};
|
||||
|
||||
static_assert(sizeof(BlurParams) == 24, "BlurParams must be 24 bytes for std140 layout");
|
||||
|
||||
blur_widget() = default;
|
||||
// Push Constants 效果参数默认值
|
||||
push_constant_effect().intensity = 1.0f;
|
||||
push_constant_effect().effect_rect = vec4f_t{0.0f, 0.0f, 0.0f, 0.0f};
|
||||
push_constant_effect().original_effect_rect = vec4f_t{0.0f, 0.0f, 0.0f, 0.0f};
|
||||
}
|
||||
~blur_widget() override = default;
|
||||
|
||||
// ========================================================================
|
||||
@@ -51,7 +48,7 @@ public:
|
||||
/// @param radius 模糊半径(像素)
|
||||
/// @return *this
|
||||
auto& set_radius(float radius) {
|
||||
params().radius = glm::max(0.0f, radius);
|
||||
params().radius = std::max(0.0f, radius);
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
}
|
||||
@@ -62,25 +59,25 @@ public:
|
||||
return params().radius;
|
||||
}
|
||||
|
||||
/// @brief 设置效果强度
|
||||
/// @param intensity 效果强度 [0, 1]
|
||||
/// @brief 设置采样次数
|
||||
/// @param samples 采样次数
|
||||
/// @return *this
|
||||
auto& set_intensity(float intensity) {
|
||||
params().intensity = glm::clamp(intensity, 0.0f, 1.0f);
|
||||
auto& set_samples(int32_t samples) {
|
||||
params().samples = std::max(1, samples);
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief 获取效果强度
|
||||
/// @return 效果强度 [0, 1]
|
||||
[[nodiscard]] auto get_intensity() const noexcept -> float {
|
||||
return params().intensity;
|
||||
/// @brief 获取采样次数
|
||||
/// @return 采样次数
|
||||
[[nodiscard]] auto get_samples() const noexcept -> int32_t {
|
||||
return params().samples;
|
||||
}
|
||||
|
||||
/// @brief 设置模糊方向
|
||||
/// @param direction 模糊方向向量(归一化)
|
||||
/// @return *this
|
||||
auto& set_direction(const glm::vec2& direction) {
|
||||
auto& set_direction(const vec2f_t& direction) {
|
||||
params().direction = direction;
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
@@ -88,14 +85,14 @@ public:
|
||||
|
||||
/// @brief 获取模糊方向
|
||||
/// @return 模糊方向向量
|
||||
[[nodiscard]] auto get_direction() const noexcept -> glm::vec2 {
|
||||
[[nodiscard]] auto get_direction() const noexcept -> vec2f_t {
|
||||
return params().direction;
|
||||
}
|
||||
|
||||
/// @brief 设置水平模糊方向
|
||||
/// @return *this
|
||||
auto& set_horizontal() {
|
||||
params().direction = glm::vec2{1.0f, 0.0f};
|
||||
params().direction = vec2f_t{1.0f, 0.0f};
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
}
|
||||
@@ -103,64 +100,70 @@ public:
|
||||
/// @brief 设置垂直模糊方向
|
||||
/// @return *this
|
||||
auto& set_vertical() {
|
||||
params().direction = glm::vec2{0.0f, 1.0f};
|
||||
params().direction = vec2f_t{0.0f, 1.0f};
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// 基类虚函数实现
|
||||
// Push Constants 效果参数接口
|
||||
// ========================================================================
|
||||
|
||||
/// @brief 设置效果强度
|
||||
/// @param intensity 强度值 [0.0, 1.0]
|
||||
/// @return *this
|
||||
auto& set_intensity(float intensity) {
|
||||
push_constant_effect().intensity = std::clamp(intensity, 0.0f, 1.0f);
|
||||
mark_push_constant_effect_dirty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief 获取效果强度
|
||||
/// @return 强度值 [0.0, 1.0]
|
||||
[[nodiscard]] auto get_intensity() const noexcept -> float {
|
||||
return push_constant_effect().intensity;
|
||||
}
|
||||
|
||||
/// @brief 设置效果区域
|
||||
/// @param rect 效果区域 (x, y, width, height)
|
||||
/// @return *this
|
||||
auto& set_effect_rect(const vec4f_t& rect) {
|
||||
push_constant_effect().effect_rect = rect;
|
||||
mark_push_constant_effect_dirty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief 获取效果区域
|
||||
/// @return 效果区域 (x, y, width, height)
|
||||
[[nodiscard]] auto get_effect_rect() const noexcept -> vec4f_t {
|
||||
return push_constant_effect().effect_rect;
|
||||
}
|
||||
|
||||
/// @brief 设置原始效果区域(用于 UV 计算)
|
||||
/// @param rect 原始效果区域 (x, y, width, height)
|
||||
/// @return *this
|
||||
auto& set_original_effect_rect(const vec4f_t& rect) {
|
||||
push_constant_effect().original_effect_rect = rect;
|
||||
mark_push_constant_effect_dirty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief 获取原始效果区域
|
||||
/// @return 原始效果区域 (x, y, width, height)
|
||||
[[nodiscard]] auto get_original_effect_rect() const noexcept -> vec4f_t {
|
||||
return push_constant_effect().original_effect_rect;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// 基类虚函数实现 - 只需重写渲染模式
|
||||
// ========================================================================
|
||||
|
||||
protected:
|
||||
/// @brief 获取着色器唯一标识符
|
||||
[[nodiscard]] auto get_shader_id() const noexcept -> uint32_t override {
|
||||
return hash_compile_time("blur_widget");
|
||||
}
|
||||
|
||||
/// @brief 获取片段着色器 SPIR-V
|
||||
/// @note TODO: 使用着色器工具链预编译的 SPIR-V
|
||||
[[nodiscard]] auto get_fragment_shader_spirv() const
|
||||
-> std::span<const uint32_t> override {
|
||||
// TODO: 返回预编译的 blur.frag.glsl SPIR-V
|
||||
// 从生成的着色器头文件获取:
|
||||
// return shaders::blur_frag_spirv;
|
||||
return {};
|
||||
}
|
||||
|
||||
/// @brief 获取描述符绑定信息
|
||||
[[nodiscard]] auto get_bindings() const
|
||||
-> std::span<const shader_binding_info> override {
|
||||
static constexpr shader_binding_info bindings[] = {
|
||||
{
|
||||
.binding = 0,
|
||||
.type = vk::DescriptorType::eUniformBuffer,
|
||||
.count = 1,
|
||||
.stage = vk::ShaderStageFlagBits::eFragment
|
||||
},
|
||||
{
|
||||
.binding = 1,
|
||||
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||
.count = 1,
|
||||
.stage = vk::ShaderStageFlagBits::eFragment
|
||||
}
|
||||
};
|
||||
return bindings;
|
||||
}
|
||||
|
||||
/// @brief 获取渲染模式
|
||||
[[nodiscard]] auto get_render_mode() const noexcept
|
||||
-> custom_shader_render_mode override {
|
||||
return custom_shader_render_mode::post_process;
|
||||
}
|
||||
|
||||
/// @brief 获取顶点着色器 SPIR-V
|
||||
/// @note 使用默认的程序化四边形顶点着色器
|
||||
[[nodiscard]] auto get_vertex_shader_spirv() const
|
||||
-> std::span<const uint32_t> override {
|
||||
// 返回空 span 使用默认顶点着色器
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mirage::ui
|
||||
} // namespace mirage
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "ui/widgets/custom_shader/custom_shader_widget.h"
|
||||
#include <glm/vec2.hpp>
|
||||
#include "ui/widgets/custom_shader/shader_spec_widget.h"
|
||||
#include "chromatic_aberration_vert_frag.h"
|
||||
|
||||
namespace mirage::ui {
|
||||
namespace mirage {
|
||||
|
||||
/// @brief 色差效果控件
|
||||
///
|
||||
@@ -12,32 +12,25 @@ namespace mirage::ui {
|
||||
///
|
||||
/// @par 参数说明
|
||||
/// - offset: RGB 通道偏移量(归一化坐标),控制颜色分离的程度
|
||||
/// - intensity: 效果强度 [0.0, 1.0],控制色差效果的明显程度
|
||||
///
|
||||
/// @par 使用示例
|
||||
/// @code
|
||||
/// // 创建色差效果控件
|
||||
/// auto chromatic_aberration = create_widget<chromatic_aberration_widget>();
|
||||
/// chromatic_aberration->set_size({200, 100});
|
||||
/// chromatic_aberration->set_offset(glm::vec2{0.02f, 0.0f});
|
||||
/// chromatic_aberration->set_intensity(0.8f);
|
||||
/// chromatic_aberration->set_offset(vec2f_t{0.02f, 0.0f});
|
||||
/// @endcode
|
||||
class chromatic_aberration_widget : public custom_shader_widget<chromatic_aberration_widget::ChromaticAberrationParams> {
|
||||
class chromatic_aberration_widget : public shader_spec_widget<shaders::chromatic_aberration_shader_spec<>> {
|
||||
public:
|
||||
/// @brief 色差效果参数结构体
|
||||
/// @note 对应 shader 中的 ChromaticAberrationParams UBO
|
||||
/// @note 结构体大小为 24 字节,符合 std140 布局对齐要求
|
||||
struct ChromaticAberrationParams {
|
||||
alignas(8) glm::vec2 offset{ ///< RGB 通道偏移量
|
||||
0.01f, 0.01f
|
||||
};
|
||||
float intensity{1.0f}; ///< 效果强度 [0, 1]
|
||||
float padding[2]{0.0f, 0.0f}; ///< 对齐填充
|
||||
};
|
||||
chromatic_aberration_widget() {
|
||||
// Uniform Buffer 参数默认值
|
||||
params().offset = vec2f_t{0.02f, 0.0f};
|
||||
|
||||
static_assert(sizeof(ChromaticAberrationParams) == 24, "ChromaticAberrationParams must be 24 bytes for std140 layout");
|
||||
|
||||
chromatic_aberration_widget() = default;
|
||||
// Push Constants 效果参数默认值
|
||||
push_constant_effect().intensity = 1.0f;
|
||||
push_constant_effect().effect_rect = vec4f_t{0.0f, 0.0f, 0.0f, 0.0f};
|
||||
push_constant_effect().original_effect_rect = vec4f_t{0.0f, 0.0f, 0.0f, 0.0f};
|
||||
}
|
||||
~chromatic_aberration_widget() override = default;
|
||||
|
||||
// ========================================================================
|
||||
@@ -47,7 +40,7 @@ public:
|
||||
/// @brief 设置 RGB 通道偏移量
|
||||
/// @param offset 偏移量(归一化坐标)
|
||||
/// @return *this
|
||||
auto& set_offset(const glm::vec2& offset) {
|
||||
auto& set_offset(const vec2f_t& offset) {
|
||||
params().offset = offset;
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
@@ -55,7 +48,7 @@ public:
|
||||
|
||||
/// @brief 获取 RGB 通道偏移量
|
||||
/// @return 偏移量
|
||||
[[nodiscard]] auto get_offset() const noexcept -> glm::vec2 {
|
||||
[[nodiscard]] auto get_offset() const noexcept -> vec2f_t {
|
||||
return params().offset;
|
||||
}
|
||||
|
||||
@@ -63,7 +56,7 @@ public:
|
||||
/// @param x_offset X 轴偏移量
|
||||
/// @return *this
|
||||
auto& set_offset_x(float x_offset) {
|
||||
params().offset.x = x_offset;
|
||||
params().offset.x() = x_offset;
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
}
|
||||
@@ -71,14 +64,14 @@ public:
|
||||
/// @brief 获取 X 轴偏移量
|
||||
/// @return X 轴偏移量
|
||||
[[nodiscard]] auto get_offset_x() const noexcept -> float {
|
||||
return params().offset.x;
|
||||
return params().offset.x();
|
||||
}
|
||||
|
||||
/// @brief 设置 Y 轴偏移量
|
||||
/// @param y_offset Y 轴偏移量
|
||||
/// @return *this
|
||||
auto& set_offset_y(float y_offset) {
|
||||
params().offset.y = y_offset;
|
||||
params().offset.y() = y_offset;
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
}
|
||||
@@ -86,77 +79,68 @@ public:
|
||||
/// @brief 获取 Y 轴偏移量
|
||||
/// @return Y 轴偏移量
|
||||
[[nodiscard]] auto get_offset_y() const noexcept -> float {
|
||||
return params().offset.y;
|
||||
return params().offset.y();
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Push Constants 效果参数接口
|
||||
// ========================================================================
|
||||
|
||||
/// @brief 设置效果强度
|
||||
/// @param intensity 效果强度 [0, 1]
|
||||
/// @param intensity 强度值 [0.0, 1.0]
|
||||
/// @return *this
|
||||
auto& set_intensity(float intensity) {
|
||||
params().intensity = glm::clamp(intensity, 0.0f, 1.0f);
|
||||
mark_params_dirty();
|
||||
push_constant_effect().intensity = std::clamp(intensity, 0.0f, 1.0f);
|
||||
mark_push_constant_effect_dirty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief 获取效果强度
|
||||
/// @return 效果强度 [0, 1]
|
||||
/// @return 强度值 [0.0, 1.0]
|
||||
[[nodiscard]] auto get_intensity() const noexcept -> float {
|
||||
return params().intensity;
|
||||
return push_constant_effect().intensity;
|
||||
}
|
||||
|
||||
/// @brief 设置效果区域
|
||||
/// @param rect 效果区域 (x, y, width, height)
|
||||
/// @return *this
|
||||
auto& set_effect_rect(const vec4f_t& rect) {
|
||||
push_constant_effect().effect_rect = rect;
|
||||
mark_push_constant_effect_dirty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief 获取效果区域
|
||||
/// @return 效果区域 (x, y, width, height)
|
||||
[[nodiscard]] auto get_effect_rect() const noexcept -> vec4f_t {
|
||||
return push_constant_effect().effect_rect;
|
||||
}
|
||||
|
||||
/// @brief 设置原始效果区域(用于 UV 计算)
|
||||
/// @param rect 原始效果区域 (x, y, width, height)
|
||||
/// @return *this
|
||||
auto& set_original_effect_rect(const vec4f_t& rect) {
|
||||
push_constant_effect().original_effect_rect = rect;
|
||||
mark_push_constant_effect_dirty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief 获取原始效果区域
|
||||
/// @return 原始效果区域 (x, y, width, height)
|
||||
[[nodiscard]] auto get_original_effect_rect() const noexcept -> vec4f_t {
|
||||
return push_constant_effect().original_effect_rect;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// 基类虚函数实现
|
||||
// 基类虚函数实现 - 只需重写渲染模式
|
||||
// ========================================================================
|
||||
|
||||
protected:
|
||||
/// @brief 获取着色器唯一标识符
|
||||
[[nodiscard]] auto get_shader_id() const noexcept -> uint32_t override {
|
||||
return hash_compile_time("chromatic_aberration_widget");
|
||||
}
|
||||
|
||||
/// @brief 获取片段着色器 SPIR-V
|
||||
/// @note TODO: 使用着色器工具链预编译的 SPIR-V
|
||||
[[nodiscard]] auto get_fragment_shader_spirv() const
|
||||
-> std::span<const uint32_t> override {
|
||||
// TODO: 返回预编译的 chromatic_aberration.frag.glsl SPIR-V
|
||||
// 从生成的着色器头文件获取:
|
||||
// return shaders::chromatic_aberration_frag_spirv;
|
||||
return {};
|
||||
}
|
||||
|
||||
/// @brief 获取描述符绑定信息
|
||||
[[nodiscard]] auto get_bindings() const
|
||||
-> std::span<const shader_binding_info> override {
|
||||
static constexpr shader_binding_info bindings[] = {
|
||||
{
|
||||
.binding = 0,
|
||||
.type = vk::DescriptorType::eUniformBuffer,
|
||||
.count = 1,
|
||||
.stage = vk::ShaderStageFlagBits::eFragment
|
||||
},
|
||||
{
|
||||
.binding = 1,
|
||||
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||
.count = 1,
|
||||
.stage = vk::ShaderStageFlagBits::eFragment
|
||||
}
|
||||
};
|
||||
return bindings;
|
||||
}
|
||||
|
||||
/// @brief 获取渲染模式
|
||||
[[nodiscard]] auto get_render_mode() const noexcept
|
||||
-> custom_shader_render_mode override {
|
||||
return custom_shader_render_mode::post_process;
|
||||
}
|
||||
|
||||
/// @brief 获取顶点着色器 SPIR-V
|
||||
/// @note 使用默认的程序化四边形顶点着色器
|
||||
[[nodiscard]] auto get_vertex_shader_spirv() const
|
||||
-> std::span<const uint32_t> override {
|
||||
// 返回空 span 使用默认顶点着色器
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mirage::ui
|
||||
} // namespace mirage
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "ui/widgets/custom_shader/custom_shader_widget.h"
|
||||
#include <glm/vec4.hpp>
|
||||
#include "ui/widgets/custom_shader/shader_spec_widget.h"
|
||||
#include "color_adjust_vert_frag.h"
|
||||
|
||||
namespace mirage::ui {
|
||||
namespace mirage {
|
||||
|
||||
/// @brief 颜色调整控件
|
||||
///
|
||||
@@ -20,21 +20,20 @@ namespace mirage::ui {
|
||||
/// color_adjust->set_saturation(1.5f);
|
||||
/// color_adjust->set_gamma(0.8f);
|
||||
/// @endcode
|
||||
class color_adjust_widget : public custom_shader_widget<color_adjust_widget::ColorAdjustParams> {
|
||||
class color_adjust_widget : public shader_spec_widget<shaders::color_adjust_shader_spec<>> {
|
||||
public:
|
||||
/// @brief 颜色调整参数结构体
|
||||
/// @note 对应 shader 中的 ColorAdjustParams UBO
|
||||
/// @note 结构体大小为 32 字节,符合 std140 布局对齐要求
|
||||
struct ColorAdjustParams {
|
||||
float brightness{0.0f}; ///< 亮度 [-1, 1]
|
||||
float contrast{1.0f}; ///< 对比度 [0, 2]
|
||||
float saturation{1.0f}; ///< 饱和度 [0, 2]
|
||||
float gamma{1.0f}; ///< 伽马 [0.1, 3]
|
||||
};
|
||||
color_adjust_widget() {
|
||||
// Uniform Buffer 参数默认值
|
||||
params().brightness = 0.0f;
|
||||
params().contrast = 1.0f;
|
||||
params().saturation = 1.0f;
|
||||
params().gamma = 1.0f;
|
||||
|
||||
static_assert(sizeof(ColorAdjustParams) == 16, "ColorAdjustParams must be 16 bytes for std140 layout");
|
||||
|
||||
color_adjust_widget() = default;
|
||||
// Push Constants 效果参数默认值
|
||||
push_constant_effect().intensity = 1.0f;
|
||||
push_constant_effect().effect_rect = vec4f_t{0.0f, 0.0f, 0.0f, 0.0f};
|
||||
push_constant_effect().original_effect_rect = vec4f_t{0.0f, 0.0f, 0.0f, 0.0f};
|
||||
}
|
||||
~color_adjust_widget() override = default;
|
||||
|
||||
// ========================================================================
|
||||
@@ -45,7 +44,7 @@ public:
|
||||
/// @param brightness 亮度 [-1, 1]
|
||||
/// @return *this
|
||||
auto& set_brightness(float brightness) {
|
||||
params().brightness = glm::clamp(brightness, -1.0f, 1.0f);
|
||||
params().brightness = std::clamp(brightness, -1.0f, 1.0f);
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
}
|
||||
@@ -60,7 +59,7 @@ public:
|
||||
/// @param contrast 对比度 [0, 2]
|
||||
/// @return *this
|
||||
auto& set_contrast(float contrast) {
|
||||
params().contrast = glm::clamp(contrast, 0.0f, 2.0f);
|
||||
params().contrast = std::clamp(contrast, 0.0f, 2.0f);
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
}
|
||||
@@ -75,7 +74,7 @@ public:
|
||||
/// @param saturation 饱和度 [0, 2]
|
||||
/// @return *this
|
||||
auto& set_saturation(float saturation) {
|
||||
params().saturation = glm::clamp(saturation, 0.0f, 2.0f);
|
||||
params().saturation = std::clamp(saturation, 0.0f, 2.0f);
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
}
|
||||
@@ -90,7 +89,7 @@ public:
|
||||
/// @param gamma 伽马 [0.1, 3]
|
||||
/// @return *this
|
||||
auto& set_gamma(float gamma) {
|
||||
params().gamma = glm::clamp(gamma, 0.1f, 3.0f);
|
||||
params().gamma = std::clamp(gamma, 0.1f, 3.0f);
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
}
|
||||
@@ -102,58 +101,64 @@ public:
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// 基类虚函数实现
|
||||
// Push Constants 效果参数接口
|
||||
// ========================================================================
|
||||
|
||||
/// @brief 设置效果强度
|
||||
/// @param intensity 强度值 [0.0, 1.0]
|
||||
/// @return *this
|
||||
auto& set_intensity(float intensity) {
|
||||
push_constant_effect().intensity = std::clamp(intensity, 0.0f, 1.0f);
|
||||
mark_push_constant_effect_dirty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief 获取效果强度
|
||||
/// @return 强度值 [0.0, 1.0]
|
||||
[[nodiscard]] auto get_intensity() const noexcept -> float {
|
||||
return push_constant_effect().intensity;
|
||||
}
|
||||
|
||||
/// @brief 设置效果区域
|
||||
/// @param rect 效果区域 (x, y, width, height)
|
||||
/// @return *this
|
||||
auto& set_effect_rect(const vec4f_t& rect) {
|
||||
push_constant_effect().effect_rect = rect;
|
||||
mark_push_constant_effect_dirty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief 获取效果区域
|
||||
/// @return 效果区域 (x, y, width, height)
|
||||
[[nodiscard]] auto get_effect_rect() const noexcept -> vec4f_t {
|
||||
return push_constant_effect().effect_rect;
|
||||
}
|
||||
|
||||
/// @brief 设置原始效果区域(用于 UV 计算)
|
||||
/// @param rect 原始效果区域 (x, y, width, height)
|
||||
/// @return *this
|
||||
auto& set_original_effect_rect(const vec4f_t& rect) {
|
||||
push_constant_effect().original_effect_rect = rect;
|
||||
mark_push_constant_effect_dirty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief 获取原始效果区域
|
||||
/// @return 原始效果区域 (x, y, width, height)
|
||||
[[nodiscard]] auto get_original_effect_rect() const noexcept -> vec4f_t {
|
||||
return push_constant_effect().original_effect_rect;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// 基类虚函数实现 - 只需重写渲染模式
|
||||
// ========================================================================
|
||||
|
||||
protected:
|
||||
/// @brief 获取着色器唯一标识符
|
||||
[[nodiscard]] auto get_shader_id() const noexcept -> uint32_t override {
|
||||
return hash_compile_time("color_adjust_widget");
|
||||
}
|
||||
|
||||
/// @brief 获取片段着色器 SPIR-V
|
||||
/// @note TODO: 使用着色器工具链预编译的 SPIR-V
|
||||
[[nodiscard]] auto get_fragment_shader_spirv() const
|
||||
-> std::span<const uint32_t> override {
|
||||
// TODO: 返回预编译的 color_adjust.frag.glsl SPIR-V
|
||||
// 从生成的着色器头文件获取:
|
||||
// return shaders::color_adjust_frag_spirv;
|
||||
return {};
|
||||
}
|
||||
|
||||
/// @brief 获取描述符绑定信息
|
||||
[[nodiscard]] auto get_bindings() const
|
||||
-> std::span<const shader_binding_info> override {
|
||||
static constexpr shader_binding_info bindings[] = {
|
||||
{
|
||||
.binding = 0,
|
||||
.type = vk::DescriptorType::eUniformBuffer,
|
||||
.count = 1,
|
||||
.stage = vk::ShaderStageFlagBits::eFragment
|
||||
},
|
||||
{
|
||||
.binding = 1,
|
||||
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||
.count = 1,
|
||||
.stage = vk::ShaderStageFlagBits::eFragment
|
||||
}
|
||||
};
|
||||
return bindings;
|
||||
}
|
||||
|
||||
/// @brief 获取渲染模式
|
||||
[[nodiscard]] auto get_render_mode() const noexcept
|
||||
-> custom_shader_render_mode override {
|
||||
return custom_shader_render_mode::post_process;
|
||||
}
|
||||
|
||||
/// @brief 获取顶点着色器 SPIR-V
|
||||
/// @note 使用默认的程序化四边形顶点着色器
|
||||
[[nodiscard]] auto get_vertex_shader_spirv() const
|
||||
-> std::span<const uint32_t> override {
|
||||
// 返回 nullopt 使用默认顶点着色器
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mirage::ui
|
||||
} // namespace mirage
|
||||
@@ -1,14 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "ui/widgets/custom_shader/custom_shader_widget.h"
|
||||
#include <glm/vec4.hpp>
|
||||
#include "ui/widgets/custom_shader/shader_spec_widget.h"
|
||||
#include "color_tint_vert_frag.h"
|
||||
|
||||
namespace mirage::ui {
|
||||
namespace mirage {
|
||||
|
||||
/// @brief 色调映射控件
|
||||
///
|
||||
/// 使用后处理模式,对子控件或源纹理应用色调映射效果。
|
||||
/// 支持多种混合模式:Normal、Additive、Multiply、Screen、Overlay。
|
||||
/// 效果强度通过 tint_color 的 alpha 通道控制。
|
||||
///
|
||||
/// @par 混合模式
|
||||
/// - 0: Normal - 正常混合
|
||||
@@ -22,24 +23,11 @@ namespace mirage::ui {
|
||||
/// // 创建色调映射控件
|
||||
/// auto color_tint = create_widget<color_tint_widget>();
|
||||
/// color_tint->set_size({200, 100});
|
||||
/// color_tint->set_tint_color(glm::vec4{1.0f, 0.5f, 0.0f, 1.0f}); // 橙色
|
||||
/// color_tint->set_tint_color(glm::vec4{1.0f, 0.5f, 0.0f, 0.7f}); // 橙色,强度0.7
|
||||
/// color_tint->set_blend_mode(2); // Multiply 模式
|
||||
/// color_tint->set_intensity(0.7f);
|
||||
/// @endcode
|
||||
class color_tint_widget : public custom_shader_widget<color_tint_widget::ColorTintParams> {
|
||||
class color_tint_widget : public shader_spec_widget<shaders::color_tint_shader_spec<>> {
|
||||
public:
|
||||
/// @brief 色调映射参数结构体
|
||||
/// @note 对应 shader 中的 ColorTintParams UBO
|
||||
/// @note 结构体大小为 32 字节,符合 std140 布局对齐要求
|
||||
struct ColorTintParams {
|
||||
alignas(16) glm::vec4 tint_color{1.0f, 1.0f, 1.0f, 1.0f}; ///< 色调颜色
|
||||
int32_t blend_mode{0}; ///< 混合模式
|
||||
float intensity{1.0f}; ///< 效果强度 [0, 1]
|
||||
float padding{0.0f}; ///< 对齐填充
|
||||
};
|
||||
|
||||
static_assert(sizeof(ColorTintParams) == 32, "ColorTintParams must be 32 bytes for std140 layout");
|
||||
|
||||
color_tint_widget() = default;
|
||||
~color_tint_widget() override = default;
|
||||
|
||||
@@ -48,9 +36,9 @@ public:
|
||||
// ========================================================================
|
||||
|
||||
/// @brief 设置色调颜色
|
||||
/// @param color 色调颜色 [r, g, b, a]
|
||||
/// @param color 色调颜色 [r, g, b, a],a 通道控制效果强度
|
||||
/// @return *this
|
||||
auto& set_tint_color(const glm::vec4& color) {
|
||||
auto& set_tint_color(const color& color) {
|
||||
params().tint_color = color;
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
@@ -58,15 +46,30 @@ public:
|
||||
|
||||
/// @brief 获取色调颜色
|
||||
/// @return 色调颜色
|
||||
[[nodiscard]] auto get_tint_color() const noexcept -> glm::vec4 {
|
||||
[[nodiscard]] auto get_tint_color() const noexcept -> color {
|
||||
return params().tint_color;
|
||||
}
|
||||
|
||||
/// @brief 设置效果强度(通过调整 tint_color 的 alpha 通道)
|
||||
/// @param intensity 强度 [0, 1]
|
||||
/// @return *this
|
||||
auto& set_intensity(float intensity) {
|
||||
params().tint_color.a() = std::clamp(intensity, 0.0f, 1.0f);
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief 获取效果强度
|
||||
/// @return 强度 [0, 1]
|
||||
[[nodiscard]] auto get_intensity() const noexcept -> float {
|
||||
return params().tint_color.a();
|
||||
}
|
||||
|
||||
/// @brief 设置混合模式
|
||||
/// @param mode 混合模式 (0=normal, 1=additive, 2=multiply, 3=screen, 4=overlay)
|
||||
/// @return *this
|
||||
auto& set_blend_mode(int32_t mode) {
|
||||
params().blend_mode = glm::clamp(mode, 0, 4);
|
||||
params().blend_mode = std::clamp(mode, 0, 4);
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
}
|
||||
@@ -77,74 +80,16 @@ public:
|
||||
return params().blend_mode;
|
||||
}
|
||||
|
||||
/// @brief 设置效果强度
|
||||
/// @param intensity 强度 [0, 1]
|
||||
/// @return *this
|
||||
auto& set_intensity(float intensity) {
|
||||
params().intensity = glm::clamp(intensity, 0.0f, 1.0f);
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief 获取效果强度
|
||||
/// @return 强度 [0, 1]
|
||||
[[nodiscard]] auto get_intensity() const noexcept -> float {
|
||||
return params().intensity;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// 基类虚函数实现
|
||||
// 基类虚函数实现 - 只需重写渲染模式
|
||||
// ========================================================================
|
||||
|
||||
protected:
|
||||
/// @brief 获取着色器唯一标识符
|
||||
[[nodiscard]] auto get_shader_id() const noexcept -> uint32_t override {
|
||||
return hash_compile_time("color_tint_widget");
|
||||
}
|
||||
|
||||
/// @brief 获取片段着色器 SPIR-V
|
||||
/// @note TODO: 使用着色器工具链预编译的 SPIR-V
|
||||
[[nodiscard]] auto get_fragment_shader_spirv() const
|
||||
-> std::span<const uint32_t> override {
|
||||
// TODO: 返回预编译的 color_tint.frag.glsl SPIR-V
|
||||
// 从生成的着色器头文件获取:
|
||||
// return shaders::color_tint_frag_spirv;
|
||||
return {};
|
||||
}
|
||||
|
||||
/// @brief 获取描述符绑定信息
|
||||
[[nodiscard]] auto get_bindings() const
|
||||
-> std::span<const shader_binding_info> override {
|
||||
static constexpr shader_binding_info bindings[] = {
|
||||
{
|
||||
.binding = 0,
|
||||
.type = vk::DescriptorType::eUniformBuffer,
|
||||
.count = 1,
|
||||
.stage = vk::ShaderStageFlagBits::eFragment
|
||||
},
|
||||
{
|
||||
.binding = 1,
|
||||
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||
.count = 1,
|
||||
.stage = vk::ShaderStageFlagBits::eFragment
|
||||
}
|
||||
};
|
||||
return bindings;
|
||||
}
|
||||
|
||||
/// @brief 获取渲染模式
|
||||
[[nodiscard]] auto get_render_mode() const noexcept
|
||||
-> custom_shader_render_mode override {
|
||||
return custom_shader_render_mode::post_process;
|
||||
}
|
||||
|
||||
/// @brief 获取顶点着色器 SPIR-V
|
||||
/// @note 使用默认的程序化四边形顶点着色器
|
||||
[[nodiscard]] auto get_vertex_shader_spirv() const
|
||||
-> std::span<const uint32_t> override {
|
||||
// 返回 nullopt 使用默认顶点着色器
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mirage::ui
|
||||
} // namespace mirage
|
||||
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "ui/widgets/custom_shader/custom_shader_widget.h"
|
||||
#include "ui/widgets/custom_shader/shader_spec_widget.h"
|
||||
#include "noise_vert_frag.h"
|
||||
|
||||
namespace mirage::ui {
|
||||
namespace mirage {
|
||||
|
||||
/// @brief 噪点效果控件
|
||||
///
|
||||
@@ -31,20 +32,8 @@ namespace mirage::ui {
|
||||
/// animated_noise->set_grain_size(2.0f);
|
||||
/// animated_noise->set_animated(true); // 启用动画
|
||||
/// @endcode
|
||||
class noise_widget : public custom_shader_widget<noise_widget::NoiseParams> {
|
||||
class noise_widget : public shader_spec_widget<shaders::noise_shader_spec<>> {
|
||||
public:
|
||||
/// @brief 噪点效果参数结构体
|
||||
/// @note 对应 shader 中的 NoiseParams UBO
|
||||
/// @note 结构体大小为 16 字节,符合 std140 布局对齐要求
|
||||
struct NoiseParams {
|
||||
float amount{0.3f}; ///< 噪点强度 [0, 1]
|
||||
float grain_size{1.5f}; ///< 颗粒大小 [0.5, 5.0]
|
||||
int animated{0}; ///< 是否启用动画(0=静态,1=动态)
|
||||
float time{0.0f}; ///< 时间参数(用于动画)
|
||||
};
|
||||
|
||||
static_assert(sizeof(NoiseParams) == 16, "NoiseParams must be 16 bytes for std140 layout");
|
||||
|
||||
noise_widget() = default;
|
||||
~noise_widget() override = default;
|
||||
|
||||
@@ -56,7 +45,7 @@ public:
|
||||
/// @param amount 噪点强度 [0, 1]
|
||||
/// @return *this
|
||||
auto& set_amount(float amount) {
|
||||
params().amount = glm::clamp(amount, 0.0f, 1.0f);
|
||||
params().amount = std::clamp(amount, 0.0f, 1.0f);
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
}
|
||||
@@ -71,7 +60,7 @@ public:
|
||||
/// @param grain_size 颗粒大小 [0.5, 5.0]
|
||||
/// @return *this
|
||||
auto& set_grain_size(float grain_size) {
|
||||
params().grain_size = glm::clamp(grain_size, 0.5f, 5.0f);
|
||||
params().grain_size = std::clamp(grain_size, 0.5f, 5.0f);
|
||||
mark_params_dirty();
|
||||
return *this;
|
||||
}
|
||||
@@ -104,59 +93,16 @@ public:
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// 基类虚函数实现
|
||||
// 基类虚函数实现 - 只需重写渲染模式
|
||||
// ========================================================================
|
||||
|
||||
protected:
|
||||
/// @brief 获取着色器唯一标识符
|
||||
[[nodiscard]] auto get_shader_id() const noexcept -> uint32_t override {
|
||||
return hash_compile_time("noise_widget");
|
||||
}
|
||||
|
||||
/// @brief 获取片段着色器 SPIR-V
|
||||
/// @note TODO: 使用着色器工具链预编译的 SPIR-V
|
||||
[[nodiscard]] auto get_fragment_shader_spirv() const
|
||||
-> std::span<const uint32_t> override {
|
||||
// TODO: 返回预编译的 noise.frag.glsl SPIR-V
|
||||
// 从生成的着色器头文件获取:
|
||||
// return shaders::noise_frag_spirv;
|
||||
return {};
|
||||
}
|
||||
|
||||
/// @brief 获取描述符绑定信息
|
||||
[[nodiscard]] auto get_bindings() const
|
||||
-> std::span<const shader_binding_info> override {
|
||||
static constexpr shader_binding_info bindings[] = {
|
||||
{
|
||||
.binding = 0,
|
||||
.type = vk::DescriptorType::eUniformBuffer,
|
||||
.count = 1,
|
||||
.stage = vk::ShaderStageFlagBits::eFragment
|
||||
},
|
||||
{
|
||||
.binding = 1,
|
||||
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||
.count = 1,
|
||||
.stage = vk::ShaderStageFlagBits::eFragment
|
||||
}
|
||||
};
|
||||
return bindings;
|
||||
}
|
||||
|
||||
/// @brief 获取渲染模式
|
||||
[[nodiscard]] auto get_render_mode() const noexcept
|
||||
-> custom_shader_render_mode override {
|
||||
return custom_shader_render_mode::post_process;
|
||||
}
|
||||
|
||||
/// @brief 获取顶点着色器 SPIR-V
|
||||
/// @note 使用默认的程序化四边形顶点着色器
|
||||
[[nodiscard]] auto get_vertex_shader_spirv() const
|
||||
-> std::span<const uint32_t> override {
|
||||
// 返回空 span 使用默认顶点着色器
|
||||
return {};
|
||||
}
|
||||
|
||||
/// @brief 检查是否需要动画更新
|
||||
/// @return 当 animated 参数为 true 时返回 true
|
||||
[[nodiscard]] auto is_animated() const -> bool override {
|
||||
@@ -173,4 +119,4 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mirage::ui
|
||||
} // namespace mirage
|
||||
@@ -22,6 +22,15 @@ namespace mirage {
|
||||
typename T::params_type;
|
||||
};
|
||||
|
||||
/// @brief 检测 ShaderSpec 是否提供了 push_constant_effect_type
|
||||
///
|
||||
/// 如果 ShaderSpec 提供了 push_constant_effect_type,则可以使用
|
||||
/// shader_spec_widget 的 Push Constants 效果参数功能。
|
||||
template <typename T>
|
||||
concept has_push_constant_effect = requires {
|
||||
typename T::push_constant_effect_type;
|
||||
};
|
||||
|
||||
/// @brief 基于 shader_spec 的自定义着色器控件模板类
|
||||
///
|
||||
/// @tparam ShaderSpec 着色器规格类型(由着色器工具自动生成的 xxx_shader_spec)
|
||||
@@ -66,12 +75,36 @@ namespace mirage {
|
||||
using params_type = ShaderSpec::params_type;
|
||||
using vertex_type = VertexT;
|
||||
|
||||
/// @brief 条件性定义 push_constant_effect_type
|
||||
/// @note 如果 ShaderSpec 没有提供 push_constant_effect_type,则使用 void
|
||||
using push_constant_effect_type = std::conditional_t<
|
||||
has_push_constant_effect<ShaderSpec>,
|
||||
typename ShaderSpec::push_constant_effect_type,
|
||||
void
|
||||
>;
|
||||
|
||||
// 静态断言:确保 params_type 满足要求
|
||||
static_assert(std::is_standard_layout_v<params_type>,
|
||||
"params_type must be standard layout for GPU compatibility");
|
||||
static_assert(alignof(params_type) <= 16,
|
||||
"params_type alignment must not exceed 16 bytes");
|
||||
|
||||
// 静态断言:检查 Push Constants 前四个公共变量是否有效
|
||||
// 期望的顺序:projection (mat4), viewport_size (vec2), time (float), _pad0 (float)
|
||||
static_assert(!ShaderSpec::has_push_constant_base_members ||
|
||||
(ShaderSpec::push_constant_base_member_count == 4 &&
|
||||
ShaderSpec::push_constant_base_member_names[0] == "projection" &&
|
||||
ShaderSpec::push_constant_base_member_names[1] == "viewport_size" &&
|
||||
ShaderSpec::push_constant_base_member_names[2] == "time" &&
|
||||
ShaderSpec::push_constant_base_member_names[3] == "_pad0" &&
|
||||
ShaderSpec::push_constant_base_member_offsets[0] == 0 &&
|
||||
ShaderSpec::push_constant_base_member_offsets[1] == 64 &&
|
||||
ShaderSpec::push_constant_base_member_offsets[2] == 72 &&
|
||||
ShaderSpec::push_constant_base_member_offsets[3] == 76),
|
||||
"Push Constants must have exactly 4 base members: "
|
||||
"projection (mat4, offset=0), viewport_size (vec2, offset=64), "
|
||||
"time (float, offset=72), _pad0 (float, offset=76)");
|
||||
|
||||
shader_spec_widget() = default;
|
||||
~shader_spec_widget() override = default;
|
||||
|
||||
@@ -92,6 +125,38 @@ namespace mirage {
|
||||
mark_render_dirty_internal();
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Push Constants 效果参数访问(仅当 ShaderSpec 提供了 push_constant_effect_type 时可用)
|
||||
// ========================================================================
|
||||
|
||||
/// @brief 获取 Push Constants 效果参数的可变引用
|
||||
/// @note 修改后需要调用 mark_push_constant_effect_dirty()
|
||||
/// @note 仅当 ShaderSpec 提供了 push_constant_effect_type 时可用
|
||||
[[nodiscard]] auto push_constant_effect() noexcept
|
||||
-> push_constant_effect_type&
|
||||
requires has_push_constant_effect<ShaderSpec>
|
||||
{
|
||||
return push_constant_effect_;
|
||||
}
|
||||
|
||||
/// @brief 获取 Push Constants 效果参数的只读引用
|
||||
/// @note 仅当 ShaderSpec 提供了 push_constant_effect_type 时可用
|
||||
[[nodiscard]] auto push_constant_effect() const noexcept
|
||||
-> const push_constant_effect_type&
|
||||
requires has_push_constant_effect<ShaderSpec>
|
||||
{
|
||||
return push_constant_effect_;
|
||||
}
|
||||
|
||||
/// @brief 标记 Push Constants 效果参数已修改
|
||||
/// @note 仅当 ShaderSpec 提供了 push_constant_effect_type 时可用
|
||||
void mark_push_constant_effect_dirty()
|
||||
requires has_push_constant_effect<ShaderSpec>
|
||||
{
|
||||
push_constant_effect_dirty_ = true;
|
||||
mark_render_dirty_internal();
|
||||
}
|
||||
|
||||
protected:
|
||||
// ========================================================================
|
||||
// 实现基类纯虚函数 - 由 ShaderSpec 自动提供
|
||||
@@ -133,6 +198,40 @@ namespace mirage {
|
||||
params_dirty_ = false;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Push Constants 效果参数实现
|
||||
// ========================================================================
|
||||
|
||||
/// @brief 获取 Push Constants 效果参数数据指针和大小
|
||||
[[nodiscard]] auto get_push_constant_effect_data() const
|
||||
-> std::pair<const void*, size_t> override
|
||||
{
|
||||
if constexpr (has_push_constant_effect<ShaderSpec>) {
|
||||
return {&push_constant_effect_, sizeof(push_constant_effect_type)};
|
||||
} else {
|
||||
return {nullptr, 0};
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 检查 Push Constants 效果参数是否已修改
|
||||
[[nodiscard]] auto is_push_constant_effect_dirty() const noexcept
|
||||
-> bool override
|
||||
{
|
||||
if constexpr (has_push_constant_effect<ShaderSpec>) {
|
||||
return push_constant_effect_dirty_;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 清除 Push Constants 效果参数脏标志
|
||||
void clear_push_constant_effect_dirty() override
|
||||
{
|
||||
if constexpr (has_push_constant_effect<ShaderSpec>) {
|
||||
push_constant_effect_dirty_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// 自定义顶点支持
|
||||
// ========================================================================
|
||||
@@ -184,12 +283,12 @@ namespace mirage {
|
||||
|
||||
/// @brief 获取顶点缓冲配置
|
||||
[[nodiscard]] auto get_vertex_buffer_config() const
|
||||
-> std::optional<vertex_buffer_config> override {
|
||||
-> std::optional<custom_vertex_buffer_config> override {
|
||||
if (vertices_.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return vertex_buffer_config{
|
||||
return custom_vertex_buffer_config{
|
||||
.data = vertices_.data(),
|
||||
.data_size = vertices_.size() * sizeof(VertexT),
|
||||
.vertex_count = vertices_.size(),
|
||||
@@ -242,6 +341,16 @@ namespace mirage {
|
||||
bool params_dirty_ = true;
|
||||
bool vertices_dirty_ = false;
|
||||
|
||||
/// @brief 条件性存储 push_constant_effect_
|
||||
/// @note 使用 [[no_unique_address]] 避免 void 类型占用空间
|
||||
[[no_unique_address]] std::conditional_t<
|
||||
has_push_constant_effect<ShaderSpec>,
|
||||
push_constant_effect_type,
|
||||
std::monostate
|
||||
> push_constant_effect_{};
|
||||
|
||||
bool push_constant_effect_dirty_ = true; ///< 初始为 true 以确保首次渲染
|
||||
|
||||
std::vector<VertexT> vertices_;
|
||||
std::vector<uint32_t> indices_;
|
||||
};
|
||||
|
||||
@@ -22,6 +22,7 @@ from .types import (
|
||||
BufferInfo,
|
||||
CompilationResult,
|
||||
MemberInfo,
|
||||
PushConstantInfo,
|
||||
ShaderMetadata,
|
||||
SPIRVReflection,
|
||||
ToolError,
|
||||
@@ -76,6 +77,111 @@ def generate_member_definition(member: MemberInfo, type_map: Dict[int, TypeInfo]
|
||||
return result.splitlines()
|
||||
|
||||
|
||||
# ============ Push Constants Effect Structure Generation ============
|
||||
|
||||
def generate_push_constant_effect_struct(reflection: SPIRVReflection, shader_name: str) -> str:
|
||||
"""生成 Push Constants 效果部分结构体定义
|
||||
|
||||
Args:
|
||||
reflection: SPIR-V反射信息
|
||||
shader_name: 着色器名称(用于生成结构体名称)
|
||||
|
||||
Returns:
|
||||
生成的C++结构体代码,如果没有Push Constants效果部分则返回空字符串
|
||||
"""
|
||||
push_constant = reflection.push_constant
|
||||
if not push_constant or not push_constant.effect_members:
|
||||
return ""
|
||||
|
||||
# 生成结构体名称
|
||||
struct_name = f"{shader_name.capitalize()}PushConstantEffect"
|
||||
|
||||
# 准备成员信息
|
||||
members = []
|
||||
type_map = reflection.types
|
||||
|
||||
for member in push_constant.effect_members:
|
||||
# 计算对齐和大小
|
||||
alignment = calculate_std430_alignment(member.resolved_type, type_map)
|
||||
size = calculate_std430_size(member.resolved_type, type_map)
|
||||
cpp_type = spirv_type_to_cpp(member.resolved_type, type_map)
|
||||
|
||||
members.append({
|
||||
'name': member.name,
|
||||
'cpp_type': cpp_type,
|
||||
'offset': member.offset,
|
||||
'size': size,
|
||||
'alignment': alignment,
|
||||
})
|
||||
|
||||
renderer = get_renderer()
|
||||
context = {
|
||||
'struct_name': struct_name,
|
||||
'base_offset': push_constant.base_offset,
|
||||
'members': members,
|
||||
}
|
||||
|
||||
return renderer.render('push_constant/effect_struct.jinja2', context)
|
||||
|
||||
|
||||
def generate_push_constant_base_layout(reflection: SPIRVReflection, shader_name: str) -> str:
|
||||
"""生成 Push Constants 基础部分布局信息结构体和静态检查代码
|
||||
|
||||
Args:
|
||||
reflection: SPIR-V反射信息
|
||||
shader_name: 着色器名称(用于生成结构体名称)
|
||||
|
||||
Returns:
|
||||
生成的C++代码,如果没有基础部分则返回空字符串
|
||||
"""
|
||||
push_constant = reflection.push_constant
|
||||
if not push_constant or not push_constant.base_info:
|
||||
return ""
|
||||
|
||||
base_info = push_constant.base_info
|
||||
|
||||
# 准备模板数据
|
||||
base_members = [
|
||||
{
|
||||
'name': m.name,
|
||||
'offset': m.offset,
|
||||
'size': m.size,
|
||||
'expected_offset': m.expected_offset,
|
||||
'expected_size': m.expected_size,
|
||||
'is_valid': m.is_valid,
|
||||
}
|
||||
for m in base_info.members
|
||||
]
|
||||
|
||||
expected_names = ['projection', 'viewport_size', 'time', '_pad0']
|
||||
present_names = [m.name for m in base_info.members]
|
||||
|
||||
renderer = get_renderer()
|
||||
|
||||
# 渲染布局结构体
|
||||
layout_context = {
|
||||
'struct_name': shader_name,
|
||||
'base_members': base_members,
|
||||
'expected_names': expected_names,
|
||||
'present_names': present_names,
|
||||
'total_size': base_info.total_size,
|
||||
'is_standard': base_info.is_standard_layout,
|
||||
}
|
||||
|
||||
layout_code = renderer.render('push_constant/base_layout.jinja2', layout_context)
|
||||
|
||||
# 渲染静态检查代码
|
||||
check_context = {
|
||||
'struct_name': shader_name,
|
||||
'base_members': base_members,
|
||||
'is_standard': base_info.is_standard_layout,
|
||||
}
|
||||
|
||||
check_code = renderer.render('push_constant/static_check.jinja2', check_context)
|
||||
|
||||
return layout_code + "\n\n" + check_code
|
||||
|
||||
|
||||
# ============ SPIR-V Array Generation ============
|
||||
|
||||
def spirv_to_cpp_array(spirv_data: bytes, symbol_name: str) -> str:
|
||||
@@ -314,6 +420,20 @@ def generate_header(
|
||||
if metadata.generate_buffer_manager and metadata.reflection and metadata.reflection.buffers:
|
||||
buffer_manager = generate_buffer_manager_class(metadata.reflection, metadata.name)
|
||||
|
||||
# 准备Push Constants效果结构体代码
|
||||
push_constant_effect_struct = ""
|
||||
push_constant_effect_type_name = "void"
|
||||
if metadata.reflection and metadata.reflection.push_constant and metadata.reflection.push_constant.effect_members:
|
||||
push_constant_effect_struct = generate_push_constant_effect_struct(metadata.reflection, metadata.name)
|
||||
push_constant_effect_type_name = f"{metadata.name.capitalize()}PushConstantEffect"
|
||||
|
||||
# 准备Push Constants基础部分布局代码
|
||||
push_constant_base_layout = ""
|
||||
has_push_constant_base_layout = False
|
||||
if metadata.reflection and metadata.reflection.push_constant and metadata.reflection.push_constant.base_info:
|
||||
push_constant_base_layout = generate_push_constant_base_layout(metadata.reflection, metadata.name)
|
||||
has_push_constant_base_layout = bool(push_constant_base_layout)
|
||||
|
||||
# 准备SPIR-V数组和着色器类型检测
|
||||
compilation_results_with_arrays = []
|
||||
has_vert_shader = False
|
||||
@@ -350,10 +470,14 @@ def generate_header(
|
||||
})
|
||||
|
||||
# 确定参数类型名称(从 buffer 反射信息中获取)
|
||||
params_type_name = f"{_to_pascal_case(metadata.name)}Params"
|
||||
# 优先级:buffer > push_constant效果部分 > void
|
||||
params_type_name = "void"
|
||||
if metadata.reflection and metadata.reflection.buffers:
|
||||
# 使用第一个 buffer 的结构体类型名称
|
||||
params_type_name = metadata.reflection.buffers[0].struct_type.name or params_type_name
|
||||
elif metadata.reflection and metadata.reflection.push_constant and metadata.reflection.push_constant.effect_members:
|
||||
# 没有 buffer,但有 push_constant 效果部分,使用效果结构体名称
|
||||
params_type_name = f"{metadata.name.capitalize()}PushConstantEffect"
|
||||
|
||||
# 使用模板渲染
|
||||
renderer = get_renderer()
|
||||
@@ -380,6 +504,13 @@ def generate_header(
|
||||
'has_frag_shader': has_frag_shader,
|
||||
'vert_spirv_symbol': vert_spirv_symbol,
|
||||
'frag_spirv_symbol': frag_spirv_symbol,
|
||||
# Push Constants 效果结构体相关变量
|
||||
'push_constant_effect_struct': push_constant_effect_struct,
|
||||
'push_constant_effect_type_name': push_constant_effect_type_name,
|
||||
'has_push_constant_effect': bool(push_constant_effect_struct),
|
||||
# Push Constants 基础部分布局相关变量
|
||||
'push_constant_base_layout': push_constant_base_layout,
|
||||
'has_push_constant_base_layout': has_push_constant_base_layout,
|
||||
}
|
||||
|
||||
return renderer.render('base/header.jinja2', context)
|
||||
@@ -8,9 +8,10 @@ SPIR-V解析模块
|
||||
from __future__ import annotations
|
||||
|
||||
import struct
|
||||
from typing import Any, Dict, List, Tuple
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from .constants import *
|
||||
from .type_mapping import calculate_std430_size, spirv_type_to_cpp
|
||||
from .types import (
|
||||
ArrayTypeInfo,
|
||||
BaseType,
|
||||
@@ -19,6 +20,11 @@ from .types import (
|
||||
MatrixTypeInfo,
|
||||
MemberInfo,
|
||||
PointerTypeInfo,
|
||||
PUSH_CONSTANT_BASE_OFFSET,
|
||||
PushConstantBaseInfo,
|
||||
PushConstantBaseMember,
|
||||
PushConstantBaseMemberInfo,
|
||||
PushConstantInfo,
|
||||
ScalarTypeInfo,
|
||||
SPIRVReflection,
|
||||
StructTypeInfo,
|
||||
@@ -315,6 +321,9 @@ def parse_spirv_type_system(spirv_data: bytes, shader_stage: str) -> SPIRVReflec
|
||||
# 提取buffer信息
|
||||
extract_buffers(reflection)
|
||||
|
||||
# 提取Push Constants信息
|
||||
reflection.push_constant = extract_push_constants(reflection)
|
||||
|
||||
# 提取入口点
|
||||
for opcode, operands, index in instructions:
|
||||
if opcode == OP_ENTRY_POINT and len(operands) >= 2:
|
||||
@@ -414,6 +423,144 @@ def extract_buffers(reflection: SPIRVReflection):
|
||||
reflection.buffers.sort(key=lambda b: b.binding)
|
||||
|
||||
|
||||
# ============ Push Constants Extraction ============
|
||||
|
||||
# 基础成员名称到标志的映射
|
||||
BASE_MEMBER_MAP = {
|
||||
'projection': (PushConstantBaseMember.PROJECTION, 0, 64),
|
||||
'viewport_size': (PushConstantBaseMember.VIEWPORT_SIZE, 64, 8),
|
||||
'time': (PushConstantBaseMember.TIME, 72, 4),
|
||||
'_pad0': (PushConstantBaseMember.PAD0, 76, 4),
|
||||
}
|
||||
|
||||
|
||||
def _identify_base_member(member: MemberInfo, type_map: Dict[int, TypeInfo]) -> Optional[PushConstantBaseMemberInfo]:
|
||||
"""识别基础部分成员
|
||||
|
||||
Args:
|
||||
member: 结构体成员信息
|
||||
type_map: 类型映射
|
||||
|
||||
Returns:
|
||||
PushConstantBaseMemberInfo 或 None(如果不是基础部分成员)
|
||||
"""
|
||||
if member.offset >= PUSH_CONSTANT_BASE_OFFSET:
|
||||
return None
|
||||
|
||||
# 计算成员大小
|
||||
member_size = calculate_std430_size(member.resolved_type, type_map)
|
||||
cpp_type = spirv_type_to_cpp(member.resolved_type, type_map)
|
||||
|
||||
# 通过名称或偏移量匹配
|
||||
for name, (flag, expected_offset, expected_size) in BASE_MEMBER_MAP.items():
|
||||
if member.name == name or member.offset == expected_offset:
|
||||
is_valid = (member.offset == expected_offset and member_size == expected_size)
|
||||
return PushConstantBaseMemberInfo(
|
||||
name=member.name,
|
||||
member_flag=flag,
|
||||
offset=member.offset,
|
||||
size=member_size,
|
||||
expected_offset=expected_offset,
|
||||
expected_size=expected_size,
|
||||
type_name=cpp_type,
|
||||
is_valid=is_valid,
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def extract_push_constants(reflection: SPIRVReflection) -> Optional[PushConstantInfo]:
|
||||
"""从变量中提取Push Constants信息
|
||||
|
||||
查找storage class为PushConstant (9)的变量,解析其结构体类型,
|
||||
并分离出效果部分(偏移量 >= 80字节的成员)。
|
||||
|
||||
Args:
|
||||
reflection: SPIR-V反射信息
|
||||
|
||||
Returns:
|
||||
PushConstantInfo或None(如果没有Push Constants)
|
||||
"""
|
||||
push_constant_var = None
|
||||
|
||||
for var_id, var_info in reflection.variables.items():
|
||||
if var_info.storage_class == STORAGE_CLASS_PUSH_CONSTANT:
|
||||
push_constant_var = var_info
|
||||
break
|
||||
|
||||
if push_constant_var is None:
|
||||
return None
|
||||
|
||||
var_type = reflection.types.get(push_constant_var.type_id)
|
||||
if not isinstance(var_type, PointerTypeInfo):
|
||||
return None
|
||||
|
||||
struct_type = var_type.resolved_pointee_type
|
||||
if not isinstance(struct_type, StructTypeInfo):
|
||||
return None
|
||||
|
||||
# 获取结构体名称
|
||||
struct_name = struct_type.name or f"PushConstant"
|
||||
|
||||
# 分离基础部分和效果部分
|
||||
# 基础部分:offset < PUSH_CONSTANT_BASE_OFFSET
|
||||
# 效果部分:offset >= PUSH_CONSTANT_BASE_OFFSET
|
||||
base_members_info = []
|
||||
present_flags = PushConstantBaseMember.NONE
|
||||
effect_members = []
|
||||
|
||||
for member in struct_type.members:
|
||||
base_member_info = _identify_base_member(member, reflection.types)
|
||||
if base_member_info:
|
||||
# 基础部分成员
|
||||
base_members_info.append(base_member_info)
|
||||
present_flags |= base_member_info.member_flag
|
||||
elif member.offset >= PUSH_CONSTANT_BASE_OFFSET:
|
||||
# 效果部分成员 - 计算相对于效果部分的偏移量
|
||||
relative_offset = member.offset - PUSH_CONSTANT_BASE_OFFSET
|
||||
member_info = MemberInfo(
|
||||
index=member.index,
|
||||
name=member.name,
|
||||
type_id=member.type_id,
|
||||
offset=relative_offset, # 使用相对偏移量
|
||||
resolved_type=member.resolved_type,
|
||||
matrix_stride=member.matrix_stride,
|
||||
array_stride=member.array_stride,
|
||||
is_row_major=member.is_row_major,
|
||||
)
|
||||
effect_members.append(member_info)
|
||||
|
||||
# 计算基础部分总大小
|
||||
base_total_size = max(
|
||||
(m.offset + m.size for m in base_members_info),
|
||||
default=0
|
||||
)
|
||||
|
||||
# 检查是否为标准布局(包含所有标准成员且都有效)
|
||||
is_standard = (
|
||||
present_flags == PushConstantBaseMember.STANDARD and
|
||||
all(m.is_valid for m in base_members_info)
|
||||
)
|
||||
|
||||
# 只有存在基础部分成员时才创建 base_info
|
||||
base_info = None
|
||||
if base_members_info:
|
||||
base_info = PushConstantBaseInfo(
|
||||
members=base_members_info,
|
||||
present_flags=present_flags,
|
||||
total_size=base_total_size,
|
||||
is_standard_layout=is_standard,
|
||||
)
|
||||
|
||||
return PushConstantInfo(
|
||||
name=struct_name,
|
||||
struct_type=struct_type,
|
||||
base_offset=PUSH_CONSTANT_BASE_OFFSET,
|
||||
base_info=base_info,
|
||||
effect_members=effect_members,
|
||||
)
|
||||
|
||||
|
||||
# ============ Legacy Interface ============
|
||||
|
||||
def extract_spirv_reflection(spirv_data: bytes, shader_type: str) -> Dict[str, Any]:
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
{%- if generate_typed_buffers and has_buffers %}
|
||||
#include "render/vulkan/typed_buffer.h"
|
||||
{%- endif %}
|
||||
{%- if has_push_constant_base_layout or has_push_constant_effect %}
|
||||
#include "render/uniform_types.h"
|
||||
{%- endif %}
|
||||
|
||||
{%- if namespace %}
|
||||
|
||||
@@ -40,6 +43,24 @@ namespace {{ namespace }} {
|
||||
{{ typed_buffers }}
|
||||
{%- endif %}
|
||||
|
||||
{%- if has_push_constant_base_layout %}
|
||||
|
||||
// ============ Push Constants 基础部分布局 ============
|
||||
// 根据 SPIR-V 反射自动生成
|
||||
// 用于编译期验证着色器与 C++ 端定义的一致性
|
||||
|
||||
{{ push_constant_base_layout }}
|
||||
{%- endif %}
|
||||
|
||||
{%- if push_constant_effect_struct %}
|
||||
|
||||
// ============ Push Constants 效果部分结构 ============
|
||||
// 根据 SPIR-V 反射自动生成
|
||||
// 基础部分偏移量:80 字节(由渲染器自动填充)
|
||||
|
||||
{{ push_constant_effect_struct }}
|
||||
{%- endif %}
|
||||
|
||||
{%- if buffer_manager %}
|
||||
|
||||
// ============ 缓冲区管理器类 ============
|
||||
@@ -152,6 +173,16 @@ struct {{ shader_spec_name }} {
|
||||
return {};
|
||||
{%- endif %}
|
||||
}
|
||||
|
||||
{%- if has_push_constant_effect %}
|
||||
/// @brief Push Constants 效果部分类型
|
||||
using push_constant_effect_type = {{ push_constant_effect_type_name }};
|
||||
{%- endif %}
|
||||
|
||||
{%- if has_push_constant_base_layout %}
|
||||
/// @brief Push Constants 基础部分布局类型
|
||||
using push_constant_base_layout = {{ shader_name }}_push_constant_base_layout;
|
||||
{%- endif %}
|
||||
};
|
||||
{%- endif %}
|
||||
|
||||
|
||||
32
tools/templates/push_constant/base_layout.jinja2
Normal file
32
tools/templates/push_constant/base_layout.jinja2
Normal file
@@ -0,0 +1,32 @@
|
||||
{# 生成 Push Constants 基础部分布局信息结构体 #}
|
||||
/// @brief Push Constants 基础部分布局信息(由着色器工具自动生成)
|
||||
///
|
||||
/// 此结构体描述了着色器声明的 push_constant 基础部分布局,
|
||||
/// 用于编译期验证与 C++ 端定义的一致性。
|
||||
struct {{ struct_name }}_push_constant_base_layout {
|
||||
// 成员存在性标志
|
||||
{%- for member in base_members %}
|
||||
static constexpr bool has_{{ member.name }} = true;
|
||||
{%- endfor %}
|
||||
{%- for expected_name in expected_names %}
|
||||
{%- if expected_name not in present_names %}
|
||||
static constexpr bool has_{{ expected_name }} = false;
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
|
||||
// 成员偏移量
|
||||
{%- for member in base_members %}
|
||||
static constexpr size_t {{ member.name }}_offset = {{ member.offset }};
|
||||
{%- endfor %}
|
||||
|
||||
// 成员大小
|
||||
{%- for member in base_members %}
|
||||
static constexpr size_t {{ member.name }}_size = {{ member.size }};
|
||||
{%- endfor %}
|
||||
|
||||
// 总大小
|
||||
static constexpr size_t total_size = {{ total_size }};
|
||||
|
||||
// 布局类型标识
|
||||
static constexpr bool is_standard_layout = {{ 'true' if is_standard else 'false' }};
|
||||
};
|
||||
10
tools/templates/push_constant/effect_struct.jinja2
Normal file
10
tools/templates/push_constant/effect_struct.jinja2
Normal file
@@ -0,0 +1,10 @@
|
||||
{# 生成 Push Constants 效果部分结构体 #}
|
||||
{# 结构体名称:{ShaderName}PushConstantEffect #}
|
||||
// Push Constants 效果部分结构体
|
||||
// 偏移量从基础部分结束位置({{ base_offset }}字节)开始计算
|
||||
struct alignas(16) {{ struct_name }} {
|
||||
{%- for member in members %}
|
||||
// 偏移量:{{ member.offset }},大小:{{ member.size }},对齐方式:{{ member.alignment }}
|
||||
alignas({{ member.alignment }}) {{ member.cpp_type }} {{ member.name }};
|
||||
{%- endfor %}
|
||||
};
|
||||
42
tools/templates/push_constant/static_check.jinja2
Normal file
42
tools/templates/push_constant/static_check.jinja2
Normal file
@@ -0,0 +1,42 @@
|
||||
{# 生成 Push Constants 静态检查代码 #}
|
||||
// ============ Push Constants 静态验证 ============
|
||||
// 编译期验证着色器声明的基础部分与 C++ 端定义一致
|
||||
|
||||
{% if is_standard %}
|
||||
// 验证标准布局
|
||||
static_assert(
|
||||
{{ struct_name }}_push_constant_base_layout::has_projection &&
|
||||
{{ struct_name }}_push_constant_base_layout::projection_offset ==
|
||||
mirage::expected_push_constant_base_layout::projection_offset,
|
||||
"{{ struct_name }}: projection offset mismatch"
|
||||
);
|
||||
|
||||
static_assert(
|
||||
{{ struct_name }}_push_constant_base_layout::has_viewport_size &&
|
||||
{{ struct_name }}_push_constant_base_layout::viewport_size_offset ==
|
||||
mirage::expected_push_constant_base_layout::viewport_size_offset,
|
||||
"{{ struct_name }}: viewport_size offset mismatch"
|
||||
);
|
||||
|
||||
static_assert(
|
||||
{{ struct_name }}_push_constant_base_layout::has_time &&
|
||||
{{ struct_name }}_push_constant_base_layout::time_offset ==
|
||||
mirage::expected_push_constant_base_layout::time_offset,
|
||||
"{{ struct_name }}: time offset mismatch"
|
||||
);
|
||||
|
||||
static_assert(
|
||||
{{ struct_name }}_push_constant_base_layout::total_size >=
|
||||
mirage::expected_push_constant_base_layout::total_size,
|
||||
"{{ struct_name }}: base layout size too small"
|
||||
);
|
||||
{% else %}
|
||||
// 非标准布局 - 自定义验证(仅验证存在的成员)
|
||||
{%- for member in base_members %}
|
||||
{%- if not member.is_valid %}
|
||||
// WARNING: {{ member.name }} layout mismatch
|
||||
// Expected: offset={{ member.expected_offset }}, size={{ member.expected_size }}
|
||||
// Actual: offset={{ member.offset }}, size={{ member.size }}
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
{% endif %}
|
||||
@@ -8,7 +8,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from enum import Enum, Flag, auto
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
@@ -18,6 +18,73 @@ class ToolError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
# ============ Push Constant Base Members ============
|
||||
|
||||
class PushConstantBaseMember(Flag):
|
||||
"""Push Constants 基础部分成员标志"""
|
||||
NONE = 0
|
||||
PROJECTION = auto() # mat4 projection
|
||||
VIEWPORT_SIZE = auto() # vec2 viewport_size
|
||||
TIME = auto() # float time
|
||||
PAD0 = auto() # float _pad0
|
||||
|
||||
# 预定义的组合
|
||||
STANDARD = PROJECTION | VIEWPORT_SIZE | TIME | PAD0
|
||||
VERTEX_ONLY = PROJECTION
|
||||
POST_EFFECT = PROJECTION | VIEWPORT_SIZE | TIME | PAD0
|
||||
|
||||
|
||||
@dataclass
|
||||
class PushConstantBaseMemberInfo:
|
||||
"""Push Constants 基础部分单个成员信息"""
|
||||
name: str # 成员名称(如 "projection")
|
||||
member_flag: PushConstantBaseMember # 成员标志
|
||||
offset: int # 实际偏移量
|
||||
size: int # 实际大小
|
||||
expected_offset: int # 期望偏移量
|
||||
expected_size: int # 期望大小
|
||||
type_name: str # C++ 类型名称
|
||||
is_valid: bool = True # 是否与期望匹配
|
||||
|
||||
|
||||
@dataclass
|
||||
class PushConstantBaseInfo:
|
||||
"""Push Constants 基础部分完整信息"""
|
||||
members: List[PushConstantBaseMemberInfo] = field(default_factory=list)
|
||||
present_flags: PushConstantBaseMember = PushConstantBaseMember.NONE
|
||||
total_size: int = 0
|
||||
is_standard_layout: bool = False # 是否为标准布局
|
||||
|
||||
# 期望布局定义
|
||||
EXPECTED_LAYOUT = {
|
||||
'projection': (0, 64), # (offset, size)
|
||||
'viewport_size': (64, 8),
|
||||
'time': (72, 4),
|
||||
'_pad0': (76, 4),
|
||||
}
|
||||
EXPECTED_TOTAL_SIZE = 80
|
||||
|
||||
@property
|
||||
def has_projection(self) -> bool:
|
||||
"""检查是否包含 projection 成员"""
|
||||
return any(m.name == 'projection' for m in self.members)
|
||||
|
||||
@property
|
||||
def has_viewport_size(self) -> bool:
|
||||
"""检查是否包含 viewport_size 成员"""
|
||||
return any(m.name == 'viewport_size' for m in self.members)
|
||||
|
||||
@property
|
||||
def has_time(self) -> bool:
|
||||
"""检查是否包含 time 成员"""
|
||||
return any(m.name == 'time' for m in self.members)
|
||||
|
||||
@property
|
||||
def has_pad0(self) -> bool:
|
||||
"""检查是否包含 _pad0 成员"""
|
||||
return any(m.name == '_pad0' for m in self.members)
|
||||
|
||||
|
||||
# ============ Enums ============
|
||||
|
||||
class StorageClass(Enum):
|
||||
@@ -164,6 +231,24 @@ class BindingInfo:
|
||||
count: int = 1
|
||||
|
||||
|
||||
# Push Constants 基础部分偏移量常量(字节)
|
||||
# mat4 projection = 64 字节
|
||||
# vec2 viewport_size = 8 字节
|
||||
# float time = 4 字节
|
||||
# float _pad0 = 4 字节
|
||||
PUSH_CONSTANT_BASE_OFFSET = 80
|
||||
|
||||
|
||||
@dataclass
|
||||
class PushConstantInfo:
|
||||
"""Push Constants 信息"""
|
||||
name: str # 结构体名称
|
||||
struct_type: StructTypeInfo # 完整结构体类型
|
||||
base_offset: int = PUSH_CONSTANT_BASE_OFFSET # 基础部分结束的偏移量(字节)
|
||||
base_info: Optional[PushConstantBaseInfo] = None # 基础部分信息
|
||||
effect_members: List[MemberInfo] = field(default_factory=list) # 效果部分的成员列表
|
||||
|
||||
|
||||
@dataclass
|
||||
class SPIRVReflection:
|
||||
"""完整的SPIR-V反射信息"""
|
||||
@@ -175,6 +260,7 @@ class SPIRVReflection:
|
||||
member_decorations: Dict[int, Dict[int, Dict[int, Any]]] = field(default_factory=dict)
|
||||
constants: Dict[int, Any] = field(default_factory=dict)
|
||||
buffers: List[BufferInfo] = field(default_factory=list)
|
||||
push_constant: Optional[PushConstantInfo] = None # Push Constants 信息
|
||||
entry_point: str = "main"
|
||||
shader_stage: str = "compute"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user