修改布局,修改运行参数,新增顶点着色器布局解析

This commit is contained in:
daiqingshuang
2025-06-06 17:13:34 +08:00
parent 7a392281f1
commit de9cf7415e
4 changed files with 305 additions and 32 deletions

View File

@@ -3,7 +3,7 @@
SDL3_GPU Slang Compiler Package
自动处理资源绑定点的Slang着色器编译器
"""
from shader_layout_generator import ShaderLayoutGenerator
from shader_types import ShaderStage, ResourceType, TargetFormat, Resource, ShaderInfo
from compiler import SDL3GPUSlangCompiler
from slangc_finder import SlangcFinder
@@ -21,7 +21,8 @@ __all__ = [
'SlangcFinder',
'ShaderParser',
'BindingManager',
'CodeGenerator'
'CodeGenerator',
'ShaderLayoutGenerator'
]
version = '1.0.0'

View File

@@ -96,6 +96,7 @@ class CodeGenerator:
'#include <string>',
'#include <vector>',
'#include <unordered_map>',
'#include <cstdint>',
]
for header in headers:
@@ -108,43 +109,49 @@ class CodeGenerator:
source_file_name = Path(source_file_pathname).stem
with writer.block(f'class {source_file_name}ShaderBindings','};'):
self._write_public_section(writer)
self._write_public_section(writer, binding_infos)
self._write_private_section(writer)
self._write_constructor(writer, binding_infos)
self._write_public_methods(writer)
def _write_public_section(self, writer: IndentManager) -> None:
def _write_public_section(self, writer: IndentManager, binding_infos: List[Dict]) -> None:
"""写入public部分的结构体定义"""
writer.write('public:')
# Resource结构体
with writer.indent():
with writer.block('struct Resource', '};'):
with writer.block('enum Type'):
enum_values = [
'SampledTexture,',
'StorageTexture,',
'StorageBuffer,',
'UniformBuffer,',
'Sampler'
]
for value in enum_values:
writer.write(value)
writer.write()
writer.write('std::string name;')
writer.write('Type type;')
writer.write('int binding = -1;')
writer.write('int set = -1;')
writer.write('int space = -1;')
writer.write('int index = -1;')
writer.write()
# 写入二进制内容
for info in binding_infos:
entry_point = info['entry_point']
hex_list = ', '.join(f'0x{byte:02x}' for byte in info['blob'])
with writer.block(f'static constexpr uint8_t {entry_point}_blob[] = ', '};'):
writer.write(hex_list)
# ShaderInfo结构体
with writer.block('struct ShaderInfo','};'):
writer.write('std::string entryPoint;')
writer.write('SDL_GPUShaderStage stage;')
writer.write('std::vector<Resource> resources;')
# Resource结构体
with writer.block('struct Resource', '};'):
with writer.block('enum Type', '};'):
enum_values = [
'SampledTexture,',
'StorageTexture,',
'StorageBuffer,',
'UniformBuffer,',
'Sampler'
]
for value in enum_values:
writer.write(value)
writer.write()
writer.write('std::string name;')
writer.write('Type type;')
writer.write('int binding = -1;')
writer.write('int set = -1;')
writer.write('int space = -1;')
writer.write('int index = -1;')
writer.write()
# ShaderInfo结构体
with writer.block('struct ShaderInfo','};'):
writer.write('std::string entryPoint;')
writer.write('SDL_GPUShaderStage stage;')
writer.write('std::vector<Resource> resources;')
writer.write()
def _write_private_section(self, writer: IndentManager) -> None:
"""写入private部分"""

View File

@@ -18,7 +18,7 @@ def main():
parser.add_argument('input', help='Input Slang shader file')
parser.add_argument('-t', '--target', choices=['spirv', 'dxil', 'dxbc', 'msl'],
required=True, help='Target shader format')
parser.add_argument('--binding-output-dir', required=True, help='Output path for binding code')
parser.add_argument('-o', '--output-dir', required=True, help='Output path for binding code')
args = parser.parse_args()
@@ -46,7 +46,7 @@ def main():
binding_info = compiler.compile_shader(shader_info, target)
binding_infos.append(binding_info)
binding_output_file_pathname = os.path.abspath(args.binding_output_dir)
binding_output_file_pathname = os.path.abspath(args.output_dir)
binding_output_file_pathname = os.path.join(binding_output_file_pathname, f"{source_file_name}.shader.h")
# 生成绑定代码

265
shader_layout_generator.py Normal file
View File

@@ -0,0 +1,265 @@
#!/usr/bin/env python3
import json
import sys
from typing import Dict, List, Any, Tuple
class ShaderLayoutGenerator:
def __init__(self):
# SDL GPU 格式映射
self.format_mapping = {
('float32', 1): 'SDL_GPU_VERTEXELEMENTFORMAT_FLOAT',
('float32', 2): 'SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2',
('float32', 3): 'SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3',
('float32', 4): 'SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4',
('int32', 1): 'SDL_GPU_VERTEXELEMENTFORMAT_INT',
('int32', 2): 'SDL_GPU_VERTEXELEMENTFORMAT_INT2',
('int32', 3): 'SDL_GPU_VERTEXELEMENTFORMAT_INT3',
('int32', 4): 'SDL_GPU_VERTEXELEMENTFORMAT_INT4',
('uint32', 1): 'SDL_GPU_VERTEXELEMENTFORMAT_UINT',
('uint32', 2): 'SDL_GPU_VERTEXELEMENTFORMAT_UINT2',
('uint32', 3): 'SDL_GPU_VERTEXELEMENTFORMAT_UINT3',
('uint32', 4): 'SDL_GPU_VERTEXELEMENTFORMAT_UINT4',
}
# 类型大小映射
self.type_sizes = {
'float32': 4,
'int32': 4,
'uint32': 4,
}
def get_type_info(self, type_obj: Dict) -> Tuple[str, int, int]:
"""获取类型信息C类型名称、元素数量、字节大小"""
kind = type_obj.get('kind')
if kind == 'vector':
element_type = type_obj['elementType']['scalarType']
element_count = type_obj['elementCount']
c_type = 'float' if element_type == 'float32' else element_type
size = self.type_sizes[element_type] * element_count
return c_type, element_count, size
elif kind == 'scalar':
scalar_type = type_obj['scalarType']
c_type = 'float' if scalar_type == 'float32' else scalar_type
size = self.type_sizes[scalar_type]
return c_type, 1, size
elif kind == 'matrix':
rows = type_obj['rowCount']
cols = type_obj['columnCount']
element_type = type_obj['elementType']['scalarType']
size = self.type_sizes[element_type] * rows * cols
return 'float', rows * cols, size
return 'float', 1, 4
def parse_vertex_input(self, json_data: Dict) -> List[Dict]:
"""解析顶点输入字段"""
vertex_fields = []
# 查找顶点输入参数
entry_points = json_data.get('entryPoints', [])
for entry in entry_points:
if entry.get('stage') == 'vertex':
parameters = entry.get('parameters', [])
for param in parameters:
if param.get('name') == 'input' and param.get('stage') == 'vertex':
fields = param.get('type', {}).get('fields', [])
for field in fields:
field_info = {
'name': field['name'],
'type': field['type'],
'location': field['binding']['index'],
'semantic': field.get('semanticName', ''),
'semantic_index': field.get('semanticIndex', 0)
}
vertex_fields.append(field_info)
return vertex_fields
def parse_uniform_buffers(self, json_data: Dict) -> List[Dict]:
"""解析Uniform缓冲区"""
uniform_buffers = []
parameters = json_data.get('parameters', [])
for param in parameters:
binding = param.get('binding', {})
if binding.get('kind') == 'constantBuffer':
buffer_info = {
'name': param['name'],
'binding': binding['index'],
'fields': []
}
# 解析缓冲区字段
element_type = param.get('type', {}).get('elementType', {})
if element_type.get('kind') == 'struct':
fields = element_type.get('fields', [])
for field in fields:
field_info = {
'name': field['name'],
'type': field['type'],
'offset': field['binding']['offset'],
'size': field['binding']['size']
}
buffer_info['fields'].append(field_info)
uniform_buffers.append(buffer_info)
return uniform_buffers
def generate_vertex_struct(self, vertex_fields: List[Dict]) -> str:
"""生成顶点结构体"""
code = "// Auto-generated vertex structure\n"
code += "typedef struct Vertex {\n"
for field in vertex_fields:
c_type, count, _ = self.get_type_info(field['type'])
if count == 1:
code += f" {c_type} {field['name']};\n"
else:
code += f" {c_type} {field['name']}[{count}];\n"
# 添加注释
semantic = field['semantic']
if field['semantic_index'] > 0:
semantic += str(field['semantic_index'])
code += f" // location: {field['location']}, semantic: {semantic}\n"
code += "} Vertex;\n\n"
return code
def generate_vertex_attributes(self, vertex_fields: List[Dict]) -> str:
"""生成顶点属性数组"""
code = "// Vertex attribute descriptions\n"
code += f"#define VERTEX_ATTRIBUTE_COUNT {len(vertex_fields)}\n\n"
code += "static const SDL_GPUVertexAttribute g_vertexAttributes[] = {\n"
offset = 0
for i, field in enumerate(vertex_fields):
c_type, count, size = self.get_type_info(field['type'])
scalar_type = field['type'].get('elementType', field['type']).get('scalarType', 'float32')
format_key = (scalar_type, count)
format_name = self.format_mapping.get(format_key, 'SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4')
code += " {\n"
code += f" .location = {field['location']},\n"
code += f" .buffer_slot = 0,\n"
code += f" .format = {format_name},\n"
code += f" .offset = {offset}\n"
code += " }"
if i < len(vertex_fields) - 1:
code += ","
code += f" // {field['name']}\n"
offset += size
code += "};\n\n"
# 生成顶点缓冲区描述
code += "// Vertex buffer description\n"
code += "static const SDL_GPUVertexBufferDescription g_vertexBufferDesc = {\n"
code += " .slot = 0,\n"
code += f" .pitch = {offset}, // sizeof(Vertex)\n"
code += " .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX,\n"
code += " .instance_step_rate = 0\n"
code += "};\n\n"
# 生成顶点输入状态
code += "// Vertex input state\n"
code += "static const SDL_GPUVertexInputState g_vertexInputState = {\n"
code += " .vertex_buffer_descriptions = &g_vertexBufferDesc,\n"
code += " .num_vertex_buffers = 1,\n"
code += " .vertex_attributes = g_vertexAttributes,\n"
code += " .num_vertex_attributes = VERTEX_ATTRIBUTE_COUNT\n"
code += "};\n\n"
return code
def generate_uniform_structs(self, uniform_buffers: List[Dict]) -> str:
"""生成Uniform缓冲区结构体"""
code = "// Uniform buffer structures\n"
for buffer in uniform_buffers:
struct_name = buffer['name'].replace('_buffer', '').title().replace('_', '') + 'Buffer'
code += f"typedef struct {struct_name} {{\n"
for field in buffer['fields']:
c_type, count, _ = self.get_type_info(field['type'])
if field['type']['kind'] == 'matrix':
rows = field['type']['rowCount']
cols = field['type']['columnCount']
code += f" {c_type} {field['name']}[{rows}][{cols}];\n"
elif count == 1:
code += f" {c_type} {field['name']};\n"
else:
code += f" {c_type} {field['name']}[{count}];\n"
code += f"}} {struct_name};\n"
code += f"// Binding: {buffer['binding']}, Size: {sum(f['size'] for f in buffer['fields'])} bytes\n\n"
return code
def generate_helper_functions(self, vertex_fields: List[Dict]) -> str:
"""生成辅助函数"""
code = "// Helper functions\n\n"
# 创建顶点缓冲区函数
code += "static SDL_GPUBuffer* createVertexBuffer(SDL_GPUDevice* device, \n"
code += " const Vertex* vertices, \n"
code += " Uint32 vertexCount) {\n"
code += " SDL_GPUBufferCreateInfo bufferInfo = {\n"
code += " .usage = SDL_GPU_BUFFERUSAGE_VERTEX,\n"
code += " .size = static_cast<Uint32>(sizeof(Vertex)) * vertexCount\n"
code += " };\n"
code += " \n"
code += " SDL_GPUBuffer* buffer = SDL_CreateGPUBuffer(device, &bufferInfo);\n"
code += " \n"
code += " // Upload vertex data\n"
code += " SDL_GPUTransferBuffer* transfer = SDL_CreateGPUTransferBuffer(device,\n"
code += " SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD, bufferInfo.size);\n"
code += " \n"
code += " void* mapped = SDL_MapGPUTransferBuffer(device, transfer, SDL_FALSE);\n"
code += " SDL_memcpy(mapped, vertices, bufferInfo.size);\n"
code += " SDL_UnmapGPUTransferBuffer(device, transfer);\n"
code += " \n"
code += " // Copy to GPU\n"
code += " SDL_GPUCommandBuffer* cmd = SDL_AcquireGPUCommandBuffer(device);\n"
code += " SDL_GPUCopyPass* copy = SDL_BeginGPUCopyPass(cmd);\n"
code += " \n"
code += " SDL_GPUTransferBufferLocation src = {.transfer_buffer = transfer, .offset = 0};\n"
code += " SDL_GPUBufferRegion dst = {.buffer = buffer, .offset = 0, .size = bufferInfo.size};\n"
code += " \n"
code += " SDL_UploadToGPUBuffer(copy, &src, &dst, SDL_FALSE);\n"
code += " SDL_EndGPUCopyPass(copy);\n"
code += " SDL_SubmitGPUCommandBuffer(cmd);\n"
code += " \n"
code += " SDL_ReleaseGPUTransferBuffer(device, transfer);\n"
code += " return buffer;\n"
code += "}\n\n"
return code
def generate_header(self, json_file: str) -> str:
"""生成头文件内容"""
with open(json_file, 'r') as f:
json_data = json.load(f)
# 解析数据
vertex_fields = self.parse_vertex_input(json_data)
uniform_buffers = self.parse_uniform_buffers(json_data)
# 生成代码
code = "#pragma once\n\n"
code += "#include <SDL3/SDL.h>\n"
code += "#include <SDL3/SDL_gpu.h>\n\n"
code += "// Auto-generated from: " + json_file + "\n\n"
code += self.generate_vertex_struct(vertex_fields)
code += self.generate_uniform_structs(uniform_buffers)
code += self.generate_vertex_attributes(vertex_fields)
code += self.generate_helper_functions(vertex_fields)
return code