@echo off
setlocal enabledelayedexpansion
cd /D "%~dp0"
:: --- Usage ------------------------------------------------------------------
::
:: build_win.bat [example] [-r] [-c]
::
:: example Name under src\backend\conformance\ (e.g. triangle). Builds
:: src\backend\conformance\<example> with core + backend only.
:: Default (no example): full renderer build.
:: -r Release build (default is Debug)
:: -c Clean build (delete everything first)
:: --- Unpack Arguments -------------------------------------------------------
set build_type=debug
set clean_build=0
set example=
:parse_args
if "%~1"=="" goto :args_done
if /i "%~1"=="-r" set build_type=release && shift && goto :parse_args
if /i "%~1"=="-c" set clean_build=1 && shift && goto :parse_args
if /i "%~1"=="release" set build_type=release && shift && goto :parse_args
if /i "%~1"=="debug" set build_type=debug && shift && goto :parse_args
call :normalize_example "%~1"
shift
goto :parse_args
:args_done
if defined example (
echo [%build_type% vulkan build: %example%]
) else (
echo [%build_type% build]
)
:: --- Find VS Toolchain ------------------------------------------------------
for /f "usebackq tokens=*" %%i in (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath`) do set "VS_PATH=%%i"
if not defined VS_PATH echo ERROR: Visual Studio installation not found && exit /b 1
call "%VS_PATH%\VC\Auxiliary\Build\vcvarsall.bat" x64 >nul 2>&1 || exit /b 1
:: --- Vulkan SDK -------------------------------------------------------------
if not defined VULKAN_SDK (
echo ERROR: VULKAN_SDK environment variable not set.
exit /b 1
)
:: --- Project Paths ----------------------------------------------------------
set ROOT=%~dp0
set BUILD=%ROOT%build
set OBJ=%BUILD%\obj
set DEPS=%BUILD%\_deps
set SLANG_DIR=%DEPS%\slang-src
set EXAMPLES_DIR=%ROOT%src\backend\conformance\
:: --- Example mode (positional arg): build src\backend\conformance\<example>
:: --- with core + backend only, instead of the full renderer ------------------
if defined example (
if "!EXAMPLES_DIR:~-1!"=="\" set "EXAMPLES_DIR=!EXAMPLES_DIR:~0,-1!"
set "EXAMPLE_SRC=!EXAMPLES_DIR!\!example!\!example!.cpp"
if not exist "!EXAMPLE_SRC!" (
echo [error: no such example: !example! ^(expected !EXAMPLE_SRC!^)]
exit /b 1
)
set "OBJ=%BUILD%\obj-ex-!example!"
)
:: --- Download Slang (binary SDK) --------------------------------------------
if not exist "%SLANG_DIR%\lib\slang.lib" (
echo [downloading slang]
if not exist "%SLANG_DIR%" mkdir "%SLANG_DIR%"
powershell -Command "& {param($u,$d); [System.Net.WebClient]::new().DownloadFile($u,$d)}" ^
-u "https://github.com/shader-slang/slang/releases/download/v2026.17.1/slang-2026.17.1-windows-x86_64.zip" ^
-d "%DEPS%\slang.zip" >nul 2>&1
powershell -Command "Expand-Archive -Path '%DEPS%\slang.zip' -DestinationPath '%DEPS%\slang_tmp' -Force" >nul 2>&1
xcopy /s /e /q /y "%DEPS%\slang_tmp\*" "%SLANG_DIR%\" >nul 2>&1
rmdir /s /q "%DEPS%\slang_tmp" >nul 2>&1
del "%DEPS%\slang.zip" >nul 2>&1
) else (
echo [slang already downloaded]
)
set SLANG_INCLUDE=/I"%SLANG_DIR%\include"
set SLANG_LIB=%SLANG_DIR%\lib\slang.lib
:: --- Clean ------------------------------------------------------------------
if "%clean_build%"=="1" (
if defined example (
echo [cleaning example build: %example%]
if exist "%OBJ%" rmdir /s /q "%OBJ%"
) else (
echo [cleaning build]
if exist "%BUILD%" rmdir /s /q "%BUILD%"
)
)
:: --- Prep Directories -------------------------------------------------------
if not exist "%OBJ%" mkdir "%OBJ%"
if not exist "%DEPS%" mkdir "%DEPS%"
:: --- Build Third-Party Dependencies -----------------------------------------
set KTX_BUILD_TYPE=RelWithDebInfo
if "%build_type%"=="debug" set KTX_BUILD_TYPE=Debug
:: glfw
if not exist "%BUILD%\glfw3.lib" (
echo [building glfw]
if not exist "%DEPS%\glfw" mkdir "%DEPS%\glfw"
cmake -G Ninja -S "%ROOT%third-party\glfw" -B "%DEPS%\glfw" ^
-DGLFW_BUILD_DOCS=OFF -DGLFW_BUILD_TESTS=OFF -DGLFW_BUILD_EXAMPLES=OFF ^
-DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=%KTX_BUILD_TYPE% >nul 2>&1 || exit /b 1
cmake --build "%DEPS%\glfw" --config %KTX_BUILD_TYPE% >nul 2>&1 || exit /b 1
copy "%DEPS%\glfw\src\glfw3.lib" "%BUILD%\glfw3.lib" >nul 2>&1
) else (
echo [glfw already built]
)
:: KTX-Software (examples don't link it — skip)
if defined example goto :skip_ktx
if not exist "%BUILD%\ktx.lib" (
echo [building ktx]
if not exist "%DEPS%\ktx" mkdir "%DEPS%\ktx"
cmake -G Ninja -S "%ROOT%third-party\KTX-Software" -B "%DEPS%\ktx" ^
-DKTX_FEATURE_TESTS=OFF -DKTX_FEATURE_TOOLS=OFF -DKTX_FEATURE_DOC=OFF ^
-DKTX_FEATURE_GL_UPLOAD=OFF -DKTX_FEATURE_VK_UPLOAD=OFF ^
-DKTX_FEATURE_LOADTEST_APPS=OFF -DCMAKE_BUILD_TYPE=%KTX_BUILD_TYPE% >nul 2>&1 || exit /b 1
cmake --build "%DEPS%\ktx" --config %KTX_BUILD_TYPE% >nul 2>&1 || exit /b 1
copy "%DEPS%\ktx\ktx.lib" "%BUILD%\ktx.lib" >nul 2>&1
copy "%DEPS%\ktx\ktx_read.lib" "%BUILD%\ktx_read.lib" >nul 2>&1
copy "%DEPS%\ktx\external\astc-encoder\Source\astcenc-avx2-static.lib" "%BUILD%\astcenc-avx2-static.lib" >nul 2>&1
) else (
echo [ktx already built]
)
:skip_ktx
:: ==== Compile Flags ====
set CL_COMMON=/nologo /FC /Z7 /EHsc /Zc:preprocessor /std:c++20 /permissive- ^
/DRHI_BACKEND_VULKAN /DENABLE_EDITOR /D_CRT_SECURE_NO_WARNINGS /DVK_NO_PROTOTYPES /DKHRONOS_STATIC ^
/DFMT_USE_CONSTEXPR=0 /DFMT_ENFORCE_COMPILE_STRING=0
set CL_INCLUDES=/I"%ROOT%src" /I"%ROOT%third-party" ^
/I"%ROOT%third-party\glfw\include" /I"%ROOT%third-party\VMA\include" ^
/I"%ROOT%third-party\plog\include" /I"%ROOT%third-party\imgui" ^
/I"%ROOT%third-party\imgui\backends" /I"%ROOT%third-party\rtm\includes" ^
/I"%ROOT%third-party\KTX-Software\include" ^
%SLANG_INCLUDE% /I"%VULKAN_SDK%\Include"
if "%build_type%"=="debug" (
set CL_FLAGS=/Od /Ob1 /MDd /D_DEBUG /DIMGUI_IMPL_VULKAN_USE_VOLK %CL_COMMON% %CL_INCLUDES%
set LD_DEBUG=/DEBUG
) else (
set CL_FLAGS=/O2 /MD /DNDEBUG /DIMGUI_IMPL_VULKAN_USE_VOLK %CL_COMMON% %CL_INCLUDES%
set LD_DEBUG=
)
:: ==== Source Files ====
set SRC=%ROOT%src
set TP=%ROOT%third-party
set CORE_SRC=^
%SRC%\core\arena.cpp ^
%SRC%\core\platform.cpp ^
%SRC%\core\math_rtm.cpp ^
%SRC%\core\logger.cpp
set BACKEND_SRC=^
%SRC%\backend\vulkan\context.cpp ^
%SRC%\backend\vulkan\swapchain.cpp ^
%SRC%\backend\vulkan\pipeline.cpp ^
%SRC%\backend\vulkan\descriptors.cpp ^
%SRC%\backend\vulkan\debug.cpp ^
%SRC%\backend\vulkan\query_pool.cpp ^
%SRC%\backend\vulkan\cmd_pool.cpp ^
%SRC%\backend\vulkan\cmd_buffer.cpp ^
%SRC%\backend\vulkan\allocator.cpp ^
%SRC%\backend\vulkan\queue.cpp ^
%SRC%\backend\vulkan\buffer.cpp ^
%SRC%\backend\vulkan\image.cpp ^
%SRC%\backend\vulkan\sampler.cpp ^
%SRC%\backend\vulkan\shader.cpp ^
%SRC%\backend\vulkan\accel_struct.cpp ^
%SRC%\backend\vulkan\vk_conversion.cpp ^
%SRC%\backend\vulkan\rhi_helpers.cpp
set SOURCES=^
%SRC%\renderer.cpp ^
%SRC%\quick_submit.cpp ^
%SRC%\pipelines.cpp ^
%SRC%\passes\fg.cpp ^
%SRC%\asset\asset.cpp ^
%SRC%\asset\texture.cpp ^
%SRC%\asset\gltf.cpp ^
%TP%\mikktspace.c ^
%SRC%\scene\scene.cpp ^
%SRC%\scene\ibl.cpp ^
%SRC%\passes\ssr\ssr.cpp ^
%SRC%\passes\depth_pre\depth_normal.cpp ^
%SRC%\passes\dispatch_mdi\build_indirect.cpp ^
%SRC%\passes\forward\forward.cpp ^
%SRC%\passes\fwd_cpu\fwd_cpu.cpp ^
%SRC%\passes\shadow\shadow.cpp ^
%SRC%\passes\grid\grid.cpp ^
%SRC%\passes\id_blit\id_blit.cpp ^
%SRC%\passes\fullscreen\fullscreen.cpp ^
%SRC%\passes\cluster\cluster_bounds.cpp ^
%SRC%\passes\cluster\light_cull.cpp ^
%SRC%\passes\hiz\hiz.cpp ^
%SRC%\passes\imgui\imgui.cpp ^
%SRC%\passes\skybox\skybox.cpp ^
%SRC%\passes\rt_build.cpp ^
%SRC%\passes\ddgi\ddgi_trace.cpp ^
%SRC%\passes\ddgi\ddgi_update.cpp ^
%SRC%\passes\ddgi\ddgi_classify.cpp ^
%SRC%\passes\ddgi\ddgi_relocate.cpp ^
%SRC%\passes\ddgi\ddgi_probes_dbg.cpp ^
%SRC%\passes\debug\debug_lines.cpp ^
%SRC%\editor\editor.cpp ^
%SRC%\editor\debug_draw.cpp ^
%SRC%\editor\frame.cpp ^
%SRC%\editor\gizmo.cpp ^
%SRC%\editor\style.cpp ^
%SRC%\editor\viewport.cpp ^
%SRC%\editor\log_viewer.cpp ^
%SRC%\editor\texture_viewer.cpp ^
%SRC%\editor\targets.cpp ^
%SRC%\editor\timings.cpp ^
%SRC%\editor\hierarchy.cpp ^
%SRC%\editor\inspector.cpp ^
%SRC%\backend\imgui_backend.cpp ^
%TP%\imgui\imgui.cpp ^
%TP%\imgui\imgui_draw.cpp ^
%TP%\imgui\imgui_tables.cpp ^
%TP%\imgui\imgui_widgets.cpp ^
%TP%\imgui\imgui_demo.cpp ^
%TP%\imgui\backends\imgui_impl_glfw.cpp
:: ==== Compile ====
echo [compiling]
pushd "%OBJ%"
if defined example goto :compile_example
cl /c /MP %CL_FLAGS% %CORE_SRC% %BACKEND_SRC% %SOURCES% 2>&1 | findstr /v "Microsoft (R) Copyright (C)" | findstr /v "^$"
:: imgui.obj collision: src\passes\imgui\imgui.cpp and third-party\imgui\imgui.cpp
:: both emit imgui.obj in this flat dir — rebuild with distinct names.
cl /c %CL_FLAGS% /Fo"%OBJ%\imgui_pass.obj" "%SRC%\passes\imgui\imgui.cpp" 2>&1 | findstr /v "Microsoft (R) Copyright (C)" | findstr /v "^$"
cl /c %CL_FLAGS% /Fo"%OBJ%\imgui_lib.obj" "%TP%\imgui\imgui.cpp" 2>&1 | findstr /v "Microsoft (R) Copyright (C)" | findstr /v "^$"
if exist "%OBJ%\imgui.obj" del "%OBJ%\imgui.obj"
:: stale objs from renamed/removed sources (link uses *.obj wildcard)
if exist "%OBJ%\descriptor_pool.obj" del "%OBJ%\descriptor_pool.obj"
if exist "%OBJ%\descriptor_set.obj" del "%OBJ%\descriptor_set.obj"
if exist "%OBJ%\imgui_impl_vulkan.obj" del "%OBJ%\imgui_impl_vulkan.obj"
del "%OBJ%\pass_*.obj" 2>nul
goto :compile_done
:compile_example
cl /c /MP %CL_FLAGS% "%EXAMPLE_SRC%" %CORE_SRC% %BACKEND_SRC% 2>&1 | findstr /v "Microsoft (R) Copyright (C)" | findstr /v "^$"
:compile_done
popd
:: ==== Link ====
echo [linking]
if defined example (
set LIBS="%VULKAN_SDK%\Lib\vulkan-1.lib" ^
"%BUILD%\glfw3.lib" "%SLANG_LIB%" ^
gdi32.lib user32.lib shell32.lib dwmapi.lib
set "OUT=%BUILD%\vk-%example%.exe"
) else (
set LIBS="%VULKAN_SDK%\Lib\vulkan-1.lib" ^
"%BUILD%\glfw3.lib" "%BUILD%\ktx.lib" "%BUILD%\ktx_read.lib" ^
"%BUILD%\astcenc-avx2-static.lib" "%SLANG_LIB%" ^
gdi32.lib user32.lib shell32.lib dwmapi.lib
set "OUT=%BUILD%\vk-renderer.exe"
)
cl %OBJ%\*.obj %LIBS% /link /MANIFEST:EMBED /INCREMENTAL:NO %LD_DEBUG% /OUT:"%OUT%" 2>&1 | findstr /v "Microsoft (R) Copyright (C)" | findstr /v "^$"
echo [done: %OUT%]
if defined example echo [run from repo root: %OUT%]
exit /b 0
:: --- Normalize example argument to a bare name ------------------------------
:: Accepts: triangle, triangle.cpp, triangle\triangle.cpp,
:: .\triangle\triangle.cpp, ./triangle/triangle.cpp, etc.
:normalize_example
set "raw=%~1"
set "norm=!raw:/=\!"
:strip_trailing
if not defined norm goto :normalize_done
if "!norm:~-1!"=="\" set "norm=!norm:~0,-1!" & goto :strip_trailing
if "!norm:~-2!"=="\." set "norm=!norm:~0,-2!" & goto :strip_trailing
:normalize_done
for %%A in ("!norm!") do set "example=%%~nA"
if not defined example set "example=!norm!"
goto :eof