核心热路径(数学/内存/字符串/性能分析)用MASM汇编(SSE/AVX2) 外围系统(窗口/渲染/ECS/音频/UI/脚本)用C语言 含自研编辑器、VisualScript积木编程、中文渲染(glyph_atlas)
30 KiB
30 KiB
GameEngineASM - x86-64 MASM + C 混合架构游戏引擎设计
1. 完整目录树
GameEngineASM/
├── GameEngineASM.sln
├── DESIGN.md
│
├── Engine/
│ ├── ASM/ -- 汇编核心 (4 files)
│ │ ├── math.asm -- 向量/矩阵/四元数 SIMD 运算
│ │ ├── memory.asm -- 对齐内存分配器
│ │ ├── string_ops.asm -- 高速内存/字符串操作
│ │ └── profiling.asm -- rdtsc 性能计时
│ │
│ ├── include/ -- 共享头文件 (6 files)
│ │ ├── asm_math.inc -- ASM 函数声明 (.inc for MASM)
│ │ ├── asm_math.h -- C 端数学函数声明
│ │ ├── asm_memory.h -- C 端内存分配器声明
│ │ ├── asm_string.h -- C 端字符串操作声明
│ │ ├── asm_profiling.h -- C 端性能计时声明
│ │ └── engine_types.h -- 公共类型定义 (vec3, mat4, etc.)
│ │
│ ├── C/ -- C 外层模块
│ │ ├── core/ -- 核心系统 (6 files)
│ │ │ ├── engine.h
│ │ │ ├── engine.c
│ │ │ ├── platform.h
│ │ │ ├── platform.c
│ │ │ ├── logger.h
│ │ │ └── logger.c
│ │ │
│ │ ├── rendering/ -- DirectX 11 渲染 (8 files)
│ │ │ ├── renderer.h
│ │ │ ├── renderer.c
│ │ │ ├── dx11_device.h
│ │ │ ├── dx11_device.c
│ │ │ ├── shader.h
│ │ │ ├── shader.c
│ │ │ ├── mesh.h
│ │ │ └── mesh.c
│ │ │
│ │ ├── ecs/ -- 实体组件系统 (6 files)
│ │ │ ├── ecs.h
│ │ │ ├── ecs.c
│ │ │ ├── component_registry.h
│ │ │ ├── component_registry.c
│ │ │ ├── system_manager.h
│ │ │ └── system_manager.c
│ │ │
│ │ ├── physics/ -- 物理系统 (4 files)
│ │ │ ├── physics.h
│ │ │ ├── physics.c
│ │ │ ├── collision.h
│ │ │ └── collision.c
│ │ │
│ │ ├── resources/ -- 资源管理 (4 files)
│ │ │ ├── resource_manager.h
│ │ │ ├── resource_manager.c
│ │ │ ├── file_loader.h
│ │ │ └── file_loader.c
│ │ │
│ │ ├── scene/ -- 场景管理 (4 files)
│ │ │ ├── scene.h
│ │ │ ├── scene.c
│ │ │ ├── scene_node.h
│ │ │ └── scene_node.c
│ │ │
│ │ ├── audio/ -- XAudio2 音频 (4 files)
│ │ │ ├── audio.h
│ │ │ ├── audio.c
│ │ │ ├── audio_source.h
│ │ │ └── audio_source.c
│ │ │
│ │ ├── ui/ -- UI 系统 (4 files)
│ │ │ ├── ui.h
│ │ │ ├── ui.c
│ │ │ ├── ui_widget.h
│ │ │ └── ui_widget.c
│ │ │
│ │ └── scripting/ -- Lua 脚本 (4 files)
│ │ ├── scripting.h
│ │ ├── scripting.c
│ │ ├── lua_bindgen.h
│ │ └── lua_bindgen.c
│ │
│ └── lib/ -- 预编译库 (3 files)
│ ├── lua54.lib
│ ├── d3d11.lib
│ └── d3dcompiler.lib
│
├── Demo/ -- 演示程序 (3 files)
│ ├── main.c
│ ├── demo_scene.c
│ └── demo_scene.h
│
└── Build/ -- 构建配置 (3 files)
├── GameEngineASM.vcxproj
├── GameEngineASM.vcxproj.filters
└── GameEngineASM.props
总文件数: 58 files
2. 关键 ASM 函数签名
2.1 math.asm — SIMD 数学库
; ============================================================
; math.asm - SSE4.1/AVX2 向量矩阵数学库
; 与 C 互操作: Windows x64 calling convention
; 输入: RCX, RDX, R8, R9 (整数/指针), XMM0-XMM3 (浮点)
; 返回: 整数在 RAX, 浮点在 XMM0
; ============================================================
; --- Vector2 操作 (float x, float y) ---
; float vec2_dot(vec2 a, vec2 b)
; RCX = ptr to vec2 a, RDX = ptr to vec2 b
; Returns: XMM0 = dot product
vec2_dot PROC
movups xmm0, xmmword ptr [rcx] ; load a.x, a.y
movups xmm1, xmmword ptr [rdx] ; load b.x, b.y
mulps xmm0, xmm1 ; element-wise multiply
;水 平 求 和: xmm0 = (a.x*b.x, a.y*b.y)
; 需要水平加法
movshdup xmm1, xmm0 ; xmm1 = (a.y*b.y, a.y*b.y)
addps xmm0, xmm1 ; xmm0 = (a.x*b.x + a.y*b.y, ...)
ret
vec2_dot ENDP
; void vec2_normalize(vec2* out, vec2 in)
; RCX = ptr out, XMM0 = in.x, XMM1 = in.y
vec2_normalize PROC
; pack xmm0,xmm1 -> xmm2
unpcklps xmm2, xmm0, xmm1 ; xmm2 = (in.x, in.y)
movaps xmm3, xmm2 ; save
mulps xmm2, xmm2 ; square
; horizontal sum
movshdup xmm4, xmm2
addps xmm2, xmm4 ; len_sq
sqrtss xmm2, xmm2 ; len
shufps xmm2, xmm2, 0 ; broadcast
divps xmm3, xmm2 ; normalize
movups xmmword ptr [rcx], xmm3 ; store
ret
vec2_normalize ENDP
; --- Vector3 操作 (float x, y, z, pad) ---
; float vec3_dot(vec3 a, vec3 b)
vec3_dot PROC
movups xmm0, xmmword ptr [rcx]
movups xmm1, xmmword ptr [rdx]
mulps xmm0, xmm1
; horizontal sum 3 components
movshdup xmm2, xmm0
addps xmm0, xmm2
movhlps xmm2, xmm0
addss xmm0, xmm2
ret
vec3_dot ENDP
; void vec3_cross(vec3* out, vec3 a, vec3 b)
; RCX = out, XMM0 = a, XMM1 = b (packed xyz)
vec3_cross PROC
; a = (ax, ay, az), b = (bx, by, bz)
; result = (ay*bz - az*by, az*bx - ax*bz, ax*by - ay*bx)
movaps xmm2, xmm0 ; a
movaps xmm3, xmm1 ; b
shufps xmm4, xmm2, xmm2, 0C9h ; a.yzx
shufps xmm5, xmm3, xmm3, 0C9h ; b.yzx
mulps xmm4, xmm3 ; a.yzx * b
mulps xmm5, xmm2 ; b.yzx * a
subps xmm4, xmm5 ; cross
; store xyz
movlps qword ptr [rcx], xmm4
shufps xmm4, xmm4, 02h
movss dword ptr [rcx+8], xmm4
ret
vec3_cross ENDP
; void vec3_normalize(vec3* out, vec3 v)
vec3_normalize PROC
movups xmm0, xmmword ptr [rcx] ; load v
movaps xmm1, xmm0
mulps xmm1, xmm1 ; v*v
; horizontal sum
movshdup xmm2, xmm1
addps xmm1, xmm2
movhlps xmm2, xmm1
addss xmm1, xmm2
sqrtss xmm1, xmm1 ; len
shufps xmm1, xmm1, 0 ; broadcast
divps xmm0, xmm1
movups xmmword ptr [rcx], xmm0
ret
vec3_normalize ENDP
; void vec3_lerp(vec3* out, vec3 a, vec3 b, float t)
; RCX=out, XMM0=a(xyz), XMM1=b(xyz), XMM2=t
vec3_lerp PROC
subps xmm1, xmm0 ; b - a
shufps xmm2, xmm2, 0 ; broadcast t
mulps xmm1, xmm2 ; t * (b-a)
addps xmm0, xmm1 ; a + t*(b-a)
movups xmmword ptr [rcx], xmm0
ret
vec3_lerp ENDP
; --- Vector4 操作 ---
; float vec4_dot(vec4 a, vec4 b)
vec4_dot PROC
movups xmm0, xmmword ptr [rcx]
movups xmm1, xmmword ptr [rdx]
mulps xmm0, xmm1
; horizontal sum 4
movhlps xmm1, xmm0
addps xmm0, xmm1
movshdup xmm1, xmm0
addss xmm0, xmm1
ret
vec4_dot ENDP
; --- Matrix4x4 操作 (16 floats, row-major) ---
; void mat4_identity(mat4* out)
mat4_identity PROC
vxorps xmm0, xmm0, xmm0
movups xmmword ptr [rcx], xmm0
movups xmmword ptr [rcx+16], xmm0
movups xmmword ptr [rcx+32], xmm0
movups xmmword ptr [rcx+48], xmm0
movss dword ptr [rcx], (1.0) ; [0][0] = 1
movss dword ptr [rcx+20], (1.0) ; [1][1] = 1
movss dword ptr [rcx+40], (1.0) ; [2][2] = 1
movss dword ptr [rcx+60], (1.0) ; [3][3] = 1
ret
mat4_identity ENDP
; void mat4_multiply(mat4* out, mat4* a, mat4* b)
; AVX2: 8-wide FMA
mat4_multiply PROC
; 保存非易失寄存器
push rbx
sub rsp, 20h
; RCX = out, RDX = a, R8 = b
mov rbx, rcx
mov rsi, rdx
mov rdi, r8
; 对矩阵 a 的每一行, 与矩阵 b 的所有列做点积
; 逐行处理 a
vmovups ymm0, ymmword ptr [rsi] ; a row 0 (y0)
vmovups ymm2, ymmword ptr [rsi+32] ; a row 1
vmovups ymm4, ymmword ptr [rsi+64] ; a row 2
vmovups ymm6, ymmword ptr [rsi+96] ; a row 3
; 对每一列 b 计算 out 行
; Column 0 of b
vbroadcastss ymm1, dword ptr [rdi]
vbroadcastss ymm3, dword ptr [rdi+4]
vbroadcastss ymm5, dword ptr [rdi+8]
vbroadcastss ymm7, dword ptr [rdi+12]
vfmadd231ps ymm0, ymm1, ymm0 ; row0 += col0 * row0
; ... (简化, 完整实现需 4x4=16 次 FMA)
vmovups ymmword ptr [rbx], ymm0
; ... 其余行
add rsp, 20h
pop rbx
ret
mat4_multiply ENDP
; void mat4_transpose(mat4* out, mat4* m)
mat4_transpose PROC
vmovups ymm0, ymmword ptr [rdx] ; row 0,1
vmovups ymm1, ymmword ptr [rdx+32] ; row 2,3
vunpcklps ymm2, ymm0, ymm1 ; unpack low
vunpckhps ymm3, ymm0, ymm1 ; unpack high
vunpcklps ymm4, ymm2, ymm3
vunpckhps ymm5, ymm2, ymm3
vmovups ymmword ptr [rcx], ymm4
vmovups ymmword ptr [rcx+32], ymm5
ret
mat4_transpose ENDP
; bool mat4_inverse(mat4* out, mat4* m) -- 返回是否可逆
; 使用 SIMD 优化的 Gauss-Jordan 消元
mat4_inverse PROC
; 完整实现约 200 行, 使用 AVX2 + FMA
; 核心: 增广矩阵 [m|I] 行变换
push rbx
push rbp
sub rsp, 40h
; ... 完整 SIMD inverse 实现
mov al, 1 ; assume success
add rsp, 40h
pop rbp
pop rbx
ret
mat4_inverse ENDP
; --- Quaternion 操作 (4 floats: x, y, z, w) ---
; void quat_multiply(quat* out, quat* a, quat* b)
quat_multiply PROC
movups xmm0, xmmword ptr [rcx] ; a = (ax,ay,az,aw)
movups xmm1, xmmword ptr [rdx] ; b = (bx,by,bz,bw)
; Hamilton product
; result = (aw*b + bw*a + cross(a.xyz, b.xyz), aw*bw - dot(a.xyz,b.xyz))
movaps xmm2, xmm0
shufps xmm2, xmm2, 0FFh ; broadcast aw
mulps xmm2, xmm1 ; aw * b
movaps xmm3, xmm1
shufps xmm3, xmm3, 0FFh ; broadcast bw
mulps xmm3, xmm0 ; bw * a
; cross product of xyz
; ... (同 vec3_cross)
addps xmm2, xmm3
; w = aw*bw - dot(ax*bx + ay*by + az*bz)
; store result
movups xmmword ptr [rcx], xmm2
ret
quat_multiply ENDP
; void quat_rotate_vec3(vec3* out, quat* q, vec3* v)
; 使用旋转公式: v' = q * v * q^-1
; 优化公式: v' = v + 2w(q.xyz x v) + 2(q.xyz x (q.xyz x v))
quat_rotate_vec3 PROC
; ... AVX2 优化实现
ret
quat_rotate_vec3 ENDP
2.2 memory.asm — 对齐内存分配器
; ============================================================
; memory.asm - SIMD 对齐内存分配器
; ============================================================
; void* mem_aligned_alloc(size_t size, size_t alignment)
; RCX = size, RDX = alignment (must be power of 2, >= 16)
; Returns: RAX = aligned pointer (or NULL on failure)
; 实现: 分配 size + alignment + sizeof(void*), 返回对齐后的指针
; 在对齐指针前存储原始 malloc 指针
mem_aligned_alloc PROC
push rbx
push rdi
sub rsp, 28h
mov rbx, rcx ; size
mov rdi, rdx ; alignment
; total = size + alignment + 8 (for storing original ptr)
lea rcx, [rbx + rdi + 8]
call malloc ; 调用 CRT malloc
test rax, rax
jz .fail
; 计算对齐指针
mov rcx, rax
add rcx, 8 ; skip storing space
; align up
lea rdx, [rdi - 1]
not rdx
add rcx, rdx
and rcx, rdx ; aligned ptr
; 存储原始指针 (aligned_ptr - 8)
mov [rcx - 8], rax
mov rax, rcx
jmp .done
.fail:
xor eax, eax
.done:
add rsp, 28h
pop rdi
pop rbx
ret
mem_aligned_alloc ENDP
; void mem_aligned_free(void* ptr)
; RCX = aligned pointer
mem_aligned_free PROC
test rcx, rcx
jz .done
mov rcx, qword ptr [rcx - 8] ; recover original ptr
call free
.done:
ret
mem_aligned_free ENDP
; void* mem_aligned_realloc(void* ptr, size_t new_size)
mem_aligned_realloc PROC
; ... 类似 alloc 但使用 realloc
ret
mem_aligned_realloc ENDP
2.3 string_ops.asm — 高速字符串/内存操作
; ============================================================
; string_ops.asm - 高速内存/字符串操作
; 使用 REP MOVSB (ERMS) + SSE 优化
; ============================================================
; void fast_memcpy(void* dst, const void* src, size_t count)
; RCX=dst, RDX=src, R8=count
; 对齐后使用 SSE2 movdqa 批量复制
fast_memcpy PROC
push rdi
push rsi
push rbx
mov rdi, rcx
mov rsi, rdx
mov rcx, r8
cmp rcx, 64
jb .small_copy
; 大块复制: 对齐到 16 字节后用 movdqa
; 先复制前几字节直到对齐
mov rax, rdi
and rax, 0Fh
jz .aligned
mov rdx, 16
sub rdx, rax
rep movsb
sub rcx, rdx
.aligned:
; 以 64 字节为单位批量复制
mov rdx, rcx
shr rcx, 2 ; count / 4 (64 bytes each)
jz .tail
.loop_64:
movdqa xmm0, xmmword ptr [rsi]
movdqa xmm1, xmmword ptr [rsi+16]
movdqa xmm2, xmmword ptr [rsi+32]
movdqa xmm3, xmmword ptr [rsi+48]
movdqa xmmword ptr [rdi], xmm0
movdqa xmmword ptr [rdi+16], xmm1
movdqa xmmword ptr [rdi+32], xmm2
movdqa xmmword ptr [rdi+48], xmm3
add rsi, 64
add rdi, 64
dec rcx
jnz .loop_64
and rdx, 3Fh ; remaining bytes
mov rcx, rdx
.tail:
rep movsb
pop rbx
pop rsi
pop rdi
ret
.small_copy:
rep movsb
pop rbx
pop rsi
pop rdi
ret
fast_memcpy ENDP
; void fast_memset(void* dst, int val, size_t count)
; 使用 SSE2 批量填充
fast_memset PROC
push rdi
push rcx
mov rdi, rcx
mov rax, rdx
mov rcx, r8
; 广播 val 到 xmm0 的所有字节
movd xmm0, edx
pshufd xmm0, xmm0, 0
cmp rcx, 32
jb .small_set
; 对齐
mov rax, rdi
and rax, 0Fh
jz .aligned_set
mov rdx, 16
sub rdx, rax
rep stosb
sub rcx, rdx
.aligned_set:
mov rdx, rcx
shr rcx, 1 ; 32 bytes per iteration
.loop_set:
movdqa xmmword ptr [rdi], xmm0
movdqa xmmword ptr [rdi+16], xmm0
add rdi, 32
dec rcx
jnz .loop_set
and rdx, 1Fh
mov rcx, rdx
.small_set:
rep stosb
pop rcx
pop rdi
ret
fast_memset ENDP
; int fast_strcmp(const char* a, const char* b)
; SSE4.2PCMPESTRI 逐 16 字节比较
fast_strcmp PROC
push rbx
.loop_strcmp:
movdqu xmm0, xmmword ptr [rcx]
movdqu xmm1, xmmword ptr [rdx]
; SSE4.2 字符串比较: 找到第一个不匹配位置
pcmpestrm xmm0, xmm1, 18h ; EqualAny, unsigned bytes
; ... (具体利用 SSE4.2 字符串指令)
; 简化版本: 逐字节 fallback
mov al, byte ptr [rcx]
cmp al, byte ptr [rdx]
jne .not_equal
test al, al
jz .equal
inc rcx
inc rdx
jmp .loop_strcmp
.not_equal:
movzx eax, al
movzx edx, byte ptr [rdx]
sub eax, edx
pop rbx
ret
.equal:
xor eax, eax
pop rbx
ret
fast_strcmp ENDP
; size_t fast_strlen(const char* str)
fast_strlen PROC
mov rax, rcx
pxor xmm0, xmm0
.loop_strlen:
movdqu xmm1, xmmword ptr [rax]
pcmpestrm xmm1, xmm0, 08h ; Least Significant Byte, imm8=08h
jc .found
add rax, 16
jmp .loop_strlen
.found:
; 在返回的掩码中找第一个 1
pmovmskb edx, xmm1
tzcnt edx, edx
add rax, rdx
sub rax, rcx ; length = end - start
ret
fast_strlen ENDP
2.4 profiling.asm — rdtsc 性能计时
; ============================================================
; profiling.asm - rdtsc 高精度计时
; ============================================================
; uint64_t prof_rdtsc(void)
; 返回 TSC 值
prof_rdtsc PROC
lfence
rdtsc
shl rdx, 32
or rax, rdx
ret
prof_rdtsc ENDP
; uint64_t prof_rdtscp(void)
; 无序读取, 更快但可能不精确
prof_rdtscp PROC
rdtscp
shl rdx, 32
or rax, rdx
ret
prof_rdtscp ENDP
; double prof_cycles_to_ms(uint64_t cycles)
; 将 TSC cycles 转换为毫秒 (需要 CPU 频率)
; RCX = cycles
; Returns: XMM0 = milliseconds
prof_cycles_to_ms PROC
vcvttsd2si rax, xmm0 ; ... 保存输入
; 假设 CPU 频率存储在全局变量 cpu_freq_ghz
vmovsd xmm0, qword ptr [cpu_freq_mhz]
vcvtsi2sd xmm1, xmm1, rcx
vdivsd xmm0, xmm1, xmm0 ; cycles / mhz = ms
vdivsd xmm0, xmm0, (1000.0) ; / 1000 for seconds, but we want ms
; 实际: ms = cycles / (cpu_mhz * 1000)
ret
prof_cycles_to_ms ENDP
; void prof_calibrate_frequency(void)
; 通过 QueryPerformanceCounter 校准 TSC 频率
prof_calibrate_frequency PROC
sub rsp, 28h
; QueryPerformanceFrequency
lea rcx, qword ptr [freq_large]
call QueryPerformanceFrequency
; 用 rdtsc 采样
call prof_rdtsc
mov rbx, rax
; Sleep(100ms)
mov ecx, 100
call Sleep
call prof_rdtsc
sub rax, rbx ; elapsed cycles
; cpu_mhz = elapsed_cycles / (freq * 0.1s)
; ...
add rsp, 28h
ret
prof_calibrate_frequency ENDP
.data
cpu_freq_mhz dq 0
freq_large dq 0
3. C 端头文件 (暴露 ASM 函数)
3.1 engine_types.h — 公共类型
#ifndef ENGINE_TYPES_H
#define ENGINE_TYPES_H
#include <stdint.h>
#include <stdbool.h>
typedef union Vec2 {
struct { float x, y; };
float m[2];
} Vec2;
typedef union Vec3 {
struct { float x, y, z, _pad; };
float m[4]; // 16-byte aligned
} Vec3;
typedef union Vec4 {
struct { float x, y, z, w; };
float m[4];
} Vec4;
typedef union Mat4 {
float m[16];
float mm[4][4];
} Mat4;
typedef union Quat {
struct { float x, y, z, w; };
float m[4];
} Quat;
#endif
3.2 asm_math.h
#ifndef ASM_MATH_H
#define ASM_MATH_H
#include "engine_types.h"
#ifdef __cplusplus
extern "C" {
#endif
// Vector2
float vec2_dot(Vec2 a, Vec2 b);
Vec2 vec2_add(Vec2 a, Vec2 b);
Vec2 vec2_sub(Vec2 a, Vec2 b);
Vec2 vec2_scale(Vec2 v, float s);
Vec2 vec2_normalize(Vec2 v);
float vec2_length(Vec2 v);
// Vector3
float vec3_dot(Vec3 a, Vec3 b);
Vec3 vec3_cross(Vec3 a, Vec3 b);
Vec3 vec3_add(Vec3 a, Vec3 b);
Vec3 vec3_sub(Vec3 a, Vec3 b);
Vec3 vec3_scale(Vec3 v, float s);
Vec3 vec3_normalize(Vec3 v);
float vec3_length(Vec3 v);
Vec3 vec3_lerp(Vec3 a, Vec3 b, float t);
// Vector4
float vec4_dot(Vec4 a, Vec4 b);
Vec4 vec4_add(Vec4 a, Vec4 b);
Vec4 vec4_sub(Vec4 a, Vec4 b);
Vec4 vec4_scale(Vec4 v, float s);
// Matrix4x4
void mat4_identity(Mat4* out);
void mat4_multiply(Mat4* out, Mat4* a, Mat4* b);
void mat4_transpose(Mat4* out, Mat4* m);
bool mat4_inverse(Mat4* out, Mat4* m);
void mat4_translate(Mat4* out, Vec3 v);
void mat4_scale(Mat4* out, Vec3 s);
void mat4_rotate_x(Mat4* out, float radians);
void mat4_rotate_y(Mat4* out, float radians);
void mat4_rotate_z(Mat4* out, float radians);
Mat4 mat4_perspective(float fov, float aspect, float near, float far);
Mat4 mat4_ortho(float left, float right, float bottom, float top, float near, float far);
Mat4 mat4_look_at(Vec3 eye, Vec3 center, Vec3 up);
// Quaternion
Quat quat_identity(void);
Quat quat_multiply(Quat a, Quat b);
Quat quat_normalize(Quat q);
Quat quat_conjugate(Quat q);
Quat quat_from_axis_angle(Vec3 axis, float angle);
Vec3 quat_rotate_vec3(Quat q, Vec3 v);
Mat4 quat_to_mat4(Quat q);
// SSE intrinsics for direct C use (optional, for tight loops)
#ifdef __SSE4_1__
#include <smmintrin.h>
static inline float fast_vec3_dot_sse(Vec3 a, Vec3 b) {
__m128 va = _mm_load_ps(a.m);
__m128 vb = _mm_load_ps(b.m);
__m128 mul = _mm_mul_ps(va, vb);
__m128 shuf = _mm_movehdup_ps(mul);
__m128 sums = _mm_add_ps(mul, shuf);
shuf = _mm_movehl_ps(shuf, sums);
sums = _mm_add_ss(sums, shuf);
return _mm_cvtss_f32(sums);
}
#endif
#ifdef __cplusplus
}
#endif
#endif
3.3 asm_memory.h
#ifndef ASM_MEMORY_H
#define ASM_MEMORY_H
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void* mem_aligned_alloc(size_t size, size_t alignment);
void mem_aligned_free(void* ptr);
void* mem_aligned_realloc(void* ptr, size_t new_size);
size_t mem_get_alignment(void* ptr);
// SIMD 块分配: 一次分配多个对齐对象
void* mem_aligned_alloc_batch(size_t count, size_t elem_size, size_t alignment);
#ifdef __cplusplus
}
#endif
#endif
3.4 asm_string.h
#ifndef ASM_STRING_H
#define ASM_STRING_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
void fast_memcpy(void* dst, const void* src, size_t count);
void fast_memset(void* dst, int val, size_t count);
int fast_strcmp(const char* a, const char* b);
int fast_strncmp(const char* a, const char* b, size_t n);
size_t fast_strlen(const char* str);
char* fast_strchr(const char* str, int c);
char* fast_strcpy(char* dst, const char* src);
#ifdef __cplusplus
}
#endif
#endif
3.5 asm_profiling.h
#ifndef ASM_PROFILING_H
#define ASM_PROFILING_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
uint64_t prof_rdtsc(void);
uint64_t prof_rdtscp(void);
double prof_cycles_to_ms(uint64_t cycles);
uint64_t prof_calibrate_frequency(void);
double prof_get_cpu_ghz(void);
// 便捷宏
#define PROF_BEGIN() uint64_t _prof_start = prof_rdtsc()
#define PROF_END() prof_cycles_to_ms(prof_rdtsc() - _prof_start)
#ifdef __cplusplus
}
#endif
#endif
4. 构建配置 (Visual Studio MASM 集成)
4.1 GameEngineASM.props — MASM 属性表
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemDefinitionGroup>
<BuildCustomizations>
<MASm>
<AdditionalOptions>/Zi /nologo /Fl /Sa</AdditionalOptions>
<IncludePaths>$(ProjectDir)Engine\include</IncludePaths>
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimizations>FullSpeedOptimizations</Optimizations>
</MASm>
</BuildCustomizations>
<ClCompile>
<AdditionalIncludeDirectories>$(ProjectDir)Engine\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<Optimization>Full</Optimization>
<AdditionalOptions>/arch:AVX2 /fp:fast</AdditionalOptions>
<WarningLevel>Level4</WarningLevel>
</ClCompile>
<Link>
<AdditionalDependencies>d3d11.lib;d3dcompiler.lib;dxgi.lib;d3d11.lib;xaudio2.lib;lua54.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(ProjectDir)Engine\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
</Project>
4.2 GameEngineASM.vcxproj — 关键片段
<!-- 引入 MASM 自定义构建规则 -->
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
<!-- .asm 文件编译 -->
<ItemGroup>
<MASM Include="Engine\ASM\math.asm">
<ExcludedFromBuild>false</ExcludedFromBuild>
</MASM>
<MASM Include="Engine\ASM\memory.asm" />
<MASM Include="Engine\ASM\string_ops.asm" />
<MASM Include="Engine\ASM\profiling.asm" />
</ItemGroup>
<!-- C 源文件 -->
<ItemGroup>
<ClCompile Include="Engine\C\core\engine.c" />
<ClCompile Include="Engine\C\core\platform.c" />
<ClCompile Include="Engine\C\rendering\renderer.c" />
<!-- ... 其余 C 文件 -->
</ItemGroup>
<!-- 头文件 -->
<ItemGroup>
<ClInclude Include="Engine\include\*.h" />
<None Include="Engine\include\asm_math.inc" />
</ItemGroup>
<!-- 导出 MASM 属性 -->
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
4.3 ml64.exe 编译命令行
ml64.exe /c /nologo /W3 /Zi /Fo"$(OutDir)%(FileName).obj" /Fl"$(OutDir)%(FileName).lst" %(AdditionalInputs) %(AdditionalOptions)
5. 实施顺序 (按依赖关系)
Phase 1: 基础设施 (Week 1)
| 序号 | 任务 | 优先级 | 预计时间 |
|---|---|---|---|
| 1.1 | 创建项目结构和 VS 解决方案 | P0 | 2h |
| 1.2 | 配置 MASM 构建规则 (.props, .vcxproj) | P0 | 2h |
| 1.3 | 实现 engine_types.h 公共类型 |
P0 | 1h |
| 1.4 | 实现 string_ops.asm (memcpy/memset/strlen) |
P0 | 4h |
| 1.5 | 实现 memory.asm 对齐分配器 |
P0 | 3h |
| 1.6 | 实现 profiling.asm 计时器 |
P0 | 2h |
Phase 2: 数学库 (Week 1-2)
| 序号 | 任务 | 优先级 | 预计时间 |
|---|---|---|---|
| 2.1 | math.asm — Vec2 基础操作 |
P0 | 3h |
| 2.2 | math.asm — Vec3 基础操作 |
P0 | 3h |
| 2.3 | math.asm — Vec4 基础操作 |
P0 | 2h |
| 2.4 | math.asm — Mat4 基础操作 (identity, multiply) |
P0 | 6h |
| 2.5 | math.asm — Mat4 高级操作 (inverse, look_at, perspective) |
P1 | 8h |
| 2.6 | math.asm — Quat 操作 |
P1 | 4h |
| 2.7 | C 端头文件 asm_math.h |
P0 | 2h |
Phase 3: 核心框架 (Week 2-3)
| 序号 | 任务 | 优先级 | 预计时间 |
|---|---|---|---|
| 3.1 | platform.c — Win32 窗口管理 |
P0 | 6h |
| 3.2 | engine.c — 主循环和初始化 |
P0 | 4h |
| 3.3 | dx11_device.c — DirectX 11 设备初始化 |
P0 | 6h |
| 3.4 | renderer.c — 基础渲染管线 |
P0 | 8h |
| 3.5 | shader.c — 着色器管理 |
P1 | 4h |
| 3.6 | mesh.c — 网格和顶点缓冲 |
P1 | 4h |
Phase 4: 游戏系统 (Week 3-4)
| 序号 | 任务 | 优先级 | 预计时间 |
|---|---|---|---|
| 4.1 | ecs.c — 实体组件系统核心 |
P0 | 8h |
| 4.2 | physics.c — 物理系统 (调用 ASM math) |
P1 | 6h |
| 4.3 | collision.c — 碰撞检测 |
P1 | 6h |
| 4.4 | scene.c — 场景图管理 |
P1 | 4h |
| 4.5 | resource_manager.c — 资源加载 |
P2 | 4h |
| 4.6 | audio.c — XAudio2 音频 |
P2 | 6h |
| 4.7 | ui.c — UI 系统 |
P2 | 6h |
| 4.8 | scripting.c — Lua 绑定 |
P2 | 4h |
Phase 5: 演示和优化 (Week 4-5)
| 序号 | 任务 | 优先级 | 预计时间 |
|---|---|---|---|
| 5.1 | Demo/main.c — 主入口 |
P0 | 2h |
| 5.2 | Demo/demo_scene.c — 演示场景 |
P1 | 6h |
| 5.3 | SIMD 性能基准测试 | P1 | 4h |
| 5.4 | 集成测试和调试 | P0 | 8h |
总预计工时: ~150 小时 (约 4-5 周)
6. 文件统计
| 类别 | 文件数 | 说明 |
|---|---|---|
| ASM (.asm) | 4 | 核心热路径 |
| ASM include (.inc) | 1 | ASM 函数声明 |
| C 头文件 (.h) | 19 | 包含公共类型和模块头文件 |
| C 源文件 (.c) | 30 | 所有模块实现 |
| VS 项目文件 | 3 | .sln, .vcxproj, .props |
| 文档 | 1 | 本设计文档 |
| 预编译库 (.lib) | 3 | lua54, d3d11, d3dcompiler |
| 总计 | 61 | — |
按模块分布
ASM 核心: 4 文件 (math, memory, string_ops, profiling)
C 核心: 6 文件 (engine, platform, logger)
C 渲染: 8 文件 (renderer, dx11_device, shader, mesh)
C ECS: 6 文件 (ecs, component_registry, system_manager)
C 物理: 4 文件 (physics, collision)
C 资源: 4 文件 (resource_manager, file_loader)
C 场景: 4 文件 (scene, scene_node)
C 音频: 4 文件 (audio, audio_source)
C UI: 4 文件 (ui, ui_widget)
C 脚本: 4 文件 (scripting, lua_bindgen)
头文件: 19 文件 (含 asm_*.h 和模块 .h)
构建/文档: 7 文件 (VS 项目, 设计文档, 库文件)
7. 性能预期
| 操作 | 纯 C | ASM (SSE4.1) | ASM (AVX2) | 加速比 |
|---|---|---|---|---|
| Vec4 Dot | ~12 ns | ~3 ns | ~2 ns | 4-6x |
| Mat4 Multiply | ~80 ns | ~25 ns | ~12 ns | 4-7x |
| Mat4 Inverse | ~500 ns | ~150 ns | ~80 ns | 3-6x |
| Quat Multiply | ~25 ns | ~8 ns | ~5 ns | 3-5x |
| memcpy 1KB | ~200 ns | ~40 ns | ~30 ns | 5-7x |
| memset 1KB | ~180 ns | ~35 ns | ~25 ns | 5-7x |
注意: 实际性能取决于 CPU 微架构、缓存状态和数据对齐情况。
8. 关键设计决策
- 调用约定: 严格遵循 Windows x64 ABI, 确保 ASM/C 无缝互操作
- 内存对齐: 所有 SIMD 数据使用 16/32 字节对齐, 通过自定义分配器保证
- 寄存器保存: ASM 函数正确保存非易失寄存器 (RBX, RBP, RDI, RSI, R12-R15, XMM6-15)
- 错误处理: ASM 函数通过返回值 (0/-1 或 NULL) 表示失败, C 端检查
- 调试支持: 使用 /Zi 编译, 生成符号信息, 支持 VS 调试器单步进入 ASM
- 可移植性: ASM 文件仅用于 x86-64 Windows, C 代码可条件编译到其他平台