测试代码

This commit is contained in:
daiqingshuang
2025-06-06 18:26:22 +08:00
parent 34a91c6792
commit b532ce2f24
8 changed files with 1037 additions and 3 deletions

327
shaders/common_2d.slang Normal file
View File

@@ -0,0 +1,327 @@
// =============================================================================
// SDL 2D Shader Common Definitions
// 全局变量和通用功能定义
// =============================================================================
#ifndef SDL_2D_COMMON_H
#define SDL_2D_COMMON_H
// =============================================================================
// 平台检测和资源绑定宏
// =============================================================================
#ifdef METAL_TARGET
// Metal使用统一索引空间
#define BIND_VERTEX_TEXTURE(slot) register(t##slot)
#define BIND_VERTEX_SAMPLER(slot) register(s##slot)
#define BIND_VERTEX_BUFFER(slot) register(b##slot)
#define BIND_VERTEX_STORAGE(slot) register(u##slot)
#define BIND_PIXEL_TEXTURE(slot) register(t##slot)
#define BIND_PIXEL_SAMPLER(slot) register(s##slot)
#define BIND_PIXEL_BUFFER(slot) register(b##slot)
#define BIND_PIXEL_STORAGE(slot) register(u##slot)
#else
// Vulkan/DirectX 使用分离空间
#define BIND_VERTEX_TEXTURE(slot) register(t##slot, space0)
#define BIND_VERTEX_SAMPLER(slot) register(s##slot, space0)
#define BIND_VERTEX_BUFFER(slot) register(b##slot, space1)
#define BIND_VERTEX_STORAGE(slot) register(u##slot, space0)
#define BIND_PIXEL_TEXTURE(slot) register(t##slot, space2)
#define BIND_PIXEL_SAMPLER(slot) register(s##slot, space2)
#define BIND_PIXEL_BUFFER(slot) register(b##slot, space3)
#define BIND_PIXEL_STORAGE(slot) register(u##slot, space2)
#endif
// =============================================================================
// 数学常量
// =============================================================================
static const float PI = 3.14159265359;
static const float TWO_PI = 6.28318530718;
static const float HALF_PI = 1.57079632679;
static const float INV_PI = 0.31830988618;
static const float EPSILON = 1e-6;
static const float GAMMA = 2.2;
static const float INV_GAMMA = 0.454545;
// =============================================================================
// 标准2D顶点格式
// =============================================================================
struct Vertex2D {
float2 position; // 位置
float2 texCoord; // 纹理坐标
float4 color; // 顶点颜色
};
struct VertexShaderOutput {
float4 clipPos : SV_Position;
float2 texCoord : TEXCOORD0;
float4 color : TEXCOORD1;
float2 worldPos : TEXCOORD2; // 世界空间位置(用于特效)
};
// =============================================================================
// 全局Uniform缓冲区结构
// =============================================================================
// 场景级别的全局数据
struct SceneGlobals {
float4x4 viewProjection; // 视图投影矩阵
float4x4 invViewProjection; // 逆视图投影矩阵
float2 screenSize; // 屏幕尺寸
float2 invScreenSize; // 1.0 / 屏幕尺寸
float time; // 当前时间(秒)
float deltaTime; // 帧时间
float2 _padding0;
};
// 每个绘制调用的数据
struct DrawCallData {
float4x4 modelMatrix; // 模型矩阵
float4 tintColor; // 色调
float4 uvTransform; // UV变换 (offset.xy, scale.xy)
float2 pivot; // 旋转中心点
float rotation; // 旋转角度(弧度)
float _padding1;
};
// 材质参数
struct MaterialParams {
float4 baseColor; // 基础颜色
float opacity; // 不透明度
float brightness; // 亮度
float contrast; // 对比度
float saturation; // 饱和度
float hue; // 色相偏移
float bloomIntensity; // 泛光强度
float2 distortionAmount; // 扭曲程度
};
// 特效参数
struct EffectParams {
float4 glowColor; // 发光颜色
float glowSize; // 发光大小
float shadowSoftness; // 阴影柔和度
float shadowDistance; // 阴影距离
float shadowAngle; // 阴影角度
float4 gradientColors[4]; // 渐变颜色最多4个
float gradientStops[4]; // 渐变停止点
float noiseScale; // 噪声缩放
float noiseIntensity; // 噪声强度
float2 _padding2;
};
// =============================================================================
// 全局资源声明宏
// =============================================================================
// 顶点着色器全局资源
#define DECLARE_VERTEX_GLOBALS \
ConstantBuffer<SceneGlobals> g_scene : BIND_VERTEX_BUFFER(0); \
ConstantBuffer<DrawCallData> g_draw : BIND_VERTEX_BUFFER(1);
// 像素着色器全局资源
#define DECLARE_PIXEL_GLOBALS \
ConstantBuffer<SceneGlobals> g_scene : BIND_PIXEL_BUFFER(0); \
ConstantBuffer<MaterialParams> g_material : BIND_PIXEL_BUFFER(1); \
ConstantBuffer<EffectParams> g_effect : BIND_PIXEL_BUFFER(2);
// 标准纹理资源
#define DECLARE_STANDARD_TEXTURES \
Texture2D g_mainTexture : BIND_PIXEL_TEXTURE(0); \
Texture2D g_normalTexture : BIND_PIXEL_TEXTURE(1); \
Texture2D g_maskTexture : BIND_PIXEL_TEXTURE(2); \
Texture2D g_noiseTexture : BIND_PIXEL_TEXTURE(3); \
SamplerState g_linearSampler : BIND_PIXEL_SAMPLER(0); \
SamplerState g_pointSampler : BIND_PIXEL_SAMPLER(1); \
SamplerState g_linearClampSampler : BIND_PIXEL_SAMPLER(2); \
SamplerState g_pointClampSampler : BIND_PIXEL_SAMPLER(3);
// =============================================================================
// 实用函数库
// =============================================================================
// 2D变换函数
float2 rotate2D(float2 v, float angle) {
float c = cos(angle);
float s = sin(angle);
return float2(
v.x * c - v.y * s,
v.x * s + v.y * c
);
}
float2 scale2D(float2 v, float2 scale) {
return v * scale;
}
float2 translate2D(float2 v, float2 offset) {
return v + offset;
}
// UV坐标变换
float2 transformUV(float2 uv, float4 uvTransform) {
return uv * uvTransform.zw + uvTransform.xy;
}
// 颜色空间转换
float3 sRGBToLinear(float3 color) {
return pow(color, float3(GAMMA));
}
float3 linearToSRGB(float3 color) {
return pow(color, float3(INV_GAMMA));
}
float4 sRGBToLinear(float4 color) {
return float4(sRGBToLinear(color.rgb), color.a);
}
float4 linearToSRGB(float4 color) {
return float4(linearToSRGB(color.rgb), color.a);
}
// HSV颜色空间
float3 rgbToHSV(float3 rgb) {
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
float4 p = lerp(float4(rgb.bg, K.wz), float4(rgb.gb, K.xy), step(rgb.b, rgb.g));
float4 q = lerp(float4(p.xyw, rgb.r), float4(rgb.r, p.yzx), step(p.x, rgb.r));
float d = q.x - min(q.w, q.y);
float e = EPSILON;
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
float3 hsvToRGB(float3 hsv) {
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
float3 p = abs(frac(hsv.xxx + K.xyz) * 6.0 - K.www);
return hsv.z * lerp(K.xxx, saturate(p - K.xxx), hsv.y);
}
// 颜色调整函数
float3 adjustBrightness(float3 color, float brightness) {
return color * brightness;
}
float3 adjustContrast(float3 color, float contrast) {
return (color - 0.5) * contrast + 0.5;
}
float3 adjustSaturation(float3 color, float saturation) {
float gray = dot(color, float3(0.299, 0.587, 0.114));
return lerp(float3(gray), color, saturation);
}
float3 adjustHue(float3 color, float hueShift) {
float3 hsv = rgbToHSV(color);
hsv.x = frac(hsv.x + hueShift);
return hsvToRGB(hsv);
}
// 混合模式
float3 blendNormal(float3 base, float3 blend, float opacity) {
return lerp(base, blend, opacity);
}
float3 blendMultiply(float3 base, float3 blend, float opacity) {
return lerp(base, base * blend, opacity);
}
float3 blendScreen(float3 base, float3 blend, float opacity) {
return lerp(base, 1.0 - (1.0 - base) * (1.0 - blend), opacity);
}
float3 blendOverlay(float3 base, float3 blend, float opacity) {
float3 result = lerp(
2.0 * base * blend,
1.0 - 2.0 * (1.0 - base) * (1.0 - blend),
step(0.5, base)
);
return lerp(base, result, opacity);
}
// 抗锯齿函数
float smootherstep(float edge0, float edge1, float x) {
x = saturate((x - edge0) / (edge1 - edge0));
return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
}
// SDF相关函数
float sdCircle(float2 p, float r) {
return length(p) - r;
}
float sdBox(float2 p, float2 b) {
float2 d = abs(p) - b;
return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
}
float sdRoundedBox(float2 p, float2 b, float r) {
float2 q = abs(p) - b + r;
return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r;
}
// =============================================================================
// 标准顶点着色器模板
// =============================================================================
#define STANDARD_VERTEX_SHADER(name) \
DECLARE_VERTEX_GLOBALS \
\
[shader("vertex")] \
VertexShaderOutput name(Vertex2D input) { \
VertexShaderOutput output; \
\
float2 pos = input.position; \
\
/* 应用旋转 */ \
if (abs(g_draw.rotation) > EPSILON) { \
pos -= g_draw.pivot; \
pos = rotate2D(pos, g_draw.rotation); \
pos += g_draw.pivot; \
} \
\
/* 应用模型变换 */ \
float4 worldPos = mul(g_draw.modelMatrix, float4(pos, 0.0, 1.0)); \
output.clipPos = mul(g_scene.viewProjection, worldPos); \
output.worldPos = worldPos.xy; \
\
/* UV变换 */ \
output.texCoord = transformUV(input.texCoord, g_draw.uvTransform); \
\
/* 颜色 */ \
output.color = input.color * g_draw.tintColor; \
\
return output; \
}
// =============================================================================
// 标准像素着色器模板
// =============================================================================
#define STANDARD_PIXEL_SHADER(name, code) \
DECLARE_PIXEL_GLOBALS \
DECLARE_STANDARD_TEXTURES \
\
[shader("fragment")] \
float4 name(VertexShaderOutput input) : SV_Target { \
float4 color = g_mainTexture.Sample(g_linearSampler, input.texCoord); \
color *= input.color; \
\
/* 用户代码 */ \
code \
\
/* 应用材质参数 */ \
color.rgb = adjustBrightness(color.rgb, g_material.brightness); \
color.rgb = adjustContrast(color.rgb, g_material.contrast); \
color.rgb = adjustSaturation(color.rgb, g_material.saturation); \
color.rgb = adjustHue(color.rgb, g_material.hue); \
color.a *= g_material.opacity; \
\
return color; \
}
#endif // SDL_2D_COMMON_H

110
shaders/core.slang Normal file
View File

@@ -0,0 +1,110 @@
// =============================================================================
// sprite_shader.slang - 使用全局变量的精灵着色器
// =============================================================================
#include "common_2d.slang"
// 自动生成标准顶点着色器
STANDARD_VERTEX_SHADER(vertexMain)
// 简单的像素着色器
STANDARD_PIXEL_SHADER(pixelMain, {
// 这里可以添加自定义代码
// color 变量已经包含了采样后的纹理颜色
})
// 带发光效果的像素着色器
DECLARE_PIXEL_GLOBALS
DECLARE_STANDARD_TEXTURES
[shader("fragment")]
float4 pixelMainGlow(VertexShaderOutput input) : SV_Target {
float4 color = g_mainTexture.Sample(g_linearSampler, input.texCoord);
color *= input.color;
// 发光效果
if (g_effect.glowSize > 0.0) {
float2 texelSize = g_scene.invScreenSize;
float4 glow = float4(0.0);
// 简单的发光采样
for (int y = -2; y <= 2; y++) {
for (int x = -2; x <= 2; x++) {
float2 offset = float2(x, y) * texelSize * g_effect.glowSize;
float4 sample = g_mainTexture.Sample(g_linearSampler, input.texCoord + offset);
float weight = 1.0 / (1.0 + length(float2(x, y)));
glow += sample * weight;
}
}
glow *= g_effect.glowColor;
color.rgb += glow.rgb * g_effect.glowColor.a;
}
// 应用标准材质参数
color.rgb = adjustBrightness(color.rgb, g_material.brightness);
color.rgb = adjustContrast(color.rgb, g_material.contrast);
color.rgb = adjustSaturation(color.rgb, g_material.saturation);
color.a *= g_material.opacity;
return color;
}
// 文字渲染着色器
DECLARE_PIXEL_GLOBALS
DECLARE_STANDARD_TEXTURES
[shader("fragment")]
float4 pixelMainText(VertexShaderOutput input) : SV_Target {
// 文字通常存储在alpha通道
float alpha = g_mainTexture.Sample(g_linearSampler, input.texCoord).a;
// SDF文字渲染
float distance = alpha;
float smoothing = fwidth(distance) * 0.75;
alpha = smootherstep(0.5 - smoothing, 0.5 + smoothing, distance);
// 应用颜色
float4 color = float4(input.color.rgb, input.color.a * alpha);
// 文字阴影
if (g_effect.shadowDistance > 0.0) {
float2 shadowOffset = float2(
cos(g_effect.shadowAngle),
sin(g_effect.shadowAngle)
) * g_effect.shadowDistance * g_scene.invScreenSize;
float shadowAlpha = g_mainTexture.Sample(g_linearSampler, input.texCoord - shadowOffset).a;
shadowAlpha = smootherstep(0.5 - smoothing * g_effect.shadowSoftness, 0.5 + smoothing * g_effect.shadowSoftness, shadowAlpha);
// 混合阴影
color.rgb = lerp(float3(0.0, 0.0, 0.0), color.rgb, alpha);
color.a = max(color.a, shadowAlpha * 0.5);
}
return color;
}
// 形状渲染着色器使用SDF
DECLARE_PIXEL_GLOBALS
[shader("fragment")]
float4 pixelMainShape(VertexShaderOutput input) : SV_Target {
float2 p = input.texCoord * 2.0 - 1.0; // 转换到[-1, 1]空间
// 圆角矩形SDF
float d = sdRoundedBox(p, float2(0.8, 0.6), 0.1);
// 抗锯齿边缘
float alpha = 1.0 - smoothstep(-0.01, 0.01, d);
// 渐变填充
float gradient = (p.y + 1.0) * 0.5;
float3 color = lerp(
g_effect.gradientColors[0].rgb,
g_effect.gradientColors[1].rgb,
gradient
);
return float4(color * input.color.rgb, alpha * input.color.a * g_material.opacity);
}

221
shaders/test.slang Normal file
View File

@@ -0,0 +1,221 @@
// ===== 平台检测 =====
#ifdef __METAL_VERSION__
#define METAL_PLATFORM
#endif
#ifdef SPIRV
#define SPIRV_PLATFORM
#endif
// ===== 基础类型定义 =====
#ifdef METAL_PLATFORM
// Metal类型别名
typealias Texture2D_float = texture2d<float>;
typealias Texture2D_float4 = texture2d<float4>;
typealias RWTexture2D_float4 = texture2d<float4, access::read_write>;
typealias SamplerState = sampler;
// Metal属性包装器
struct MetalAttribute<T> {
T value;
};
#else
// HLSL/SPIR-V使用原生类型
typealias Texture2D_float = Texture2D<float>;
typealias Texture2D_float4 = Texture2D<float4>;
typealias RWTexture2D_float4 = RWTexture2D<float4>;
#endif
// ===== 资源声明辅助函数 =====
// 顶点着色器资源
#ifdef METAL_PLATFORM
#define VERTEX_TEXTURE(Type, Name, Binding) \
[[texture(Binding)]] Type Name
#define VERTEX_SAMPLER(Name, Binding) \
[[sampler(Binding)]] sampler Name
#define VERTEX_STORAGE_TEXTURE(Type, Name, Binding) \
[[texture(Binding)]] texture2d<Type, access::read_write> Name
#define VERTEX_UNIFORM_BUFFER(Type, Name, Binding) \
[[buffer(Binding)]] constant Type& Name
#define VERTEX_STORAGE_BUFFER(Type, Name, Binding) \
[[buffer(Binding)]] device Type* Name
#else
#define VERTEX_TEXTURE(Type, Name, Binding) \
[[vk::binding(Binding, 0)]] \
Type Name : register(t##Binding, space0)
#define VERTEX_SAMPLER(Name, Binding) \
[[vk::binding(Binding, 0)]] \
SamplerState Name : register(s##Binding, space0)
#define VERTEX_STORAGE_TEXTURE(Type, Name, Binding) \
[[vk::binding(Binding, 0)]] \
RWTexture2D<Type> Name : register(t##Binding, space0)
#define VERTEX_UNIFORM_BUFFER(Type, Name, Binding) \
[[vk::binding(Binding, 1)]] \
ConstantBuffer<Type> Name : register(b##Binding, space1)
#define VERTEX_STORAGE_BUFFER(Type, Name, Binding) \
[[vk::binding(Binding, 0)]] \
RWStructuredBuffer<Type> Name : register(t##Binding, space0)
#endif
// 片元着色器资源
#ifdef METAL_PLATFORM
#define FRAGMENT_TEXTURE(Type, Name, Binding) \
[[texture(Binding)]] Type Name
#define FRAGMENT_SAMPLER(Name, Binding) \
[[sampler(Binding)]] sampler Name
#define FRAGMENT_STORAGE_TEXTURE(Type, Name, Binding) \
[[texture(Binding)]] texture2d<Type, access::read_write> Name
#define FRAGMENT_UNIFORM_BUFFER(Type, Name, Binding) \
[[buffer(Binding)]] constant Type& Name
#define FRAGMENT_STORAGE_BUFFER(Type, Name, Binding) \
[[buffer(Binding)]] device Type* Name
#else
#define FRAGMENT_TEXTURE(Type, Name, Binding) \
[[vk::binding(Binding, 2)]] \
Type Name : register(t##Binding, space2)
#define FRAGMENT_SAMPLER(Name, Binding) \
[[vk::binding(Binding, 2)]] \
SamplerState Name : register(s##Binding, space2)
#define FRAGMENT_STORAGE_TEXTURE(Type, Name, Binding) \
[[vk::binding(Binding, 2)]] \
RWTexture2D<Type> Name : register(t##Binding, space2)
#define FRAGMENT_UNIFORM_BUFFER(Type, Name, Binding) \
[[vk::binding(Binding, 3)]] \
ConstantBuffer<Type> Name : register(b##Binding, space3)
#define FRAGMENT_STORAGE_BUFFER(Type, Name, Binding) \
[[vk::binding(Binding, 2)]] \
RWStructuredBuffer<Type> Name : register(t##Binding, space2)
#endif
// ===== 更灵活的Slang风格接口方案 =====
// 定义资源接口
interface IShaderResources {
// 这里可以定义通用的资源访问方法
}
// 顶点着色器资源包装器
struct VertexResources : IShaderResources {
// 根据目标平台选择不同的实现
#ifdef METAL_PLATFORM
struct Textures {
[[texture(0)]] texture2d<float> tex0;
[[texture(1)]] texture2d<float> tex1;
};
struct Samplers {
[[sampler(0)]] sampler samp0;
[[sampler(1)]] sampler samp1;
};
struct Uniforms<T> {
[[buffer(0)]] constant T& data;
};
#else
struct Textures {
[[vk::binding(0, 0)]] Texture2D tex0 : register(t0, space0);
[[vk::binding(1, 0)]] Texture2D tex1 : register(t1, space0);
};
struct Samplers {
[[vk::binding(0, 0)]] SamplerState samp0 : register(s0, space0);
[[vk::binding(1, 0)]] SamplerState samp1 : register(s1, space0);
};
struct Uniforms<T> {
[[vk::binding(0, 1)]] ConstantBuffer<T> data : register(b0, space1);
};
#endif
}
// 片元着色器资源包装器
struct FragmentResources : IShaderResources {
#ifdef METAL_PLATFORM
struct Textures {
[[texture(0)]] texture2d<float> tex0;
[[texture(1)]] texture2d<float> tex1;
};
struct Samplers {
[[sampler(0)]] sampler samp0;
[[sampler(1)]] sampler samp1;
};
struct Uniforms<T> {
[[buffer(0)]] constant T& data;
};
#else
struct Textures {
[[vk::binding(0, 2)]] Texture2D tex0 : register(t0, space2);
[[vk::binding(1, 2)]] Texture2D tex1 : register(t1, space2);
};
struct Samplers {
[[vk::binding(0, 2)]] SamplerState samp0 : register(s0, space2);
[[vk::binding(1, 2)]] SamplerState samp1 : register(s1, space2);
};
struct Uniforms<T> {
[[vk::binding(0, 3)]] ConstantBuffer<T> data : register(b0, space3);
};
#endif
}
// ===== 使用示例 =====
/*
// 定义统一数据结构
struct MyVertexUniforms {
float4x4 mvpMatrix;
float4 color;
};
struct MyFragmentUniforms {
float4 tintColor;
float opacity;
};
// 顶点着色器
VERTEX_TEXTURE(Texture2D, vertexTexture, 0);
VERTEX_SAMPLER(vertexSampler, 0);
VERTEX_UNIFORM_BUFFER(MyVertexUniforms, vertexUniforms, 0);
// 或者使用结构化方式
VertexResources::Textures vertTextures;
VertexResources::Samplers vertSamplers;
VertexResources::Uniforms<MyVertexUniforms> vertUniforms;
// 片元着色器
FRAGMENT_TEXTURE(Texture2D, fragmentTexture, 0);
FRAGMENT_SAMPLER(fragmentSampler, 0);
FRAGMENT_UNIFORM_BUFFER(MyFragmentUniforms, fragmentUniforms, 0);
// 着色器函数
[shader("vertex")]
float4 vertexMain(float3 position : POSITION) : SV_Position {
float4 color = vertexTexture.Sample(vertexSampler, float2(0.5, 0.5));
return mul(vertexUniforms.mvpMatrix, float4(position, 1.0));
}
[shader("fragment")]
float4 fragmentMain(float2 uv : TEXCOORD0) : SV_Target {
float4 color = fragmentTexture.Sample(fragmentSampler, uv);
return color * fragmentUniforms.tintColor * fragmentUniforms.opacity;
}
*/

View File

@@ -6,6 +6,7 @@
#include "SDL3/SDL_video.h"
#include "SDL3/SDL_log.h"
#include "SDL3/SDL_timer.h"
#include "SDL3/SDL_gpu.h"
#include "SDL3_ttf/SDL_ttf.h"
int main(int argc, char* argv[]) {
@@ -15,12 +16,13 @@ int main(int argc, char* argv[]) {
SDL_Log("Could not create window: %s", SDL_GetError());
return 1;
}
SDL_Renderer* renderer = SDL_CreateRenderer(window, "direct3d11");
SDL_Renderer* renderer = SDL_CreateRenderer(window, "direct3d12,metal,vulkan");
if (renderer == nullptr) {
SDL_Log("Could not create renderer: %s", SDL_GetError());
SDL_DestroyWindow(window);
return 1;
}
auto gpu_device = (SDL_GPUDevice*)SDL_GetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_GPU_DEVICE_POINTER, NULL);
TTF_Init();
@@ -32,7 +34,7 @@ int main(int argc, char* argv[]) {
return 1;
}
// 设置字体hinting为轻量级
TTF_SetFontHinting(font, TTF_HINTING_LIGHT);
TTF_SetFontHinting(font, TTF_HINTING_LIGHT_SUBPIXEL);
// 设置字体为 SDF 模式
// TTF_SetFontSDF(font, true);
// 设置渲染器的混合模式
@@ -40,7 +42,7 @@ int main(int argc, char* argv[]) {
SDL_Color color = { 255, 255, 255, 255 }; // 白色文字
SDL_Color bg_color = { 0, 0, 0, 255 }; // 背景颜色
auto text_surface = TTF_RenderText_LCD_Wrapped(font, "Hello World!\n你好,世界!", 0, color, bg_color, 0);
auto text_surface = TTF_RenderText_LCD_Wrapped(font, "Hello World!\n你好,世界!🆒", 0, color, bg_color, 0);
if (text_surface == nullptr) {
SDL_Log("Could not render text: %s", SDL_GetError());
TTF_CloseFont(font);
@@ -65,6 +67,23 @@ int main(int argc, char* argv[]) {
SDL_GetTextureSize(texture, &text_width, &text_height);
SDL_FRect dest_rect = { 0, 0, text_width, text_height };
SDL_GPUShaderCreateInfo shader_info;
shader_info.code_size = 10;
shader_info.code = nullptr; // 这里需要填入实际的着色器代码
shader_info.entrypoint = "main";
shader_info.format = SDL_GPU_SHADERFORMAT_DXIL;
shader_info.stage = SDL_GPU_SHADERSTAGE_FRAGMENT;
shader_info.num_samplers = 0;
shader_info.num_storage_textures = 0;
shader_info.num_uniform_buffers = 0;
shader_info.num_storage_buffers = 0;
auto shader = SDL_CreateGPUShader(gpu_device, &shader_info);
SDL_GPURenderStateDesc desc;
SDL_INIT_INTERFACE(&desc);
desc.fragment_shader = shader;
auto render_state = SDL_CreateGPURenderState(renderer, &desc);
SDL_Event e;
bool running = true;
while (running) {
@@ -79,6 +98,7 @@ int main(int argc, char* argv[]) {
SDL_RenderClear(renderer); // 先清屏
SDL_RenderTexture(renderer, texture, nullptr, &dest_rect); // 然后绘制文字
SDL_RenderPresent(renderer); // 最后呈现
SDL_RenderLines(renderer, nullptr, 0); // 确保没有多余的线条
std::this_thread::sleep_for(std::chrono::milliseconds(16)); // ~60 FPS
}

21
src/shader_handle.cpp Normal file
View File

@@ -0,0 +1,21 @@
//
// Created by 46944 on 25-6-6.
//
#include "shader_handle.h"
#include "tmpxm05mgxl.layout.h"
SDL_GPUGraphicsPipeline* pixel_shader_handle_t::create_graphics_pipeline(SDL_GPUDevice* in_gpu_device) {
SDL_GPUGraphicsPipelineCreateInfo desc = {};
desc.vertex_shader = vertex_shader_;
desc.fragment_shader = fragment_shader_;
desc.vertex_input_state = g_vertexInputState;
desc.primitive_type = primitive_type_;
desc.rasterizer_state.fill_mode = fill_mode_;
desc.rasterizer_state.cull_mode = cull_mode_;
desc.rasterizer_state.front_face = front_face_;
desc.multisample_state.sample_count = sample_count_;
desc.depth_stencil_state.enable_depth_test = false;
return SDL_CreateGPUGraphicsPipeline(in_gpu_device, &desc);
}

87
src/shader_handle.h Normal file
View File

@@ -0,0 +1,87 @@
//
// Created by 46944 on 25-6-6.
//
#pragma once
#include <expected>
#include <SDL3/SDL_gpu.h>
#include <string>
class shader_handle_t {
public:
virtual ~shader_handle_t() = default;
virtual std::expected<bool, std::string> init(SDL_GPUDevice* in_gpu_device) = 0;
virtual void clear(SDL_GPUDevice* in_gpu_device) = 0;
};
class pixel_shader_handle_t : public shader_handle_t {
public:
virtual std::expected<bool, std::string> init(SDL_GPUDevice* in_gpu_device) override {
vertex_shader_ = create_vertex_shader(in_gpu_device);
if (!vertex_shader_) {
return std::unexpected("Failed to create vertex shader");
}
fragment_shader_ = create_fragment_shader(in_gpu_device);
if (!fragment_shader_) {
clear(in_gpu_device);
return std::unexpected("Failed to create fragment shader");
}
graphics_pipeline_ = create_graphics_pipeline(in_gpu_device);
if (!graphics_pipeline_) {
clear(in_gpu_device);
return std::unexpected("Failed to create graphics pipeline");
}
return true;
}
virtual void clear(SDL_GPUDevice* in_gpu_device) override {
if (graphics_pipeline_) {
SDL_ReleaseGPUGraphicsPipeline(in_gpu_device, graphics_pipeline_);
graphics_pipeline_ = nullptr;
}
if (fragment_shader_) {
SDL_ReleaseGPUShader(in_gpu_device, fragment_shader_);
fragment_shader_ = nullptr;
}
if (vertex_shader_) {
SDL_ReleaseGPUShader(in_gpu_device, vertex_shader_);
vertex_shader_ = nullptr;
}
}
protected:
virtual SDL_GPUShader* create_vertex_shader(SDL_GPUDevice* in_gpu_device) { return nullptr; }
virtual SDL_GPUShader* create_fragment_shader(SDL_GPUDevice* in_gpu_device) = 0;
virtual SDL_GPUGraphicsPipeline* create_graphics_pipeline(SDL_GPUDevice* in_gpu_device);
private:
SDL_GPUShader* vertex_shader_ = nullptr;
SDL_GPUShader* fragment_shader_ = nullptr;
SDL_GPUGraphicsPipeline* graphics_pipeline_ = nullptr;
SDL_GPUPrimitiveType primitive_type_ = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
SDL_GPUFillMode fill_mode_ = SDL_GPU_FILLMODE_FILL;
SDL_GPUCullMode cull_mode_ = SDL_GPU_CULLMODE_NONE;
SDL_GPUFrontFace front_face_ = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE;
SDL_GPUSampleCount sample_count_ = SDL_GPU_SAMPLECOUNT_1;
};
class compute_shader_handle_t : public shader_handle_t {
public:
virtual std::expected<bool, std::string> init(SDL_GPUDevice* in_gpu_device) override {
compute_shader_ = create_compute_shader(in_gpu_device);
if (!compute_shader_) {
return std::unexpected("Failed to create compute shader");
}
compute_pipeline_ = SDL_CreateGPUComputePipeline(in_gpu_device, compute_shader_);
if (!compute_pipeline_) {
clear(in_gpu_device);
return std::unexpected("Failed to create compute pipeline");
}
return true;
}
protected:
virtual SDL_GPUShader* create_compute_shader(SDL_GPUDevice* in_gpu_device) = 0;
private:
SDL_GPUShader* compute_shader_ = nullptr;
SDL_GPUComputePipeline* compute_pipeline_ = nullptr;
};

122
src/test.shader.h Normal file

File diff suppressed because one or more lines are too long

126
src/tmpxm05mgxl.layout.h Normal file
View File

@@ -0,0 +1,126 @@
#pragma once
#include <SDL3/SDL.h>
#include <SDL3/SDL_gpu.h>
// Auto-generated from: C:\Users\46944\AppData\Local\Temp\tmpufk9_wv_.json
// Auto-generated vertex structure
typedef struct Vertex {
float position[2];
// location: 0, semantic: POSITION
float uv[2];
// location: 1, semantic: TEXCOORD
float color[4];
// location: 2, semantic: COLOR
float param_a[4];
// location: 3, semantic: TEXCOORD1
float param_b[4];
// location: 4, semantic: TEXCOORD2
float param_c[4];
// location: 5, semantic: TEXCOORD3
} Vertex;
// Uniform buffer structures
typedef struct ParamBuffer {
float transform[4][4];
} ParamBuffer;
// Binding: 0, Size: 64 bytes
// Vertex attribute descriptions
#define VERTEX_ATTRIBUTE_COUNT 6
static const SDL_GPUVertexAttribute g_vertexAttributes[] = {
{
.location = 0,
.buffer_slot = 0,
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2,
.offset = 0
}, // position
{
.location = 1,
.buffer_slot = 0,
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2,
.offset = 8
}, // uv
{
.location = 2,
.buffer_slot = 0,
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4,
.offset = 16
}, // color
{
.location = 3,
.buffer_slot = 0,
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4,
.offset = 32
}, // param_a
{
.location = 4,
.buffer_slot = 0,
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4,
.offset = 48
}, // param_b
{
.location = 5,
.buffer_slot = 0,
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4,
.offset = 64
} // param_c
};
// Vertex buffer description
static const SDL_GPUVertexBufferDescription g_vertexBufferDesc = {
.slot = 0,
.pitch = 80, // sizeof(Vertex)
.input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX,
.instance_step_rate = 0
};
// Vertex input state
static const SDL_GPUVertexInputState g_vertexInputState = {
.vertex_buffer_descriptions = &g_vertexBufferDesc,
.num_vertex_buffers = 1,
.vertex_attributes = g_vertexAttributes,
.num_vertex_attributes = VERTEX_ATTRIBUTE_COUNT
};
// Helper functions
static SDL_GPUBuffer* createVertexBuffer(SDL_GPUDevice* device,
const Vertex* vertices,
Uint32 vertexCount) {
SDL_GPUBufferCreateInfo bufferInfo = {
.usage = SDL_GPU_BUFFERUSAGE_VERTEX,
.size = static_cast<Uint32>(sizeof(Vertex)) * vertexCount
};
SDL_GPUBuffer* buffer = SDL_CreateGPUBuffer(device, &bufferInfo);
SDL_GPUTransferBufferCreateInfo transferInfo = {
.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD,
.size = bufferInfo.size
};
// Upload vertex data
SDL_GPUTransferBuffer* transfer = SDL_CreateGPUTransferBuffer(device, &transferInfo);
void* mapped = SDL_MapGPUTransferBuffer(device, transfer, false);
SDL_memcpy(mapped, vertices, bufferInfo.size);
SDL_UnmapGPUTransferBuffer(device, transfer);
// Copy to GPU
SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device);
SDL_GPUCopyPass* copy = SDL_BeginGPUCopyPass(cmd);
SDL_GPUTransferBufferLocation src = {.transfer_buffer = transfer, .offset = 0};
SDL_GPUBufferRegion dst = {.buffer = buffer, .offset = 0, .size = bufferInfo.size};
SDL_UploadToGPUBuffer(copy, &src, &dst, false);
SDL_EndGPUCopyPass(copy);
SDL_SubmitGPUCommandBuffer(cmd);
SDL_ReleaseGPUTransferBuffer(device, transfer);
return buffer;
}