Skip to content

perf(dynamic cubemaps): encode to b6h#2162

Merged
alandtse merged 5 commits into
devfrom
cubemapb6h
Apr 21, 2026
Merged

perf(dynamic cubemaps): encode to b6h#2162
alandtse merged 5 commits into
devfrom
cubemapb6h

Conversation

@doodlum
Copy link
Copy Markdown
Collaborator

@doodlum doodlum commented Apr 20, 2026

Summary by CodeRabbit

  • New Features
    • Implemented BC6H compression for dynamic cubemaps. Environment and reflection cubemaps are now automatically compressed during the processing pipeline. BC6H-compressed textures are used in rendering for improved performance and memory efficiency.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 20, 2026

📝 Walkthrough

Walkthrough

This pull request introduces real-time BC6H GPU encoding for dynamic cubemaps. It adds a new HLSL compute shader implementing fast P1-mode BC6H block encoding, integrates it into the cubemap pipeline via a compression state machine, and allocates supporting GPU resources including BC6H textures, shader resource views, and constant buffers.

Changes

Cohort / File(s) Summary
BC6H Compute Shader
features/Dynamic Cubemaps/Shaders/DynamicCubemaps/BC6HEncodeCS.hlsl
New HLSL compute shader implementing BC6H encoding with MSLE metric, quantization/unquantization, endpoint optimization, and P1 block encoding. Entry point processes 4x4 texel blocks per thread and writes packed uint4 results.
Header Interface Updates
src/Features/DynamicCubemaps.h
Extended NextTask state machine with kBC6HCompress and kBC6HCompress2 stages. Added public methods CompressToBC6H() and GetComputeShaderBC6HEncode(). Introduced BC6H resource declarations (textures, SRVs, UAVs, constant buffers, mip levels).
Pipeline Implementation
src/Features/DynamicCubemaps.cpp
Added CompressToBC6H() pipeline binding compute shader, updating constant buffers per mip, dispatching work for all faces, and copying results to BC6H destination textures. Integrated BC6H compression into cubemap task state machine after irradiance stages. Extended SetupResources() for shader precompilation and BC6H texture/buffer allocation. Updated PostDeferred() to use BC6H-compressed cubemap SRVs.

Sequence Diagram

sequenceDiagram
    participant CubemapTask as Cubemap Task
    participant Irradiance as Irradiance Stage
    participant BC6H as BC6H Compression
    participant GPU as GPU Compute
    participant OutputTex as Output Textures
    
    CubemapTask->>Irradiance: Execute irradiance capture
    Irradiance->>Irradiance: Generate cubemap face
    Irradiance->>CubemapTask: Return to task
    CubemapTask->>BC6H: Transition to kBC6HCompress
    BC6H->>BC6H: Bind BC6H encode shader
    BC6H->>BC6H: Iterate mip levels
    BC6H->>BC6H: Update encode constant buffer
    BC6H->>GPU: Dispatch compute shader<br/>(6 faces per iteration)
    GPU->>GPU: Encode 4x4 blocks to BC6H
    GPU->>OutputTex: Write to scratch UAV
    BC6H->>OutputTex: Copy scratch to destination
    BC6H->>CubemapTask: Return to task
    CubemapTask->>CubemapTask: Continue pipeline
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • Pentalimbed

Poem

🐰 Whiskers twitching with delight,
GPU shaders encode blocks so tight,
BC6H magic in compute so fast,
Cubemaps compressed at last, at last!
Six faces dancing, mips aligned,
HDR textures, beautifully signed!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'encode to b6h' is a shortened form that appears to refer to BC6H encoding, but uses an ambiguous and non-standard abbreviation that would not be immediately clear to reviewers scanning the commit history. Clarify the title to use the full term 'BC6H' instead of 'b6h' for clarity, e.g., 'perf(dynamic cubemaps): encode to BC6H format' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cubemapb6h

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@doodlum
Copy link
Copy Markdown
Collaborator Author

doodlum commented Apr 20, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 20, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

1 similar comment
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 20, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Automated formatting by clang-format, prettier, and other hooks.
See https://pre-commit.ci for details.
@github-actions
Copy link
Copy Markdown

No actionable suggestions for changed features.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
features/Dynamic Cubemaps/Shaders/DynamicCubemaps/BC6HEncodeCS.hlsl (1)

69-103: Optional: Pattern / PatternFixupID are unused in P1-only mode.

With ENCODE_P2 = 0, these helpers (and PATTERN_NUM) are dead code. The compiler will strip them, but since the adaptation notes already document P2 removal, you could gate these behind #if ENCODE_P2 for clarity with the rest of the file (e.g. the #if INSET_COLOR_BBOX / #if OPTIMIZE_ENDPOINTS conventions used elsewhere).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@features/Dynamic` Cubemaps/Shaders/DynamicCubemaps/BC6HEncodeCS.hlsl around
lines 69 - 103, Pattern and PatternFixupID (and the related PATTERN_NUM helper)
are only needed when P2 encoding is enabled, so wrap their definitions with a
preprocessor guard to avoid dead code when ENCODE_P2 == 0; locate the functions
Pattern(uint p, uint i) and PatternFixupID(uint i) and surround their full
definitions (and any associated constants like PATTERN_NUM) with `#if` ENCODE_P2
... `#endif` following the project's existing convention (e.g., similar to the
INSET_COLOR_BBOX / OPTIMIZE_ENDPOINTS guards).
src/Features/DynamicCubemaps.cpp (1)

485-539: LGTM — BC6H dispatch pipeline.

The per-mip loop correctly updates bc6hEncodeCB (blocks-X/Y + mip level), binds the per-mip scratch UAV at slot 0, and dispatches ceil(blocks/8) groups × 6 faces. The CopyResource between R32G32B32A32_UINT (W/4 × H/4) and BC6H_UF16 (W × H) is valid because each 16-byte UINT4 texel aligns 1:1 with a 16-byte BC6H block, and both resources have identical mip counts and array size. Cleanup of SRV/UAV/CB/CS slots at the end is also correct.

Minor nit: mipDim = max(Width, Height) on line 503 differs from scratchBase = max(1u, Width/4) used in SetupResources (line 729). Cubemap faces are always square so this is benign today, but for consistency consider using texDesc.Width in both places.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Features/DynamicCubemaps.cpp` around lines 485 - 539, Summary: Use the
texture width instead of max(width,height) for mipDim to match SetupResources
and maintain consistency. Fix: In DynamicCubemaps::CompressToBC6H replace the
mipDim initialization (currently std::max(envTexture->desc.Width,
envTexture->desc.Height)) with the texture width used in SetupResources (use
envTexture->desc.Width); update the variable at its declaration so the loop and
block calculations use that width. Reference symbols:
DynamicCubemaps::CompressToBC6H, mipDim, envTexture->desc.Width, and
SetupResources's scratchBase usage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Features/DynamicCubemaps.cpp`:
- Around line 617-621: The shader is sampling mip level 15 from BC6H SRVs
(EnvReflectionsTexture, EnvTexture) but those textures only have 8 mips (0–7);
update the code so the sampled mip is clamped to the texture's actual mip count.
Change the hard-coded SampleLevel(…, 15) uses in DynamicCubemaps.hlsli to use a
clamped value (e.g., min(15, MaxMip)) or replace the literal with a shader
constant/uniform supplied from the C++ side that is computed from the SRV
texture description (mipLevels - 1), and ensure the C++ code that binds
EnvReflectionsTexture/EnvTexture (the views array and caller that sets shader
constants) sets that MaxMip value accordingly so SampleLevel never exceeds 7 for
BC6H textures.
- Around line 725-784: The BC6H path reduces bc6hMipLevels (see variable
bc6hMipLevels and the scratch/BC6H texture creation blocks) which makes
hardcoded SampleLevel(..., R, 15) calls in DeferredCompositePS.hlsl
out-of-range; replace those hardcoded 15s with a dynamic value (e.g., MIPLEVELS
- 1 or computed LOD from roughness) so sampling clamps to the actual mip count,
and ensure any code that uses envTexture/envTextureBC6H or
envReflectionsTextureBC6H queries/assumes MIPLEVELS or bc6hMipLevels rather than
a magic 15; update the five SampleLevel occurrences (previously at lines ~244,
272, 279, 286, 294) to use the new constant or computed LOD and validate
specular IBL behavior for reduced BC6H mip counts.

---

Nitpick comments:
In `@features/Dynamic` Cubemaps/Shaders/DynamicCubemaps/BC6HEncodeCS.hlsl:
- Around line 69-103: Pattern and PatternFixupID (and the related PATTERN_NUM
helper) are only needed when P2 encoding is enabled, so wrap their definitions
with a preprocessor guard to avoid dead code when ENCODE_P2 == 0; locate the
functions Pattern(uint p, uint i) and PatternFixupID(uint i) and surround their
full definitions (and any associated constants like PATTERN_NUM) with `#if`
ENCODE_P2 ... `#endif` following the project's existing convention (e.g., similar
to the INSET_COLOR_BBOX / OPTIMIZE_ENDPOINTS guards).

In `@src/Features/DynamicCubemaps.cpp`:
- Around line 485-539: Summary: Use the texture width instead of
max(width,height) for mipDim to match SetupResources and maintain consistency.
Fix: In DynamicCubemaps::CompressToBC6H replace the mipDim initialization
(currently std::max(envTexture->desc.Width, envTexture->desc.Height)) with the
texture width used in SetupResources (use envTexture->desc.Width); update the
variable at its declaration so the loop and block calculations use that width.
Reference symbols: DynamicCubemaps::CompressToBC6H, mipDim,
envTexture->desc.Width, and SetupResources's scratchBase usage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4456f0a0-17fb-49ff-8e25-04259d22fa13

📥 Commits

Reviewing files that changed from the base of the PR and between 24c22be and e399bba.

📒 Files selected for processing (3)
  • features/Dynamic Cubemaps/Shaders/DynamicCubemaps/BC6HEncodeCS.hlsl
  • src/Features/DynamicCubemaps.cpp
  • src/Features/DynamicCubemaps.h

Comment thread src/Features/DynamicCubemaps.cpp
Comment thread src/Features/DynamicCubemaps.cpp
@doodlum doodlum marked this pull request as ready for review April 20, 2026 22:39
@github-actions
Copy link
Copy Markdown

✅ A pre-release build is available for this PR:
Download

@alandtse alandtse merged commit 28ee046 into dev Apr 21, 2026
17 checks passed
ParticleTroned pushed a commit to ParticleTroned/skyrim-community-shaders that referenced this pull request May 2, 2026
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
(cherry picked from commit 28ee046)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants