圆角矩形着色器
This commit is contained in:
parent
3479b9443b
commit
4727a47616
10
.gitignore
vendored
10
.gitignore
vendored
@ -3,3 +3,13 @@
|
||||
/.idea
|
||||
/scripts/shader_paths.txt
|
||||
/cache/shader_loader.h
|
||||
#>fips
|
||||
# this area is managed by fips, do not edit
|
||||
.fips-*
|
||||
fips-files/build/
|
||||
fips-files/deploy/
|
||||
*.pyc
|
||||
.vscode/
|
||||
.idea/
|
||||
CMakeUserPresets.json
|
||||
#<fips
|
||||
|
@ -1,13 +1,22 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
#
|
||||
# project: mirage
|
||||
#
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
project(mirage)
|
||||
|
||||
project(mirage LANGUAGES C CXX)
|
||||
set(CMAKE_CXX_STANDARD 26)
|
||||
|
||||
if (MSVC)
|
||||
# MSVC编译器设置C++标准
|
||||
add_compile_options(/std:c++latest)
|
||||
# 设置utf-8编码
|
||||
add_compile_options(/utf-8)
|
||||
endif ()
|
||||
if (WIN32)
|
||||
# 定义Windows版本宏
|
||||
add_definitions(-DWIN32_LEAN_AND_MEAN)
|
||||
add_definitions(-DUNICODE -D_UNICODE)
|
||||
endif ()
|
||||
|
||||
set(MSDFGEN_USE_SKIA OFF CACHE BOOL "Use Skia for MSDFGen" FORCE)
|
||||
set(MSDFGEN_USE_VCPKG OFF CACHE BOOL "Use VCPKG for MSDFGen" FORCE)
|
||||
@ -18,15 +27,12 @@ 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 "着色器编译输出路径")
|
||||
set(MIRAGE_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
include(cmake/retrieve_files.cmake)
|
||||
include(cmake/detect_os.cmake)
|
||||
include(cmake/compile_shaders.cmake)
|
||||
include(cmake/configure_glfw_native.cmake)
|
||||
include(cmake/config_macos.cmake)
|
||||
include(cmake/compile_shaders.cmake)
|
||||
|
||||
# 如果是Debug模式, 添加宏定义
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
|
@ -1,56 +1,75 @@
|
||||
# 查找编译器和Python
|
||||
find_program(PYTHON_EXECUTABLE python3)
|
||||
if (NOT PYTHON_EXECUTABLE)
|
||||
find_program(PYTHON_EXECUTABLE python)
|
||||
endif ()
|
||||
if (NOT PYTHON_EXECUTABLE)
|
||||
message(FATAL_ERROR "无法找到Python解释器")
|
||||
endif ()
|
||||
find_program(SLANG_COMPILER slangc REQUIRED)
|
||||
include(CMakeParseArguments)
|
||||
|
||||
message(STATUS "Python解释器: ${PYTHON_EXECUTABLE}")
|
||||
message(STATUS "SLANG编译器: ${SLANG_COMPILER}")
|
||||
# 查找Python解释器
|
||||
find_package(Python3 REQUIRED)
|
||||
|
||||
set(SHADER_PATH_FILE ${CMAKE_CURRENT_SOURCE_DIR}/scripts/shader_paths.txt)
|
||||
set(SHADER_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cache)
|
||||
set(SHADER_HEADER_FILE ${SHADER_HEADER_DIR}/shader_loader.h)
|
||||
# 创建文件
|
||||
file(WRITE ${SHADER_HEADER_FILE} "")
|
||||
# 存储脚本路径
|
||||
set(SHADER_COMPILE_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/tools/compile_shaders.py")
|
||||
|
||||
# 删除文件
|
||||
# 在cache目录下创建着色器目录.txt
|
||||
set(SHADER_PATH_FILE ${CMAKE_CACHEFILE_DIR}/shader_paths.txt)
|
||||
file(REMOVE ${SHADER_PATH_FILE})
|
||||
file(WRITE ${SHADER_PATH_FILE} "")
|
||||
|
||||
function(shader_compile_target INPUT_DIR)
|
||||
# 将路径写到scripts/shader_paths.txt中
|
||||
file(WRITE ${SHADER_PATH_FILE} ${INPUT_DIR})
|
||||
# 添加着色器目录的函数
|
||||
function(add_mirage_shader_directory path)
|
||||
# 将路径写入shader_paths.txt
|
||||
file(APPEND ${SHADER_PATH_FILE} "${path}\n")
|
||||
|
||||
# 观察目录文件是否修改, 触发compile_shaders目标重新编译
|
||||
file(GLOB_RECURSE SHADER_FILES "${path}/*.slang")
|
||||
|
||||
# 设置依赖关系,当shader文件变化时重新编译
|
||||
foreach(SHADER_FILE ${SHADER_FILES})
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${SHADER_FILE})
|
||||
endforeach()
|
||||
|
||||
# 添加到全局变量以便在其他地方使用
|
||||
set(SHADER_FILES_GLOBAL ${SHADER_FILES_GLOBAL} ${SHADER_FILES} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
set(SLANGC_ARGS "")
|
||||
if (LLGL_BUILD_RENDERER_OPENGL OR LLGL_BUILD_RENDERER_OPENGLES3 OR LLGL_BUILD_RENDERER_WEBGL)
|
||||
list(APPEND SLANGC_ARGS "--opengl")
|
||||
endif ()
|
||||
if (LLGL_BUILD_RENDERER_VULKAN)
|
||||
list(APPEND SLANGC_ARGS "--vulkan")
|
||||
endif ()
|
||||
if (LLGL_BUILD_RENDERER_DIRECT3D11)
|
||||
list(APPEND SLANGC_ARGS "--d3d11")
|
||||
endif ()
|
||||
if (LLGL_BUILD_RENDERER_DIRECT3D12)
|
||||
list(APPEND SLANGC_ARGS "--d3d12")
|
||||
endif ()
|
||||
if (LLGL_BUILD_RENDERER_METAL)
|
||||
list(APPEND SLANGC_ARGS "--metal")
|
||||
endif ()
|
||||
set(SHADER_COMPILE_ARGS "")
|
||||
set(SHADER_SHDC "")
|
||||
if (WIN32)
|
||||
list(APPEND SHADER_COMPILE_ARGS "--hlsl")
|
||||
set(SHADER_SHDC ${MIRAGE_ROOT_DIR}/tools/mirage_shdc.exe)
|
||||
elseif (APPLE)
|
||||
list(APPEND SHADER_COMPILE_ARGS "--metal")
|
||||
set(SHADER_SHDC ${MIRAGE_ROOT_DIR}/tools/mirage_shdc)
|
||||
else()
|
||||
list(APPEND SHADER_COMPILE_ARGS "--glsl")
|
||||
set(SHADER_SHDC ${MIRAGE_ROOT_DIR}/tools/mirage_shdc)
|
||||
endif()
|
||||
|
||||
# 如果是Debug模式, 添加--debug选项
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
list(APPEND SLANGC_ARGS "--debug")
|
||||
list(APPEND SHADER_COMPILE_ARGS "--debug")
|
||||
endif ()
|
||||
|
||||
message(STATUS "着色器编译输出路径: ${SHADER_OUTPUT_DIR}")
|
||||
|
||||
# 添加自定义命令, 用于编译着色器, 调用scripts/compile_shaders.py
|
||||
add_custom_target(compile_shaders
|
||||
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/compile_shaders.py --header ${SHADER_HEADER_FILE} --shader-list ${SHADER_PATH_FILE} --output-dir ${SHADER_OUTPUT_DIR} ${SLANGC_ARGS}
|
||||
COMMENT "编译着色器"
|
||||
VERBATIM
|
||||
# 添加编译目标, 调用tools/compile_shaders.py
|
||||
add_custom_target(compile_shaders ALL
|
||||
COMMAND ${Python3_EXECUTABLE} ${SHADER_COMPILE_SCRIPT}
|
||||
--shdc ${SHADER_SHDC}
|
||||
--shader_list ${SHADER_PATH_FILE}
|
||||
${SHADER_COMPILE_ARGS}
|
||||
COMMENT "编译着色器"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
# 添加强制重新编译着色器的目标
|
||||
add_custom_target(force_recompile_shaders
|
||||
COMMAND ${CMAKE_COMMAND} -E remove -f ${SHADER_PATH_FILE}
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${SHADER_PATH_FILE}
|
||||
COMMAND ${Python3_EXECUTABLE} ${SHADER_COMPILE_SCRIPT}
|
||||
--shdc ${SHADER_SHDC}
|
||||
--shader_list ${SHADER_PATH_FILE}
|
||||
${SHADER_COMPILE_ARGS}
|
||||
--force
|
||||
COMMENT "强制重新编译所有着色器"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
# 定义一个宏,将编译着色器作为其他目标的依赖
|
||||
function(add_shader_dependencies target)
|
||||
add_dependencies(${target} compile_shaders)
|
||||
endfunction()
|
||||
|
@ -5,4 +5,6 @@ set(SRC_FILES "")
|
||||
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_FILES)
|
||||
add_executable(${PROJECT_NAME} ${SRC_FILES})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE mirage_core)
|
||||
target_link_options(${PROJECT_NAME} PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup")
|
||||
if (WIN32)
|
||||
target_link_options(${PROJECT_NAME} PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup")
|
||||
endif()
|
||||
|
@ -7,14 +7,13 @@
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
mirage_app app;
|
||||
app.init();
|
||||
|
||||
mirage_window window;
|
||||
window.create_window(800, 600, L"Hello, World!");
|
||||
window.show();
|
||||
app.get_render_context()->setup_surface(&window, false);
|
||||
|
||||
while (!mirage_window::get_windows().empty()) {
|
||||
mirage_window::poll_events();
|
||||
}
|
||||
|
||||
app.init();
|
||||
app.run();
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,470 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import List, Tuple, Iterator
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
|
||||
# 设置控制台输出编码
|
||||
# if sys.platform.startswith('win'):
|
||||
# # Windows系统下设置
|
||||
# sys.stdout.reconfigure(encoding='utf-8')
|
||||
# sys.stderr.reconfigure(encoding='utf-8')
|
||||
|
||||
def print_utf8(message: str):
|
||||
"""以UTF-8编码打印消息"""
|
||||
print(message)
|
||||
|
||||
# 着色器类型和扩展名定义
|
||||
SHADER_TYPES = {
|
||||
'vertex': 'LLGL::ShaderType::Vertex',
|
||||
'pixel': 'LLGL::ShaderType::Fragment',
|
||||
'fragment': 'LLGL::ShaderType::Fragment',
|
||||
'compute': 'LLGL::ShaderType::Compute',
|
||||
'geometry': 'LLGL::ShaderType::Geometry',
|
||||
'tess_control': 'LLGL::ShaderType::TessControl',
|
||||
'tess_evaluation': 'LLGL::ShaderType::TessEvaluation'
|
||||
}
|
||||
|
||||
SHADER_EXTENSIONS = {
|
||||
'glsl': 'glsl',
|
||||
'spirv': 'spirv',
|
||||
'dxil': 'dxil',
|
||||
'dxbc': 'dxbc',
|
||||
'metallib': 'metallib',
|
||||
'metal': 'metal',
|
||||
'wgsl': 'wgsl'
|
||||
}
|
||||
|
||||
# 不同目标平台的编译配置
|
||||
TARGET_PROFILES = {
|
||||
'glsl': ['-profile', 'glsl_460'],
|
||||
'spirv': ['-profile', 'spirv_1_6'],
|
||||
'dxbc': ['-profile', 'sm_5_0'],
|
||||
'dxil': ['-profile', 'sm_6_6'],
|
||||
'metallib': ['-capability', 'metallib'],
|
||||
'metal': ['-capability', 'metal'],
|
||||
}
|
||||
|
||||
class ShaderEntry:
|
||||
"""着色器入口点信息"""
|
||||
def __init__(self, name: str, shader_type: str):
|
||||
self.name = name
|
||||
self.shader_type = shader_type
|
||||
|
||||
class CompiledShaderInfo:
|
||||
"""编译后的着色器信息"""
|
||||
def __init__(self, output_file: str, base: str, entry: ShaderEntry):
|
||||
self.output_file = output_file
|
||||
self.base = base
|
||||
self.entry = entry
|
||||
if entry.shader_type == 'pixel':
|
||||
self.entry.shader_type = 'fragment'
|
||||
|
||||
# 存放所有编译成功的着色器信息
|
||||
compiled_shaders: List[CompiledShaderInfo] = []
|
||||
|
||||
def find_shader_files(input_dir: Path, extensions: List[str]) -> Iterator[Path]:
|
||||
"""递归查找指定目录下的着色器文件"""
|
||||
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[ShaderEntry]:
|
||||
"""从着色器文件中提取入口点函数名和类型"""
|
||||
# 匹配 [shader("xxx")] 形式的着色器类型声明,以及后面的函数名
|
||||
pattern = re.compile(
|
||||
r'\[\s*shader\s*\(\s*"([^"]+)"\s*\)\s*\]\s*' # 匹配 [shader("xxx")]
|
||||
r'(?:\[\s*[^\]]+\])*' # 可选:匹配其他属性如 [numthreads(8,8,1)]
|
||||
r'\s*\w+\s+(\w+)\s*\(' # 匹配函数声明:返回类型 函数名(
|
||||
)
|
||||
try:
|
||||
content = input_file.read_text(encoding='utf-8')
|
||||
matches = pattern.findall(content)
|
||||
print_utf8(f"**调试**: 在文件 {input_file} 中找到的匹配: {matches}")
|
||||
|
||||
entries = []
|
||||
for shader_type, name in matches:
|
||||
if shader_type in SHADER_TYPES:
|
||||
entries.append(ShaderEntry(name, shader_type))
|
||||
else:
|
||||
print_utf8(f"**警告**: 未知的着色器类型 {shader_type}")
|
||||
return entries
|
||||
except Exception as e:
|
||||
print_utf8(f"**错误**: 解析文件 {input_file} 失败: {e}")
|
||||
return []
|
||||
|
||||
|
||||
def get_shader_extension(build_type: str) -> str:
|
||||
"""根据构建类型获取对应的着色器文件扩展名"""
|
||||
return SHADER_EXTENSIONS.get(build_type, 'dat')
|
||||
|
||||
def create_compiler_command(
|
||||
input_file: Path,
|
||||
entry: ShaderEntry,
|
||||
output_file: Path,
|
||||
target_type: str,
|
||||
args: argparse.Namespace
|
||||
) -> List[str]:
|
||||
"""生成着色器编译命令"""
|
||||
cmd = [args.slangc,
|
||||
str(input_file),
|
||||
"-entry", entry.name,
|
||||
"-o", str(output_file),
|
||||
"-target", target_type,
|
||||
"-g3" if args.debug else "-O3",
|
||||
]
|
||||
|
||||
if target_type in TARGET_PROFILES:
|
||||
cmd.extend(TARGET_PROFILES[target_type])
|
||||
|
||||
return cmd
|
||||
|
||||
def needs_recompile(input_file: Path, output_file: Path) -> bool:
|
||||
"""检查是否需要重新编译着色器"""
|
||||
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:
|
||||
"""编译单个着色器文件"""
|
||||
try:
|
||||
entries = find_slang_entries(input_file)
|
||||
if not entries:
|
||||
print_utf8(f"**跳过**: {input_file} - 未找到着色器入口点")
|
||||
return True
|
||||
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
base = input_file.stem
|
||||
success = True
|
||||
|
||||
|
||||
for entry in entries:
|
||||
compiled_shaders.append(CompiledShaderInfo(f"{base}_{entry.name}", base, entry))
|
||||
|
||||
for target_type, enabled in target_types:
|
||||
if not enabled:
|
||||
continue
|
||||
|
||||
for entry in entries:
|
||||
output_file = output_dir / f"{base}_{entry.name}.{get_shader_extension(target_type)}"
|
||||
|
||||
if not needs_recompile(input_file, output_file):
|
||||
print_utf8(f"**跳过**: {output_file} - 文件已是最新")
|
||||
else:
|
||||
cmd = create_compiler_command(input_file, entry, output_file, target_type, args)
|
||||
try:
|
||||
subprocess.run(cmd, check=True, capture_output=True, text=True)
|
||||
print_utf8(f"**成功**: 编译 {input_file}:{entry.name} -> {output_file}")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print_utf8(f"**错误**: 编译 {input_file}:{entry.name} 失败")
|
||||
print_utf8(e.stderr)
|
||||
success = False
|
||||
continue
|
||||
|
||||
return success
|
||||
except Exception as e:
|
||||
print_utf8(f"**错误**: 处理 {input_file} 时发生异常: {e}")
|
||||
return False
|
||||
|
||||
def generate_pipeline_header_preamble() -> List[str]:
|
||||
"""Generate the header file preamble"""
|
||||
|
||||
return [
|
||||
"#pragma once",
|
||||
"",
|
||||
"#include \"mirage.h\"",
|
||||
"#include \"misc/mirage_type.h\"",
|
||||
"#include <LLGL/LLGL.h>",
|
||||
"#include <LLGL/Utils/VertexFormat.h>",
|
||||
"#include <memory>",
|
||||
"#include <string>",
|
||||
"#include <vector>",
|
||||
"#include <fstream>",
|
||||
"#include <stdexcept>",
|
||||
"",
|
||||
"namespace generated_pipelines {",
|
||||
"",
|
||||
"// 辅助函数:加载着色器",
|
||||
"inline auto LoadShader(",
|
||||
" LLGL::RenderSystem* renderer,",
|
||||
" const std::string& filename,",
|
||||
" const LLGL::ShaderType type,",
|
||||
" const char* entryPoint,",
|
||||
" const LLGL::ShaderDescriptor& shaderDesc = {}) {",
|
||||
"",
|
||||
" // 根据渲染器类型选择着色器文件后缀",
|
||||
" auto rendererID = renderer->GetRendererID();",
|
||||
" std::string ext;",
|
||||
" // 选择对应的文件扩展名",
|
||||
" if (rendererID == LLGL::RendererID::OpenGL) {",
|
||||
" ext = \".glsl\";",
|
||||
" } else if (rendererID == LLGL::RendererID::Vulkan) {",
|
||||
" ext = \".spirv\";",
|
||||
" } else if (rendererID == LLGL::RendererID::Direct3D11) {",
|
||||
" ext = \".dxbc\";",
|
||||
" } else if (rendererID == LLGL::RendererID::Direct3D12) {",
|
||||
" ext = \".dxil\";",
|
||||
" } else if (rendererID == LLGL::RendererID::Metal) {",
|
||||
" ext = \".metallib\";",
|
||||
" } else {",
|
||||
" ext = \".dat\";",
|
||||
" }",
|
||||
"",
|
||||
" // 构造最终的文件名",
|
||||
" std::string finalFilename = filename;",
|
||||
" size_t pos = finalFilename.find_last_of('.');",
|
||||
" if (pos != std::string::npos) {",
|
||||
" finalFilename = finalFilename.substr(0, pos) + ext;",
|
||||
" } else {",
|
||||
" finalFilename += ext;",
|
||||
" }",
|
||||
" finalFilename = (mirage::get_shader_path() / finalFilename).string();",
|
||||
"",
|
||||
" // 读取着色器文件",
|
||||
" std::vector<char> shaderData;",
|
||||
" try {",
|
||||
" std::ifstream file(finalFilename, std::ios::binary | std::ios::ate);",
|
||||
" if (!file.is_open()) {",
|
||||
" throw std::runtime_error(\"Failed to open shader file: \" + finalFilename);",
|
||||
" }",
|
||||
" size_t fileSize = static_cast<size_t>(file.tellg());",
|
||||
" shaderData.resize(fileSize);",
|
||||
" file.seekg(0);",
|
||||
" file.read(shaderData.data(), fileSize);",
|
||||
" } catch (const std::exception& e) {",
|
||||
" throw std::runtime_error(\"Failed to read shader file: \" + std::string(e.what()));",
|
||||
" }",
|
||||
"",
|
||||
" if (rendererID == LLGL::RendererID::OpenGL) {",
|
||||
" // 添加终止符",
|
||||
" shaderData.push_back('\\0');",
|
||||
" }",
|
||||
" // 创建着色器",
|
||||
" LLGL::ShaderDescriptor desc = shaderDesc;",
|
||||
" desc.source = shaderData.data();",
|
||||
" desc.sourceSize = shaderData.size();",
|
||||
" desc.entryPoint = rendererID == LLGL::RendererID::OpenGL ? \"main\" : entryPoint;",
|
||||
" desc.type = type;",
|
||||
" desc.profile = \"460\";",
|
||||
" desc.sourceType = rendererID == LLGL::RendererID::OpenGL ? LLGL::ShaderSourceType::CodeString : LLGL::ShaderSourceType::BinaryBuffer;",
|
||||
"",
|
||||
" auto shader = renderer->CreateShader(desc);",
|
||||
" if (auto report = shader->GetReport()) {",
|
||||
" spdlog::error(\"Shader compilation report: {}\", report->GetText());",
|
||||
" }",
|
||||
" return mirage::shader_ptr(shader, mirage::llgl_deleter<LLGL::Shader>);",
|
||||
"}",
|
||||
""
|
||||
"inline auto create_pipeline_layout(LLGL::RenderSystem* renderer, const LLGL::PipelineLayoutDescriptor& in_desc) {",
|
||||
" auto pipelineLayout = renderer->CreatePipelineLayout(in_desc);",
|
||||
" return mirage::pipeline_layout_ptr(pipelineLayout, mirage::llgl_deleter<LLGL::PipelineLayout>);",
|
||||
"}",
|
||||
]
|
||||
|
||||
def generate_compute_pipeline(header_lines: List[str], shader: CompiledShaderInfo):
|
||||
"""Generate compute pipeline creation function"""
|
||||
func_name = f"create_{shader.base}_{shader.entry.name}_pipeline"
|
||||
|
||||
header_lines.extend([
|
||||
f"// 计算管线: {shader.base} - {shader.entry.name}",
|
||||
f"inline auto {func_name}(LLGL::RenderSystem* renderer) {{",
|
||||
" // 加载计算着色器",
|
||||
f" auto computeShader = LoadShader(renderer, \"{shader.output_file.name}\", {SHADER_TYPES['compute']}, \"{shader.entry.name}\");",
|
||||
"",
|
||||
" // 创建管线布局",
|
||||
" LLGL::PipelineLayoutDescriptor layoutDesc;",
|
||||
" auto pipelineLayout = create_pipeline_layout(renderer, layoutDesc);",
|
||||
"",
|
||||
" // 创建计算管线",
|
||||
" LLGL::ComputePipelineDescriptor pipelineDesc;",
|
||||
" pipelineDesc.computeShader = computeShader.get();",
|
||||
" pipelineDesc.pipelineLayout = pipelineLayout.get();",
|
||||
"",
|
||||
" auto pipeline = renderer->CreatePipelineState(pipelineDesc);",
|
||||
" mirage::pipeline_info info;",
|
||||
" info.pipeline_state = mirage::pipeline_state_ptr(pipeline, mirage::llgl_deleter<LLGL::PipelineState>);",
|
||||
" info.pipeline_layout = pipelineLayout;",
|
||||
" info.shaders = {computeShader};",
|
||||
" return info;",
|
||||
"}",
|
||||
""
|
||||
])
|
||||
|
||||
def generate_graphics_pipeline(header_lines: List[str], base: str, shaders: List[CompiledShaderInfo]):
|
||||
"""Generate graphics pipeline creation function"""
|
||||
func_name = f"create_{base}_pipeline"
|
||||
|
||||
header_lines.extend([
|
||||
f"// 图形管线: {base}",
|
||||
f"inline auto {func_name}(LLGL::RenderSystem* renderer, const LLGL::RenderPass* render_pass, const LLGL::PipelineLayoutDescriptor& in_pipeline_layout_desc, const LLGL::VertexFormat& vertex_format = mirage::create_vertex_format()) {{",
|
||||
f" // 加载各个阶段的着色器",
|
||||
f" LLGL::ShaderDescriptor vertexShaderDesc, fragShaderDesc;",
|
||||
f" vertexShaderDesc.vertex.inputAttribs = vertex_format.attributes;",
|
||||
])
|
||||
|
||||
SHADER_DESC_NAME = {
|
||||
'vertex': 'vertexShaderDesc',
|
||||
'pixel': 'fragShaderDesc',
|
||||
'fragment': 'fragShaderDesc',
|
||||
}
|
||||
|
||||
# Load all shader stages
|
||||
for shader in shaders:
|
||||
shader_type = shader.entry.shader_type
|
||||
if shader_type in SHADER_TYPES:
|
||||
header_lines.append(
|
||||
f" auto {shader_type}Shader = LoadShader(renderer, "
|
||||
f"\"{shader.output_file}\", {SHADER_TYPES[shader_type]}, "
|
||||
f"\"{shader.entry.name}\", {SHADER_DESC_NAME[shader_type]});"
|
||||
)
|
||||
|
||||
# Create pipeline layout and descriptor
|
||||
header_lines.extend([
|
||||
" // 创建管线布局",
|
||||
" auto pipelineLayout = create_pipeline_layout(renderer, in_pipeline_layout_desc);",
|
||||
"",
|
||||
" // 创建图形管线",
|
||||
" LLGL::GraphicsPipelineDescriptor pipelineDesc;",
|
||||
])
|
||||
|
||||
# Set all shader stages
|
||||
for shader in shaders:
|
||||
shader_type = shader.entry.shader_type
|
||||
if shader_type in SHADER_TYPES:
|
||||
header_lines.append(f" pipelineDesc.{shader_type}Shader = {shader_type}Shader.get();")
|
||||
|
||||
# Set basic render states
|
||||
header_lines.extend([
|
||||
" pipelineDesc.pipelineLayout = pipelineLayout.get();",
|
||||
"",
|
||||
" // 设置基本渲染状态",
|
||||
" pipelineDesc.renderPass = render_pass;",
|
||||
" pipelineDesc.rasterizer.multiSampleEnabled = true;",
|
||||
" pipelineDesc.blend.targets[0].blendEnabled = true;",
|
||||
" pipelineDesc.depth.testEnabled = false;",
|
||||
" pipelineDesc.depth.writeEnabled = false;",
|
||||
"",
|
||||
" auto pipeline = renderer->CreatePipelineState(pipelineDesc);",
|
||||
])
|
||||
|
||||
# Finish function
|
||||
header_lines.extend([
|
||||
" mirage::pipeline_info info;",
|
||||
" info.pipeline_state = mirage::pipeline_state_ptr(pipeline, mirage::llgl_deleter<LLGL::PipelineState>);",
|
||||
" info.pipeline_layout = pipelineLayout;",
|
||||
" info.shaders = {",
|
||||
])
|
||||
|
||||
for shader in shaders:
|
||||
shader_type = shader.entry.shader_type
|
||||
if shader_type in SHADER_TYPES:
|
||||
header_lines.append(f" {shader_type}Shader,")
|
||||
|
||||
header_lines.append(" };")
|
||||
|
||||
header_lines.extend([
|
||||
" return info;",
|
||||
"}",
|
||||
""
|
||||
])
|
||||
|
||||
def generate_pipeline_header(header_path: Path):
|
||||
"""Generate the complete pipeline header file"""
|
||||
header_lines = generate_pipeline_header_preamble()
|
||||
|
||||
# Group shaders by base name
|
||||
shader_groups = {}
|
||||
for shader in compiled_shaders:
|
||||
if shader.base not in shader_groups:
|
||||
shader_groups[shader.base] = []
|
||||
shader_groups[shader.base].append(shader)
|
||||
|
||||
# Generate pipeline functions
|
||||
for base, shaders in shader_groups.items():
|
||||
has_compute = any(s.entry.shader_type == "compute" for s in shaders)
|
||||
if has_compute:
|
||||
for shader in shaders:
|
||||
if shader.entry.shader_type == "compute":
|
||||
generate_compute_pipeline(header_lines, shader)
|
||||
else:
|
||||
generate_graphics_pipeline(header_lines, base, shaders)
|
||||
|
||||
# Close namespace
|
||||
header_lines.extend([
|
||||
"} // namespace generated_pipelines",
|
||||
""
|
||||
])
|
||||
|
||||
try:
|
||||
header_path.write_text("\n".join(header_lines), encoding="utf-8")
|
||||
print_utf8(f"**成功**: 生成管线 C++ 头文件 {header_path}")
|
||||
except Exception as e:
|
||||
print_utf8(f"**错误**: 写入头文件 {header_path} 失败: {e}")
|
||||
|
||||
def main():
|
||||
"""主函数:解析命令行参数并执行编译流程"""
|
||||
if sys.platform.startswith('win'):
|
||||
subprocess.run(['chcp', '65001'], shell=True)
|
||||
|
||||
parser = argparse.ArgumentParser(description="使用 slangc 编译着色器并生成 LLGL 渲染管线 C++ 头文件")
|
||||
parser.add_argument("--shader-list", help="着色器列表文件路径")
|
||||
parser.add_argument("--output-dir", help="输出目录")
|
||||
parser.add_argument("--slangc", default="/Users/nanako/Documents/Slang/bin/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 着色器")
|
||||
parser.add_argument("--header", help="生成的头文件路径")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
target_types = [
|
||||
['glsl', args.opengl],
|
||||
['spirv', args.vulkan],
|
||||
['dxbc', args.d3d11],
|
||||
['dxil', args.d3d12],
|
||||
['metallib', args.metal],
|
||||
['metal', args.metal],
|
||||
]
|
||||
|
||||
output_dir = Path(args.output_dir or "shaders")
|
||||
shader_list = Path(args.shader_list or "shader_paths.txt")
|
||||
|
||||
try:
|
||||
shader_paths = shader_list.read_text(encoding="utf-8").splitlines()
|
||||
except Exception as e:
|
||||
print_utf8(f"**错误**: 读取着色器列表文件 {shader_list} 失败: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
all_success = True
|
||||
for shader_path in shader_paths:
|
||||
shader_path = shader_path.strip()
|
||||
if not shader_path:
|
||||
continue
|
||||
for file in find_shader_files(Path(shader_path), ['.slang']):
|
||||
if not compile_shader(file, target_types, output_dir, args):
|
||||
all_success = False
|
||||
|
||||
# 输出到shader_list所在目录
|
||||
header_file = Path(args.header or shader_list.parent / "generated_pipelines.h")
|
||||
generate_pipeline_header(header_file)
|
||||
|
||||
if not all_success:
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -2,17 +2,6 @@ cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
project(mirage_core LANGUAGES C CXX)
|
||||
set(CMAKE_CXX_STANDARD 26)
|
||||
if (MSVC)
|
||||
# MSVC编译器设置C++标准
|
||||
add_compile_options(/std:c++latest)
|
||||
# 设置utf-8编码
|
||||
add_compile_options(/utf-8)
|
||||
endif ()
|
||||
if (WIN32)
|
||||
# 定义Windows版本宏
|
||||
add_definitions(-DWIN32_LEAN_AND_MEAN)
|
||||
add_definitions(-DUNICODE -D_UNICODE)
|
||||
endif()
|
||||
|
||||
find_package(Freetype REQUIRED)
|
||||
find_package(Eigen3 REQUIRED)
|
||||
@ -23,14 +12,14 @@ retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} SRC_FILES)
|
||||
add_library(${PROJECT_NAME} STATIC ${SRC_FILES})
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Freetype::Freetype Eigen3::Eigen)
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
configure_glfw_native(${PROJECT_NAME})
|
||||
add_os_definitions(${PROJECT_NAME})
|
||||
|
||||
# 添加编译shader的自定义命令
|
||||
add_mirage_shader_directory(${CMAKE_CURRENT_SOURCE_DIR}/shaders)
|
||||
add_shader_dependencies(${PROJECT_NAME})
|
||||
|
||||
if (WIN32)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC SOKOL_D3D11=1)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE d3d11 dxgi)
|
||||
elseif (APPLE)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC SOKOL_METAL=1)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC -DSOKOL_D3D11)
|
||||
elseif (UNIX)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC SOKOL_GLCORE=1)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC -DSOKOL_GLCORE33)
|
||||
endif ()
|
||||
|
@ -1,18 +1,22 @@
|
||||
#pragma once
|
||||
#include "sokol/sokol_gfx.h"
|
||||
#include <memory>
|
||||
|
||||
#include "misc/mirage_type.h"
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
class mirage_window;
|
||||
|
||||
|
||||
class mirage_render_context {
|
||||
public:
|
||||
virtual ~mirage_render_context() = default;
|
||||
|
||||
virtual bool init() { return false; }
|
||||
virtual void cleanup() { }
|
||||
virtual void tick(const duration_type& in_delta) = 0;
|
||||
virtual sg_environment get_environment() = 0;
|
||||
virtual bool setup_surface(mirage_window* in_window, bool in_hdr) { return false; }
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
std::unique_ptr<mirage_render_context> mirage_create_render_context();
|
||||
mirage_render_context* mirage_create_render_context();
|
||||
|
@ -1,3 +1,29 @@
|
||||
#include "render_window.h"
|
||||
|
||||
Eigen::Matrix4f mirage_window::create_screen_to_dci_matrix(float in_screen_width, float in_screen_height) {
|
||||
// 创建一个单位矩阵
|
||||
Eigen::Matrix4f matrix = Eigen::Matrix4f::Identity();
|
||||
|
||||
// 缩放因子
|
||||
const float scale_x = 2.0f / in_screen_width;
|
||||
const float scale_y = -2.0f / in_screen_height; // Y轴翻转,因为窗口坐标系Y轴向下
|
||||
|
||||
// 平移因子
|
||||
constexpr float translate_x = -1.0f;
|
||||
constexpr float translate_y = 1.0f;
|
||||
|
||||
// 设置缩放
|
||||
matrix(0, 0) = scale_x;
|
||||
matrix(1, 1) = scale_y;
|
||||
|
||||
// 设置平移
|
||||
matrix(0, 3) = translate_x;
|
||||
matrix(1, 3) = translate_y;
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
Eigen::Matrix4f mirage_window::create_screen_to_dci_matrix() const {
|
||||
const auto size = get_window_frame_size();
|
||||
return create_screen_to_dci_matrix(size.x(), size.y());
|
||||
}
|
||||
|
@ -2,6 +2,23 @@
|
||||
#include "windows/windows_render_context.h"
|
||||
#include <Eigen/Eigen>
|
||||
|
||||
class mirage_window;
|
||||
|
||||
struct mirage_window_state {
|
||||
virtual ~mirage_window_state() {
|
||||
clear();
|
||||
}
|
||||
sg_buffer buffer;
|
||||
sg_swapchain swapchain;
|
||||
sg_bindings bindings;
|
||||
sg_pipeline pipeline;
|
||||
bool vsync = true;
|
||||
|
||||
virtual void clear() {}
|
||||
virtual void present() {}
|
||||
virtual void resize(const Eigen::Vector2i& size) {}
|
||||
};
|
||||
|
||||
class mirage_window {
|
||||
public:
|
||||
bool create_window(int width, int height, const wchar_t* title);
|
||||
@ -18,6 +35,12 @@ public:
|
||||
void move(const Eigen::Vector2i& pos) { move(pos.x(), pos.y()); }
|
||||
|
||||
[[nodiscard]] Eigen::Vector2i get_window_size() const;
|
||||
[[nodiscard]] Eigen::Vector2i get_window_position() const;
|
||||
[[nodiscard]] Eigen::Vector2i get_window_frame_size() const;
|
||||
// 创建从屏幕坐标到DCI坐标的正交投影矩阵
|
||||
[[nodiscard]] static Eigen::Matrix4f create_screen_to_dci_matrix(float in_screen_width, float in_screen_height);
|
||||
[[nodiscard]] Eigen::Matrix4f create_screen_to_dci_matrix() const;
|
||||
|
||||
[[nodiscard]] void* get_window_handle() const;
|
||||
|
||||
// style functions
|
||||
@ -34,6 +57,10 @@ public:
|
||||
[[nodiscard]] bool close_requested() const { return close_request; }
|
||||
static bool poll_events();
|
||||
static const std::vector<mirage_window*>& get_windows();
|
||||
|
||||
void on_resize(int width, int height);
|
||||
|
||||
std::unique_ptr<mirage_window_state> state;
|
||||
private:
|
||||
void* window_handle{};
|
||||
bool close_request = false;
|
||||
|
@ -5,141 +5,216 @@
|
||||
#include "windows_render_context.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <ranges>
|
||||
|
||||
#include "core/render_window.h"
|
||||
#include <windows.h>
|
||||
|
||||
mirage_windows_render_context::~mirage_windows_render_context() {
|
||||
cleanup();
|
||||
}
|
||||
#include "windows_window_state.h"
|
||||
#include "misc/scope_exit.h"
|
||||
#include "shaders/test.hlsl.h"
|
||||
#include "shaders/mirage_rounded_rect.hlsl.h"
|
||||
|
||||
bool mirage_windows_render_context::init() {
|
||||
try {
|
||||
// 定义支持的特性级别(从高到低排序)
|
||||
D3D_FEATURE_LEVEL feature_levels[] = {
|
||||
D3D_FEATURE_LEVEL_11_1,
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
D3D_FEATURE_LEVEL_10_1,
|
||||
D3D_FEATURE_LEVEL_10_0
|
||||
};
|
||||
windows_mirage_render_context::~windows_mirage_render_context() { cleanup(); }
|
||||
|
||||
// 设置设备创建标志
|
||||
UINT device_flags = 0;
|
||||
#if DEBUG
|
||||
device_flags |= D3D11_CREATE_DEVICE_DEBUG; // 在Debug模式下启用调试层
|
||||
#endif
|
||||
bool windows_mirage_render_context::init() {
|
||||
try {
|
||||
// 定义支持的特性级别(从高到低排序)
|
||||
D3D_FEATURE_LEVEL feature_levels[] = {
|
||||
D3D_FEATURE_LEVEL_11_1,
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
D3D_FEATURE_LEVEL_10_1,
|
||||
D3D_FEATURE_LEVEL_10_0
|
||||
};
|
||||
|
||||
// 定义要尝试的驱动类型数组
|
||||
constexpr D3D_DRIVER_TYPE driver_types[] = {
|
||||
D3D_DRIVER_TYPE_HARDWARE, // 首选硬件加速
|
||||
D3D_DRIVER_TYPE_WARP, // 其次是WARP软件渲染器
|
||||
D3D_DRIVER_TYPE_REFERENCE // 最后是参考软件渲染器
|
||||
};
|
||||
// 设置设备创建标志
|
||||
UINT device_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_SINGLETHREADED; // BGRA支持和单线程模式
|
||||
#if DEBUG
|
||||
device_flags |= D3D11_CREATE_DEVICE_DEBUG; // 在Debug模式下启用调试层
|
||||
#endif
|
||||
|
||||
// 尝试按优先级创建设备
|
||||
HRESULT hr = E_FAIL;
|
||||
D3D_DRIVER_TYPE used_driver_type = D3D_DRIVER_TYPE_UNKNOWN;
|
||||
// 定义要尝试的驱动类型数组
|
||||
constexpr D3D_DRIVER_TYPE driver_types[] = {
|
||||
D3D_DRIVER_TYPE_HARDWARE,
|
||||
// 首选硬件加速
|
||||
D3D_DRIVER_TYPE_WARP,
|
||||
// 其次是WARP软件渲染器
|
||||
D3D_DRIVER_TYPE_REFERENCE // 最后是参考软件渲染器
|
||||
};
|
||||
|
||||
for (const auto& driver_type : driver_types) {
|
||||
hr = D3D11CreateDevice(
|
||||
nullptr, // 使用默认适配器
|
||||
driver_type, // 驱动类型
|
||||
nullptr, // 软件栅格化模块句柄(仅用于软件设备)
|
||||
device_flags, // 设备创建标志
|
||||
feature_levels, // 特性级别数组
|
||||
ARRAYSIZE(feature_levels), // 特性级别数量
|
||||
D3D11_SDK_VERSION, // SDK版本
|
||||
&device, // 输出设备
|
||||
&feature_level, // 输出获取的特性级别
|
||||
&device_context // 输出设备上下文
|
||||
);
|
||||
// 尝试按优先级创建设备
|
||||
HRESULT hr = E_FAIL;
|
||||
D3D_DRIVER_TYPE used_driver_type = D3D_DRIVER_TYPE_UNKNOWN;
|
||||
// 使用 DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2(推荐)
|
||||
if (SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {
|
||||
std::cout << "mirage: " << "DPI awareness set to per-monitor aware v2" << std::endl;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
used_driver_type = driver_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (const auto& driver_type: driver_types) {
|
||||
hr = D3D11CreateDevice(
|
||||
nullptr,
|
||||
// 使用默认适配器
|
||||
driver_type,
|
||||
// 驱动类型
|
||||
nullptr,
|
||||
// 软件栅格化模块句柄(仅用于软件设备)
|
||||
device_flags,
|
||||
// 设备创建标志
|
||||
feature_levels,
|
||||
// 特性级别数组
|
||||
ARRAYSIZE(feature_levels),
|
||||
// 特性级别数量
|
||||
D3D11_SDK_VERSION,
|
||||
// SDK版本
|
||||
&device,
|
||||
// 输出设备
|
||||
&feature_level,
|
||||
// 输出获取的特性级别
|
||||
&device_context // 输出设备上下文
|
||||
);
|
||||
|
||||
// 检查是否成功创建设备
|
||||
if (FAILED(hr)) {
|
||||
std::cerr << "Failed to create D3D11 device with any driver type. HRESULT: 0x"
|
||||
<< std::hex << hr << std::dec << std::endl;
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
if (SUCCEEDED(hr)) {
|
||||
used_driver_type = driver_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 输出使用设备
|
||||
DXGI_ADAPTER_DESC adapter_desc;
|
||||
// 检查是否成功创建设备
|
||||
if (FAILED(hr)) {
|
||||
std::cerr << "mirage: " << "Failed to create D3D11 device with any driver type. HRESULT: 0x"
|
||||
<< std::hex << hr << std::dec << std::endl;
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取DXGI工厂以便后续创建交换链
|
||||
// 输出使用设备
|
||||
DXGI_ADAPTER_DESC adapter_desc;
|
||||
|
||||
// 获取DXGI工厂以便后续创建交换链
|
||||
IDXGIAdapter* dxgi_adapter = nullptr;
|
||||
IDXGIDevice* dxgi_device = nullptr;
|
||||
hr = device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgi_device));
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = dxgi_device->GetAdapter(&dxgi_adapter);
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = dxgi_adapter->GetDesc(&adapter_desc);
|
||||
if (FAILED(hr)) {
|
||||
std::wcerr << L"Failed to get DXGI Adapter description" << std::endl;
|
||||
}
|
||||
hr = dxgi_adapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&dxgi_factory));
|
||||
if (FAILED(hr)) {
|
||||
dxgi_factory = nullptr;
|
||||
}
|
||||
dxgi_adapter->Release();
|
||||
}
|
||||
dxgi_device->Release();
|
||||
}
|
||||
IDXGIDevice* dxgi_device = nullptr;
|
||||
hr = device->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgi_device));
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = dxgi_device->GetAdapter(&dxgi_adapter);
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = dxgi_adapter->GetDesc(&adapter_desc);
|
||||
if (FAILED(hr)) { std::wcerr << L"mirage: " << L"Failed to get DXGI Adapter description" << std::endl; }
|
||||
hr = dxgi_adapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&dxgi_factory));
|
||||
if (FAILED(hr)) { dxgi_factory = nullptr; }
|
||||
dxgi_adapter->Release();
|
||||
}
|
||||
dxgi_device->Release();
|
||||
}
|
||||
|
||||
if (!dxgi_factory) {
|
||||
std::cerr << "Failed to get DXGI Factory" << std::endl;
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
if (!dxgi_factory) {
|
||||
std::cerr << "Failed to get DXGI Factory" << std::endl;
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 输出初始化成功信息
|
||||
std::cout << "D3D11 device created successfully" << std::endl;
|
||||
std::wcout << L"Using adapter: " << adapter_desc.Description << std::endl;
|
||||
// 输出初始化成功信息
|
||||
std::cout << "mirage: " << "D3D11 device created successfully" << std::endl;
|
||||
std::wcout << L"mirage: " << L"Using adapter: " << adapter_desc.Description << std::endl;
|
||||
|
||||
// 输出驱动类型信息
|
||||
auto driver_type_str = "Unknown";
|
||||
switch (used_driver_type) {
|
||||
case D3D_DRIVER_TYPE_HARDWARE: driver_type_str = "Hardware"; break;
|
||||
case D3D_DRIVER_TYPE_WARP: driver_type_str = "WARP"; break;
|
||||
case D3D_DRIVER_TYPE_REFERENCE: driver_type_str = "Reference"; break;
|
||||
default: ;
|
||||
}
|
||||
std::cout << "Using driver type: " << driver_type_str << std::endl;
|
||||
// 输出驱动类型信息
|
||||
auto driver_type_str = "Unknown";
|
||||
switch (used_driver_type) {
|
||||
case D3D_DRIVER_TYPE_HARDWARE:
|
||||
driver_type_str = "Hardware";
|
||||
break;
|
||||
case D3D_DRIVER_TYPE_WARP:
|
||||
driver_type_str = "WARP";
|
||||
break;
|
||||
case D3D_DRIVER_TYPE_REFERENCE:
|
||||
driver_type_str = "Reference";
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
std::cout << "mirage: " << "Using driver type: " << driver_type_str << std::endl;
|
||||
|
||||
// 输出特性级别信息
|
||||
auto feature_level_str = "Unknown";
|
||||
switch (feature_level) {
|
||||
case D3D_FEATURE_LEVEL_11_1: feature_level_str = "11.1"; break;
|
||||
case D3D_FEATURE_LEVEL_11_0: feature_level_str = "11.0"; break;
|
||||
case D3D_FEATURE_LEVEL_10_1: feature_level_str = "10.1"; break;
|
||||
case D3D_FEATURE_LEVEL_10_0: feature_level_str = "10.0"; break;
|
||||
default: ;
|
||||
}
|
||||
std::cout << "Using feature level: " << feature_level_str << std::endl;
|
||||
// 输出特性级别信息
|
||||
auto feature_level_str = "Unknown";
|
||||
switch (feature_level) {
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
feature_level_str = "11.1";
|
||||
break;
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
feature_level_str = "11.0";
|
||||
break;
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
feature_level_str = "10.1";
|
||||
break;
|
||||
case D3D_FEATURE_LEVEL_10_0:
|
||||
feature_level_str = "10.0";
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
std::cout << "mirage: " << "Using feature level: " << feature_level_str << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "Exception during D3D11 initialization: " << e.what() << std::endl;
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "mirage: " << "Exception during D3D11 initialization: " << e.what() << std::endl;
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 资源清理函数
|
||||
void mirage_windows_render_context::cleanup() {
|
||||
// 安全释放COM接口
|
||||
if (device_context) { device_context->Release(); device_context = nullptr; }
|
||||
if (device) { device->Release(); device = nullptr; }
|
||||
if (dxgi_factory) { dxgi_factory->Release(); dxgi_factory = nullptr; }
|
||||
void windows_mirage_render_context::cleanup() {
|
||||
mirage_render_context::cleanup();
|
||||
// 安全释放COM接口
|
||||
sg_shutdown();
|
||||
if (device_context) {
|
||||
device_context->Release();
|
||||
device_context = nullptr;
|
||||
}
|
||||
if (device) {
|
||||
device->Release();
|
||||
device = nullptr;
|
||||
}
|
||||
if (dxgi_factory) {
|
||||
dxgi_factory->Release();
|
||||
dxgi_factory = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void windows_mirage_render_context::tick(const duration_type& in_delta) {
|
||||
const auto& windows = mirage_window::get_windows();
|
||||
for (const auto& window: windows) {
|
||||
auto& window_state = window->state;
|
||||
sg_pass pass{};
|
||||
pass.action.colors[0].load_action = SG_LOADACTION_CLEAR;
|
||||
pass.action.colors[0].store_action = SG_STOREACTION_STORE;
|
||||
pass.action.colors[0].clear_value = { 0.f, 0.f, 0.f, 1.0f };
|
||||
|
||||
sg_environment mirage_windows_render_context::get_environment() {
|
||||
pass.action.depth.load_action = SG_LOADACTION_CLEAR;
|
||||
pass.action.depth.store_action = SG_STOREACTION_DONTCARE;
|
||||
pass.action.depth.clear_value = 1.0f;
|
||||
pass.swapchain = window_state->swapchain;
|
||||
|
||||
sg_begin_pass(pass);
|
||||
sg_apply_pipeline(pip);
|
||||
|
||||
sg_apply_viewport(0, 0, window_state->swapchain.width, window_state->swapchain.height, true);
|
||||
|
||||
sg_bindings bindings{};
|
||||
bindings.vertex_buffers[0] = vertex_buffer;
|
||||
bindings.index_buffer = index_buffer;
|
||||
sg_apply_bindings(bindings);
|
||||
|
||||
const auto& matrix = window->create_screen_to_dci_matrix();
|
||||
|
||||
sg_apply_uniforms(0, SG_RANGE(matrix));
|
||||
|
||||
sg_draw(0, 12, 2);
|
||||
sg_end_pass();
|
||||
sg_commit();
|
||||
|
||||
window_state->present();
|
||||
}
|
||||
}
|
||||
|
||||
sg_environment windows_mirage_render_context::get_environment() {
|
||||
return {
|
||||
.d3d11 = {
|
||||
.device = device,
|
||||
@ -148,35 +223,80 @@ sg_environment mirage_windows_render_context::get_environment() {
|
||||
};
|
||||
}
|
||||
|
||||
bool mirage_windows_render_context::setup_surface(mirage_window* in_window, bool in_hdr) {
|
||||
const auto& window_size = in_window->get_window_size();
|
||||
bool windows_mirage_render_context::setup_surface(mirage_window* in_window, bool in_hdr) {
|
||||
auto state = std::make_unique<windows_window_state>();
|
||||
if (!state->init(device, dxgi_factory, in_window, in_hdr)) { return false; }
|
||||
|
||||
const auto format = in_hdr ? DXGI_FORMAT_R16G16B16A16_FLOAT : DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
shader = sg_make_shader(get_mirage_rounded_rect_shader_desc());
|
||||
|
||||
// 创建D3D11渲染目标视图
|
||||
IDXGISwapChain* swap_chain = nullptr;
|
||||
DXGI_SWAP_CHAIN_DESC swap_chain_desc = {
|
||||
.BufferDesc = {
|
||||
.Width = static_cast<UINT>(window_size.x()),
|
||||
.Height = static_cast<UINT>(window_size.y()),
|
||||
.RefreshRate = {
|
||||
.Numerator = 60,
|
||||
.Denominator = 1
|
||||
},
|
||||
.Format = format,
|
||||
},
|
||||
.SampleDesc = {
|
||||
.Count = 1,
|
||||
.Quality = 0
|
||||
},
|
||||
.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
||||
.BufferCount = 1,
|
||||
.OutputWindow = nullptr,
|
||||
.Windowed = TRUE
|
||||
sg_pipeline_desc pipeline_desc = get_mirage_rounded_rect_pipeline_desc(shader, state->swapchain);
|
||||
pip = sg_make_pipeline(pipeline_desc);
|
||||
|
||||
mirage_triangle_t triangles[4];
|
||||
|
||||
// 创建顶点缓冲区(一个矩形)
|
||||
std::vector<mirage_vertex_t> vertices = {
|
||||
// x, y, r, g, b, a
|
||||
{ { 0.f, 0.f }, { 0.f, 0.f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||
// 左上 - 黄色
|
||||
{ { 100.f, 0.f }, { 1.f, 0.f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||
// 右上 - 蓝色
|
||||
{ { 0.f, 100.f }, { 0.f, 1.f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||
// 左下 - 红色
|
||||
{ { 100.f, 100.f }, { 1.f, 1.f }, { 1.0f, 1.0f, 1.0f, 1.0f } },
|
||||
// 右下 - 绿色
|
||||
{ { 200.f, 200.f }, { 0.f, 0.f }, { 0.0f, 1.0f, 1.0f, 1.0f } },
|
||||
// 左上 - 黄色
|
||||
{ { 300.f, 200.f }, { 1.f, 0.f }, { 1.0f, 0.0f, 1.0f, 1.0f } },
|
||||
// 右上 - 蓝色
|
||||
{ { 200.f, 300.f }, { 0.f, 1.f }, { 1.0f, 0.0f, 1.0f, 1.0f } },
|
||||
// 左下 - 红色
|
||||
{ { 300.f, 300.f }, { 1.f, 1.f }, { 0.0f, 1.0f, 0.0f, 1.0f } },
|
||||
// 右下 - 绿色
|
||||
};
|
||||
for (auto& v: vertices) {
|
||||
v.param_a.a = 100;
|
||||
v.param_a.b = 100;
|
||||
|
||||
v.param_b.a = 0;
|
||||
v.param_b.b = 5;
|
||||
v.param_b.c = 10;
|
||||
v.param_b.d = 20;
|
||||
}
|
||||
|
||||
// 三角形索引不变
|
||||
triangles[0].indices[0] = 0;
|
||||
triangles[0].indices[1] = 1;
|
||||
triangles[0].indices[2] = 2;
|
||||
triangles[1].indices[0] = 1;
|
||||
triangles[1].indices[1] = 3;
|
||||
triangles[1].indices[2] = 2;
|
||||
|
||||
triangles[2].indices[0] = 4;
|
||||
triangles[2].indices[1] = 5;
|
||||
triangles[2].indices[2] = 6;
|
||||
triangles[3].indices[0] = 5;
|
||||
triangles[3].indices[1] = 7;
|
||||
triangles[3].indices[2] = 6;
|
||||
|
||||
std::span vertex_span{ vertices.data(), vertices.size() };
|
||||
sg_buffer_desc vertex_buffer_desc{
|
||||
.size = vertex_span.size_bytes() * 2,
|
||||
.type = SG_BUFFERTYPE_VERTEXBUFFER,
|
||||
.usage = SG_USAGE_DYNAMIC,
|
||||
};
|
||||
vertex_buffer = sg_make_buffer(vertex_buffer_desc);
|
||||
std::span vertex_span2{ vertices.data(), vertices.size() };
|
||||
sg_update_buffer(vertex_buffer, sg_range{ vertex_span2.data(), vertex_span2.size_bytes() });
|
||||
|
||||
index_buffer = sg_make_buffer(sg_buffer_desc{
|
||||
.type = SG_BUFFERTYPE_INDEXBUFFER,
|
||||
.usage = SG_USAGE_IMMUTABLE,
|
||||
.data = SG_RANGE(triangles),
|
||||
});
|
||||
|
||||
in_window->state = std::move(state);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<mirage_render_context> mirage_create_render_context() {
|
||||
return std::make_unique<mirage_windows_render_context>();
|
||||
}
|
||||
mirage_render_context* mirage_create_render_context() { return new windows_mirage_render_context(); }
|
||||
|
@ -3,21 +3,26 @@
|
||||
|
||||
#include "core/render_context.h"
|
||||
|
||||
class mirage_windows_render_context : public mirage_render_context {
|
||||
class windows_mirage_render_context : public mirage_render_context {
|
||||
public:
|
||||
mirage_windows_render_context() = default;
|
||||
virtual ~mirage_windows_render_context() override;
|
||||
windows_mirage_render_context() = default;
|
||||
virtual ~windows_mirage_render_context() override;
|
||||
|
||||
bool init() override;
|
||||
|
||||
void cleanup();
|
||||
void cleanup() override;
|
||||
virtual void tick(const duration_type& in_delta) override;
|
||||
|
||||
sg_environment get_environment() override;
|
||||
virtual bool setup_surface(mirage_window* in_window, bool in_hdr) override;
|
||||
bool setup_surface(mirage_window* in_window, bool in_hdr) override;
|
||||
private:
|
||||
ID3D11Device* device = nullptr;
|
||||
ID3D11DeviceContext* device_context = nullptr;
|
||||
ID3D11Device* device{};
|
||||
ID3D11DeviceContext* device_context{};
|
||||
|
||||
IDXGIFactory* dxgi_factory = nullptr;
|
||||
IDXGIFactory* dxgi_factory{};
|
||||
D3D_FEATURE_LEVEL feature_level;
|
||||
|
||||
sg_shader shader{};
|
||||
sg_pipeline pip{};
|
||||
sg_buffer vertex_buffer{};
|
||||
sg_buffer index_buffer{};
|
||||
};
|
||||
|
@ -13,21 +13,25 @@ std::vector<mirage_window*> windows;
|
||||
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (uMsg) {
|
||||
case WM_CLOSE:
|
||||
// 标记关闭请求,但暂不销毁窗口
|
||||
// 实际销毁操作应在主循环中处理
|
||||
for (const auto& window : windows) {
|
||||
for (const auto& window: windows) {
|
||||
if (window->get_window_handle() == hwnd) {
|
||||
window->close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::erase_if(windows, [hwnd](const mirage_window* window) {
|
||||
return window->get_window_handle() == hwnd;
|
||||
});
|
||||
std::erase_if(windows, [hwnd](const mirage_window* window) { return window->get_window_handle() == hwnd; });
|
||||
return 0;
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
case WM_SIZE:
|
||||
for (const auto& window: windows) {
|
||||
if (window->get_window_handle() == hwnd) {
|
||||
window->on_resize(LOWORD(lParam), HIWORD(lParam));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
@ -37,21 +41,23 @@ bool mirage_window::create_window(int width, int height, const wchar_t* title) {
|
||||
WNDCLASS wc = {};
|
||||
wc.lpfnWndProc = WindowProc;
|
||||
wc.hInstance = GetModuleHandle(nullptr);
|
||||
wc.lpszClassName = L"mirage_window";
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.lpszClassName = L"mirage_window_class";
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
|
||||
RegisterClass(&wc);
|
||||
|
||||
window_handle = (void*) CreateWindow(wc.lpszClassName,
|
||||
title,
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
height,
|
||||
nullptr,
|
||||
nullptr,
|
||||
wc.hInstance,
|
||||
nullptr);
|
||||
RECT rect = { 0, 0, width, height };
|
||||
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
|
||||
|
||||
window_handle = (void*)CreateWindowW(
|
||||
L"mirage_window_class", title,
|
||||
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
rect.right - rect.left, rect.bottom - rect.top,
|
||||
NULL, NULL, GetModuleHandleW(NULL), NULL
|
||||
);
|
||||
|
||||
if (!window_handle) {
|
||||
std::cerr << "Failed to create window" << std::endl;
|
||||
return false;
|
||||
@ -63,7 +69,12 @@ bool mirage_window::create_window(int width, int height, const wchar_t* title) {
|
||||
|
||||
void mirage_window::show() { ShowWindow(WINDOW_HANDLE, SW_SHOW); }
|
||||
void mirage_window::hide() { ShowWindow(WINDOW_HANDLE, SW_HIDE); }
|
||||
void mirage_window::close() { close_request = true; DestroyWindow(WINDOW_HANDLE); }
|
||||
|
||||
void mirage_window::close() {
|
||||
close_request = true;
|
||||
DestroyWindow(WINDOW_HANDLE);
|
||||
}
|
||||
|
||||
void mirage_window::maximize() { ShowWindow(WINDOW_HANDLE, SW_MAXIMIZE); }
|
||||
void mirage_window::minimize() { ShowWindow(WINDOW_HANDLE, SW_MINIMIZE); }
|
||||
|
||||
@ -80,9 +91,31 @@ void mirage_window::resize(int width, int height) {
|
||||
}
|
||||
|
||||
Eigen::Vector2i mirage_window::get_window_size() const {
|
||||
// 获取窗口大小, 包括边框和标题栏
|
||||
RECT rect;
|
||||
if (!GetClientRect(WINDOW_HANDLE, &rect)) { return {}; }
|
||||
return { rect.right - rect.left, rect.bottom - rect.top };
|
||||
if (GetWindowRect(WINDOW_HANDLE, &rect)) {
|
||||
int width = rect.right - rect.left;
|
||||
int height = rect.bottom - rect.top;
|
||||
return Eigen::Vector2i(width, height);
|
||||
}
|
||||
return Eigen::Vector2i(0, 0);
|
||||
}
|
||||
|
||||
Eigen::Vector2i mirage_window::get_window_frame_size() const {
|
||||
// 获取窗口大小, 不包括边框和标题栏 (客户区大小)
|
||||
RECT rect;
|
||||
if (GetClientRect(WINDOW_HANDLE, &rect)) {
|
||||
int width = rect.right - rect.left;
|
||||
int height = rect.bottom - rect.top;
|
||||
return Eigen::Vector2i(width, height);
|
||||
}
|
||||
return Eigen::Vector2i(0, 0);
|
||||
}
|
||||
|
||||
Eigen::Vector2i mirage_window::get_window_position() const {
|
||||
RECT rect;
|
||||
if (!GetWindowRect(WINDOW_HANDLE, &rect)) { return {}; }
|
||||
return { rect.left, rect.top };
|
||||
}
|
||||
|
||||
void* mirage_window::get_window_handle() const { return window_handle; }
|
||||
@ -153,3 +186,9 @@ bool mirage_window::poll_events() {
|
||||
}
|
||||
|
||||
const std::vector<mirage_window*>& mirage_window::get_windows() { return windows; }
|
||||
|
||||
void mirage_window::on_resize(int width, int height) {
|
||||
state->swapchain.width = width;
|
||||
state->swapchain.height = height;
|
||||
state->resize(Eigen::Vector2i(width, height));
|
||||
}
|
||||
|
132
src/core/windows/windows_window_state.cpp
Normal file
132
src/core/windows/windows_window_state.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
#include "windows_window_state.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "misc/scope_exit.h"
|
||||
|
||||
bool windows_window_state::init(ID3D11Device* in_device, IDXGIFactory* in_factory, mirage_window* in_window,
|
||||
bool in_hdr) {
|
||||
dx_device = in_device;
|
||||
dxgi_factory = in_factory;
|
||||
|
||||
const auto size = in_window->get_window_frame_size();
|
||||
const auto window_handle = in_window->get_window_handle();
|
||||
|
||||
const auto format = in_hdr ? DXGI_FORMAT_R16G16B16A16_FLOAT : DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
|
||||
// 创建D3D11渲染目标视图
|
||||
DXGI_SWAP_CHAIN_DESC swap_chain_desc = {
|
||||
.BufferDesc = {
|
||||
.Width = static_cast<UINT>(size.x()),
|
||||
.Height = static_cast<UINT>(size.y()),
|
||||
.RefreshRate = {
|
||||
.Numerator = 240,
|
||||
.Denominator = 1
|
||||
},
|
||||
.Format = format,
|
||||
},
|
||||
.SampleDesc = {
|
||||
.Count = 1,
|
||||
.Quality = 0
|
||||
},
|
||||
.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
||||
.BufferCount = 1,
|
||||
.OutputWindow = (HWND) window_handle,
|
||||
.Windowed = TRUE
|
||||
};
|
||||
|
||||
// 创建交换链
|
||||
HRESULT hr = dxgi_factory->CreateSwapChain(dx_device, &swap_chain_desc, &dx_swap_chain);
|
||||
if (FAILED(hr)) {
|
||||
std::cerr << "mirage: " << "Failed to create DXGI Swap Chain. HRESULT: 0x" << std::hex << hr << std::dec <<
|
||||
std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取后台缓冲区
|
||||
ID3D11Texture2D* back_buffer = nullptr;
|
||||
hr = dx_swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**) &back_buffer);
|
||||
if (FAILED(hr)) {
|
||||
std::cerr << "mirage: " << "Failed to get back buffer from DXGI Swap Chain. HRESULT: 0x" << std::hex << hr <<
|
||||
std::dec << std::endl;
|
||||
return false;
|
||||
}
|
||||
ON_SCOPE_EXIT { back_buffer->Release(); };
|
||||
|
||||
// 创建渲染目标视图
|
||||
ID3D11RenderTargetView* render_target_view = nullptr;
|
||||
hr = dx_device->CreateRenderTargetView(back_buffer, nullptr, &render_target_view);
|
||||
if (FAILED(hr)) {
|
||||
std::cerr << "mirage: " << "Failed to create render target view. HRESULT: 0x" << std::hex << hr << std::dec <<
|
||||
std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
swapchain.d3d11.render_view = render_target_view;
|
||||
swapchain.width = static_cast<int>(size.x());
|
||||
swapchain.height = static_cast<int>(size.y());
|
||||
swapchain.color_format = in_hdr ? SG_PIXELFORMAT_RGBA16F : SG_PIXELFORMAT_RGBA8;
|
||||
swapchain.depth_format = SG_PIXELFORMAT_NONE;
|
||||
swapchain.sample_count = 1;
|
||||
swapchain.d3d11.resolve_view = nullptr;
|
||||
swapchain.d3d11.depth_stencil_view = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
void windows_window_state::clear() {
|
||||
dx_swap_chain->Release();
|
||||
get_dx_render_target_view()->Release();
|
||||
}
|
||||
|
||||
void windows_window_state::present() { dx_swap_chain->Present(vsync ? 1 : 0, 0); }
|
||||
|
||||
void windows_window_state::resize(const Eigen::Vector2i& size) {
|
||||
if (size.x() == 0 || size.y() == 0) { return; }
|
||||
|
||||
// 保存当前格式
|
||||
D3D11_RENDER_TARGET_VIEW_DESC rtv_desc = {};
|
||||
auto dx_render_target_view = get_dx_render_target_view();
|
||||
if (dx_render_target_view) {
|
||||
dx_render_target_view->GetDesc(&rtv_desc);
|
||||
|
||||
// 释放旧的渲染目标视图
|
||||
dx_render_target_view->Release();
|
||||
}
|
||||
|
||||
// 重设交换链缓冲区大小
|
||||
HRESULT hr = dx_swap_chain->ResizeBuffers(
|
||||
1,
|
||||
// 缓冲区数量
|
||||
size.x(),
|
||||
// 新宽度
|
||||
size.y(),
|
||||
// 新高度
|
||||
rtv_desc.Format,
|
||||
// 保持原格式
|
||||
0 // 标志
|
||||
);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
// 重设失败
|
||||
std::cerr << "重设交换链缓冲区失败" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取新的后台缓冲区
|
||||
ID3D11Texture2D* back_buffer = nullptr;
|
||||
hr = dx_swap_chain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**) &back_buffer);
|
||||
if (FAILED(hr)) {
|
||||
std::cerr << "获取后台缓冲区失败" << std::endl;
|
||||
return;
|
||||
}
|
||||
ON_SCOPE_EXIT { back_buffer->Release(); };
|
||||
|
||||
// 创建新的渲染目标视图
|
||||
hr = dx_device->CreateRenderTargetView(back_buffer,
|
||||
nullptr,
|
||||
(ID3D11RenderTargetView**) &swapchain.d3d11.render_view);
|
||||
if (FAILED(hr)) {
|
||||
std::cerr << "创建新的渲染目标视图失败" << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
21
src/core/windows/windows_window_state.h
Normal file
21
src/core/windows/windows_window_state.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include "core/render_window.h"
|
||||
#include <d3d11.h>
|
||||
|
||||
struct windows_window_state final : mirage_window_state {
|
||||
ID3D11RenderTargetView* get_dx_render_target_view() const {
|
||||
return (ID3D11RenderTargetView*)swapchain.d3d11.render_view;
|
||||
}
|
||||
|
||||
bool init(ID3D11Device* in_device, IDXGIFactory* in_factory, mirage_window* in_window, bool in_hdr);
|
||||
|
||||
virtual void clear() override;
|
||||
|
||||
virtual void present() override;
|
||||
|
||||
virtual void resize(const Eigen::Vector2i& size) override;
|
||||
private:
|
||||
ID3D11Device* dx_device{};
|
||||
IDXGIFactory* dxgi_factory{};
|
||||
IDXGISwapChain* dx_swap_chain{};
|
||||
};
|
@ -1,11 +1,15 @@
|
||||
#include "mirage.h"
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#define SOKOL_IMPL
|
||||
#include "sokol/sokol_gfx.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include "core/render_window.h"
|
||||
#include "misc/mirage_scoped_duration_timer.h"
|
||||
|
||||
|
||||
void mirage_log(const char* tag, uint32_t log_level, uint32_t log_item_id, const char* message_or_null,
|
||||
uint32_t line_nr, const char* filename_or_null, void* user_data) {
|
||||
if (log_level == 0) // painc
|
||||
@ -18,21 +22,35 @@ void mirage_log(const char* tag, uint32_t log_level, uint32_t log_item_id, const
|
||||
std::clog << "sg: " << message_or_null << std::endl;
|
||||
}
|
||||
|
||||
mirage_app::mirage_app() {
|
||||
}
|
||||
|
||||
void mirage_app::init() {
|
||||
render_context = mirage_create_render_context();
|
||||
render_context->init();
|
||||
sg_desc desc = {
|
||||
.logger = {
|
||||
.func = mirage_log,
|
||||
.user_data = nullptr
|
||||
},
|
||||
.environment = render_context->get_environment(),
|
||||
};
|
||||
sg_setup(desc);
|
||||
duration_type duration;
|
||||
{
|
||||
mirage_scoped_duration_timer timer(duration);
|
||||
|
||||
last_time = get_current_time();
|
||||
render_context = mirage_create_render_context();
|
||||
render_context->init();
|
||||
const sg_desc desc = {
|
||||
.logger = {
|
||||
.func = mirage_log,
|
||||
.user_data = nullptr
|
||||
},
|
||||
.environment = render_context->get_environment(),
|
||||
};
|
||||
sg_setup(desc);
|
||||
}
|
||||
// 初始化用时
|
||||
std::cout << "mirage: " << "Initialization took " << std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() << "ms" << std::endl;
|
||||
}
|
||||
|
||||
void mirage_app::run() {
|
||||
while (!mirage_window::get_windows().empty()) {
|
||||
duration_type delta_time = get_current_time() - last_time;
|
||||
mirage_window::poll_events();
|
||||
render_context->tick(delta_time);
|
||||
|
||||
last_time = get_current_time();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
delete render_context;
|
||||
}
|
||||
|
11
src/mirage.h
11
src/mirage.h
@ -1,16 +1,17 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "core/render_context.h"
|
||||
|
||||
class mirage_render_context;
|
||||
|
||||
class mirage_app {
|
||||
public:
|
||||
mirage_app();
|
||||
|
||||
void init();
|
||||
|
||||
void run();
|
||||
|
||||
[[nodiscard]] mirage_render_context* get_render_context() const {
|
||||
return render_context;
|
||||
}
|
||||
private:
|
||||
std::unique_ptr<mirage_render_context> render_context;
|
||||
mirage_render_context* render_context{};
|
||||
time_type last_time = {};
|
||||
};
|
||||
|
15
src/misc/mirage_scoped_duration_timer.h
Normal file
15
src/misc/mirage_scoped_duration_timer.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "mirage_type.h"
|
||||
|
||||
class mirage_scoped_duration_timer {
|
||||
public:
|
||||
explicit mirage_scoped_duration_timer(duration_type& out_duration) : duration(out_duration) {
|
||||
start_time = get_current_time();
|
||||
}
|
||||
~mirage_scoped_duration_timer() {
|
||||
duration = get_current_time() - start_time;
|
||||
}
|
||||
private:
|
||||
time_type start_time;
|
||||
duration_type& duration;
|
||||
};
|
49
src/misc/mirage_type.h
Normal file
49
src/misc/mirage_type.h
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
#include <chrono>
|
||||
#include <Eigen/Eigen>
|
||||
|
||||
using time_type = decltype(std::chrono::high_resolution_clock::now());
|
||||
using duration_type = decltype(std::chrono::high_resolution_clock::now() - std::chrono::high_resolution_clock::now());
|
||||
|
||||
inline time_type get_current_time() {
|
||||
return std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
// struct VSInput {
|
||||
// float2 position : POSITION;
|
||||
// float2 uv : TEXCOORD0;
|
||||
// float4 color : COLOR0;
|
||||
// float4 param_a : TEXCOORD1;
|
||||
// float4 param_b : TEXCOORD2;
|
||||
// float4 param_c : TEXCOORD3;
|
||||
// };
|
||||
struct mirage_vertex_param_t{
|
||||
union {
|
||||
float a;
|
||||
float x;
|
||||
};
|
||||
union {
|
||||
float b;
|
||||
float y;
|
||||
};
|
||||
union {
|
||||
float c;
|
||||
float z;
|
||||
};
|
||||
union {
|
||||
float d;
|
||||
float w;
|
||||
};
|
||||
};
|
||||
struct mirage_vertex_t {
|
||||
Eigen::Vector2f position;
|
||||
Eigen::Vector2f uv;
|
||||
Eigen::Vector4f color;
|
||||
mirage_vertex_param_t param_a;
|
||||
mirage_vertex_param_t param_b;
|
||||
mirage_vertex_param_t param_c;
|
||||
};
|
||||
|
||||
struct mirage_triangle_t {
|
||||
uint32_t indices[3];
|
||||
};
|
28
src/misc/scope_exit.h
Normal file
28
src/misc/scope_exit.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
template<typename FuncType>
|
||||
class scope_exit_guard {
|
||||
public:
|
||||
scope_exit_guard(FuncType&& in_func) : func((FuncType&&)in_func) {
|
||||
}
|
||||
virtual ~scope_exit_guard() {
|
||||
func();
|
||||
}
|
||||
private:
|
||||
FuncType func;
|
||||
};
|
||||
|
||||
struct scope_exit_syntax_support {
|
||||
virtual ~scope_exit_syntax_support() = default;
|
||||
template <typename FuncType>
|
||||
scope_exit_guard<FuncType> operator+(FuncType&& InFunc)
|
||||
{
|
||||
return scope_exit_guard<FuncType>((FuncType&&)InFunc);
|
||||
}
|
||||
};
|
||||
|
||||
#define PRIVATE_CONCATENATE_DETAIL(x, y) x##y
|
||||
#define PRIVATE_CONCATENATE(x, y) PRIVATE_CONCATENATE_DETAIL(x, y)
|
||||
|
||||
#define ON_SCOPE_EXIT const auto PRIVATE_CONCATENATE(scope_exit, __LINE__) = scope_exit_syntax_support() + [&]()
|
||||
|
85
src/shaders/mirage_rounded_rect.slang
Normal file
85
src/shaders/mirage_rounded_rect.slang
Normal file
@ -0,0 +1,85 @@
|
||||
#include "mirage_util.slang"
|
||||
|
||||
cbuffer ParamBuffer
|
||||
{
|
||||
matrix transform;
|
||||
};
|
||||
|
||||
struct PSInput {
|
||||
float4 position : SV_POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 color : COLOR;
|
||||
float2 size : TEXCOORD1; // 矩形大小(像素单位)
|
||||
float4 radius : TEXCOORD3; // 四角圆角(像素单位): [左上,右上,左下,右下]
|
||||
};
|
||||
|
||||
[shader("vertex")]
|
||||
PSInput vertex_main(VSInput input)
|
||||
{
|
||||
PSInput output;
|
||||
|
||||
// 并通过常量缓冲区或结构化缓冲区传递
|
||||
output.position = mul(float4(input.position, 0.0, 1.0), transform);
|
||||
output.uv = input.uv;
|
||||
output.color = input.color;
|
||||
|
||||
// 传递尺寸和半径数据
|
||||
output.size = input.param_a.xy;
|
||||
output.radius = input.param_b;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// 改进的距离函数计算
|
||||
float distance_from_rect_uv(float2 p, float2 size, float corner_radius) {
|
||||
// 保护除零
|
||||
corner_radius = max(corner_radius, 0.001);
|
||||
|
||||
// 转换圆角半径为UV空间
|
||||
float2 corner_radius_uv = corner_radius / size;
|
||||
|
||||
// 计算内部矩形边界(圆角内切矩形)
|
||||
float2 inner_rect = float2(1.0, 1.0) - corner_radius_uv;
|
||||
|
||||
// 计算到内部矩形的距离
|
||||
float2 q = abs(p) - inner_rect;
|
||||
|
||||
// 转换回像素空间进行距离计算
|
||||
q *= size;
|
||||
|
||||
// 计算SDF(有符号距离场)
|
||||
return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - corner_radius;
|
||||
}
|
||||
|
||||
[shader("pixel")]
|
||||
float4 pixel_main(PSInput input) : SV_Target
|
||||
{
|
||||
// 将UV坐标转换为从中心点(-1,1)的归一化设备坐标
|
||||
float2 p = uv_to_ndc(input.uv);
|
||||
|
||||
// 确定当前像素位于哪个象限,以选择正确的圆角半径
|
||||
// 0=左上(x<0,y<0), 1=右上(x>0,y<0), 2=左下(x<0,y>0), 3=右下(x>0,y>0)
|
||||
int idx = (p.x < 0 ? 0 : 1) + (p.y < 0 ? 0 : 2);
|
||||
|
||||
// 获取当前象限的圆角半径 * 2
|
||||
float r = input.radius[idx];
|
||||
|
||||
// 计算到圆角矩形边界的有符号距离
|
||||
float d = distance_from_rect_uv(p, input.size, r);
|
||||
|
||||
// 改进的抗锯齿算法 - 使用特定的像素宽度计算
|
||||
float pixelWidth = 1.0;
|
||||
float2 ddx_p = ddx(p * input.size);
|
||||
float2 ddy_p = ddy(p * input.size);
|
||||
|
||||
// 计算基于像素梯度的边缘宽度
|
||||
float edge_width = 0.5 * length(float2(length(ddx_p), length(ddy_p)));
|
||||
|
||||
// 应用平滑过渡 - 提高抗锯齿质量
|
||||
float alpha_factor = 1.0 - smoothstep(-edge_width, edge_width, d);
|
||||
|
||||
// 输出最终颜色
|
||||
float4 final_color = input.color;
|
||||
final_color.a *= alpha_factor;
|
||||
return final_color;
|
||||
}
|
13
src/shaders/mirage_util.slang
Normal file
13
src/shaders/mirage_util.slang
Normal file
@ -0,0 +1,13 @@
|
||||
struct VSInput {
|
||||
float2 position : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 color : COLOR0;
|
||||
float4 param_a : TEXCOORD1;
|
||||
float4 param_b : TEXCOORD2;
|
||||
float4 param_c : TEXCOORD3;
|
||||
};
|
||||
|
||||
// 将uv坐标系从[0, 0]-[1, 1] -> [-1, -1]-[1, 1]
|
||||
float2 uv_to_ndc(float2 uv) {
|
||||
return uv * 2 - 1;
|
||||
}
|
27
src/shaders/test.slang
Normal file
27
src/shaders/test.slang
Normal file
@ -0,0 +1,27 @@
|
||||
#include "mirage_util.slang"
|
||||
|
||||
struct ParamBuffer
|
||||
{
|
||||
matrix transform;
|
||||
};
|
||||
ParameterBlock<ParamBuffer> param_buffer : register(b1);
|
||||
|
||||
struct PSInput {
|
||||
float4 position : SV_POSITION; // 裁剪空间坐标
|
||||
float4 color : COLOR; // 颜色
|
||||
};
|
||||
|
||||
[shader("vertex")]
|
||||
PSInput vertex_main(VSInput input)
|
||||
{
|
||||
PSInput output;
|
||||
output.position = mul(float4(input.position, 0, 1.0), param_buffer.transform);
|
||||
output.color = input.color;
|
||||
return output;
|
||||
}
|
||||
|
||||
[shader("pixel")]
|
||||
float4 pixel_main(PSInput input) : SV_TARGET
|
||||
{
|
||||
return input.color;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
157
tools/compile_shaders.py
Normal file
157
tools/compile_shaders.py
Normal file
@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple, Iterator
|
||||
|
||||
# 支持的后端列表
|
||||
BACKENDS = [
|
||||
"glsl", # SG_BACKEND_GLCORE
|
||||
"essl", # SG_BACKEND_GLES3
|
||||
"hlsl", # SG_BACKEND_D3D11
|
||||
"metal", # SG_BACKEND_METAL_IOS, SG_BACKEND_METAL_MACOS, SG_BACKEND_METAL_SIMULATOR
|
||||
"wgsl", # SG_BACKEND_WGPU
|
||||
]
|
||||
|
||||
SHADER_EXTENSIONS = {
|
||||
'glsl': 'glsl',
|
||||
'essl': 'glsl',
|
||||
'hlsl': 'dxil',
|
||||
'metal': 'metallib',
|
||||
'wgsl': 'wgsl'
|
||||
}
|
||||
|
||||
TARGET_PROFILES = {
|
||||
# 'glsl': ['-profile', 'glsl_460'],
|
||||
# 'essl': ['-profile', 'glsl_300es'],
|
||||
# 'hlsl': ['-profile', 'sm_5_0'],
|
||||
# 'metal': ['-capability', 'metallib'],
|
||||
# 'wgsl': ['-profile', 'wgsl']
|
||||
}
|
||||
|
||||
def need_recompile(input_file: Path, output_path: Path) -> bool:
|
||||
"""检查是否需要重新编译"""
|
||||
# 着色器输出文件名的格式为input.file.stem + '.' + backend + '.h'
|
||||
# 所以需要检查是否有input.file.stem + '.*.h'文件存在
|
||||
for backend in BACKENDS:
|
||||
output_file = output_path / f"{input_file.stem}.{backend}.h"
|
||||
if not output_file.exists():
|
||||
continue
|
||||
else:
|
||||
input_time = input_file.stat().st_mtime
|
||||
output_time = output_file.stat().st_mtime
|
||||
return input_time > output_time
|
||||
return True
|
||||
|
||||
|
||||
def find_shader_files(input_dir: Path, extensions: List[str]) -> Iterator[Path]:
|
||||
"""递归查找指定目录下的着色器文件"""
|
||||
for file_path in Path(input_dir).rglob('*'):
|
||||
if file_path.suffix in extensions:
|
||||
yield file_path
|
||||
|
||||
def create_compiler_command(
|
||||
input_file: Path,
|
||||
output_file: Path,
|
||||
target_type: str,
|
||||
args: argparse.Namespace
|
||||
) -> List[str]:
|
||||
"""生成着色器编译命令"""
|
||||
cmd = [args.shdc,
|
||||
str(input_file),
|
||||
"-o", str(output_file),
|
||||
"-t", target_type,
|
||||
]
|
||||
|
||||
if args.debug:
|
||||
cmd.append('-d')
|
||||
|
||||
if target_type in TARGET_PROFILES:
|
||||
cmd.extend(TARGET_PROFILES[target_type])
|
||||
|
||||
return cmd
|
||||
|
||||
def compile_shader(
|
||||
input_file: Path,
|
||||
target_types: List[Tuple[str, bool]],
|
||||
args: argparse.Namespace
|
||||
) -> bool:
|
||||
"""编译单个着色器文件并读取二进制数据"""
|
||||
try:
|
||||
base = input_file.stem
|
||||
output_dir = input_file.parent
|
||||
success = True
|
||||
|
||||
for target_type, enabled in target_types:
|
||||
if not enabled:
|
||||
continue
|
||||
if not need_recompile(input_file, output_dir):
|
||||
print(f"**跳过**: {input_file} 已经是最新的")
|
||||
continue
|
||||
|
||||
cmd = create_compiler_command(input_file, output_dir, target_type, args)
|
||||
try:
|
||||
# 修改这里: 明确指定编码为utf-8,并添加errors参数处理无法解码的字符
|
||||
subprocess.run(cmd, check=True, capture_output=True, text=True, encoding='utf-8', errors='replace')
|
||||
print(f"**成功**: 编译 {input_file}")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"**错误**: 编译 {input_file} 失败")
|
||||
print(e.stderr)
|
||||
success = False
|
||||
continue
|
||||
|
||||
return success
|
||||
except Exception as e:
|
||||
print(f"**错误**: 处理 {input_file} 时发生异常: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='编译slang着色器为C++头文件')
|
||||
parser.add_argument('--shdc', help='着色器编译器路径')
|
||||
parser.add_argument('--shader_list', help='着色器目录列表文件路径')
|
||||
parser.add_argument("--hlsl", action="store_true", help="编译HLSL着色器")
|
||||
parser.add_argument("--glsl", action="store_true", help="编译GLSL着色器")
|
||||
parser.add_argument("--essl", action="store_true", help="编译ESSL着色器")
|
||||
parser.add_argument("--metal", action="store_true", help="编译Metal着色器")
|
||||
parser.add_argument("--wgsl", action="store_true", help="编译WGSL着色器")
|
||||
parser.add_argument("--debug", action="store_true", help="编译调试版本")
|
||||
args = parser.parse_args()
|
||||
|
||||
# 确定要编译的目标后端
|
||||
target_types: List[Tuple[str, bool]] = [
|
||||
('glsl', args.glsl),
|
||||
('essl', args.essl),
|
||||
('hlsl', args.hlsl),
|
||||
('metal', args.metal),
|
||||
('wgsl', args.wgsl),
|
||||
]
|
||||
|
||||
# 如果没有指定任何后端,默认启用所有后端
|
||||
if not any(enabled for _, enabled in target_types):
|
||||
target_types = [(backend, True) for backend, _ in target_types]
|
||||
|
||||
shader_list = Path(args.shader_list or "shader_paths.txt")
|
||||
|
||||
try:
|
||||
shader_paths = shader_list.read_text(encoding="utf-8").splitlines()
|
||||
except Exception as e:
|
||||
print(f"**错误**: 读取着色器列表文件 {shader_list} 失败: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
all_success = True
|
||||
for shader_path in shader_paths:
|
||||
shader_path = shader_path.strip()
|
||||
if not shader_path:
|
||||
continue
|
||||
for file in find_shader_files(Path(shader_path), ['.slang']):
|
||||
if not compile_shader(file, target_types, args):
|
||||
all_success = False
|
||||
|
||||
if not all_success:
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
BIN
tools/mirage_shdc.exe
Normal file
BIN
tools/mirage_shdc.exe
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user