build_win.bat

cross platform rendering playground

build_win.bat

12.4 KB
@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