Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
219 lines (190 loc) Β· 10.6 KB
/
Copy pathMakefile
File metadata and controls
219 lines (190 loc) Β· 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# Blender β WebAssembly build orchestration.
#
# Reproducible from scratch: make all
# Target MVP: headless Cycles CPU rendering in the browser, then scene
# loading/manipulation, then GUI (WebGL2). WebGPU backend is out of scope for now.
#
# Emscripten decisions baked in here:
# * pthreads enabled (-pthread, requires COOP/COEP on the web server)
# * WASMFS + preload for assets (-sWASMFS, --preload-file)
# * NO JSPI (avoid -sASYNCIFY/JSPI unless forced)
# * OffscreenCanvas (-sOFFSCREENCANVAS_SUPPORT)
ROOT := $(CURDIR)
BLENDER_URL := https://github.com/HeyPuter/blender
BLENDER_REF := 6b031d3d41c392883e3c495aa72343e10d15b43d
# NOTE: ':=' (not '?=') so a stale exported EMSDK in the environment cannot
# point us at the wrong tree. Command-line `make EMSDK=...` still overrides.
EMSDK := $(ROOT)/emsdk
EMSDK_VERSION := 6.0.1
# --- emscripten toolchain handles ------------------------------------------
EM_BIN := $(EMSDK)/upstream/emscripten
EMCC := $(EM_BIN)/emcc
EMXX := $(EM_BIN)/em++
EMCMAKE := $(EM_BIN)/emcmake
EMMAKE := $(EM_BIN)/emmake
EM_TOOLCHAIN := $(EM_BIN)/cmake/Modules/Platform/Emscripten.cmake
# `emcmake cmake ...` needs emcc/em++/emcmake on PATH. Sourcing emsdk_env.sh is
# unreliable when a stale EMSDK is already exported in the environment, so just
# prepend the toolchain bindir directly (emcc finds node via its own config).
EM_ENV := export PATH="$(EM_BIN):$$PATH";
# --- layout (keep comments off these lines: trailing spaces leak into values) -
# SYSROOT : install prefix for cross-compiled deps
# DEPS : dep sources + build trees
# BUILD_CYCLES : cmake build dir for cycles standalone
# WEB : html/js harness + final artifacts
SYSROOT := $(ROOT)/wasm-sysroot
DEPS := $(ROOT)/deps
BUILD_CYCLES := $(ROOT)/build-cycles
WEB := $(ROOT)/web
NPROC := $(shell nproc)
# --- common compile flags for every wasm object (deps + blender) -----------
# Keep these identical across all libraries or linking will fail: pthreads,
# exceptions and SIMD must agree. SSE4.2 intrinsics are emulated onto wasm SIMD.
WASM_CFLAGS := -O2 -pthread -msimd128 -msse4.2 -fexceptions
WASM_CXXFLAGS := $(WASM_CFLAGS)
.PHONY: all mvp toolchain blender blender-assets deps configure-cycles cycles cycles-web configure-blender blender-web verify-blender-webgpu web smoke serve verify verify-render verify-webgpu clean-build print-env
all: toolchain blender
# One command, from scratch, to the headless-Cycles-CPU-render MVP: toolchain β
# source β patches β deps β build β web relink β Playwright render verification.
mvp: cycles-web verify-render
# ---------------------------------------------------------------------------
# Toolchain: local, patchable emsdk pinned to $(EMSDK_VERSION).
# ---------------------------------------------------------------------------
toolchain: $(EMCC)
$(EMCC):
@if [ ! -x "$(EMSDK)/emsdk" ]; then \
echo ">> cloning emsdk -> $(EMSDK)"; \
git clone https://github.com/emscripten-core/emsdk.git "$(EMSDK)"; \
fi
cd "$(EMSDK)" && ./emsdk install $(EMSDK_VERSION) && ./emsdk activate $(EMSDK_VERSION)
# >> patch emsdk here if needed <<
@test -x "$(EMCC)" && echo ">> emcc ready: $(EMCC)"
print-env:
@echo "EMSDK=$(EMSDK)"; "$(EMCC)" --version | head -1
# ---------------------------------------------------------------------------
# Blender source (pinned fork ref).
# ---------------------------------------------------------------------------
blender: blender/.git
blender/.git:
git init -q blender
git -C blender remote add origin $(BLENDER_URL) 2>/dev/null || true
GIT_LFS_SKIP_SMUDGE=1 git -C blender fetch --depth 1 origin $(BLENDER_REF)
# Skip LFS smudge on checkout: the fork's GitHub LFS storage does NOT host the
# LFS objects (forks don't inherit LFS), so smudging every pointer 404s and
# aborts the checkout. Check out pointers; the real objects are pulled from
# upstream by content hash in `blender-assets` below.
GIT_LFS_SKIP_SMUDGE=1 git -C blender checkout -q --detach FETCH_HEAD
@echo ">> blender at $$(git -C blender rev-parse --short HEAD)"
# Git-LFS datafiles (startup.blend, fonts, icons, colormanagement, studiolights)
# needed by the FULL Blender build. The GitHub fork's LFS storage does NOT host
# them (all objects 404), so pull from upstream projects.blender.org β which
# DOES serve them anonymously, but ONLY if we tell git-lfs the endpoint needs no
# auth via `lfs.<url>.access none`. Without that, git-lfs demands credentials
# and fails in CI (this was the missing piece). The checkout above skips smudge,
# so the pointers are materialized here.
# (The essentials `assets/brushes/**` blends are vendored in-repo β demo/brush-
# assets/ β and bundled by scripts/link_blender_release.sh, so they need no LFS.)
BLENDER_LFS_URL := https://projects.blender.org/blender/blender.git/info/lfs
blender-assets: blender
cd blender && git lfs install --local 2>/dev/null || true
cd blender && git config lfs.url "$(BLENDER_LFS_URL)"
cd blender && git config "lfs.$(BLENDER_LFS_URL).access" none
cd blender && GIT_TERMINAL_PROMPT=0 git lfs pull --include="release/datafiles/**"
@echo ">> release/datafiles LFS pulled ($$(du -sh blender/release/datafiles | cut -f1))"
# ---------------------------------------------------------------------------
# Dependencies β $(SYSROOT). Built by per-dep scripts/build_<dep>.sh sharing
# scripts/dep_common.sh; all use the same ABI flags (pthreads/exceptions) so
# they link together. `make deps` runs them in dependency-ordered waves.
# Full set: zlib fmt imath zstd jpeg png libdeflate robinmap openjph openexr
# tbb yamlcpp expat pystring minizip ocio oiio
# ---------------------------------------------------------------------------
deps: toolchain
bash scripts/build_all_deps.sh
# Build (or rebuild) a single dependency, e.g. make dep-oiio
dep-%: toolchain
bash scripts/build_$*.sh
# ---------------------------------------------------------------------------
# Cycles standalone (headless CPU renderer).
# ---------------------------------------------------------------------------
# NOTE: the WASM source patches (host-tool codegen, makesdna alignment, sizeof
# asserts, etc.) are now committed in the fork and pulled by `make blender`, so
# there is no separate patch step.
# Cycles objects must be built with -pthread (enables atomics/bulk-memory) to
# match the deps and allow the shared-memory (pthreads) link. NOT -msimd128: it
# makes OpenImageIO's simd.h take an x86 SSE-intrinsic path (__m128i) that fails
# on wasm. Cycles' own kernel files add per-file SIMD flags as needed. Plus the
# wasm compat shim (uint/ushort).
WASM_COMPAT := -pthread -fexceptions -include $(ROOT)/cmake/wasm_compat.h
configure-cycles: toolchain blender deps
$(EM_ENV) "$(EMCMAKE)" cmake -S blender -B $(BUILD_CYCLES) -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH="$(SYSROOT)" \
-DCMAKE_FIND_ROOT_PATH="$(SYSROOT)" \
-DCMAKE_C_FLAGS="$(WASM_COMPAT)" \
-DCMAKE_CXX_FLAGS="$(WASM_COMPAT)" \
-C $(ROOT)/cmake/cycles-wasm-cache.cmake
# Build the cycles standalone wasm module (CMake links a non-web bin/cycles.js).
cycles: configure-cycles
$(EM_ENV) ninja -C $(BUILD_CYCLES) cycles
# Relink the module with web-ready flags β web/cycles.{js,wasm,data}.
cycles-web: cycles
bash scripts/link_cycles_web.sh
# ---------------------------------------------------------------------------
# Full Blender (WITH_BLENDER=ON) β WASM. In progress; gates the WebGPU backend
# and .blend loading. Needs CPython (make dep-python) + the dep stack + LFS
# datafiles. Host codegen tools (makesdna/makesrna/datatoc/shader_tool) run via
# node (wiring committed in the fork). Build dir: build-blender.
# ---------------------------------------------------------------------------
configure-blender: toolchain blender blender-assets deps dep-python
bash scripts/build_shader_tool_native.sh # native codegen tool (wasm one is buggy)
$(EM_ENV) "$(EMCMAKE)" cmake -S blender -B build-blender -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH="$(SYSROOT)" -DCMAKE_FIND_ROOT_PATH="$(SYSROOT)" \
-DCMAKE_C_FLAGS="-pthread -fexceptions $(WASM_COMPAT)" \
-DCMAKE_CXX_FLAGS="-pthread -fexceptions $(WASM_COMPAT)" \
-DWITH_WEBGPU_BACKEND=ON \
-C $(ROOT)/cmake/blender-wasm-cache.cmake
# ---------------------------------------------------------------------------
# Full Blender β browser (WebGPU). Web-relink the built blender objects with
# WASMFS + asset preload + web environment, then verify in chromium+SwiftShader
# that the render pipeline acquires a REAL WebGPU device handed in from JS.
# (EEVEE pixels need the rest of the WebGPU backend; this proves the device path.)
# ---------------------------------------------------------------------------
blender-web:
bash scripts/link_blender_web.sh
verify-blender-webgpu: blender-web
node scripts/verify_blender_webgpu.mjs
# ---------------------------------------------------------------------------
# Toolchain smoke test: pthreads + SIMD β canvas, proven via Playwright.
# ---------------------------------------------------------------------------
SMOKE_FLAGS := -O2 -pthread -msimd128 -msse4.2 -sPTHREAD_POOL_SIZE=8 \
-sWASMFS -sOFFSCREENCANVAS_SUPPORT -sALLOW_MEMORY_GROWTH=1 \
-sEXPORTED_RUNTIME_METHODS=ccall,cwrap,HEAPU8 \
-sEXPORTED_FUNCTIONS=_render,_img_w,_img_h,_main,_malloc
smoke: toolchain
$(EM_ENV) "$(EMCC)" smoke/smoke.c -o $(WEB)/smoke.js $(SMOKE_FLAGS)
serve:
node scripts/serve.mjs $(WEB) 8080
# Playwright verification. Defaults to the smoke page; override:
# make verify PAGE=render.html TITLE="RENDER OK"
PAGE ?= smoke.html
TITLE ?= SMOKE OK
verify:
node scripts/verify.mjs $(PAGE) "$(TITLE)"
# Verify the headless Cycles CPU render in-browser (screenshots web/verify-shot.png).
verify-render:
node scripts/verify.mjs render.html "RENDER OK"
# WebGPU availability checks (uses the FULL chromium build + bundled SwiftShader
# software Vulkan ICD β there is no GPU on the box). (1) browser JS compute,
# (2) wasmβWebGPU compute via emdawnwebgpu, NO JSPI. De-risks the EEVEE/WebGPU plan.
verify-webgpu: web/wgpu_compute.js web/wgpu_triangle.js
node scripts/verify_webgpu.mjs webgpu-probe.html "WEBGPU OK"
node scripts/verify_webgpu.mjs wgpu-wasm.html "WGPU WASM OK"
node scripts/verify_webgpu.mjs wgpu-tri.html "WGPU TRI OK"
WGPU_PROBE_FLAGS := --use-port=emdawnwebgpu -sASYNCIFY=0 -sASSERTIONS=1 -O2 -sENVIRONMENT=web
web/wgpu_compute.js: smoke/wgpu_compute.c toolchain
$(EM_ENV) "$(EMCC)" smoke/wgpu_compute.c -o $@ $(WGPU_PROBE_FLAGS)
web/wgpu_triangle.js: smoke/wgpu_triangle.c toolchain
$(EM_ENV) "$(EMCC)" smoke/wgpu_triangle.c -o $@ $(WGPU_PROBE_FLAGS)
clean-build:
rm -rf $(BUILD_CYCLES)