# vulkan-compute-samples **Repository Path**: brt2/vulkan-compute-samples ## Basic Information - **Project Name**: vulkan-compute-samples - **Description**: MiniMax 实现的demo示例集 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-28 - **Last Updated**: 2026-07-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # vulkan-test · Vulkan Compute Pipeline 教程 一份跑在 Termux + 高通骁龙(Adreno 644 / Turnip)上的 Vulkan compute pipeline 教程。13 个 demo,前 9 个按"每章一个新 Vulkan 概念" 线性推进(base → 多 dispatch → shared → multi-buffer → specialization → push descriptor → subgroup → timeline → mini-GEMM 综合)。demo10-13 是"把 9 章汇起来做四个好玩的小应用",每个 demo 都自包含。 所有 demo 都针对真 GPU(Turnip)跑通;如果你的设备不一样, fallback 策略在每个 demo 的 README 里写明。 ## 学习路径 **前 9 个 demo** 是给 Vulkan compute 新手的入门,按 1 → 2 → ... → 9 顺序读。 每一个 demo 都会在前一个 demo 的基础上**只加一个新概念**(barrier → shared memory → multi-buffer → specialization → push descriptor → subgroup → timeline → 综合),不会一次性把所有特性塞进来。 **demo10-13** 是"前 9 章招式用一遍"的实战: - **demo10 Mandelbrot ASCII** —— 把 spec + push constant 用到 *渲染* - **demo11 Game of Life** —— shared memory halo + 100 代 ping-pong 演化 - **demo12 N-Queens** —— atomic + 多 submit + CPU↔GPU 速度对比 - **demo13 Monte Carlo π** —— subgroup reduce + multi-dispatch + sparkline 如果只想看某个具体概念,直接跳到对应章节即可——每个 demo 都能 独立编译、运行。 ## 章节索引 | # | 目录 | 新概念 | 验证 | |---|---|---|---| | 1 | [01-base-compute-pipeline](demos/01-base-compute-pipeline/README.md) | 整个 baseline:instance → device → SPIR-V → SSBO → dispatch → 读回 | `out[i] == (magic<<16) \| i` | | 2 | [02-multiple-dispatches-and-barriers](demos/02-multiple-dispatches-and-barriers/README.md) | 单 command buffer 内两个 dispatch + `vkCmdPipelineBarrier` | `values[i] == i+1` | | 3 | [03-shared-memory-reduction](demos/03-shared-memory-reduction/README.md) | workgroup-local shared memory + `barrier()` butterfly 规约 | 4 个 workgroup 输出 = 各分组和 | | 4 | [04-multi-buffer-descriptor-array](demos/04-multi-buffer-descriptor-array/README.md) | 描述符集绑定 3 个 SSBO,shader 端按 binding 索引 | `out[i] = A[i] + B[i]` | | 5 | [05-specialization-constants](demos/05-specialization-constants/README.md) | `VkSpecializationInfo` 传递编译期常量 | 两个 bound 各自对应累加和 | | 6 | [06-push-descriptors](demos/06-push-descriptors/README.md) | `VK_KHR_push_descriptor` 跳过 pool,inline 写 descriptor | `out[i] == in[i]`(不支持时 skip) | | 7 | [07-subgroups](demos/07-subgroups/README.md) | `gl_NumSubgroups`、`subgroupAdd`、`subgroupBroadcast` | `subgroupAdd(i)` 与按 `subgroupSize` 划分的预期值匹配 | | 8 | [08-async-compute-and-timeline-semaphores](demos/08-async-compute-and-timeline-semaphores/README.md) | `VK_KHR_timeline_semaphore`(1.2 core)跨 submit 同步 | `B[0] == sum(0..255) == 32640` | | 9 | [09-mini-gemm-capstone](demos/09-mini-gemm-capstone/README.md) | 综合 demo2~8:多 dispatch + barrier + shared + push + subgroup | 32×32 整数 GEMM 与 reference 完全一致 | | 10 | [10-mandelbrot-ascii](demos/10-mandelbrot-ascii/README.md) | 把 spec constant + push constant 串到 *渲染*:ANSI 半字符 80×24 像素画 | 集合内 + 逃逸都 > 0,证明 GPU 真算了一帧 | | 11 | [11-game-of-life](demos/11-game-of-life/README.md) | shared memory halo + 100 代 ping-pong + multi-dispatch 屏障 | GPU/CPU 演化 100 代后逐字节一致 | | 12 | [12-n-queens](demos/12-n-queens/README.md) | `vkCmdFillBuffer` 复位 + atomicAdd 拿 slot + 跳出库边界用 raw `VkCommandBuffer` | N=12 解数 == 14200 == CPU reference | | 13 | [13-pi-monte-carlo](demos/13-pi-monte-carlo/README.md) | `subgroupAdd` + `subgroupElect` 限频 + multi-dispatch 累积 + Unicode 块字符 sparkline | \|估计 - π\| < 0.001 | > demo6 和 demo9 用到 `VK_KHR_push_descriptor`。在 Turnip 上 instance > 层不一定暴露该扩展,demo6 选择 graceful skip(exit 0),demo9 > 回退到普通 descriptor set 继续跑。两条路径都不会让 ctest 失败。 ## 需要的 Termux 包 ```sh pkg install shaderc vulkan-headers spirv-headers cmake ``` `shaderc` 顺带拉入 `glslang`(提供 `glslangValidator`)和 `spirv-tools`。Vulkan loader 与 Turnip ICD 在设备上已自带。 可选:`pkg install vulkan-validation-layers`(让 `VKC_VALIDATION=1` 真能起作用)。 ## 构建与运行 ```sh cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build -j ctest --test-dir build --output-on-failure ``` 期望: ``` 100% tests passed, 0 tests failed out of 13 ``` 单独跑某个 demo: ```sh cmake --build build --target run-demo5 ./build/demos/05-specialization-constants/demo5 ``` 或直接用 ctest 跑单个 / 子集: ```sh ctest --test-dir build -R '^demo(10|11|12|13)$' --output-on-failure # 新加的 4 个 ctest --test-dir build -R '^demo5$' --output-on-failure # 单个 ``` 清理: ```sh rm -rf build ``` ## 文件结构 ``` . ├── CMakeLists.txt # 顶层:find_package(Vulkan) + add_subdirectory 每个 demo ├── cmake/DemoHelper.cmake # vulkan_add_demo() / vulkan_add_shader() ├── common/ │ └── vkcompute.hpp # RAII 公共库(每个 demo link `vkcompute` target) ├── README.md # 本文件:教程总览 + 章节索引 ├── CLAUDE.md # 环境 + 跨 demo 踩坑 + 库架构 + 新增 demo 流程 └── demos/ # 13 个 demo ├── 01-base-compute-pipeline/ ──┐ ├── 02-multiple-dispatches-and-barriers/│ ├── 03-shared-memory-reduction/ │ 9 章:每章一个新概念 ├── 04-multi-buffer-descriptor-array/ │ ├── 05-specialization-constants/ │ ├── 06-push-descriptors/ │ ├── 07-subgroups/ │ ├── 08-async-compute-and-timeline-semaphores/ │ ├── 09-mini-gemm-capstone/ ──┘ ├── 10-mandelbrot-ascii/ ──┐ ├── 11-game-of-life/ │ 4 个"实战" demo:把 9 章招式串起来 ├── 12-n-queens/ │ ├── 13-pi-monte-carlo/ ──┘ ``` 每个 demo 目录自包含: ``` demos/0N-xxx/ ├── CMakeLists.txt ├── README.md ├── src/main.cpp # C++ 主程序,使用 common/vkcompute.hpp └── shaders/*.comp ``` ## 代码组织 所有 demo 都用 C++17 + `common/vkcompute.hpp` 写。库把每个 demo 都一样 的样板(创建实例、给设备打分选设备、找 compute queue、分配 host-visible buffer、找内存类型、录制命令、submit + fence 等待、逆序销毁……)收进几 个 RAII 类,让 `main.cpp` 只剩"这一章真正在讲的部分": - `vkc::ComputeContext` — 拥有 instance / gpu / device / queue / 命令池; 构造函数一口气跑完"创建 → 选设备 → 创逻辑设备 → 创命令池"。 - `vkc::Buffer` — host-visible + host-coherent SSBO;`fill()` / `write()` / `read(fn)`。`read` 通过 map/unmap 的 lambda 完成,回调里把要保留的 值快照到栈上(Turnip 上 unmap 之后再读会 SIGSEGV)。 - `vkc::Pipeline` — 一条 compute pipeline 的全部对象(shader module + descriptor set layout + pipeline layout + pipeline,必要时还有 pool + set 或 push descriptor)。`PipelineDesc` 用聚合初始化配置: `spvPath / bindingCount / bindingDescriptorCounts / pushConstantBytes / pushDescriptor / spec / entryPoint`。 - `vkc::Recorder` — 录制期传给 lambda 的把手;`bind(pipe, {bufs})` / `pushConstants()` / `dispatch()` / `barrier()`。 `Recorder::handle()` 取裸 `VkCommandBuffer` 以便跳出库边界调用 `vkCmdFillBuffer` / `vkCmdPipelineBarrier` 等库未封装的原语 (demo12 用了这条路)。 - `vkc::TimelineSemaphore` + `vkc::CmdBuf` + `ctx.submit()` — demo8 拆开 `run()` 的"一次性 submit"便利,覆盖"多次 submit / 不同 wait/signal"。 - `vkc::verdict(pass, passMsg, failMsg)` — 统一打印 `"验证结果 : ..."`, 是 ctest 抓的成功契约。 > C 版(`src/main.c`)已被全部替换为 C++ 版。`common/vkcompute.hpp` > header-only + 公共 CMake INTERFACE target `vkcompute`,每个 demo 的 > CMakeLists 只剩一句 `target_link_libraries(demoX PRIVATE vkcompute)`。 ## 运行环境(验证于 2026-07-08) - **宿主机**:Termux on Android,内核 5.10,`aarch64-unknown-linux-android24` - **编译器**:clang 21.1.8(也自带 gcc) - **Vulkan loader**:`$PREFIX/lib/libvulkan.so.1.4.355` - **ICD #1**:`libvulkan_freedreno.so` → **Turnip Adreno (TM) 644** (Qualcomm 厂商 `0x5143`,设备 `0x6060201`,Vulkan 1.3) - **ICD #2**:`libvulkan_lvp.so` → llvmpipe(软件兜底) ## 阅读每个 demo 的格式 每个 demo 的 README.md 都按统一格式: 1. **本章新概念**:相对上一个 demo 的增量(一两句话) 2. **核心代码差异**:与 demo1 比,主机代码 / shader 改了哪些行 3. **预期输出**:在 Adreno 644 上跑出来的实际样例(含数字) 4. **踩坑**:当前 demo 的 Turnip 特有坑 5. **下一步**:指向下一个 demo `CLAUDE.md` 记录跨 demo 的公共坑(最经典的就是 Turnip 上 `vkUnmapMemory` 后 host 读会 SIGSEGV),以及"如何新增一个 demo" 的完整流程——是给维护者看的开发文档。