Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,15 @@ if(TARGET ggml-vulkan)
target_link_libraries(trellis_core PUBLIC ggml-vulkan)
message(STATUS "trellis.cpp: Vulkan backend enabled")
endif()
if(TARGET ggml-metal)
# macOS/Apple Silicon: ggml's Metal backend (GGML_METAL defaults ON for
# Apple builds). The generic device-enumeration path in make_backend() picks
# the Metal GPU automatically; the two custom kernels (deform_conv,
# decimate_qem) run their CPU fallbacks on this backend.
set(TRELLIS_BUILD_BACKEND "metal")
target_link_libraries(trellis_core PUBLIC ggml-metal)
message(STATUS "trellis.cpp: Metal backend enabled")
endif()
if(TARGET ggml-hip)
set(TRELLIS_BUILD_BACKEND "hip")
target_link_libraries(trellis_core PUBLIC ggml-hip)
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,12 @@ On Strix Halo, Vulkan is the fastest backend: ROCm requires
`GGML_CUDA_DISABLE_GRAPHS=1` (ggml's HIP graph capture stalls on these graphs)
and still trails Vulkan by 10–40 %.

**Apple Silicon (Metal):** verified end-to-end on an Apple M5 (24 GB unified):
res-512 image → textured GLB in **9:21** with a **5.6 GB** peak RSS, all
neural stages on Metal (2.4M decoded voxels, 4.8M-face raw mesh). bfloat16 and
f16 tensor APIs are available from M2 on; on M1 use `TRELLIS_FA_FAST=1`
(f16 K/V) since the default FlashAttention path casts K/V to bf16.

## Tools

| tool | purpose |
Expand All @@ -255,9 +261,15 @@ GGML is vendored in `thirdparty/ggml`. Pick a backend:
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DGGML_VULKAN=ON # Vulkan
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DGGML_CUDA=ON # CUDA
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DGGML_HIP=ON # ROCm
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release # macOS: Metal (auto)
cmake --build build -j
```

On **macOS/Apple Silicon** no backend flag is needed — ggml's Metal backend
defaults ON for Apple builds and the generic device selection picks the GPU.
The two custom kernels (BiRefNet deformable conv, QEM decimation) run their
CPU fallbacks there.

See `.github/workflows/release.yml` for the exact flags the release binaries use
(GPU target lists, `-DGGML_OPENMP=OFF` on Windows). Releases also include a
`cuda12` variant built with CUDA 12.9 for Pascal/Volta GPUs (compute capability
Expand Down
2 changes: 1 addition & 1 deletion src/smoke_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ int main(int argc, char** argv) {
const std::string path = argv[1];
const int gpu = argc > 2 ? atoi(argv[2]) : 0;

printf("loading %s on %s\n", path.c_str(), gpu >= 0 ? "CUDA" : "CPU");
printf("loading %s on %s\n", path.c_str(), gpu >= 0 ? "GPU" : "CPU");
trellis::Model m = trellis::Model::load(path, gpu);

printf("arch : %s\n", m.arch.c_str());
Expand Down
13 changes: 12 additions & 1 deletion src/ss_decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,19 @@ static T* conv3d(ggml_context* c, const Model& m, const std::string& p, T* x, in
T* w = m.get(p + ".weight");
const int k = (int)w->ne[0];
const int pad = (k - 1) / 2;
T* y = ggml_conv_3d(c, w, x, IC, 1, 1, 1, pad, pad, pad, 1, 1, 1); // [s0,s1,s2,OC]
const int64_t OC = w->ne[3] / IC;
#ifdef __APPLE__
// ggml_conv_3d lowers to IM2COL_3D + GEMM; the Metal backend implements
// the direct CONV_3D op but not IM2COL_3D, and trellis.cpp runs whole
// graphs on one backend (no sched fallback) — so the im2col lowering
// aborts on Apple GPUs. Same math, same [k,k,k,IC*OC] / [W,H,D,C]
// layouts via the direct op; non-Apple backends keep the validated
// im2col path.
T* y = ggml_conv_3d_direct(c, w, x, 1, 1, 1, pad, pad, pad, 1, 1, 1,
IC, /*n_batch=*/1, (int)OC); // [s0,s1,s2,OC]
#else
T* y = ggml_conv_3d(c, w, x, IC, 1, 1, 1, pad, pad, pad, 1, 1, 1); // [s0,s1,s2,OC]
#endif
T* b = ggml_reshape_4d(c, m.get(p + ".bias"), 1, 1, 1, OC);
return ggml_add(c, y, b);
}
Expand Down