diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 223bd4b9f1..f7a40a1260 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -100,8 +100,12 @@ cmake --build ./build/ALL --target PREPARE_AIO # Prepare shaders only (useful for CI shader validation) cmake --build ./build/ALL --target prepare_shaders -# Copy shaders to deployment directories (when AUTO_PLUGIN_DEPLOYMENT=ON) -cmake --build ./build/ALL --target COPY_SHADERS +# Fast shader-only deployment (no DLL build, no tests - for dev iteration) +# See docs/development/shader-workflow.md for details +cmake --build ./build/ALL-WITH-AUTO-DEPLOYMENT --target COPY_SHADERS + +# Full deployment with DLL build and tests +cmake --build ./build/ALL-WITH-AUTO-DEPLOYMENT --target DEPLOY_ALL # Create AIO zip package (when AIO_ZIP_TO_DIST=ON) cmake --build ./build/ALL --target AIO_ZIP_PACKAGE diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index c851a6ceff..b0033dc09e 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -99,6 +99,10 @@ globals::d3d::* // DirectX 11 device/context access ### Common Development Commands ```bash +# Fast shader deployment (dev iteration - no DLL build) +# See docs/development/shader-workflow.md and docs/development/vscode-setup.md +cmake --build ./build/ALL-WITH-AUTO-DEPLOYMENT --target COPY_SHADERS + # Shader validation (targeted testing recommended during development) cmake --build ./build/ALL --target prepare_shaders hlslkit-compile --shader-dir build/ALL/aio/Shaders/[specific-feature] --output-dir build/ShaderCache --config .github/configs/shader-validation.yaml diff --git a/CMakeLists.txt b/CMakeLists.txt index 89de3e8ea0..ebd439b090 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -283,6 +283,16 @@ string(TIMESTAMP UTC_NOW "%Y-%m-%dT%H-%MZ" UTC) # Set AIO directory path used by multiple targets below set(AIO_DIR "${CMAKE_CURRENT_BINARY_DIR}/aio") +# Robocopy wrapper for Windows incremental file copy (used by deployment targets) +if(WIN32) + set(ROBOCOPY_WRAPPER "${CMAKE_BINARY_DIR}/robocopy_wrapper.cmd") + file( + WRITE + ${ROBOCOPY_WRAPPER} + "@echo off\r\nrem Robocopy wrapper: forwards all args to robocopy and normalizes exit codes\r\nrobocopy %*\r\nset rc=%ERRORLEVEL%\r\nif %rc% GEQ 8 exit /b %rc%\r\nexit /b 0\r\n" + ) +endif() + # ####################################################################################################################### # # CMake install() infrastructure for manual packaging # ####################################################################################################################### @@ -539,14 +549,6 @@ endif() if(AUTO_PLUGIN_DEPLOYMENT) set(DEPLOY_TARGET_HASHES) if(WIN32) - # Write a small wrapper once at configure time to normalize robocopy exit codes. - set(ROBOCOPY_WRAPPER "${CMAKE_BINARY_DIR}/robocopy_wrapper.cmd") - file( - WRITE - ${ROBOCOPY_WRAPPER} - "@echo off\r\nrem Robocopy wrapper: forwards all args to robocopy and normalizes exit codes\r\nrobocopy %*\r\nset rc=%ERRORLEVEL%\r\nif %rc% GEQ 8 exit /b %rc%\r\nexit /b 0\r\n" - ) - foreach(DEPLOY_TARGET $ENV{CommunityShadersOutputDir}) message("Deploying AIO to ${DEPLOY_TARGET} (incremental)") @@ -600,9 +602,34 @@ if(AUTO_PLUGIN_DEPLOYMENT) list(APPEND DEPLOY_TARGET_HASHES ${DEPLOY_TARGET_HASH}_plugin.stamp) - # Incremental shader copy (only changed/new shader files are copied) + # Incremental shader-only copy for fast dev iteration + # Depends ONLY on copy_shaders.stamp (no DLL, no PREPARE_AIO) + add_custom_command( + OUTPUT ${DEPLOY_TARGET_HASH}_shaders_only.stamp + COMMAND + ${CMAKE_COMMAND} -E make_directory + "${DEPLOY_TARGET}/Shaders" + COMMAND + ${ROBOCOPY_WRAPPER} "${AIO_DIR}/Shaders" + "${DEPLOY_TARGET}/Shaders" "/E" "/COPY:DAT" "/XO" "/R:1" + "/W:1" "/NFL" "/NDL" "/NJH" "/NJS" + COMMAND + ${CMAKE_COMMAND} -E touch + ${DEPLOY_TARGET_HASH}_shaders_only.stamp + DEPENDS copy_shaders.stamp + COMMENT "Fast shader-only deploy to ${DEPLOY_TARGET}/Shaders" + ) + + list( + APPEND + SHADER_ONLY_HASHES + ${DEPLOY_TARGET_HASH}_shaders_only.stamp + ) + + # Full shader copy for packaging (includes PREPARE_AIO dependency) + # This ensures DLL is built and all AIO files are ready add_custom_command( - OUTPUT ${DEPLOY_TARGET_HASH}.stamp + OUTPUT ${DEPLOY_TARGET_HASH}_shaders_full.stamp COMMAND ${CMAKE_COMMAND} -E make_directory "${DEPLOY_TARGET}/Shaders" @@ -610,16 +637,22 @@ if(AUTO_PLUGIN_DEPLOYMENT) ${ROBOCOPY_WRAPPER} "${AIO_DIR}/Shaders" "${DEPLOY_TARGET}/Shaders" "/E" "/COPY:DAT" "/XO" "/R:1" "/W:1" "/NFL" "/NDL" "/NJH" "/NJS" - COMMAND ${CMAKE_COMMAND} -E touch ${DEPLOY_TARGET_HASH}.stamp + COMMAND + ${CMAKE_COMMAND} -E touch + ${DEPLOY_TARGET_HASH}_shaders_full.stamp DEPENDS copy_shaders.stamp ${CMAKE_CURRENT_BINARY_DIR}/prepare_aio.stamp COMMENT - "Incremental shader copy to ${DEPLOY_TARGET}/Shaders (robocopy-wrapper)" + "Full shader deploy to ${DEPLOY_TARGET}/Shaders (with PREPARE_AIO)" ) list(APPEND DEPLOY_TARGET_HASHES ${DEPLOY_TARGET_HASH}_deploy.stamp) - list(APPEND DEPLOY_TARGET_HASHES ${DEPLOY_TARGET_HASH}.stamp) + list( + APPEND + DEPLOY_TARGET_HASHES + ${DEPLOY_TARGET_HASH}_shaders_full.stamp + ) endforeach() else() # AUTO_PLUGIN_DEPLOYMENT is enabled but the host is not Windows. Do @@ -632,11 +665,21 @@ if(AUTO_PLUGIN_DEPLOYMENT) ) endif() + # Lightweight target for fast shader dev iteration + # Deploys ONLY shaders to game directory (no DLL build, no tests) add_custom_target( COPY_SHADERS + DEPENDS ${SHADER_ONLY_HASHES} + COMMENT "Fast shader-only deploy to game directory (no DLL, no tests)" + ) + + # Full deployment target for packaging/CI + # Builds DLL, prepares AIO, deploys everything, runs tests + add_custom_target( + DEPLOY_ALL ALL DEPENDS copy_shaders.stamp ${DEPLOY_TARGET_HASHES} - COMMENT "Prepare and copy AIO/shaders to CommunityShadersOutputDir" + COMMENT "Full deployment: DLL + shaders + all files to game directory" ) endif() @@ -891,8 +934,8 @@ if(BUILD_SHADER_TESTS) if(TARGET prepare_shaders) add_dependencies(prepare_shaders run_shader_tests) endif() - if(TARGET COPY_SHADERS) - add_dependencies(COPY_SHADERS run_shader_tests) + if(TARGET DEPLOY_ALL) + add_dependencies(DEPLOY_ALL run_shader_tests) endif() message( diff --git a/docs/development/README.md b/docs/development/README.md new file mode 100644 index 0000000000..532dbccf19 --- /dev/null +++ b/docs/development/README.md @@ -0,0 +1,35 @@ +# Development Documentation + +## Getting Started + +- **[VSCode Setup](./vscode-setup.md)** - IDE configuration, extensions, and auto-deploy +- **[Shader Workflow](./shader-workflow.md)** - Fast shader iteration and deployment + +## Quick Links + +### Common Tasks + +- **Fast shader deployment:** `cmake --build build/ALL-WITH-AUTO-DEPLOYMENT --target COPY_SHADERS` +- **Full build with deployment:** `.\BuildRelease.bat ALL-WITH-AUTO-DEPLOYMENT` +- **Run tests:** `cmake --build build/ALL --target run_shader_tests` + +### Build Presets + +- `ALL` - Standard build (no auto-deployment) +- `ALL-WITH-AUTO-DEPLOYMENT` - Build + deploy to game directory +- `Dev` - Fast iteration preset (recommended for development) + +See `CMakePresets.json` for all available presets. + +## Build Targets + +| Target | Builds DLL | Runs Tests | Copies Shaders | Use Case | +| ------------------ | ---------- | ---------- | -------------- | ---------------------- | +| `COPY_SHADERS` | ❌ | ❌ | ✅ | Fast shader iteration | +| `DEPLOY_ALL` | ✅ | ✅ | ✅ | Full deployment (auto) | +| `prepare_shaders` | ❌ | ✅ | ✅ (AIO only) | CI shader validation | +| `run_shader_tests` | ❌ | ✅ | ❌ | Test shaders only | + +## Contributing + +When adding new features or documentation, please keep development docs organized under `docs/development/`. diff --git a/docs/development/shader-workflow.md b/docs/development/shader-workflow.md new file mode 100644 index 0000000000..3d5179864b --- /dev/null +++ b/docs/development/shader-workflow.md @@ -0,0 +1,66 @@ +# Shader Development Workflow + +## Quick Reference + +```bash +# Fast shader-only deployment (recommended for dev iteration) +cmake --build build/ALL-WITH-AUTO-DEPLOYMENT --target COPY_SHADERS + +# Full deployment (DLL + tests + shaders) +cmake --build build/ALL-WITH-AUTO-DEPLOYMENT --target DEPLOY_ALL +``` + +## Overview + +Two deployment targets for different workflows: + +- **`COPY_SHADERS`** - Fast shader-only deployment (seconds) +- **`DEPLOY_ALL`** - Full build + tests + deployment (minutes) + +### Requirements + +- Must have `AUTO_PLUGIN_DEPLOYMENT=ON` in your CMake preset +- Must have `CommunityShadersOutputDir` environment variable set to your Skyrim directory + +### Usage + +#### Manual + +```bash +# Fast iteration: Only copy changed shaders to game directory +cmake --build build/ALL-WITH-AUTO-DEPLOYMENT --target COPY_SHADERS + +# Or in Visual Studio: Right-click "COPY_SHADERS" target -> Build + +# Full deployment (same as running cmake --build with no target): +cmake --build build/ALL-WITH-AUTO-DEPLOYMENT --target DEPLOY_ALL +``` + +#### Automatic (VSCode) + +You can configure VSCode to automatically deploy shaders when you save `.hlsl` or `.hlsli` files using the [RunOnSave](https://marketplace.visualstudio.com/items?itemName=emeraldwalk.RunOnSave) extension. + +**See [VSCode Setup](../development/vscode-setup.md) for complete configuration instructions.** + +### Prerequisites + +1. Run `cmake --preset ALL-WITH-AUTO-DEPLOYMENT` at least once to create build directory +2. Set `CommunityShadersOutputDir` environment variable to your Skyrim `Data` directory +3. Ensure `AUTO_PLUGIN_DEPLOYMENT=ON` in your CMake preset + +### What COPY_SHADERS does now + +1. ✅ Transforms shaders from source layout → game layout (via AIO staging) +2. ✅ Copies only changed shader files (incremental robocopy) +3. ✅ Deploys to `$CommunityShadersOutputDir/Shaders` +4. ❌ Does NOT build the DLL +5. ❌ Does NOT run shader tests +6. ❌ Does NOT deploy non-shader files + +### Target Comparison + +| Target | Builds DLL | Runs Tests | Copies Shaders | Use Case | +| ----------------- | ---------- | ---------- | -------------- | --------------------- | +| `COPY_SHADERS` | ❌ | ❌ | ✅ | Fast shader iteration | +| `DEPLOY_ALL` | ✅ | ✅ | ✅ | Full deployment | +| `prepare_shaders` | ❌ | ✅ | ✅ (AIO only) | CI validation | diff --git a/docs/development/vscode-setup.md b/docs/development/vscode-setup.md new file mode 100644 index 0000000000..4d268eea56 --- /dev/null +++ b/docs/development/vscode-setup.md @@ -0,0 +1,84 @@ +# VSCode Development Setup + +## Quick Start + +1. Install recommended extensions +2. Configure auto-deploy (optional) + +## Recommended Extensions + +### Required for Shader Development + +- **HLSL Tools** (`TimGJones.hlsltools`) + - Syntax highlighting and IntelliSense for HLSL +- **CMake Tools** (`ms-vscode.cmake-tools`) + - Build system integration + +### Optional for Productivity + +- **Run On Save** (`emeraldwalk.RunOnSave`) + - Auto-deploy shaders when saving files + - See configuration below + +## Auto-Deploy on Save (Optional) + +Automatically deploy shaders when you save `.hlsl` or `.hlsli` files. + +**Setup:** + +1. Install extension: `ext install emeraldwalk.RunOnSave` +2. Create `.vscode/settings.json` in the repository root (if it doesn't exist) +3. **Add the following** to your `.vscode/settings.json`: + ```json + { + "emeraldwalk.runonsave": { + "commands": [ + { + "match": "\\.(hlsl|hlsli)$", + "notMatch": "[\\\\\\/](build|extern|dist|Tests)[\\\\\\/]", + "isAsync": true, + "cmd": "cmake --build ${workspaceFolder}/build/ALL-WITH-AUTO-DEPLOYMENT --target COPY_SHADERS", + "runIn": "terminal", + "runningStatusMessage": "Deploying shaders...", + "finishStatusMessage": "Shaders deployed!" + } + ] + } + } + ``` +4. Run `cmake --preset ALL-WITH-AUTO-DEPLOYMENT` once to create the build directory +5. Save any shader → Auto-deploys in seconds! + +**Note:** If the build directory doesn't exist, you'll see an error in the terminal. Just run the preset command and try again. + +**How it works:** + +- Triggers `COPY_SHADERS` target on shader file saves +- Only copies shaders (no DLL build, no tests) +- Excludes build artifacts and test files +- Shows status messages in VSCode + +**Interaction with built-in filewatcher:** + +Community Shaders has a built-in filewatcher (**Settings → Advanced → Shader Compilation → Enable File Watcher**) that hot-reloads shaders when files change in the game's `Data/Shaders/` directory. The workflow is: + +1. Edit shader in VSCode +2. Save → RunOnSave deploys to `Data/Shaders/` +3. Built-in filewatcher detects change → Recompiles shader in-game +4. See results immediately without restarting Skyrim! + +This provides near-instant iteration: edit → save → see changes in seconds. + +**To disable auto-deploy:** Remove or comment out the `emeraldwalk.runonsave` section in your local `.vscode/settings.json` + +## Customization + +Your `.vscode/settings.json` is gitignored, so you can customize it without affecting other developers: + +- Adjust auto-deploy behavior +- Add your own file associations +- Configure workspace-specific settings + +## See Also + +- [Shader Development Workflow](./shader-workflow.md) - Manual and automated shader deployment