编译脚本
This commit is contained in:
parent
b7936d2e1a
commit
b38aa6d65b
@ -4,15 +4,18 @@ cmake_policy(SET CMP0167 NEW)
|
||||
project(mirage LANGUAGES C CXX)
|
||||
set(CMAKE_CXX_STANDARD 26)
|
||||
|
||||
# 设置全局着色器输出目录
|
||||
set(SHADER_OUTPUT_DIR "${CMAKE_BINARY_DIR}/shaders" CACHE PATH "着色器编译输出路径")
|
||||
# 设置全局着色器路径列表
|
||||
set(SHADER_SOURCE_DIRS "" CACHE STRING "着色器源文件路径列表")
|
||||
mark_as_advanced(SHADER_OUTPUT_DIR)
|
||||
|
||||
set(MSDFGEN_USE_SKIA OFF CACHE BOOL "Use Skia for MSDFGen" FORCE)
|
||||
set(MSDFGEN_USE_VCPKG OFF CACHE BOOL "Use VCPKG for MSDFGen" FORCE)
|
||||
set(MSDFGEN_USE_OPENMP ON CACHE BOOL "Use OpenMP for MSDFGen" FORCE)
|
||||
set(MSDFGEN_BUILD_STANDALONE ON CACHE BOOL "Build MSDFGen standalone" FORCE)
|
||||
|
||||
# 配置输出目录
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
|
||||
# 设置全局着色器输出目录
|
||||
set(SHADER_OUTPUT_DIR "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/resource/shaders" CACHE PATH "着色器编译输出路径")
|
||||
|
||||
include(cmake/retrieve_files.cmake)
|
||||
include(cmake/detect_os.cmake)
|
||||
|
@ -1,12 +1,6 @@
|
||||
#include "mirage.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
window_desc desc{};
|
||||
desc.title = "mirage";
|
||||
desc.resolution.width = 1280;
|
||||
desc.resolution.height = 720;
|
||||
desc.resizable = true;
|
||||
|
||||
mirage::init_info init{};
|
||||
return run(init);
|
||||
}
|
||||
|
@ -1,108 +1,226 @@
|
||||
from typing import List, Tuple, Iterator, Optional
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
|
||||
def find_shader_files(input_dir, extensions):
|
||||
for root, _, files in os.walk(input_dir):
|
||||
for file in files:
|
||||
if any(file.endswith(ext) for ext in extensions):
|
||||
yield os.path.join(root, file)
|
||||
# 设置控制台输出编码
|
||||
if sys.platform.startswith('win'):
|
||||
# Windows系统下设置
|
||||
sys.stdout.reconfigure(encoding='utf-8')
|
||||
sys.stderr.reconfigure(encoding='utf-8')
|
||||
|
||||
def find_slang_entries(input_file):
|
||||
def print_utf8(message: str):
|
||||
"""
|
||||
以UTF-8编码打印消息
|
||||
|
||||
Args:
|
||||
message: 要打印的消息
|
||||
"""
|
||||
print(message.encode('utf-8').decode(sys.stdout.encoding))
|
||||
|
||||
# 常量定义
|
||||
SHADER_EXTENSIONS = {
|
||||
'glsl': 'glsl',
|
||||
'spirv': 'spirv',
|
||||
'dxil': 'dxil',
|
||||
'dxbc': 'dxbc',
|
||||
'metallib': 'metallib',
|
||||
'wgsl': 'wgsl'
|
||||
}
|
||||
|
||||
# 不同目标平台的编译配置
|
||||
TARGET_PROFILES = {
|
||||
'glsl': ['-profile', 'glsl_460'],
|
||||
'spirv': ['-profile', 'glsl_460', '-capability', 'glsl_spirv_1_6'],
|
||||
'dxbc': ['-profile', 'sm_5_1'],
|
||||
'dxil': ['-profile', 'sm_6_6'],
|
||||
'metallib': ['-capability', 'metallib_3_1']
|
||||
}
|
||||
|
||||
def find_shader_files(input_dir: Path, extensions: List[str]) -> Iterator[Path]:
|
||||
"""
|
||||
递归查找指定目录下的着色器文件
|
||||
|
||||
Args:
|
||||
input_dir: 输入目录路径
|
||||
extensions: 着色器文件扩展名列表
|
||||
|
||||
Yields:
|
||||
符合扩展名的着色器文件路径
|
||||
"""
|
||||
for file_path in Path(input_dir).rglob('*'):
|
||||
if file_path.suffix in extensions:
|
||||
yield file_path
|
||||
|
||||
def find_slang_entries(input_file: Path) -> List[str]:
|
||||
"""
|
||||
从着色器文件中提取入口点函数名
|
||||
|
||||
Args:
|
||||
input_file: 着色器文件路径
|
||||
|
||||
Returns:
|
||||
入口点函数名列表
|
||||
"""
|
||||
# 匹配 [shader("xxx")] 形式的着色器入口点声明
|
||||
pattern = re.compile(r'\[shader\(\s*"(?:\w+)"\s*\)\]\s*\n\s*\w+\s+(\w+)\s*\(')
|
||||
try:
|
||||
with open(input_file, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
pattern = r'\[shader\(\s*"(?:\w+)"\s*\)\]\s*\n\s*\w+\s+(\w+)\s*\('
|
||||
return list(set(re.findall(pattern, content)))
|
||||
content = input_file.read_text(encoding='utf-8')
|
||||
return list(set(pattern.findall(content)))
|
||||
except Exception as e:
|
||||
print(f"Error parsing {input_file}: {str(e)}")
|
||||
print_utf8(f"**错误**: 解析文件 {input_file} 失败: {e}")
|
||||
return []
|
||||
|
||||
def gen_shader_ext(build_type):
|
||||
if build_type == 'glsl':
|
||||
return 'glsl'
|
||||
elif build_type == 'spirv':
|
||||
return 'spirv'
|
||||
elif build_type == 'dxil':
|
||||
return 'dxil'
|
||||
elif build_type == 'dxbc':
|
||||
return 'dxbc'
|
||||
elif build_type == 'metallib':
|
||||
return 'metallib'
|
||||
elif build_type == 'wgsl':
|
||||
return 'wgsl'
|
||||
else:
|
||||
return 'dat'
|
||||
def get_shader_extension(build_type: str) -> str:
|
||||
"""
|
||||
根据构建类型获取对应的着色器文件扩展名
|
||||
|
||||
Args:
|
||||
build_type: 构建类型
|
||||
|
||||
Returns:
|
||||
对应的文件扩展名
|
||||
"""
|
||||
return SHADER_EXTENSIONS.get(build_type, 'dat')
|
||||
|
||||
def gen_slangc_cmd(input_file, entry, output_file, target_type, args):
|
||||
slangc = args.slangc
|
||||
cmd = [slangc, input_file, "-entry", entry, "-o", output_file, "-target", target_type]
|
||||
if args.debug:
|
||||
cmd.append("-g3")
|
||||
else:
|
||||
cmd.append("-O3")
|
||||
def create_compiler_command(
|
||||
input_file: Path,
|
||||
entry: str,
|
||||
output_file: Path,
|
||||
target_type: str,
|
||||
args: argparse.Namespace
|
||||
) -> List[str]:
|
||||
"""
|
||||
生成着色器编译命令
|
||||
|
||||
Args:
|
||||
input_file: 输入文件路径
|
||||
entry: 着色器入口点
|
||||
output_file: 输出文件路径
|
||||
target_type: 目标平台类型
|
||||
args: 命令行参数
|
||||
|
||||
Returns:
|
||||
编译命令列表
|
||||
"""
|
||||
cmd = [args.slangc,
|
||||
str(input_file),
|
||||
"-entry", entry,
|
||||
"-o", str(output_file),
|
||||
"-target", target_type,
|
||||
"-g3" if args.debug else "-O3"
|
||||
]
|
||||
|
||||
# 添加优化或调试标志
|
||||
|
||||
if target_type == 'glsl':
|
||||
cmd.extend(["-profile", "glsl_460"])
|
||||
if target_type == 'spirv':
|
||||
cmd.extend(["-profile", "glsl_460"])
|
||||
cmd.extend(["-capability", "glsl_spirv_1_6"])
|
||||
if target_type == 'dxbc':
|
||||
cmd.extend(["-profile", "sm_5_1"])
|
||||
if target_type == 'dxil':
|
||||
cmd.extend(["-profile", "sm_6_6"])
|
||||
if target_type == 'metallib':
|
||||
cmd.extend(["-capability", "metallib_3_1"])
|
||||
# 添加目标平台特定的编译选项
|
||||
if target_type in TARGET_PROFILES:
|
||||
cmd.extend(TARGET_PROFILES[target_type])
|
||||
|
||||
return cmd
|
||||
|
||||
def compile_slang(input_file, target_types, output_dir, args):
|
||||
def needs_recompile(input_file: Path, output_file: Path) -> bool:
|
||||
"""
|
||||
检查是否需要重新编译着色器
|
||||
|
||||
Args:
|
||||
input_file: 输入文件路径
|
||||
output_file: 输出文件路径
|
||||
|
||||
Returns:
|
||||
是否需要重新编译
|
||||
"""
|
||||
if not output_file.exists():
|
||||
return True
|
||||
try:
|
||||
return input_file.stat().st_mtime > output_file.stat().st_mtime
|
||||
except OSError:
|
||||
return True
|
||||
|
||||
def compile_shader(
|
||||
input_file: Path,
|
||||
target_types: List[Tuple[str, bool]],
|
||||
output_dir: Path,
|
||||
args: argparse.Namespace
|
||||
) -> bool:
|
||||
"""
|
||||
编译单个着色器文件
|
||||
|
||||
Args:
|
||||
input_file: 输入文件路径
|
||||
target_types: 目标平台类型列表
|
||||
output_dir: 输出目录
|
||||
args: 命令行参数
|
||||
|
||||
Returns:
|
||||
编译是否成功
|
||||
"""
|
||||
try:
|
||||
# 获取着色器入口点
|
||||
entries = find_slang_entries(input_file)
|
||||
if not entries:
|
||||
print(f"Skipping {input_file}: No shader entries found")
|
||||
print_utf8(f"**跳过**: {input_file} - 未找到着色器入口点")
|
||||
return True
|
||||
|
||||
base = os.path.splitext(os.path.basename(input_file))[0]
|
||||
|
||||
abs_path = os.path.abspath(output_dir)
|
||||
|
||||
os.makedirs(abs_path, exist_ok=True)
|
||||
|
||||
# 创建输出目录
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
base = input_file.stem
|
||||
success = True
|
||||
|
||||
# 针对每个目标平台编译
|
||||
for target_type, enabled in target_types:
|
||||
if not enabled:
|
||||
continue
|
||||
|
||||
for entry in entries:
|
||||
output_file = os.path.join(abs_path, f"{base}_{entry}.{gen_shader_ext(target_type)}")
|
||||
cmd = gen_slangc_cmd(input_file, entry, output_file, target_type, args)
|
||||
output_file = output_dir / f"{base}_{entry}.{get_shader_extension(target_type)}"
|
||||
|
||||
# 检查是否需要重新编译
|
||||
if not needs_recompile(input_file, output_file):
|
||||
print_utf8(f"**跳过**: {output_file} - 文件已是最新")
|
||||
continue
|
||||
|
||||
# 执行编译
|
||||
cmd = create_compiler_command(input_file, entry, output_file, target_type, args)
|
||||
try:
|
||||
subprocess.run(cmd, check=True, capture_output=True, text=True)
|
||||
print(f"Compiled Slang: {input_file}:{entry} -> {output_file}")
|
||||
result = subprocess.run(cmd, check=True, capture_output=True, text=True)
|
||||
print_utf8(f"**成功**: 编译 {input_file}:{entry} -> {output_file}")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Error compiling {input_file}:{entry}")
|
||||
print(e.stderr)
|
||||
print_utf8(f"**错误**: 编译 {input_file}:{entry} 失败")
|
||||
print_utf8(e.stderr)
|
||||
success = False
|
||||
|
||||
return success
|
||||
except Exception as e:
|
||||
print(f"Unexpected error with {input_file}: {str(e)}")
|
||||
print_utf8(f"**错误**: 处理 {input_file} 时发生异常: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Compile slang shaders using slangc")
|
||||
parser.add_argument("--shader-list", help="Input shader list .txt file")
|
||||
parser.add_argument("--output-dir", help="Output directory")
|
||||
parser.add_argument("--slangc", default="slangc", help="Path to slangc")
|
||||
parser.add_argument("--debug", action="store_true", help="Compile in debug mode")
|
||||
parser.add_argument("--opengl", action="store_true", help="Compile Slang for OpenGL")
|
||||
parser.add_argument("--vulkan", action="store_true", help="Compile Slang for Vulkan")
|
||||
parser.add_argument("--d3d11", action="store_true", help="Compile Slang for D3D11")
|
||||
parser.add_argument("--d3d12", action="store_true", help="Compile Slang for D3D12")
|
||||
parser.add_argument("--metal", action="store_true", help="Compile Slang for Metal")
|
||||
"""
|
||||
主函数:解析命令行参数并执行编译流程
|
||||
"""
|
||||
# 设置UTF-8编码
|
||||
if sys.platform.startswith('win'):
|
||||
# Windows下设置控制台代码页
|
||||
subprocess.run(['chcp', '65001'], shell=True)
|
||||
|
||||
# 设置命令行参数
|
||||
parser = argparse.ArgumentParser(description="使用 slangc 编译着色器")
|
||||
parser.add_argument("--shader-list", help="着色器列表文件路径")
|
||||
parser.add_argument("--output-dir", help="输出目录")
|
||||
parser.add_argument("--slangc", default="slangc", help="slangc 编译器路径")
|
||||
parser.add_argument("--debug", action="store_true", help="启用调试模式编译")
|
||||
parser.add_argument("--opengl", action="store_true", help="编译 OpenGL 着色器")
|
||||
parser.add_argument("--vulkan", action="store_true", help="编译 Vulkan 着色器")
|
||||
parser.add_argument("--d3d11", action="store_true", help="编译 D3D11 着色器")
|
||||
parser.add_argument("--d3d12", action="store_true", help="编译 D3D12 着色器")
|
||||
parser.add_argument("--metal", action="store_true", help="编译 Metal 着色器")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# 配置目标平台
|
||||
target_types = [
|
||||
['glsl', args.opengl],
|
||||
['spirv', args.vulkan],
|
||||
@ -111,21 +229,19 @@ def main():
|
||||
['metallib', args.metal],
|
||||
]
|
||||
|
||||
output_dir = args.output_dir or "shaders"
|
||||
shader_dir = args.shader_list or "shader_paths.txt"
|
||||
# 设置输出目录和着色器列表文件
|
||||
output_dir = Path(args.output_dir or "shaders")
|
||||
shader_list = Path(args.shader_list or "shader_paths.txt")
|
||||
|
||||
# 读取当前同级目录下的shader_paths.txt
|
||||
with open(shader_dir, 'r') as f:
|
||||
shader_paths = f.readlines()
|
||||
|
||||
slang_ext = ['.slang']
|
||||
# 读取着色器路径列表
|
||||
shader_paths = shader_list.read_text().splitlines()
|
||||
|
||||
# 编译所有着色器
|
||||
all_success = True
|
||||
|
||||
for shader_path in shader_paths:
|
||||
# Compile Slang
|
||||
for file in find_shader_files(shader_path, slang_ext):
|
||||
if not compile_slang(file, target_types, output_dir, args):
|
||||
shader_path = shader_path.strip()
|
||||
for file in find_shader_files(shader_path, ['.slang']):
|
||||
if not compile_shader(file, target_types, output_dir, args):
|
||||
all_success = False
|
||||
|
||||
if not all_success:
|
||||
|
@ -13,7 +13,7 @@ set(RENDERER_SOURCES "")
|
||||
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} RENDERER_SOURCES)
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC ${RENDERER_SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Freetype::Freetype glfw harfbuzz Eigen3::Eigen spdlog::spdlog msdfgen-full Boost::boost Vulkan::Vulkan)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Freetype::Freetype glfw harfbuzz Eigen3::Eigen spdlog::spdlog msdfgen-full Boost::boost Vulkan::Vulkan LLGL)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE NOMINMAX)
|
||||
add_os_definitions(${PROJECT_NAME})
|
||||
@ -27,18 +27,3 @@ endif ()
|
||||
shader_compile_target(${CMAKE_CURRENT_SOURCE_DIR}/shaders)
|
||||
# 添加依赖, 当编译mirage_core时, 会先执行compile_shaders
|
||||
add_dependencies(${PROJECT_NAME} compile_shaders)
|
||||
|
||||
# 如果需要编译example, 添加自定义命令用于拷贝shader文件
|
||||
if (BUILD_EXAMPLE)
|
||||
# 复制${SHADER_OUTPUT_DIR}文件到${CMAKE_CURRENT_BINARY_DIR}/example/resource/shaders
|
||||
set(SOURCE_DIR ${SHADER_OUTPUT_DIR})
|
||||
set(DEST_DIR ${CMAKE_BINARY_DIR}/example/resource/shaders)
|
||||
|
||||
# 添加自定义命令, 当目标mirage_core被编译时, 将${SOURCE_DIR}文件复制到${DEST_DIR}
|
||||
add_custom_command(
|
||||
TARGET ${PROJECT_NAME}
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${SOURCE_DIR} ${DEST_DIR}
|
||||
COMMENT "Copying shaders to example"
|
||||
)
|
||||
endif ()
|
||||
|
@ -5,16 +5,56 @@ using time_type = decltype(std::chrono::high_resolution_clock::now());
|
||||
std::chrono::duration<double> delta_time = {};
|
||||
time_type begin_time = {};
|
||||
time_type last_time = {};
|
||||
LLGL::RenderSystemPtr renderer = nullptr;
|
||||
|
||||
namespace mirage {
|
||||
void on_llgl_log(LLGL::Log::ReportType type, const char* text, void* user_data) {
|
||||
switch (type) {
|
||||
case LLGL::Log::ReportType::Default:
|
||||
spdlog::info(text);
|
||||
break;
|
||||
case LLGL::Log::ReportType::Error:
|
||||
spdlog::error(text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::string to_string(renderer_api api) {
|
||||
switch (api) {
|
||||
case renderer_api::dx11: return "Direct3D11";
|
||||
case renderer_api::dx12: return "Direct3D12";
|
||||
case renderer_api::vulkan: return "Vulkan";
|
||||
case renderer_api::opengl: return "OpenGL";
|
||||
case renderer_api::metal: return "Metal";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
bool init_renderer(const init_info& in_info) {
|
||||
RegisterCallback(on_llgl_log);
|
||||
LLGL::RenderSystemDescriptor desc{};
|
||||
desc.moduleName = to_string(in_info.api);
|
||||
|
||||
spdlog::info("初始化渲染器: {}", desc.moduleName.c_str());
|
||||
renderer = LLGL::RenderSystem::Load(desc);
|
||||
if (renderer != nullptr) {
|
||||
spdlog::info("渲染器加载成功");
|
||||
return true;
|
||||
}
|
||||
spdlog::error("渲染器加载失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool init(const init_info& in_info) {
|
||||
spdlog::info("初始化 mirage");
|
||||
begin_time = std::chrono::high_resolution_clock::now();
|
||||
if (!init_renderer(in_info)) {
|
||||
return false;
|
||||
}
|
||||
begin_time = std::chrono::high_resolution_clock::now();
|
||||
last_time = std::chrono::high_resolution_clock::now();
|
||||
return true;
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
renderer.reset();
|
||||
spdlog::info("mirage 销毁");
|
||||
}
|
||||
|
||||
@ -36,6 +76,7 @@ namespace mirage {
|
||||
int run(const init_info& in_init_info) {
|
||||
try {
|
||||
if (!init(in_init_info)) {
|
||||
spdlog::error("初始化 mirage 失败");
|
||||
return -1;
|
||||
}
|
||||
while (!should_exit()) {
|
||||
|
@ -1,12 +1,27 @@
|
||||
#pragma once
|
||||
#include <spdlog/spdlog.h>
|
||||
#include "LLGL/LLGL.h"
|
||||
|
||||
#define MIRAGE_VERSION_MAJOR 0
|
||||
#define MIRAGE_VERSION_MINOR 1
|
||||
#define MIRAGE_VERSION_PATCH 0
|
||||
|
||||
namespace mirage {
|
||||
enum class renderer_api {
|
||||
dx11,
|
||||
dx12,
|
||||
vulkan,
|
||||
opengl,
|
||||
metal,
|
||||
};
|
||||
struct init_info {
|
||||
#if MIRAGE_PLATFORM_WINDOWS
|
||||
renderer_api api = renderer_api::dx11;
|
||||
#elif MIRAGE_PLATFORM_MACOS
|
||||
renderer_api api = renderer_api::metal;
|
||||
#elif MIRAGE_PLATFORM_LINUX
|
||||
renderer_api api = renderer_api::vulkan;
|
||||
#endif
|
||||
};
|
||||
int run(const init_info& in_init_info);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user