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
8 changes: 6 additions & 2 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
75 changes: 59 additions & 16 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
# #######################################################################################################################
Expand Down Expand Up @@ -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)")

Expand Down Expand Up @@ -600,26 +602,57 @@ 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"
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}.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
Expand All @@ -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()

Expand Down Expand Up @@ -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(
Expand Down
35 changes: 35 additions & 0 deletions docs/development/README.md
Original file line number Diff line number Diff line change
@@ -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.
Comment on lines +19 to +22

Copilot AI Jan 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This "Build Presets" section calls out an ALL-WITH-AUTO-DEPLOYMENT preset and then says to "See CMakePresets.json for all available presets", but that file does not define an ALL-WITH-AUTO-DEPLOYMENT build preset (the only reference is a configure preset in CMakeUserPresets.json.template). To avoid confusing new contributors, it would be better to either (a) explicitly mention that ALL-WITH-AUTO-DEPLOYMENT comes from a user CMakeUserPresets file, or (b) adjust the wording so this section and the file reference accurately reflect where each preset is defined.

Suggested change
- `ALL-WITH-AUTO-DEPLOYMENT` - Build + deploy to game directory
- `Dev` - Fast iteration preset (recommended for development)
See `CMakePresets.json` for all available presets.
- `ALL-WITH-AUTO-DEPLOYMENT` - Build + deploy to game directory (defined in user `CMakeUserPresets.json`)
- `Dev` - Fast iteration preset (recommended for development)
See `CMakePresets.json` for built-in presets, and your local `CMakeUserPresets.json` (created from `CMakeUserPresets.json.template`) for optional user presets such as `ALL-WITH-AUTO-DEPLOYMENT`.

Copilot uses AI. Check for mistakes.

## 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/`.
66 changes: 66 additions & 0 deletions docs/development/shader-workflow.md
Original file line number Diff line number Diff line change
@@ -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 |
84 changes: 84 additions & 0 deletions docs/development/vscode-setup.md
Original file line number Diff line number Diff line change
@@ -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