37 Commits

Author SHA1 Message Date
173ab89158 new_editor: close startup screenshot ownership 2026-04-22 02:47:28 +08:00
b863dfe727 new_editor: unify d3d12 ui primitive pipeline 2026-04-22 02:47:27 +08:00
d21f573cc5 docs(new_editor): archive legacy closure plan 2026-04-22 02:47:26 +08:00
8b646bf30a refactor(srp): centralize renderer data collections 2026-04-22 02:40:51 +08:00
3187ccbfe1 refactor(srp): formalize renderer feature collections 2026-04-22 02:31:07 +08:00
6950bd15c2 refactor(srp): split feature runtime controllers 2026-04-22 02:23:33 +08:00
9b4a302f6a refactor(srp): unify main-scene feature injection 2026-04-22 02:15:03 +08:00
36c4ae414b new_editor: close legacy d2d host path 2026-04-22 02:14:26 +08:00
35e7602eb8 refactor(srp): centralize post-process stage planning 2026-04-22 02:08:09 +08:00
a231bf1fe1 refactor(srp): extract universal renderer block owners 2026-04-22 02:00:25 +08:00
eb636dbd89 refactor(srp): scope managed pass collection to active stage 2026-04-22 01:53:25 +08:00
0ec0eff90c new_editor: unify shared UI text measurement semantics 2026-04-22 01:50:00 +08:00
26e75e093e docs: archive completed and superseded new_editor plans 2026-04-22 01:49:45 +08:00
99eae1fe9f refactor(srp): formalize renderer block recording 2026-04-22 01:43:54 +08:00
33e9041d60 refactor(srp): require explicit managed renderer stage planning 2026-04-22 01:23:52 +08:00
9760bcb00e new_editor: fix adaptive tab width semantics 2026-04-22 01:12:46 +08:00
ed90911a5c refactor(srp): resolve imported render graph textures through multi-view runtime 2026-04-22 01:05:38 +08:00
4dda59a510 refactor(srp): bind managed fullscreen auxiliary inputs through render graph 2026-04-22 00:43:25 +08:00
b40eeb32b8 docs: add new editor closure notes and reference captures 2026-04-22 00:22:45 +08:00
bc47e6e5ac tests: remove legacy test tree 2026-04-22 00:22:32 +08:00
8bfca5e8f2 new_editor: isolate project panel state and harden runtime reset 2026-04-22 00:19:35 +08:00
fff33185b9 new_editor: tighten d3d12 ui frame resource handling 2026-04-22 00:19:19 +08:00
0411cd0ec1 new_editor: stabilize multi-window host lifecycle 2026-04-22 00:19:06 +08:00
08ff505b67 refactor(srp): add depth-aware managed fullscreen raster graph bridge 2026-04-22 00:07:10 +08:00
1bbbc22bcb refactor(rendering): treat object id as top-level tooling pass 2026-04-21 23:34:03 +08:00
76452a9c73 refactor(srp): move standalone stage fallback ownership into backend 2026-04-21 23:22:29 +08:00
a2d21e69b6 refactor(srp): move native scene feature registration into backend setup 2026-04-21 23:06:17 +08:00
f1d7e879ac refactor(srp): replace native scene feature strings with ids 2026-04-21 22:52:08 +08:00
d75bd95e89 refactor(srp): move final color policy into request seam 2026-04-21 22:34:40 +08:00
808335126f refactor(srp): make URP scene setup policy explicit 2026-04-21 22:03:24 +08:00
4b105ec88f fix(new_editor): stabilize detached window close lifecycle 2026-04-21 21:47:05 +08:00
ee1f817dc6 refactor(srp): tighten request and scene setup seams 2026-04-21 21:42:03 +08:00
01dabcf6b0 fix(new_editor): tune native d3d12 text sizing 2026-04-21 21:37:52 +08:00
0f84e52c21 refactor(new_editor): unify d3d12 text run caching 2026-04-21 21:07:06 +08:00
5d3d52496e fix(urp): prevent shadow fallback when shadow caster is disabled 2026-04-21 21:05:27 +08:00
75cf48f4fe refactor(rendering): remove unused pipeline factory registries 2026-04-21 20:57:29 +08:00
13ad95dc23 refactor(srp): unify probe scriptableobject authoring 2026-04-21 20:51:53 +08:00
943 changed files with 9554 additions and 3523329 deletions

View File

@@ -0,0 +1,196 @@
# NewEditor Architecture Closure Plan
Date: 2026-04-22
## 1. Objective
彻底收口 `new_editor` 当前仍然残留的旧语义、冗余结构和重复控制面。
这次不是补丁式修正,而是把当前主架构重新收成单一路径:
1. 主窗口 UI 渲染只保留一条 `D3D12` 实例化 primitive pass。
2. 启动截图策略只保留一个控制源。
3. `Rendering/Native` 这层已经失效的旧模块边界被移除。
4. 已确认无用的死代码和错误语义命名被清理。
## 2. Confirmed Root Issues
### 2.1 D3D12 UI renderer still contains a legacy geometry sub-pipeline
当前 `D3D12UiRenderer` 虽然已经是 `D3D12` 主路径,但内部仍然并存两套 UI 几何编译/提交策略:
1. `QuadInstanced`
2. `LegacyIndexed`
其中绝大多数 UI 命令已经走实例化 primitive 路径,只有少量三角形命令仍然维持整套:
- legacy vertex buffer
- legacy index buffer
- legacy pipeline state
- legacy batch kind
这会导致:
- UI renderer 不是单一路径
- 缓冲管理、缓存结构、绘制分发继续为旧几何方案付复杂度成本
- “legacy” 语义真正活着,而不是只有名字没改
### 2.2 Startup auto-capture ownership is split across two layers
当前 startup capture 既在 `EditorWindowScreenshotController::Initialize(...)` 内通过环境变量触发,
又在 `EditorWindowRuntimeController::Initialize(...)` 内通过
`autoCaptureOnStartup + env` 触发。
这导致:
- 策略决定权不是单点
- `autoCaptureOnStartup` 形参不是唯一真实来源
- 非主窗口也可能被环境变量隐式触发 startup request
### 2.3 Rendering/Native module boundary is obsolete
`app/Rendering/Native/` 目录现在只剩 `AutoScreenshot.*`
它已经不再承担旧的 native renderer backend 职责,但目录和 include 关系仍然保留旧时代边界。
### 2.4 Confirmed dead code remains in the hot renderer unit
`D3D12UiRenderer.cpp` 里存在已无调用方的辅助函数,说明之前的旧几何阶段没有清理彻底。
## 3. Target End State
完成后应满足:
1. `D3D12UiRenderer` 不再存在 `LegacyIndexed` / `legacy*` 动态几何资源。
2. 所有 UI draw command 都编译为同一类实例化 primitive 数据。
3. 渲染时只绑定一套 UI primitive pipeline。
4. `EditorWindowScreenshotController` 不再自行读取 startup env也不再拥有策略判断权。
5. startup capture 是否发生,只由窗口创建策略单点决定。
6. `Rendering/Native` 目录被清空或完全移除。
7. 已确认无调用的渲染死代码删除。
## 4. Refactor Strategy
### Phase A. Collapse UI geometry into one primitive pipeline
把当前 UI pass 改成单一实例化 primitive 方案:
- 保留单位 quad carrier vertex/index buffer
- 删除动态 legacy vertex/index buffer
- 删除 legacy pipeline state
- 删除 legacy batch kind
- 统一 batch 为 instance range + texture + scissor
需要新增的 primitive 能力:
- 现有 rect / outline / circle / text / image / gradient
- 新增 triangle primitive`FilledTriangle` 也走实例化路径
triangle 的正确实现目标:
- 不是回退到 indexed geometry
- 不是临时特判 draw call
- 而是作为实例化 primitive 的一种 kind被统一编译、缓存、上传和绘制
### Phase B. Rebuild renderer data model around the unified path
同步调整:
- `UiBatchKind` 去除或退化
- `UiQuadInstance` 升级为更通用的 `UiPrimitiveInstance`
- `CompiledDrawList` 不再缓存 legacy vertices / indices
- `EnsureFrameBufferCapacity(...)` 只维护 primitive instance buffer
- render dispatch 只保留单一 pipeline bind 分支
### Phase C. Collapse startup capture ownership to one source of truth
把 startup capture 的策略权上移并单点化:
- `Application` 或窗口创建层读取 env / policy
- `CreateParams.autoCaptureOnStartup` 成为唯一窗口级输入
- `EditorWindowRuntimeController` 只消费该参数
- `EditorWindowScreenshotController` 只做请求/路径/结果管理,不做策略判断
### Phase D. Remove obsolete Native module shell
将截图控制器从 `app/Rendering/Native/` 迁移到更合理的位置,
预计是窗口运行时或通用 support/capture 模块。
要求:
- 迁移后 active include 不再引用 `Rendering/Native`
- `new_editor/CMakeLists.txt` 同步更新
### Phase E. Delete dead helpers and normalize semantics
删除已经确认无调用的旧辅助函数,并统一命名:
- `legacy*` -> 按真实职责改名,或随着删除一起消失
- 清理无用 helper
- 保证 renderer 术语与当前架构一致
## 5. File-Level Work
### 5.1 UI renderer core
Primary:
- `new_editor/app/Rendering/D3D12/D3D12UiRenderer.h`
- `new_editor/app/Rendering/D3D12/D3D12UiRenderer.cpp`
### 5.2 Startup capture boundary
Primary:
- `new_editor/app/Bootstrap/Application.cpp`
- `new_editor/app/Platform/Win32/EditorWindow.cpp`
- `new_editor/app/Platform/Win32/EditorWindowRuntimeController.h`
- `new_editor/app/Platform/Win32/EditorWindowRuntimeController.cpp`
- `new_editor/app/Platform/Win32/EditorWindowManager.h`
### 5.3 Screenshot controller relocation
Current source:
- `new_editor/app/Platform/Win32/EditorWindowScreenshotController.h`
- `new_editor/app/Platform/Win32/EditorWindowScreenshotController.cpp`
Target:
- move into non-legacy module location
### 5.4 Build graph cleanup
- `new_editor/CMakeLists.txt`
## 6. Validation
### 6.1 Structural validation
完成后搜索应满足:
- no `LegacyIndexed` in active UI renderer
- no `m_legacyPipelineState`
- no `legacyVertexBuffer`
- no `legacyIndexBuffer`
- no `app/Rendering/Native/AutoScreenshot.*` active include path
### 6.2 Runtime validation
必须验证:
1. `XCUIEditorApp` Debug 构建通过
2. editor 正常启动
3. 主窗口 UI 正常显示与交互
4. startup auto-capture 正常生成
5. detached window 不会错误触发 startup capture
## 7. Completion Criteria
只有满足以下条件,这个 plan 才算真正收口:
1. UI 渲染路径内部不再存在旧几何子管线
2. startup capture 策略控制权单点化
3.`Native` 模块边界消失
4. 死代码删除
5. 构建、启动、截图验证全部通过

View File

@@ -0,0 +1,274 @@
# NewEditor D3D12 Legacy D2D Closure Plan
Date: 2026-04-22
## 1. Problem Statement
`new_editor` main-window realtime presentation has already moved onto the native `D3D12` path, but the codebase still retains a legacy `D2D / D3D11On12` bridge in the host layer.
That residual path is no longer the main realtime hot path, but it is still architecturally serious because it keeps a second rendering/composition implementation alive for the same UI draw model.
Current residual seam:
- `app/Rendering/Native/NativeRenderer.*`
- `app/Rendering/D3D12/D3D12WindowInteropContext.*`
- `app/Rendering/D3D12/D3D12WindowInteropHelpers.h`
- host/build references that still compile and link the old bridge
## 2. Confirmed Current Facts
### 2.1 Main window realtime presentation no longer depends on D2D
Main realtime presentation flows through:
- `D3D12WindowRenderer`
- `D3D12UiRenderer`
- `D3D12WindowRenderLoop`
The active main path does not call `NativeRenderer::Render(...)`.
### 2.2 Residual D2D bridge is concentrated, not scattered
The old bridge is now effectively concentrated in:
- screenshot/export flow
- dead hwnd-native D2D window rendering code that is no longer wired into the main frame loop
### 2.3 NativeRenderer is no longer the main texture host
`TexturePort` for the active editor path is already `D3D12UiTextureHost`.
This means the remaining `NativeRenderer` responsibilities can be removed instead of preserved as an active subsystem.
## 3. Root Architectural Issue
The root issue is not “some D2D symbols still exist”.
The root issue is that `new_editor` still retains two incompatible host-side ways to turn UI output into pixels:
1. Active path: native `D3D12` rendering into the swapchain backbuffer.
2. Residual path: `UIDrawData -> D2D replay`, with optional `D3D11On12` resource interop.
As long as both remain alive:
- draw semantics can drift between live output and capture/export output
- future UI/rendering changes must be kept compatible with two host backends
- dead-window code remains available to be accidentally reused
- build/link dependencies preserve obsolete platform coupling
So the correct goal is full single-path closure, not incremental patching.
## 4. Target End State
After this refactor:
1. Main-window realtime rendering remains native `D3D12`.
2. Main-window screenshot capture also uses native `D3D12` backbuffer capture.
3. `new_editor` no longer contains any host-side `D3D11On12` or `D2D` bridge code for the main window.
4. Old hwnd `D2D` renderer code is deleted, not merely disconnected.
5. `XCUIEditorHost` no longer compiles obsolete interop units.
6. Host link dependencies only retain what is still genuinely required.
## 5. Non-Goals
- Do not roll the editor back to `D2D`.
- Do not reintroduce a fallback composition backend.
- Do not change the active `D3D12UiRenderer` architecture back into draw-data replay through another API.
- Do not remove `DirectWrite` from `D3D12UiTextSystem`; text shaping/raster generation remains valid there.
## 6. Refactor Strategy
### Phase A. Replace screenshot bridge with native D3D12 capture
Introduce a native `D3D12` capture path that reads the final swapchain backbuffer and writes PNG through CPU-side WIC encoding.
This capture path must:
- capture the final composited editor frame
- avoid `UIDrawData` replay
- avoid `D3D11On12`
- avoid `D2D`
- operate on the same swapchain backbuffer the user actually sees
Preferred integration point:
- after UI rendering has finished for the active backbuffer
- after the frame has been submitted to the queue
- before `PresentFrame()`
Reason:
- the frame is already fully rendered
- the current backbuffer is still the one about to be presented
- capture remains aligned with the user-visible final image
### Phase B. Collapse screenshot orchestration around the active D3D12 path
Rework `AutoScreenshotController` so it only:
- tracks pending capture requests
- resolves output/history paths
- finalizes success/error summaries
It must no longer own the rendering backend choice.
### Phase C. Delete obsolete NativeRenderer window-render path
Delete the old hwnd `D2D` window renderer behavior:
- `Initialize(HWND)`
- `Resize(...)`
- `Render(...)`
- hwnd render-target management
- D2D draw command replay entrypoint for window presentation
If a remaining utility is still needed after this phase, it must live in a narrowly-scoped replacement component, not inside a zombie renderer class.
### Phase D. Delete D3D11On12 interop bridge
Once native `D3D12` capture is live:
- delete `D3D12WindowInteropContext.*`
- delete `D3D12WindowInteropHelpers.h`
- delete all `NativeRenderer` interop code
### Phase E. Build and link closure
Update host build definitions so obsolete units and libraries are removed.
Expected removals if no remaining consumer exists:
- `app/Rendering/Native/NativeRenderer.cpp`
- `app/Rendering/D3D12/D3D12WindowInteropContext.cpp`
- `d2d1.lib`
- `d3d11.lib`
Expected retained dependencies:
- `d3d12.lib`
- `d3dcompiler.lib`
- `dwrite.lib`
- `dxgi.lib`
- `windowscodecs.lib`
## 7. Concrete File-Level Work
### 7.1 Add new native capture unit
Add new host-side unit(s), likely under `app/Rendering/D3D12/`:
- `D3D12WindowCapture.h`
- `D3D12WindowCapture.cpp`
Responsibilities:
- copy current swapchain backbuffer to readback
- map CPU pixels
- encode PNG via WIC
- return rich error text
### 7.2 Extend window renderer / render loop
Modify:
- `app/Rendering/D3D12/D3D12WindowRenderer.h`
- `app/Rendering/D3D12/D3D12WindowRenderer.cpp`
- `app/Rendering/D3D12/D3D12WindowRenderLoop.h`
- `app/Rendering/D3D12/D3D12WindowRenderLoop.cpp`
Needed changes:
- expose a native capture operation on the active backbuffer
- extend present result with capture outcome
- allow present flow to execute capture before `PresentFrame()`
### 7.3 Rework screenshot controller boundary
Modify:
- `app/Rendering/Native/AutoScreenshot.h`
- `app/Rendering/Native/AutoScreenshot.cpp`
- `app/Platform/Win32/EditorWindowRuntimeController.h`
- `app/Platform/Win32/EditorWindowRuntimeController.cpp`
- `app/Platform/Win32/EditorWindow.cpp`
Needed changes:
- stop passing `UIDrawData` into screenshot rendering
- stop depending on `NativeRenderer`
- move screenshot triggering into the D3D12 present path
### 7.4 Delete obsolete renderer/interop code
Delete if fully unreferenced after the above:
- `app/Rendering/Native/NativeRenderer.h`
- `app/Rendering/Native/NativeRenderer.cpp`
- `app/Rendering/Native/NativeRendererHelpers.h`
- `app/Rendering/D3D12/D3D12WindowInteropContext.h`
- `app/Rendering/D3D12/D3D12WindowInteropContext.cpp`
- `app/Rendering/D3D12/D3D12WindowInteropHelpers.h`
### 7.5 Build-system cleanup
Modify:
- `new_editor/CMakeLists.txt`
Remove:
- old source units
- dead link libraries
## 8. Validation Requirements
### 8.1 Build validation
Must build:
- `XCUIEditorHost`
- `XCUIEditorAppLib`
- `XCUIEditorApp`
### 8.2 Runtime validation
Must validate:
1. editor launches normally
2. main window still presents correctly
3. manual screenshot still succeeds
4. startup auto-capture still succeeds if enabled
5. no screenshot path closes or stalls the main window unexpectedly
### 8.3 Structural validation
Searches after completion must show:
- no `NativeRenderer` references in `new_editor/app`
- no `D3D12WindowInteropContext` references in `new_editor`
- no `D3D11On12` references in `new_editor`
- no `ID2D` / `D2D1` references in `new_editor/app`
Exception:
- `DirectWrite` references inside `D3D12UiTextSystem` remain allowed
## 9. Execution Order
1. Add native `D3D12` backbuffer capture path.
2. Route `AutoScreenshotController` through that new path.
3. Remove runtime-controller dependence on `NativeRenderer`.
4. Delete `NativeRenderer` and `D3D12WindowInteropContext`.
5. Clean CMake/link dependencies.
6. Build and smoke-test.
7. Run structural grep validation.
## 10. Success Criteria
This plan is complete only if all of the following are true:
- screenshots come from the native `D3D12` backbuffer path
- no main-window host rendering code path can fall back to `D2D`
- no `D3D11On12` bridge remains in `new_editor`
- old dead window-render code is physically removed
- build and smoke validation pass

View File

@@ -0,0 +1,146 @@
# NewEditor UI Text Measurement Semantic Unification Plan
Date: `2026-04-22`
## Goal
Refactor the shared `new_editor` UI widget layer so text measurement, layout sizing, draw positioning and hit-test geometry stop sharing ambiguous width fields.
This is not a symptom patch.
This is a semantic cleanup of the shared UI model.
## Root Problem
The shared widget layer currently mixes multiple width meanings under vague names such as:
- `desiredLabelWidth`
- `desiredShortcutWidth`
- `desiredWidth`
Across different controls, those fields are used as one or more of:
- measured glyph advance
- padded control width input
- arranged rect width surrogate
- draw-time text positioning basis
That breaks the semantic boundary between:
- text measurement
- layout width solving
- final arranged geometry
- draw clipping and hit testing
The `tab strip` bug was only one visible symptom of this broader design problem.
## Confirmed Shared Impacted Controls
- `new_editor/include/XCEditor/Collections/UIEditorTabStrip.h`
- `new_editor/include/XCEditor/Menu/UIEditorMenuBar.h`
- `new_editor/include/XCEditor/Menu/UIEditorMenuPopup.h`
- `new_editor/include/XCEditor/Shell/UIEditorStatusBar.h`
- `new_editor/include/XCEditor/Viewport/UIEditorViewportSlot.h`
Confirmed propagation paths:
- `new_editor/src/Shell/UIEditorShellInteraction.cpp`
- `new_editor/src/Shell/UIEditorShellCompose.cpp`
- `new_editor/src/Workspace/UIEditorWorkspaceCompose.cpp`
- `new_editor/src/Workspace/UIEditorWorkspaceInteraction.cpp`
- `new_editor/src/Viewport/UIEditorViewportShell.cpp`
- `new_editor/src/Docking/UIEditorDockHost.cpp`
## End State
All shared text-bearing widgets must follow one rule:
- model fields store measured text width only
- layout derives padded control width from measured text width
- arranged rects remain the only source of final geometry
- draw and hit-test consume arranged rects plus measured text width, never repurposed control widths
## Refactor Principles
- Use one semantic name for one meaning.
- Do not reuse a measured text width field as a control width field.
- Do not let individual widgets invent incompatible width semantics.
- Push actual text measurement to request/model build points where a `UIEditorTextMeasurer` is available.
- Keep estimated glyph-width fallback only as a fallback, not the primary semantic.
## Workstream A: Introduce Shared Text-Width Semantics
Required changes:
- add shared helper(s) for resolving measured text width from:
- cached measured width
- `UIEditorTextMeasurer`
- estimated glyph fallback
- document the semantic contract in the shared widget structs
Acceptance:
- shared controls no longer expose ambiguous width names for pure text measurement
## Workstream B: Normalize Shared Widget Models
Required changes:
- convert the following fields to explicit measured-text semantics:
- `UIEditorTabStripItem`
- `UIEditorMenuBarItem`
- `UIEditorMenuPopupItem`
- `UIEditorStatusBarSegment`
- `UIEditorViewportSlotToolItem`
- update each widget so layout derives control width from measured text width locally
Acceptance:
- measurement/layout/draw code paths in those widgets are semantically aligned
## Workstream C: Push Real Measurement Through Shared Request Paths
Required changes:
- shell interaction:
- measure menu bar items
- measure popup labels and shortcuts
- measure shell status-bar segments
- workspace / viewport compose:
- measure viewport tool-item labels
- measure viewport status-bar segments
- carry the measured viewport shell model through compose/frame so append uses the same measured data as layout
Acceptance:
- top-level editor shell and external viewport chrome no longer rely on ad-hoc estimated widths in the steady state
## Workstream D: Regression Validation
Required checks:
- build `XCUIEditorLib`
- build `XCUIEditorAppLib`
- build `XCUIEditorApp`
- smoke-launch `build/new_editor/Debug/XCUIEditor.exe`
Manual follow-up target:
- verify long/short mixed menu labels
- verify long tab labels
- verify status-bar and viewport toolbar labels remain aligned after measurement unification
## Out Of Scope For This Pass
- tree/list/property-grid virtualization
- scene rendering optimization
- renderer backend work
- visual redesign
## Success Criteria
This pass is complete only if:
- the shared widget layer uses one consistent measured-text semantic
- layout width derivation is local and explicit
- shell/workspace/viewport request paths feed measured text widths into shared widgets
- the tab fix becomes one instance of a general rule, not a special case

View File

@@ -0,0 +1,271 @@
# NewEditor 审查遗留总收口计划
## 背景
当前 `new_editor` 已完成旧 `editor` / ImGui 依赖切离,也完成了 Scene、Project、Hierarchy、Win32 宿主、多窗口、测试体系等多轮迁移与重构。但从现状审查结果看,仍有一整组未收口的结构问题,它们彼此关联,不能只挑一部分处理:
1. `include/XCEditor` 的公共头并没有稳定地充当接口层,而是在持续聚合具体实现域。
2. `new_editor/src``new_editor/app` 的拆分标准不一致,出现“过碎薄文件”和“超大职责文件”并存。
3. `EditorShellRuntime` 仍是 feature 编排、状态汇总、事件中转、渲染协调、指针捕获决策的中心大对象。
4. `EditorWindow` 与 Win32 controller 的 ownership 没有真正收拢,仍保留大量私有转发行为与跨对象透权。
5. 平台层仍直接依赖上层 UI 语义与 theme / panel registry 等对象,平台宿主隔离未彻底完成。
6. `ProjectPanel` 仍然是严重超载的 feature树、网格、布局、命令、菜单、拖放、重命名全部耦合在一起。
7. `HierarchyPanel``InspectorPanel`、Scene feature 的边界虽然比 `ProjectPanel` 清楚,但仍缺少统一 feature event 契约。
8. `WorkspaceEventSync` 仍是 feature event 到 `EditorContext` / runtime 的临时胶水,而不是正式 app-level 事件入口。
9. Scene gizmo / viewport 相关实现仍有大块高复杂度单体文件,后续会持续阻碍维护与验证。
这些问题的根因不是“代码多”本身而是边界定义、文件粒度、ownership、公共接口层设计都还没有稳定下来。
## 本计划覆盖的全部未收口问题
### 一. 公共接口层失真
问题:
1. `UIEditorTheme.h` 等公共头直接吸入 list / tree / field / dock / shell / viewport 具体类型。
2. `UIEditorWorkspaceCompose.h` 同时承载 compose types、update API、append API并直接依赖 dock host、panel host、viewport shell。
3. 一些 `XCEditor` 头更像“实现域聚合入口”而不是“稳定公共接口”。
根因:
- 公共头、契约头、实现头没有分层。
- 迁移阶段用聚合头降低了接线成本,但没有在后续回收。
收口动作:
1. 将公共头拆成 `types/contracts``ops/services` 两层。
2. 公共头只保留稳定数据结构、前置声明、轻量枚举和必要查询接口。
3. 将 update / resolve / append / interaction 这类依赖实现细节的 API 下沉到独立 ops 头。
4. 全量清理 `new_editor/app``tests/UI/Editor` 的 include 面。
验收:
- `XCEditor` 主要公共头不再通过一层 include 拉入整片实现域。
- 任一 feature 引入 theme / compose 合同时,不再被动依赖大量 widget/field/shell 类型。
### 二. 文件粒度标准失控
问题:
1. 某些文件过碎,只剩几行转发或包装,没有形成独立 ownership。
2. 某些文件又持续膨胀到数百上千行,承载多个变化理由。
3. `new_editor` 的拆分策略与 `engine` 主体并不一致,当前粒度不稳定。
典型表现:
1. `EditorWindowTitleBarRendering.cpp` 这类纯转发薄文件。
2. `ProjectPanel.cpp``SceneViewportTransformGizmoSupport.cpp``EditorWindowChromeController.cpp` 这类超大文件。
根因:
- 一部分文件是重构中间态,没有在边界明确后回收。
- 拆分依据偏向“临时改动落点”,而不是“稳定职责边界”。
收口动作:
1. 建立明确拆分标准:按 ownership、状态归属、修改耦合、测试边界拆不按函数数量拆。
2. 回收纯转发薄文件,合并到真正拥有行为的实现文件。
3. 将超大文件按真实子域拆开,而不是继续切更多壳文件。
验收:
- 不再存在大量只做单纯转发的宿主文件。
- 大文件拆分后每个子文件都对应稳定责任,而不是“某个大文件的一个切片”。
### 三. EditorShellRuntime 中心化过重
问题:
1. `EditorShellRuntime` 同时拥有 panel feature、viewport host、built-in icons、pointer ownership、workspace trace。
2. 它直接暴露 `HierarchyPanel::Event``ProjectPanel::Event` 等 feature-specific 细节。
3. 顶层 runtime 既是编排器,又是状态中转站,又承担 feature 间粘合。
根因:
- 缺少统一 feature contract。
- feature 输出和 app-level 输出没有分层。
收口动作:
1. 提取统一 feature presentation / interaction / event contract。
2.`EditorShellRuntime` 只承担编排与生命周期,不再泄露具体 panel 事件容器。
3. 让 pointer capture / hosted content cursor / shell interaction 聚合为统一 runtime 输出模型。
验收:
- `EditorShellRuntime` 对外只暴露 app-level 结果,不直接透出具体 panel 类型。
- 新增 feature 时不需要继续给 runtime 增加一组定制 getter。
### 四. Win32 宿主 ownership 不清
问题:
1. `EditorWindow` 仍保留大量窗口、输入、渲染、DPI、capture、chrome、workspace 行为。
2. controller 已经存在,但很多只是借 `friend` 操作 `EditorWindow` 内部状态。
3. 宿主与 controller 同时拥有职责,边界不稳定。
根因:
- controller 是从大对象里抽出来的,但 `EditorWindow` 自身没有同步瘦身。
- 共享状态 contract 未明确,导致继续透权。
收口动作:
1. 重新定义 `EditorWindow` 的职责,只保留 HWND / message / facade /生命周期入口。
2. 将输入、chrome、frame orchestration、runtime 更新的实际 ownership 下沉到 controller。
3. 用明确 state contract 替代大面积 `friend` 与私有转发。
4. 清理薄转发 cpp 文件。
验收:
- `EditorWindow.h` 私有方法数量显著下降。
- controller 不再依赖大量跨域私有入口。
### 五. 平台层反向依赖 UI 语义
问题:
1. `EditorWindowChromeController` 仍直接依赖 `UIEditorTheme``UIEditorPanelRegistry` 等上层 UI 类型。
2. 平台层对“标题栏显示什么 tab、什么 panel title、什么 theme metrics”知道得太多。
根因:
- 宿主 chrome 渲染逻辑仍混入编辑器语义,而不是依赖独立的宿主展示 contract。
收口动作:
1. 提取宿主 chrome 所需的独立 presentation contract。
2. 平台层只消费宿主展示结果,不直接查询 panel registry 或 theme 聚合头。
3. 将 detached tab/title 的编辑器语义计算上移到 app/runtime 层。
验收:
- `app/Platform/Win32` 不再直接 include 聚合 UI 头来计算编辑器展示语义。
### 六. ProjectPanel 职责堆积
问题:
1. `ProjectPanel` 同时管理 tree、grid、breadcrumb、rename、context menu、drag/drop、命令路由、命中测试、布局。
2. 头文件里聚集了大量私有子域结构与帮助函数。
3. 后续任何功能调整都会继续把该类推大。
根因:
- Project feature 尚未形成独立子域。
- 之前为尽快打通真实行为,把所有逻辑先集中放进了主 panel。
收口动作:
1. 提取 layout / hit test 子域。
2. 提取 breadcrumb / grid presentation 子域。
3. 提取 context menu / rename / command target 子域。
4. 提取 tree-grid drag/drop 协调子域。
5. `ProjectPanel` 只保留 runtime 注入、focus 编排、事件汇总。
验收:
- `ProjectPanel.h/.cpp` 不再承载全部 UI 子域细节。
- Project feature 的每个子文件都有明确 ownership。
### 七. Feature 事件模型不统一
问题:
1. `HierarchyPanel``ProjectPanel` 使用各自的局部 event 结构。
2. Scene / Inspector 也在各自路径里用专有交互结果。
3. 顶层同步逻辑必须知道每个 feature 的细节。
根因:
- 缺少统一的 app event 契约和 feature output 契约。
收口动作:
1. 定义统一 `EditorAppEvent` 或等价契约。
2. feature 局部事件先映射为 app event再由同步入口消费。
3. 保留 feature 内部私有状态,但不再将私有事件结构外泄。
验收:
- 顶层不再显式依赖多个 feature-specific event 类型。
### 八. WorkspaceEventSync 仍是临时胶水
问题:
1. `WorkspaceEventSync` 直接读 panel event再同步 `EditorContext` / `SceneRuntime`
2. 它仍包含具体 panel 事件描述逻辑和面板级状态文案拼装。
根因:
- 统一 app event 管线尚未建立。
收口动作:
1.`WorkspaceEventSync` 只消费统一 app event。
2. 把 panel-specific 事件描述、状态消息格式化下沉到各 feature adapter。
3. 将 scene open、selection sync、status update 都纳入正式事件消费流程。
验收:
- `WorkspaceEventSync` 不再包含对具体 panel event 结构的硬编码。
### 九. Scene viewport / gizmo 复杂度仍过高
问题:
1. `SceneViewportTransformGizmoSupport.cpp` 仍是超大单体实现。
2. gizmo 数学、命中测试、绘制、操作状态、模式逻辑仍高度耦合。
根因:
- 旧逻辑迁移后完成了行为闭环,但还没有按稳定子域回收。
收口动作:
1. 按 move / rotate / scale 或按 pick / render / manipulate 子域拆分 gizmo 支撑实现。
2. 提取共享数学 / 投影 / 命中工具。
3. 让 controller 只编排,不直接承担高复杂度细节。
验收:
- gizmo 支撑逻辑不再集中在一个超大文件中。
- gizmo 模式切换与交互行为更容易定向测试。
## 执行顺序
为了避免返工,按以下顺序执行:
1. 公共接口层去聚合
2. 文件粒度与 ownership 标准归一
3. Win32 宿主 ownership 收拢
4. 平台层反向 UI 依赖切除
5. `EditorShellRuntime` 去中心化
6. `ProjectPanel` 子域拆分
7. feature 统一事件契约
8. `WorkspaceEventSync` 正式化
9. Scene viewport / gizmo 子域拆分
10. 测试与回归收口
## 验证
每个阶段至少执行:
1. `cmake --build build_codex_verify --config Debug --target XCUIEditor editor_ui_smoke_targets`
2. `ctest --test-dir build_codex_verify -C Debug -R xcui_editor_app_smoke --output-on-failure`
3. `tests/UI/Editor/unit` 的相关定向回归
必要时补充:
1. 公共头 include 面回归
2. Win32 多窗口 / tab 拖放 / 独立窗口回归
3. Scene gizmo 交互回归
4. Project tree / grid / rename / context menu / drag-drop 回归
## 风险控制
1. 不修改 `managed``SRP`、用户其他工作流中的脏改动。
2. 任何拆分都必须围绕稳定 ownership不允许再出现“一两个函数一个 cpp”的假拆分。
3. 任何合并都必须基于修改耦合与职责一致性,不做机械回并。
4. 若执行中发现某条边界不足以支撑后续步骤,优先补 contract再迁移实现。

View File

@@ -0,0 +1,144 @@
# SRP / URP Explicit Scene Setup Policy Plan
## 背景
上一阶段已经把 request-level 的一部分策略从 native default 挪到了 managed URP
- `Camera.clearMode`
- `Camera.stackType`
- `CameraRenderRequestContext.clearFlags`
- `UniversalRenderPipelineAsset` 中的默认 clear / shadow request policy
`RenderSceneSetup` 这一层还没有真正收口。
当前 `UniversalRenderer.ConfigureRenderSceneSetup(...)` 仍然只是调用:
- `UseDefaultEnvironment()`
- `UseDefaultGlobalShaderKeywords()`
这意味着:
- URP 还没有显式决定“这帧环境到底是什么”
- URP 还没有显式决定“全局 shader keyword 到底开哪些”
- native default 仍然在替 URP 做 scene setup policy
这和目标中的 Unity 风格 `SRP substrate + URP package policy` 不一致。
## 本阶段目标
把 scene setup 从“调用 native 默认策略”收成“managed URP 显式配置策略”。
本阶段只做 seam 收口,不做 deferred不改 Render Graph 主执行骨架。
### 目标 1
扩展 `RenderSceneSetupContext`,让 managed 层拿到显式决策所需的最小上下文:
- `clearFlags`
- `hasMainSceneDepthAttachment`
- `hasMainDirectionalShadow`
### 目标 2
扩展 managed `Camera` 只读能力,让 URP 可以显式决定 skybox policy
- `projectionType`
- `skyboxEnabled`
- `hasSkyboxMaterial`
- `skyboxTopColor`
- `skyboxHorizonColor`
- `skyboxBottomColor`
### 目标 3
扩展 `RenderSceneSetupContext` 的显式写入口:
- `SetEnvironmentNone()`
- `UseCameraSkyboxMaterial()`
- `SetProceduralSkybox(...)`
- `SetGlobalShaderKeyword(string keyword, bool enabled)`
### 目标 4
`UniversalRenderer.ConfigureRenderSceneSetup(...)` 改成显式逻辑,复刻当前 native default 行为:
- 先清空 environment / global keywords
- 再根据 camera + request + main scene surface 条件显式设置 skybox
- 再根据 `hasMainDirectionalShadow` 显式设置 `XC_MAIN_LIGHT_SHADOWS`
## 实施步骤
### Step 1. 补齐 managed / native scene setup bridge
`RenderSceneSetupContext``MonoScriptRuntime` 之间增加新的只读属性和显式写接口。
要求:
- 不引入兼容层
- 不保留“旧 API + 新 API 并存但无人使用”的半弃用状态
- scene setup 的显式接口命名要直接表达意图
### Step 2. 补齐 Camera 的只读 skybox / projection seam
通过 internal call 暴露 managed 决策所需的 camera 状态。
要求:
- 只补当前 scene setup 确实需要的读取能力
- 不顺手扩一堆暂时无用的 Camera API
### Step 3. 切换 UniversalRenderer 的 scene setup 实现
把当前两句 `UseDefault...` 换成显式策略代码。
要求:
- 行为尽量与当前默认行为一致
- 不再依赖 native default 来决定 keyword / environment
- feature 后续仍可以在 `ConfigureRenderSceneSetup(...)` 链路里继续覆写
## 收口标准
- `UniversalRenderer.ConfigureRenderSceneSetup(...)` 不再调用 native default environment / keyword policy
- URP 可以显式配置:
- environment none
- camera material skybox
- procedural skybox
- global shader keyword on/off
- `XC_MAIN_LIGHT_SHADOWS` 由 managed scene setup 显式决定
- `XCEditor` Debug 编译通过
- 旧版 editor 冒烟通过
## 非目标
本阶段不做以下内容:
- deferred rendering
- shadow 算法本体迁移
- gaussian / volumetric pass 迁移
- Render Graph 结构大改
- editor / new_editor 相关重构
## 完成情况
- 已补齐 managed `Camera` 的 scene setup 只读 seam
- `projectionType`
- `skyboxEnabled`
- `hasSkyboxMaterial`
- `skyboxTopColor`
- `skyboxHorizonColor`
- `skyboxBottomColor`
- 已补齐 `RenderSceneSetupContext` 的显式 scene setup seam
- `clearFlags`
- `hasMainSceneDepthAttachment`
- `hasMainDirectionalShadow`
- `SetEnvironmentNone()`
- `UseCameraSkyboxMaterial()`
- `SetProceduralSkybox(...)`
- `SetGlobalShaderKeyword(string, bool)`
- 已删除不再使用的 managed scene setup default / 清空兼容 API避免双轨状态继续存在
- `UniversalRenderer.ConfigureRenderSceneSetup(...)` 已切换为显式策略:
- 显式决定 skybox environment 是否启用
- 显式决定材质天空盒 / procedural skybox
- 显式决定 `XC_MAIN_LIGHT_SHADOWS`
- `XCEditor` Debug 编译通过
- 旧版 editor 冒烟通过

View File

@@ -0,0 +1,68 @@
# SRP / URP Feature Runtime Controller Split Plan
时间2026-04-22
## 背景
当前 renderer block 和 feature injection 骨架已经基本成形,但 feature 层还有最后一块不够整齐:
1. `BuiltinGaussianSplatRendererFeature` / `BuiltinVolumetricRendererFeature` 已经走了 runtime controller 模式。
2. `ColorScalePostProcessRendererFeature` 仍然直接持有 runtime pass并且 pass 反向引用 feature。
3. `RenderObjectsRendererFeature` 也仍然把配置解析、runtime pass 构建、enqueue 逻辑都混在 feature 里。
这导致 feature 层的边界还不统一:
- 有的 feature 是“配置数据 + controller”
- 有的 feature 还是“配置数据 + runtime pass 直接混写”
## 本阶段目标
`ColorScalePostProcessRendererFeature``RenderObjectsRendererFeature` 也收成统一的“配置数据 + runtime controller”模式。
目标结果:
1. `ColorScalePostProcessPass` 不再反向持有 feature 资产引用。
2. `RenderObjectsRendererFeature` 的配置解析与 runtime pass 持有分离。
3. 当前内建 feature 的 runtime 边界风格统一。
## 范围
本阶段只处理 feature runtime 边界,不做:
- public renderer feature API 改造
- deferred rendering
- C++ host / RenderGraph 改造
## 实施步骤
### 1. 拆出 feature settings / controller
新增:
- `ColorScalePostProcessSettings`
- `UniversalColorScalePostProcessController`
- `RenderObjectsFeatureSettings`
- `UniversalRenderObjectsFeatureController`
### 2. 接入现有 feature
接入:
- `ColorScalePostProcessRendererFeature`
- `RenderObjectsRendererFeature`
### 3. 验证
要求:
1. `XCEditor` Debug 构建通过
2. old editor 冒烟至少 10 秒
3. `editor.log` 出现 `SceneReady`
## 完成标准
满足以下条件才算本阶段收口:
1. `ColorScale``RenderObjects` 都改成配置数据 + runtime controller。
2. 不再存在 runtime pass 直接反向持有 feature 资产的耦合。
3. `XCEditor` 编译与 old editor 冒烟通过。

View File

@@ -0,0 +1,73 @@
# SRP / URP Main Scene Feature Injection Plan
时间2026-04-22
## 背景
当前 renderer block 主线已经基本清晰:
- `ShadowCaster`
- `DepthPrepass`
- `MainScene`
- `PostProcess`
- `FinalOutput`
`UniversalRenderer` 也已经拆出了对应 block owner。
`main scene` 这一面的 renderer feature 注入还不够干净:
1. `RenderObjectsRendererFeature` 自己手写 scene-stage 与 pass-stage 判断。
2. `BuiltinGaussianSplatRendererFeature` / `BuiltinVolumetricRendererFeature` 各自重复一套 native scene feature pass 注入逻辑。
3. 缺少统一的 main-scene feature 注入骨架,后续继续加 scene feature 时还会复制这些判断和样板。
## 本阶段目标
补齐 `main scene` feature 注入的统一 utility / controller把当前散落在 feature 里的 main-scene 注入规则收口。
目标结果:
1. `RenderObjectsRendererFeature` 走统一的 main-scene pass 注入 helper。
2. Gaussian / Volumetric 共用同一套 native scene feature controller。
3. 后续再加 main-scene renderer feature 时,有稳定的落点可复用。
## 范围
本阶段只处理 main-scene feature 注入骨架,不做:
- public renderer feature API 改造
- deferred rendering
- C++ host / RenderGraph 改造
## 实施步骤
### 1. 新增 main-scene feature 注入 utility
职责:
- 统一判断当前是否处于 main scene stage
- 统一判断 pass 是否属于当前 stage
- 统一执行 enqueue
### 2. 新增 native scene feature controller
职责:
- 持有 `NativeSceneFeaturePass`
- 统一 create / configure / enqueue
- 供 Gaussian / Volumetric 复用
### 3. 接入现有 feature
接入:
- `RenderObjectsRendererFeature`
- `BuiltinGaussianSplatRendererFeature`
- `BuiltinVolumetricRendererFeature`
## 完成标准
满足以下条件才算本阶段收口:
1. main-scene feature 注入规则不再散落在多个 feature 里重复实现。
2. Gaussian / Volumetric 共用统一 native scene feature controller。
3. `XCEditor` 编译通过old editor 冒烟通过。

View File

@@ -0,0 +1,63 @@
# SRP / URP Managed Final Color Request Policy Plan
## Background
The previous SRP cleanup already moved several policies out of native defaults and into managed URP request/planning seams.
The remaining native baseline dependency was `final color policy`:
- pipeline default final color settings
- camera final color overrides
- `requiresProcessing` source data
That policy was still injected from native camera-frame baseline into `CameraFramePlan.finalColorPolicy`, which meant renderer-backed URP was not yet the real owner of final color policy.
## Goal
Move final color policy ownership from native camera-frame baseline into the managed request seam.
After this phase:
- URP resolves final color policy in `ConfigureRendererCameraRequest(...)`
- `CameraRenderRequest.finalColorPolicy` becomes the source of truth
- `CameraFramePlan` simply inherits the resolved request policy
- the native `UsesNativeCameraFramePlanBaseline*` bridge is removed
## Design
### 1. Camera read seam
Expose managed read access for camera final color overrides:
- `Camera.hasFinalColorOverrides`
- `Camera.GetFinalColorOverrideSettings()`
### 2. Request write seam
Expose managed write access for resolved request policy:
- `CameraRenderRequestContext.SetResolvedFinalColorPolicy(...)`
- `CameraRenderRequestContext.ClearFinalColorPolicy()`
### 3. URP policy ownership
`UniversalRenderPipelineAsset.ConfigureRendererCameraRequest(...)` should:
- read pipeline default final color settings
- read camera overrides
- resolve the final settings
- write the resolved policy back into request context
## Completion
- Status: completed on 2026-04-21
- Added managed `FinalColorOverrideSettings`
- Added camera final color override read seam
- Added request-context final color policy write seam
- Moved URP final color resolution into managed request configuration
- Removed `UsesNativeCameraFramePlanBaseline*` from managed/native SRP bridge
## Verification
- `cmake --build . --config Debug --target XCEditor`
- old editor smoke passed
- `SceneReady elapsed_ms=6129 first_frame_ms=719`

View File

@@ -0,0 +1,107 @@
# SRP / URP Managed Fullscreen Auxiliary Texture Binding Plan
时间2026-04-22
## 背景
上一阶段已经补上了 managed raster pass 对 depth 读依赖和 depth attachment 的声明能力,但这条链只走到了 render graph 依赖记录层,并没有真正把额外输入纹理绑定到 fullscreen/custom pass 的 shader 资源槽位。
当前实际问题:
1. `RenderGraphRasterPassBuilder.UseTexture(...)` / `UseDepthTexture(...)` 只声明读依赖,不会形成 shader 资源绑定。
2. `BuiltinVectorFullscreenPass` 仍然是手写单 `SourceColorTexture` + 单 sampler 的 descriptor layout。
3. render graph callback 在执行 `RenderPassContext` 时只携带 `sourceColorView`,没有携带额外输入纹理的 SRV。
4. render graph 对 transient depth 只建了 DSV没有建可采样的 SRV导致 graph 内部深度纹理即使声明为 read depth也不能被 fullscreen shader 真正采样。
这会导致 managed SRP / URP 侧写出来的 fullscreen/custom pass 只能做“单输入 source color”效果无法形成真正可用的自定义后处理输入面。
## 本阶段目标
把 managed fullscreen/custom pass 的“声明输入纹理”与“运行时真实绑定纹理”收成闭环,并保持架构方向继续对齐 Unity 风格:
- C++ core 继续拥有 render graph、资源生命周期和执行调度。
- managed SRP / URP 继续拥有 pass authoring 和 shader 输入声明。
- fullscreen pass 不再手写固定单纹理布局,而是接到现有 shader 资源绑定计划能力上。
## 范围
本阶段只做 fullscreen/custom raster pass 输入绑定闭环,不做:
- deferred pipeline
- shadow 系统迁移
- surface/imported texture 多视图系统大改
- renderer 多实现切换
## 实施步骤
### 1. Managed API 补齐“按 shader 资源名绑定输入纹理”
`RenderGraphRasterPassBuilder` 增加显式输入绑定 API
- `BindTexture(string shaderResourceName, RenderGraphTextureHandle texture)`
- `BindDepthTexture(string shaderResourceName, RenderGraphTextureHandle texture)`
这两个 API 需要同时完成两件事:
1. 自动登记 graph read dependency
2. 自动登记 runtime shader resource binding request
这样 managed 侧不会再出现“声明读了,但执行没绑上”的双轨状态。
### 2. Mono bridge 保留纹理绑定描述
`ManagedScriptableRenderContextState::RasterPassRecordRequest` 中新增 fullscreen 输入绑定记录,至少包含:
- shader resource name
- render graph texture handle
- texture aspectcolor / depth
并增加 internal call把 managed builder 的输入绑定请求带到 native。
### 3. RenderGraph callback 执行上下文补额外 SRV
扩展 `RenderPassContext`,让 callback/fullscreen pass 在执行时能拿到:
- `sourceColorView`
- 额外输入纹理对应的已解析 SRV 列表
执行阶段需要按 handle 解析实际 view
- `sourceColorTexture` 特殊走现有 `sourceColorView`
- 其他 graph-managed 纹理走 `ResolveTextureView(..., ShaderResource)`
- 如果拿不到 shader-readable view则 pass 执行失败
### 4. 补 transient depth SRV
render graph runtime 目前对 transient depth 只创建 DSV不创建 SRV。
需要修改 runtime texture allocation 逻辑,让 transient depth 也能生成 `shaderResourceView`,从而支持 fullscreen shader 读取 graph 内部 depth texture。
### 5. BuiltinVectorFullscreenPass 接入 shader 资源绑定计划
`BuiltinVectorFullscreenPass` 从“手写 3 个 descriptor set”改成
- 解析 shader pass 的资源绑定计划
- 基于 binding plan 自动创建 set layout / pipeline layout
- 自动填充 `PassConstants`
- 自动填充 `SourceColorTexture`
- 自动填充 `LinearClampSampler`
- 对其余 `Texture2D` 资源按 resource name 从 runtime 输入绑定表里解析
也就是说fullscreen vector pass 要变成一个真正的“受控小型 material/fullscreen pass”而不是只支持 `SourceColorTexture` 的专用壳。
## 阶段完成标准
满足以下条件才算本阶段收口:
1. managed fullscreen/custom pass 可以声明并真正绑定额外 color/depth 输入纹理。
2. `BuiltinVectorFullscreenPass` 不再硬编码单纹理 descriptor layout。
3. graph 内部 transient depth 能生成并提供可采样 SRV。
4. `XCEditor` Debug 构建通过。
5. old editor 冒烟至少 10-15 秒通过,日志出现 `SceneReady`
## 已知边界
本阶段不主动扩 surface/imported texture 的多视图系统。
也就是说,若某些 imported texture 当前只有 RTV / DSV、没有独立 SRV 视图,这部分仍然不是完整方案;后续如果要让任意 imported color/depth 都可被 graph 中任意 pass 采样,需要单独做 imported resource multi-view / surface-view ownership 收口计划。

View File

@@ -0,0 +1,107 @@
# SRP / URP Managed Render Graph Fullscreen Depth Surface Plan
Date: 2026-04-21
## Background
The current SRP / URP managed render-graph surface is usable, but still too
thin in one important place:
- managed fullscreen raster passes can read source color
- managed fullscreen raster passes can write color targets
- managed fullscreen raster passes cannot explicitly declare depth-texture reads
- managed fullscreen raster passes cannot explicitly keep or override a depth
attachment
That is an architectural gap, not just a convenience issue.
If a C# renderer feature wants to implement a depth-aware fullscreen effect
(for example edge detection, fog composition, SSAO-style composition, depth
conditioned blur, or custom outline logic), it currently has no correct managed
API surface to describe that dependency to the native render graph.
So even though the native render graph already supports depth texture access,
the managed SRP surface still under-expresses the dependency graph.
## Goal
Close the first managed render-graph execution-surface gap by making managed
fullscreen raster recording depth-aware.
After this stage:
- managed C# fullscreen raster passes can declare depth texture reads
- managed C# fullscreen raster passes can explicitly set a depth attachment when
needed
- the Mono bridge preserves those declarations into the native render graph
- native graph recording uses depth-as-depth semantics instead of treating every
read texture as color
## Scope
Included:
- `managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderContext.cs`
- `managed/XCEngine.ScriptCore/Rendering/Graph/RenderGraphRasterPassBuilder.cs`
- `managed/XCEngine.ScriptCore/InternalCalls.cs`
- `engine/src/Scripting/Mono/MonoScriptRuntime.cpp`
- `engine/include/XCEngine/Rendering/RenderPassGraphContract.h`
- `engine/src/Rendering/RenderPassGraphContract.cpp`
Not included:
- deferred renderer work
- moving shadow / gaussian / volumetric runtime ownership in this phase
- generic managed compute-pass authoring in this phase
- editor / new_editor work
## Implementation Plan
1. Extend managed raster-pass builder with depth read / depth attachment APIs
2. Extend Mono internal calls and pending managed fullscreen-pass request state
3. Preserve depth reads separately from color reads through native bridge flush
4. Teach native raster-pass graph recording to issue depth reads with correct
render-graph aspect semantics
5. Rebuild old `XCEditor`
6. Run old editor smoke for at least 10 seconds and verify `SceneReady`
7. Archive the plan, commit, and push
## Exit Criteria
- managed code can call APIs equivalent to:
- `UseDepthTexture(...)`
- `SetDepthAttachment(...)`
- native bridge stores depth reads independently from color reads
- native render-graph recording emits `ReadDepthTexture(...)` for managed depth
inputs
- old `XCEditor` Debug build succeeds
- old editor smoke succeeds
## Why This Stage First
This is the right next step because it improves the managed SRP execution
surface without prematurely expanding into deferred rendering or feature
migration.
It makes the current managed URP layer materially more useful for real custom
renderer features, while keeping the change scoped and architecture-driven.
## Result
Completed on 2026-04-21.
- extended managed fullscreen raster-pass authoring with:
- `UseDepthTexture(...)`
- `SetDepthAttachment(...)`
- extended Mono internal-call bridge to preserve fullscreen managed depth reads
and optional depth attachment overrides
- extended native raster-pass graph recording to emit depth reads with
`ReadDepthTexture(...)` instead of treating all managed read dependencies as
color
- preserved existing fullscreen source-color path and final-output behavior
## Verification
- `cmake --build . --config Debug --target XCEditor`
- old editor smoke passed
- `SceneReady elapsed_ms=5621 first_frame_ms=602`

View File

@@ -0,0 +1,74 @@
# SRP / URP Native Scene Feature Id Bridge Plan
## Background
Current managed URP feature wrappers for gaussian splat and volumetric rendering
already live in the URP package, but the bridge into native runtime still uses
string names:
- managed `NativeSceneFeaturePass("BuiltinGaussianSplatPass", ...)`
- managed `NativeSceneFeaturePass("BuiltinVolumetricPass", ...)`
- native host resolves feature passes by string comparison
This is a transitional seam, not a stable long-term SRP/URP backbone.
## Goal
Replace string-based native scene feature dispatch with an explicit feature id bridge.
After this phase:
- managed URP records native scene features by enum/id
- native scene feature host resolves by stable feature id
- feature pass names remain only for logging / graph labeling
- future native-backed URP features can reuse the same bridge cleanly
## Scope
### Step 1. Add explicit native scene feature id type
- add native enum for scene feature ids
- add managed enum mirror
- keep values explicit and stable
### Step 2. Move recorder bridge from string to id
- `ScriptableRenderContext.RecordNativeSceneFeaturePass(...)`
- Mono internal call bridge
- `NativeSceneRecorder::RecordFeaturePass(...)`
- `SceneRenderFeatureHost::RecordFeaturePass(...)`
### Step 3. Bind builtin native features to explicit ids
- `BuiltinGaussianSplatPass`
- `BuiltinVolumetricPass`
- managed `NativeSceneFeaturePass`
- managed builtin renderer features
## Non-goals
- changing gaussian splat runtime logic
- changing volumetric runtime logic
- moving shadow runtime in this phase
- deferred renderer work
## Exit Criteria
- no managed/native string-based native feature dispatch remains
- old editor `XCEditor` Debug build passes
- old editor smoke reaches `SceneReady`
## Result
Completed on 2026-04-21.
- added explicit native/managed `NativeSceneFeaturePassId` enums
- replaced string-based native scene feature pass recording with id-based dispatch
- bound builtin gaussian splat / volumetric native passes to stable ids
- kept pass names only for logging and render-graph labeling
## Verification
- `cmake --build . --config Debug --target XCEditor`
- old editor smoke passed
- `SceneReady elapsed_ms=6277 first_frame_ms=637`

View File

@@ -0,0 +1,86 @@
# SRP / URP Native Scene Feature Registration Ownership Plan
## Background
Current native gaussian splat / volumetric scene feature passes have already
been lifted into a managed URP-facing wrapper layer:
- `UniversalRendererData` owns the default feature list
- managed URP records native scene features explicitly
- native dispatch now uses stable `NativeSceneFeaturePassId`
But one C++ ownership seam is still dirty:
- `BuiltinForwardPipeline` constructor silently registers default native scene
feature passes
- that means pipeline instantiation itself still decides which first-party
native scene features exist
- the default backend asset / scene draw backend factory do not own that policy
This keeps an avoidable hidden side effect inside the pipeline runtime object.
## Goal
Move default native scene feature registration out of
`BuiltinForwardPipeline` construction and into explicit backend
configuration/factory ownership.
After this phase:
- `BuiltinForwardPipeline` only owns execution/runtime state
- default native scene feature availability is configured by
backend asset/factory code
- default backend asset creation and default scene draw backend creation share
the same setup path
## Scope
### Step 1. Remove constructor-side feature registration
- stop registering default scene features inside
`BuiltinForwardPipeline::BuiltinForwardPipeline()`
### Step 2. Centralize configured builtin forward creation
- introduce one explicit setup path for default builtin forward scene features
- use that path from `BuiltinForwardPipelineAsset`
- use that path from default scene draw backend creation / fallback creation
### Step 3. Verify no behavior regression
- rebuild old `XCEditor`
- run old editor smoke until `SceneReady`
## Non-goals
- changing gaussian splat runtime logic
- changing volumetric runtime logic
- moving shadow runtime in this phase
- deferred renderer work
- editor / new_editor work
## Exit Criteria
- `BuiltinForwardPipeline` constructor no longer performs implicit native scene
feature registration
- default builtin forward backend creation still exposes gaussian splat /
volumetric native features through the explicit factory path
- old editor `XCEditor` Debug build passes
- old editor smoke reaches `SceneReady`
## Result
Completed on 2026-04-21.
- removed constructor-side default native scene feature registration from
`BuiltinForwardPipeline`
- centralized configured builtin forward creation in
`BuiltinForwardSceneSetup`
- routed builtin forward asset creation, default scene draw backend creation,
and host fallback creation through the same configured pipeline path
## Verification
- `cmake --build . --config Debug --target XCEditor`
- old editor smoke passed
- `SceneReady elapsed_ms=5493 first_frame_ms=614`

View File

@@ -0,0 +1,40 @@
# SRP/URP ObjectId Tooling Boundary Plan
日期2026-04-21
## 背景
`ObjectId` 这条链路当前主要用于 editor 视口拾取和选中描边,不属于 runtime SRP/URP 主渲染能力。
上一阶段把 standalone stage fallback ownership 从 host 往 backend 收口时,`ObjectId` 也一起落到了 builtin forward backend setup 中。这个方向不对:
1. `ShadowCaster` / `DepthOnly` 属于 scene rendering stage适合归到 backend 或 renderer 规划边界。
2. `ObjectId` 更像 tooling render request只在 editor / picking / selection 这条链路上使用。
3. 如果把 `ObjectId` 继续和 shadow/depth 混在一起,会误导后续 SRP/URP 分层,让它看起来像 URP runtime feature。
## 目标
1.`ObjectId` 从 builtin forward backend ownership 中移出。
2.`ObjectId` 重新挂到顶层 `CameraRenderer` 执行入口,作为通用 tooling pass 能力。
3. 保持 editor 视口 object-id picking 行为不变。
## 实施步骤
1.`BuiltinForwardSceneSetup` 中移除 `BuiltinObjectIdPass` 注册。
2.`CameraRenderer` 顶层 pipeline 绑定路径中补上 object-id tooling pass 注入。
3. 重新编译旧版 `XCEditor`,运行旧版 editor 冒烟并确认 `SceneReady`
## 完成判定
1. builtin forward backend 不再拥有 `ObjectId` fallback 注册。
2. `CameraRenderer` 创建或切换顶层 pipeline 后,会显式提供 `ObjectId` tooling pass。
3. 旧版 editor 编译通过并冒烟通过。
## 结果
1. `BuiltinForwardSceneSetup` 已移除 `BuiltinObjectIdPass` 注册builtin forward backend 现在只保留 scene-stage 相关 fallback。
2. `CameraRenderer` 在顶层 pipeline 绑定路径中统一注入 `ObjectId` standalone pass语义上归为 tooling/editor request。
3. 验证结果:
`cmake --build . --config Debug --target XCEditor` 通过。
旧版 editor 冒烟 15 秒通过。
日志结果:`SceneReady elapsed_ms=5621 first_frame_ms=602`

View File

@@ -0,0 +1,28 @@
# SRP/URP Probe ScriptableObject Authoring Cleanup Plan
日期2026-04-21
## 背景
当前生产代码里的 `RenderPipelineAsset``ScriptableRendererData``ScriptableRendererFeature` 已经切到 `ScriptableObject` 基底,并且默认创建路径开始优先走 `ScriptableObject.CreateInstance(...)`
`managed/GameScripts/RenderPipelineApiProbe.cs` 里仍然残留一批直接 `new` 出 render asset、renderer data、renderer feature 的路径。这会让 probe 的 authoring 语义落后于当前 SRP/URP 主线,也会让后续继续按 Unity 风格推进时,测试/探针层和产品层出现分叉。
## 目标
1. 把 probe 中由脚本直接 author 的 render asset / renderer data / renderer feature 创建路径统一到 `ScriptableObject.CreateInstance(...)`
2. 对少数仍依赖带参构造的 probe `ScriptableObject` 子类,改成 Unity 风格的“无参创建 + 字段配置”。
3. 不改 native backend不改 `new_editor`,只收口 probe authoring 语义。
## 实施步骤
1.`RenderPipelineApiProbe.cs` 中补一个轻量的 ScriptableObject probe 工具,统一创建和空值过滤。
2. 迁移 probe asset 构造、runtime selection probe、renderer data 默认 feature 配置,移除直接 `new``ScriptableObject` 派生类型的路径。
3. 处理少数带参构造的 probe feature / renderer data使其可通过 `CreateInstance(...)` 创建后再配置。
4. 重新编译 `XCEditor`,运行旧版 `editor/bin/Debug/XCEngine.exe` 冒烟至少 10 秒,确认 `SceneReady`
## 完成判定
1. `RenderPipelineApiProbe.cs` 中 probe authoring 路径不再直接 `new` 出 render asset / renderer data / renderer feature。
2. `cmake --build build --config Debug --target XCEditor` 成功。
3. 旧版 editor 冒烟通过,日志出现新的 `SceneReady`

View File

@@ -0,0 +1,93 @@
# SRP / URP Render Graph Imported Surface Multi-View Plan
时间2026-04-22
## 背景
上一阶段已经打通了 managed fullscreen/custom pass 的额外纹理绑定链路,也补上了 transient depth 的 SRV 创建。
但 render graph 对 imported texture 的建模仍然是不完整的:
1. `RenderGraph::TextureResource` 只保存了一个 `importedView`
2. `RenderGraphRuntimeResources::ResolveTextureView(...)` 对 imported texture 不区分请求的 view type直接返回这一份 view
3. imported color / depth 一旦进入 graph就无法稳定地在不同阶段之间切换 `RTV / DSV / SRV`
4. graph-managed imported surface 在 fullscreen/custom pass 中采样 imported depth / color 时,仍然可能拿到错误类型的 view
这会导致 render graph 表面上已经接管 imported surface 的生命周期与状态调度,但在真正执行时还没有形成“纹理资源 + 多视图解析”的闭环。
## 本阶段目标
把 imported texture 从“只有一个盲视图指针”升级成“保留底层纹理资源,并能按需解析不同 view type”的运行时模型。
阶段完成后应满足:
1. imported texture 能从 `RHIResourceView` 反查到底层 `RHITexture`
2. render graph 能为 imported texture 按请求解析 `RenderTarget / DepthStencil / ShaderResource / UnorderedAccess`
3. 对 graph-owned imported transitions不再依赖导入时碰巧传进来的那一个 view 类型
4. managed fullscreen/custom pass 采样 imported surface 时color / depth 都能走统一的 `ResolveTextureView(..., ShaderResource)` 路径
5. `XCEditor` Debug 构建通过old editor 冒烟至少 10-15 秒并出现 `SceneReady`
## 范围
本阶段只收口 imported texture multi-view 运行时能力,不做:
- deferred pipeline
- shadow 系统迁移
- editor 侧功能扩展
- imported buffer multi-view 建模
- RenderSurface 大规模重做
## 实施步骤
### 1. 抬升 texture-backed view 抽象
`RHIResourceView` 抽象层增加统一接口,让上层可以判断一个 view 是否绑定到某个 `RHITexture`
要求:
- `RHIResourceView` 暴露 `GetTextureResource()`
- Vulkan / OpenGL 返回各自已经持有的 texture 指针
- D3D12 纹理视图补齐 `D3D12Texture*` 存储,并通过该接口返回
- buffer view 继续返回空指针
### 2. 扩展 render graph imported texture 元数据
在 render graph builder / compiler / runtime 之间,把 imported texture 的“底层纹理资源”一起传下去,而不是只传一份 primary view。
要求:
- `RenderGraph::TextureResource` 记录 imported texture 指针
- `CompiledRenderGraph::CompiledTexture` 同步保存该信息
- compiler 对 graph-owned imported transitions 增加更严格校验:
`graphOwnsTransitions == true` 时必须导入 texture-backed view
### 3. 重做 imported texture runtime view 解析
把 imported texture 的运行时解析从“固定返回 importedView”改成
1. 如果 primary imported view 类型正好匹配请求,则直接返回 primary view
2. 如果类型不匹配,但有底层 imported texture则按需创建目标 view
3. 运行时缓存这些按需创建的派生 view并在 graph 执行结束后释放
要求:
- `ResolveTextureView(handle, viewType)` 对 imported / transient 路径统一
- 派生 view 创建走 `RHIDevice`,不允许在 render graph 里做后端特化 cast
- depth texture 不创建 RTVcolor texture 不创建 DSV
- 失败时返回空指针,由上层执行链路报错
### 4. 完成验证与归档
执行以下验证闭环:
1. `cmake --build . --config Debug --target XCEditor`
2. 运行 old editor 冒烟 15 秒
3. 检查 `editor/bin/Debug/editor.log` 出现 `SceneReady`
4. plan 归档到 `docs/used`
5. 使用规范 Conventional Commit 提交并推送
## 风险与边界
1. swapchain backbuffer 是否支持 SRV取决于后端和资源创建方式本阶段不为此额外改造 swapchain 资源描述
2. 如果某个 imported view 不是 texture-backed view本阶段不会伪造多视图能力
3. 本阶段先解决“可正确建模并解析 imported texture view”的根问题不扩展更高层 surface API

View File

@@ -0,0 +1,90 @@
# SRP / URP Renderer Block Formalization Plan
时间2026-04-22
## 背景
当前渲染主线已经完成了两件更底层的事情:
1. C++ 侧的 RenderGraph / runtime resource / stage contract 已经能稳定承接 managed SRP。
2. managed 侧也已经有 `ScriptableRenderer / RendererFeature / RenderPass` 这套骨架,并且 post-process / final output 的 graph 绑定已经打通。
但 renderer 这一层还有一个明显的问题没有收口:
- `ScriptableRenderer` 现在还是把所有 pass 丢进一个总队列,然后在录制时按 `CameraFrameStage` 逐个扫描、过滤。
- 这意味着 renderer 的“组织单位”依然是 stage而不是 renderer 自己拥有的 block。
- 对后续把阴影、体积、Gaussian、更多 scene feature 逐步迁到 URP 层不够友好,因为缺少稳定的 block 落点。
这一步的目标不是继续扩 RenderGraph 功能,也不是开始 deferred而是先把 managed renderer 的组织方式收紧。
## 本阶段目标
把 managed `ScriptableRenderer` 从“单队列 + stage 过滤”重构成“显式 renderer block 录制”,并保持当前 C++ stage 边界不变。
目标结果:
1. `ScriptableRenderer` 内部显式识别 `ShadowCaster / DepthPrepass / MainOpaque / MainSkybox / MainTransparent / PostProcess / FinalOutput`
2. stage 仍然只是 native 执行边界renderer 内部真正按 block 组织与录制。
3. `UniversalRenderer` 后续迁移阴影、体积、Gaussian 等逻辑时,有稳定的 block 入口可以承接。
4. 不引入新的兼容层,不保留“旧逻辑先留着”的临时路线。
## 范围
本阶段只做 managed SRP / URP 组织重构,不做:
- deferred rendering
- shadow 算法升级
- editor 侧面板与资源工作流
- ObjectId 这类 editor-only 特性迁移
## 实施步骤
### 1. 补齐 renderer block 基础类型
新增 renderer block 枚举与辅助工具,统一维护:
- pass event -> renderer block
- renderer block -> camera frame stage
- renderer block 的运行时范围描述
### 2. 重构 ScriptableRenderer 的录制入口
保留 active pass queue 作为排序输入,但录制逻辑改为:
1. 先按 `RenderPassEvent` 排序构建 active pass queue
2. 再根据 event range 构建 renderer block range
3. 按当前 stage 对应的 block 顺序执行
也就是说:
- `MainScene` 不再是“扫完整队列找属于 MainScene 的 pass”
- 而是显式录制 `MainOpaque -> MainSkybox -> MainTransparent`
### 3. 清理 stage-driven 痕迹
重点清理:
- `ScriptableRenderer` 内部 `renderPass.SupportsStage(...)` 式的全队列过滤
-`SupportsRendererRecording / RecordRenderer` 改成基于 block 判断
保留:
- native C++ 仍然通过 `CameraFrameStage` 调用 managed
- `ScriptableRenderPass.SupportsStage(...)` 作为公共 API 兼容入口,但内部改为基于 block 推导
### 4. 验证主线不回退
要求:
1. `XCEditor` Debug 构建通过
2. old editor 冒烟运行至少 10 秒
3. `editor.log` 出现 `SceneReady`
## 完成标准
满足以下条件才算本阶段收口:
1. `ScriptableRenderer` 不再通过“单队列 + stage 过滤”驱动录制。
2. renderer block 成为 managed renderer 内部的正式组织单位。
3. `UniversalRenderer` 当前默认路径行为不回退。
4. `XCEditor` 构建与 old editor 冒烟通过。

View File

@@ -0,0 +1,64 @@
# SRP / URP Renderer Data Collection Plan
时间2026-04-22
## 背景
上一阶段已经把 `ScriptableRendererData` 里的 `rendererFeatures` 生命周期收成了
`ScriptableRendererFeatureCollection`,但 pipeline asset 这一层还有同类问题:
1. `RendererBackedRenderPipelineAsset` 直接持有并管理 `rendererDataList/defaultRendererIndex`
2. renderer data 的默认创建、fallback 解析、重复引用释放、runtime hash 都散落在 asset 类里
3. 这会让 asset 同时承担 authoring 表达和 runtime collection 管理两类职责
这和上一阶段收 `rendererFeatures` 之前的状态很像,也不利于后续继续往 Unity 风格的
多个 renderer variant 演进。
## 目标
把 asset 层的 renderer data 管理正式收成一个 collection 边界。
阶段完成后要达到:
1. `RendererBackedRenderPipelineAsset` 不再散写 renderer data 列表生命周期细节
2. 默认 renderer data 创建、index fallback、runtime hash、release 都有统一落点
3. 不改变现有外部 authoring 入口,仍然保留 `rendererDataList/defaultRendererIndex`
4. 为后续继续做 Unity 风格的 renderer variant / renderer profile 留出干净接缝
## 范围
本阶段只处理 renderer data collection 收口,不做:
- deferred renderer
- editor inspector / 面板
- public API 大改
- 阴影或 post-process 功能扩展
## 实施步骤
### 1. 新增 ScriptableRendererDataCollection
职责:
- 统一解析 `rendererDataList`
- 统一保证默认 renderer data 存在
- 统一处理 `defaultRendererIndex` fallback
- 统一计算 collection runtime hash
- 统一释放 renderer data runtime 资源
### 2. 接入 RendererBackedRenderPipelineAsset
迁移内容:
- renderer data 解析
- renderer 选择
- runtime version 同步
- release 流程
## 完成标准
满足以下条件才算本阶段收口:
1. `RendererBackedRenderPipelineAsset` 不再自己散写 renderer data collection 细节
2. `XCEditor` 编译通过
3. old editor 冒烟至少 10 秒通过

View File

@@ -0,0 +1,82 @@
# SRP / URP Renderer Explicit Stage Planning Plan
时间2026-04-22
## 背景
当前 managed `ScriptableRenderer / ScriptableRendererFeature / ScriptableRenderPass` 骨架已经可用,
但 renderer 这一层还有一个不干净的旧接缝:
1. `ScriptableRenderer.FinalizeCameraFramePlan(...)` 仍然会根据 active pass queue 自动推断
`ShadowCaster / DepthOnly / PostProcess / FinalOutput` stage
2. 这个推断依赖一份“planning 阶段伪造的 `RenderingData(MainScene)`”,并不是真正的 renderer planning contract
3. 结果是 renderer / feature 看起来已经在控制管线,但 stage ownership 仍然有一部分藏在基类启发式里
这不符合要对齐 Unity SRP / URP 的目标。
Unity 风格应该是:
- renderer / feature 显式决定本帧需要哪些阶段
- native C++ 只负责 stage 执行、RenderGraph、scene draw substrate
- 不能再让基类偷偷扫描 pass queue 替上层“猜阶段”
## 本阶段目标
把 managed renderer 的 stage planning 从“隐式推断”收成“显式声明”:
1. 去掉 `ScriptableRenderer` 基类里的 stage 推断逻辑
2. 让真正拥有 pass 的 renderer / feature 自己在 planning hook 中申请所需 stage
3. 保证现有 Universal 默认路径和 probe/sample 路径仍然能工作
4. 完成后renderer-driven SRP 的组织权更清晰,后续再继续往 renderer pass / renderer feature 主线推进
## 范围
本阶段只处理 managed renderer 的显式 stage planning不做
- deferred pipeline
- shadow 资源系统迁移
- RenderGraph 新功能扩展
- editor 逻辑
## 实施步骤
### 1. 清理 `ScriptableRenderer` 基类隐式推断
删除以下旧逻辑:
- `CreatePlanningRenderingData(...)`
- `ApplyInferredFullscreenStageRequests(...)`
- `ApplyInferredStandaloneStageRequests(...)`
- `HasQueuedPassForStage(...)`
`FinalizeCameraFramePlan(...)` 保持为空默认实现,不再隐式改 plan。
### 2. 把 stage planning 放回真正拥有 pass 的类型
至少补齐:
- `ColorScalePostProcessRendererFeature`
- GameScripts 里的 fullscreen probe feature / renderer
原则:
- post-process feature 显式请求 `PostProcess`
- 如需把结果交给 `FinalOutput`,则显式申请 graph-managed output color
- 如有 final-output pass则显式请求 `FinalOutput`
### 3. 验证当前主线不回退
要求:
1. `XCEditor` Debug 构建通过
2. old editor 冒烟 15 秒通过
3. `editor.log` 出现 `SceneReady`
## 完成标准
满足以下条件才算收口:
1. managed renderer 的 stage planning 不再依赖基类扫描 pass queue 的启发式
2. 现有 Universal 默认 renderer 仍可运行
3. probe/sample fullscreen renderer 走显式 planning 后仍能编译通过
4. `XCEditor` 编译和 old editor 冒烟通过

View File

@@ -0,0 +1,70 @@
# SRP / URP Renderer Feature Collection Plan
时间2026-04-22
## 背景
当前 feature 层的 runtime boundary 已经基本收好,但 `renderer data` 这一层还有明显的结构问题:
1. `ScriptableRendererData` 直接持有并操作 `rendererFeatures` 数组。
2. feature owner bind、active 遍历、runtime state hash、runtime release 这些逻辑在 `ScriptableRendererData` 里分散重复。
3. `UniversalRendererData` 的默认 feature 组合也还是直接在 `CreateDefaultRendererFeatures()` 里硬编码构造。
这会导致:
- `renderer data` 既在做 renderer asset 表达,又在做 feature collection 运行时管理。
- 默认 feature 组合没有正式落点,后续扩展不同 renderer profile 时不利于演进。
## 本阶段目标
`rendererFeatures` 这层正式收成 collection / factory 结构。
目标结果:
1. `ScriptableRendererFeatureCollection` 统一管理 feature 数组的 bind、active 遍历、hash、release。
2. `ScriptableRendererData` 不再散写 feature 集合生命周期。
3. `UniversalRendererData` 的默认 feature 组合改走明确工厂。
## 范围
本阶段只处理 renderer feature collection不做
- public renderer feature API 改造
- deferred rendering
- editor feature 分类面板
- C++ host / RenderGraph 改造
## 实施步骤
### 1. 新增 ScriptableRendererFeatureCollection
职责:
- 持有 feature 数组引用
- 统一 bind owner
- 统一 active 遍历
- 统一计算 collection hash
- 统一 runtime release
### 2. 接入 ScriptableRendererData
迁移:
- `ConfigureCameraRenderRequestInstance`
- `ConfigureCameraFramePlanInstance`
- `ConfigureRenderSceneSetupInstance`
- `ConfigureDirectionalShadowExecutionStateInstance`
- `ReleaseRendererSetupCache`
- renderer feature collection state sync
### 3. 抽离 Universal 默认 feature 工厂
新增 `UniversalDefaultRendererFeatureFactory`,负责默认 builtin feature 组合。
## 完成标准
满足以下条件才算本阶段收口:
1. `ScriptableRendererData` 不再自己散写 feature collection 生命周期细节。
2. `UniversalRendererData` 默认 feature 组合走明确工厂。
3. `XCEditor` 编译通过old editor 冒烟通过。

View File

@@ -0,0 +1,100 @@
# SRP / URP Request Policy And Scene Setup Seam Plan
## 背景
当前渲染模块已经基本形成了如下分层:
- C++ 层负责 Render Graph、frame execution、scene extraction、native scene draw backend、shadow runtime、fullscreen substrate 等执行底座
- managed SRP / URP 层负责 renderer 选择、pass 组织、feature 组织、camera/frame planning 策略
但当前仍有两类关键策略口没有完全收干净:
1. `CameraRenderRequest` 阶段仍有部分默认策略固定在 C++ 层
2. `RenderSceneSetup` 阶段 managed 层还缺少足够的配置能力,当前主要仍在调用 native default
这会导致 SRP / URP 虽然已经能组织 pass但还没有完全接管“为什么这么渲染”的策略层。
## 本阶段目标
本阶段不继续搬运 native draw backend不做 deferred不扩张底层执行复杂度只收策略边界。
### 目标一
把 request seam 做实,让 managed URP 可以直接接管以下 request-level 策略:
- camera stack / clear mode 读取
- request clear flags 覆盖
- directional shadow request 抑制与规划参数调整
- renderer 选择仍保持由 managed 决定
### 目标二
为后续 scene setup seam 做准备,明确下一阶段 managed 需要接管的 scene setup 内容:
- environment policy
- skybox policy
- global shader keywords policy
## 本阶段实施步骤
### Step 1. 扩展 request context 与 camera managed API
补齐 managed 侧 request policy 所需的最小上下文:
- `Camera.clearMode`
- `Camera.stackType`
- `CameraRenderRequestContext.clearFlags`
要求:
- 通过 Mono internal call 打通
- 不引入兼容层、废弃层或双轨 API
- 保持 request 仍由 C++ 创建,但允许 managed 在 request 阶段覆盖策略结果
### Step 2. 把默认 request clear / shadow policy 收进 URP
`UniversalRenderPipelineAsset` 中接管默认 request policy
- 依据 camera clear mode 和 stack type 解析 request clear flags
- 继续在 managed 层控制 main light shadow request 是否保留
- 继续在 managed 层控制 shadow planning settings
要求:
- 默认行为与当前引擎已有表现保持一致
- native default policy 退化为底座 fallback而不是 URP 主路径
### Step 3. 预留 scene setup seam 下一阶段入口
本阶段先不大改 scene setup但要确认下一阶段的直接入口
- `RenderSceneSetupContext` 需要扩展哪些显式设置能力
- `UniversalRenderer.ConfigureRenderSceneSetup(...)` 之后如何从“调用 default”过渡为“显式配置环境与关键字”
## 收口标准
- managed 层可以读取 camera stack / clear mode
- managed 层可以覆盖 request clear flags
- URP 默认 clear / shadow request 策略由 managed 决定
- `XCEditor` Debug 编译通过
- 旧版 editor 冒烟通过
## 非目标
本阶段不做以下事项:
- deferred rendering
- render graph 大改
- native scene draw backend 搬迁
- 阴影算法本体迁移到 managed
- gaussian / volumetric native 执行实现迁移
## 完成情况
- 已补齐 managed request seam 所需的 `Camera.clearMode``Camera.stackType``CameraRenderRequestContext.clearFlags`
- 已将 URP 默认 request clear policy 收进 managed `UniversalRenderPipelineAsset`
- 已将 `RenderClearFlags` 收敛到 rendering core移除 URP 包内重复定义
- 已让 `UniversalRenderer.ConfigureRenderSceneSetup(...)` 从 bundled `UseDefaultSceneSetup()` 过渡为显式组合 environment / global keywords
- 已补齐 `RenderSceneSetupContext.camera` 入口,便于下一阶段继续接管 scene setup policy
- `XCEditor` Debug 编译通过
- 旧版 editor 冒烟通过

View File

@@ -0,0 +1,31 @@
# SRP/URP Shadow Boundary Closure Plan
日期2026-04-21
## 背景
当前 SRP/URP 骨架已经基本成型,但阴影这条链路在 managed 与 native 之间还有一个关键边界没收干净:
1. `UniversalRenderPipelineAsset` / `UniversalRenderer` 已经在 managed 层表达阴影开关、stage 规划与 renderer 级别控制。
2. native 侧仍保留阴影图分配与默认执行策略,这本身是当前阶段合理的 substrate。
3. 但当 managed renderer 明确不想执行阴影时,如果只是不配置 execution statehost 仍可能回落到 native 默认阴影执行,导致 managed 决策失效。
这会让 shadow 的“策略在 managed执行底座在 native”的边界重新变脏。
## 目标
1. 收紧 shadow execution 边界,确保 managed renderer 明确关闭阴影时,不会再落回 native 默认执行。
2. 保持当前 native 阴影 runtime / surface allocation / default execution substrate 不变,不扩功能,不碰 deferred。
3. 通过一次编译和旧版 editor 冒烟验证,尽快把这一个骨架口子收掉。
## 实施步骤
1. 修正 `UniversalRenderer.ConfigureDirectionalShadowExecutionState(...)`,让 shadow caster block 禁用或无阴影计划时显式清空 execution state而不是隐式留给 host fallback。
2. 复查这条路径的 host fallback 行为,确认 managed 明确配置后不会再重回 native 默认阴影执行。
3. 重新编译 `XCEditor`,运行旧版 `editor/bin/Debug/XCEngine.exe` 冒烟至少 10 秒,确认 `SceneReady`
## 完成判定
1. managed renderer 明确关闭阴影时shadow execution state 会被显式清空。
2. `cmake --build build --config Debug --target XCEditor` 成功。
3. 旧版 editor 冒烟通过,日志出现新的 `SceneReady`

View File

@@ -0,0 +1,85 @@
# SRP / URP Stage-Scoped Pass Collection Plan
时间2026-04-22
## 背景
上一阶段已经把 managed renderer 的执行组织收成了 renderer block
- `ShadowCaster`
- `DepthPrepass`
- `MainOpaque`
- `MainSkybox`
- `MainTransparent`
- `PostProcess`
- `FinalOutput`
但当前还有一个没有完全收口的问题:
1. native C++ 这一层仍然按 `CameraFrameStage` 分阶段调用 managed renderer。
2. `ScriptableRenderer.BuildPassQueue(...)` 也是每个 stage 都会执行一次。
3. 可现在 renderer / feature 仍然可能在这个阶段里把所有 stage 的 pass 都先塞进总队列,再交给后面的 block 过滤。
这意味着:
- 组织方式虽然已经比之前清晰,但 pass collection 仍然混着跨 stage 的内容。
- `UniversalRenderer` 自己对 block 的 ownership 也还不够直接。
- 后续把 shadow / volumetric / gaussian 等能力继续往 URP 层迁时,边界会继续发虚。
## 本阶段目标
把 managed renderer 的 pass collection 也收成 stage-scoped并同步把 `UniversalRenderer` 的内建 pass 入口拆成更清晰的 block-owned 结构。
目标结果:
1. 当前 stage 构建 pass queue 时,不再混入明显属于其他 stage 的 pass。
2. `UniversalRenderer` 明确区分 shadow / depth / main scene / final output 这些 block-owned 入口。
3. 继续保留现在的 `RenderPassEvent + RenderBlocks` 路线,不引入额外兼容层。
## 范围
本阶段只处理 managed SRP / URP 的 pass collection 与 block ownership不做
- deferred rendering
- 阴影算法迁移
- editor-only 渲染能力迁移
- C++ RenderGraph 功能扩展
## 实施步骤
### 1. ScriptableRenderer pass collection stage-scoped 化
重构 `ScriptableRenderer`
- 在 build active pass queue 时记录当前 `RenderingData.stage`
- `EnqueuePass(...)` 在 pass queue build 期间只接受与当前 stage 匹配的 pass
- 非 build 期间保持现有安全行为
这样可以让当前 stage 的 queue 从源头上变干净,而不是先混入、后过滤。
### 2. UniversalRenderer 显式按 block 组织内建 pass
重构 `UniversalRenderer.AddRenderPasses(...)`
- `ShadowCaster` 只处理 shadow block
- `DepthOnly` 只处理 depth prepass block
- `MainScene` 只处理 opaque / skybox / transparent
- `FinalOutput` 只处理 final output block
必要时同步清理内建 feature 的 stage 边界判断,避免继续依赖下游过滤。
### 3. 验证主线不回退
要求:
1. `XCEditor` Debug 构建通过
2. old editor 冒烟至少 10 秒
3. `editor.log` 出现 `SceneReady`
## 完成标准
满足以下条件才算本阶段收口:
1. active pass queue 的 collection 已经是 stage-scoped。
2. `UniversalRenderer` 内建 pass ownership 更直接,不再在单个入口里混着所有 stage。
3. `XCEditor` 编译与 old editor 冒烟通过。

View File

@@ -0,0 +1,48 @@
# SRP/URP Standalone Stage Ownership Boundary Plan
日期2026-04-21
## 背景
当前 SRP/URP 主线已经有了基本骨架,但 `ScriptableRenderPipelineHostAsset` 里仍然直接注册了三类 native standalone pass
1. `BuiltinShadowCasterPass`
2. `BuiltinDepthOnlyPass`
3. `BuiltinObjectIdPass`
这会带来两个结构问题:
1. 通用 SRP host 和 builtin forward fallback 耦合在一起。`ScriptableRenderPipelineHost` 本应只负责 managed/native 桥接、stage recorder 绑定和 fallback 分发,不应该自己偷偷决定 builtin standalone stage 的具体实现。
2. ownership 不清晰。managed URP 已经在 C# 层负责 shadow/depth 的 stage 规划和 render-graph 录制,但 native fallback 仍然挂在 host asset 上,导致“谁拥有这些 fallback pass”这个问题没有收口。
这一步不是做新功能,而是把这条边界收干净,让后续继续按 Unity 风格往 SRP + URP 分层推进。
## 目标
1.`ScriptableRenderPipelineHost` 退回到真正的 host 角色,不再在 asset 层硬编码 builtin standalone pass。
2. 让 builtin forward backend 显式拥有自己的 native standalone fallback pass。
3. 保持当前运行结果不变managed renderer 录制 stage 时优先走 managed需要 native fallback 时,由 backend 明确提供。
## 实施步骤
1.`BuiltinForward...Setup` 路径中显式配置 builtin forward pipeline 的 standalone fallback pass而不是在 host asset 中配置。
2. 调整 `ScriptableRenderPipelineHost::GetCameraFrameStandalonePass(...)`,让 host 在自身未持有 pass 时,从 backend 查询 standalone pass。
3. 清理 `ScriptableRenderPipelineHostAsset` 中已过期的 builtin pass 注入逻辑。
4. 重新编译旧版 `XCEditor`,运行旧版 editor 冒烟至少 10 秒,确认没有把 fallback 链路改坏。
## 完成判定
1. `ScriptableRenderPipelineHostAsset` 不再直接注册 builtin shadow/depth/object-id standalone pass。
2. builtin forward backend 仍可为 fallback stage 提供 native standalone pass。
3. `cmake --build . --config Debug --target XCEditor` 成功。
4. 旧版 `editor/bin/Debug/XCEngine.exe` 冒烟通过,并出现新的 `SceneReady` 记录。
## 结果
1. `ScriptableRenderPipelineHostAsset` 已移除 builtin standalone pass 注入逻辑。
2. builtin forward backend 现在在自身 setup 中显式注册 `ObjectId``DepthOnly``ShadowCaster` fallback pass。
3. `ScriptableRenderPipelineHost` 现在会在自身未持有 standalone pass 时,向 backend 查询 fallback pass。
4. 验证结果:
`cmake --build . --config Debug --target XCEditor` 通过。
旧版 editor 冒烟 15 秒通过。
日志结果:`SceneReady elapsed_ms=5505 first_frame_ms=619`

View File

@@ -0,0 +1,69 @@
# SRP / URP UniversalPostProcessBlock Plan
时间2026-04-22
## 背景
当前 `UniversalRenderer` 已经把这些 block 拆出来了:
- `UniversalShadowCasterBlock`
- `UniversalDepthPrepassBlock`
- `UniversalMainSceneBlock`
- `UniversalFinalOutputBlock`
`post-process` 这一面还没有自己的正式落点:
1. fullscreen post-process stage planning 还散在具体 feature 里。
2. `UniversalFinalOutputBlock` 又需要读取并调整 post-process stage 的 graph-managed output 状态。
3. 结果是 post-process / final output 的协作语义分散在多个类里,不利于后续继续接更多 post-process feature。
## 本阶段目标
补齐 `UniversalPostProcessBlock`,把 post-process 共享 planning 语义收口到统一 helper。
目标结果:
1. `ColorScalePostProcessRendererFeature` 不再内联维护 fullscreen post-process planning 逻辑。
2. `UniversalFinalOutputBlock` 不再直接手写 post-process stage promotion 逻辑。
3. 后续新增更多 post-process feature 时,可以复用 `UniversalPostProcessBlock` 的共享行为。
## 范围
本阶段只处理 post-process / final output 共享 planning不做
- 新的 post-process feature API 设计
- deferred rendering
- C++ host / RenderGraph 改造
## 实施步骤
### 1. 新增 UniversalPostProcessBlock
职责:
- 统一请求 post-process fullscreen stage
- 统一处理 graph-managed output color 的 promotion
- 为 final output 提供 post-process color source 解析
### 2. 接入现有使用点
接入:
- `ColorScalePostProcessRendererFeature`
- `UniversalFinalOutputBlock`
### 3. 验证
要求:
1. `XCEditor` Debug 构建通过
2. old editor 冒烟至少 10 秒
3. `editor.log` 出现 `SceneReady`
## 完成标准
满足以下条件才算本阶段收口:
1. post-process shared planning 已经集中到 `UniversalPostProcessBlock`
2. `ColorScalePostProcessRendererFeature``UniversalFinalOutputBlock` 都走统一 helper。
3. `XCEditor` 编译与 old editor 冒烟通过。

View File

@@ -0,0 +1,80 @@
# SRP / URP UniversalRenderer Block Ownership Plan
时间2026-04-22
## 背景
当前主线已经做到:
1. managed renderer 的执行已经按 renderer block 组织。
2. pass collection 也已经收成 stage-scoped。
3. `UniversalRenderer` 现在会按 `ShadowCaster / DepthOnly / MainScene / FinalOutput` 分入口添加内建 pass。
但还有一个明显的结构问题:
- `UniversalRenderer` 自己仍然同时承担了 block planning、scene setup、shadow execution state、builtin pass setup 这些职责。
- 虽然逻辑已经按 block 分段,但仍然都堆在一个类里。
这会直接影响下一阶段把更多能力往 URP 层迁:
- 没有稳定的 block owner 落点。
- 以后 shadow / lighting / volumetric / gaussian / post-process 继续增强时,`UniversalRenderer` 会再次膨胀。
## 本阶段目标
`UniversalRenderer` 的内联 block 逻辑正式拆成 block controller / owner 类,让 renderer 自己退化成编排者。
目标结果:
1. `ShadowCaster` block 自己负责 stage planning、shadow execution state、builtin pass setup。
2. `DepthPrepass` block 自己负责 planning 和 builtin pass setup。
3. `MainScene` block 自己负责 scene pass setup并承接 scene environment/setup 相关逻辑。
4. `FinalOutput` block 自己负责 final output planning 与 builtin final color pass setup。
5. `UniversalRenderer` 自己只负责拿 data、协调这些 block、暴露 renderer 级入口。
## 范围
本阶段只做 `UniversalRenderer` 内部 block ownership 拆分,不做:
- deferred rendering
- 新的 renderer feature API
- 阴影算法功能升级
- C++ host / RenderGraph 扩展
## 实施步骤
### 1. 提取 block controller 类
新增内部 block controller
- `UniversalShadowCasterBlock`
- `UniversalDepthPrepassBlock`
- `UniversalMainSceneBlock`
- `UniversalFinalOutputBlock`
### 2. 迁移 block 职责
迁移内容:
- shadow stage planning
- depth stage planning
- final output planning
- directional shadow execution state
- render scene setup 中属于 main scene block 的内容
- builtin pass configure / enqueue
### 3. 收紧 UniversalRenderer
`UniversalRenderer` 只保留:
- renderer data 获取
- 调用各 block controller
- renderer 级生命周期协调
## 完成标准
满足以下条件才算本阶段收口:
1. `UniversalRenderer` 不再内联维护大段 block-specific 逻辑。
2. 四个核心 block 都有自己的 owner/controller 落点。
3. `XCEditor` 编译通过old editor 冒烟通过。

BIN
docs/used/c.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
docs/used/color.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -539,6 +539,7 @@ add_library(XCEngine STATIC
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/RenderSurface.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/RenderSurfacePipelineUtils.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/SceneRenderFeaturePass.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/SceneRenderFeaturePassId.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/SceneRenderFeatureHost.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/ShaderVariantUtils.h
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Internal/RenderSurfacePipelineUtils.h

View File

@@ -6,6 +6,7 @@
#include "../RHIResourceView.h"
#include "../RHIEnums.h"
#include "D3D12Texture.h"
#include "D3D12Enums.h"
using Microsoft::WRL::ComPtr;
@@ -15,7 +16,6 @@ namespace RHI {
class D3D12DescriptorHeap;
class D3D12Buffer;
class D3D12ResourceView : public RHIResourceView {
public:
D3D12ResourceView();
@@ -30,8 +30,10 @@ public:
ResourceViewType GetViewType() const override { return m_viewType; }
ResourceViewDimension GetDimension() const override { return m_dimension; }
Format GetFormat() const override { return m_format; }
RHITexture* GetTextureResource() const override { return m_texture; }
void SetOwnedHeap(std::unique_ptr<class D3D12DescriptorHeap> heap);
void SetTextureResource(D3D12Texture* texture) { m_texture = texture; }
void InitializeAsRenderTarget(ID3D12Device* device, ID3D12Resource* resource,
const D3D12_RENDER_TARGET_VIEW_DESC* desc,
@@ -86,6 +88,7 @@ private:
ResourceViewDimension m_dimension;
D3D12_CPU_DESCRIPTOR_HANDLE m_handle;
ID3D12Resource* m_resource;
D3D12Texture* m_texture;
D3D12DescriptorHeap* m_heap;
uint32_t m_slotIndex;
std::unique_ptr<D3D12DescriptorHeap> m_ownedHeap;

View File

@@ -1,6 +1,7 @@
#pragma once
#include "XCEngine/RHI/OpenGL/OpenGLFramebuffer.h"
#include "XCEngine/RHI/OpenGL/OpenGLTexture.h"
#include "XCEngine/RHI/RHIResourceView.h"
#include "XCEngine/RHI/RHITypes.h"
@@ -71,7 +72,8 @@ public:
uint32_t GetBufferSize() const { return m_bufferSize; }
uint32_t GetBufferStride() const { return m_bufferStride; }
const FramebufferAttachment& GetFramebufferAttachment() const { return m_framebufferAttachment; }
const OpenGLTexture* GetTextureResource() const { return m_texture; }
RHITexture* GetTextureResource() const override { return m_texture; }
OpenGLTexture* GetOpenGLTextureResource() const { return m_texture; }
private:
ResourceViewType m_viewType;

View File

@@ -6,6 +6,8 @@
namespace XCEngine {
namespace RHI {
class RHITexture;
class RHIResourceView {
public:
virtual ~RHIResourceView() = default;
@@ -19,6 +21,9 @@ public:
virtual ResourceViewType GetViewType() const = 0;
virtual ResourceViewDimension GetDimension() const = 0;
virtual Format GetFormat() const = 0;
virtual RHITexture* GetTextureResource() const {
return nullptr;
}
};
class RHIVertexBufferView : public RHIResourceView {

View File

@@ -2,13 +2,12 @@
#include "XCEngine/RHI/RHIResourceView.h"
#include "XCEngine/RHI/Vulkan/VulkanCommon.h"
#include "XCEngine/RHI/Vulkan/VulkanTexture.h"
namespace XCEngine {
namespace RHI {
class VulkanBuffer;
class VulkanTexture;
class VulkanResourceView : public RHIResourceView {
public:
VulkanResourceView() = default;
@@ -30,6 +29,7 @@ public:
ResourceViewType GetViewType() const override { return m_viewType; }
ResourceViewDimension GetDimension() const override { return m_dimension; }
Format GetFormat() const override { return m_format; }
RHITexture* GetTextureResource() const override { return m_texture; }
VulkanTexture* GetTexture() const { return m_texture; }
VkImageView GetImageView() const { return m_imageView; }

View File

@@ -48,6 +48,10 @@ public:
SceneRenderInjectionPoint GetInjectionPoint() const override {
return SceneRenderInjectionPoint::BeforeTransparent;
}
NativeSceneFeaturePassId GetNativeSceneFeaturePassId()
const override {
return NativeSceneFeaturePassId::BuiltinGaussianSplat;
}
bool Initialize(const RenderContext& context) override;
bool IsActive(const RenderSceneData& sceneData) const override;
bool Prepare(

View File

@@ -43,6 +43,10 @@ public:
SceneRenderInjectionPoint GetInjectionPoint() const override {
return SceneRenderInjectionPoint::BeforeTransparent;
}
NativeSceneFeaturePassId GetNativeSceneFeaturePassId()
const override {
return NativeSceneFeaturePassId::BuiltinVolumetric;
}
bool Initialize(const RenderContext& context) override;
bool IsActive(const RenderSceneData& sceneData) const override;
bool Prepare(

View File

@@ -32,6 +32,7 @@ private:
RenderGraphTextureDesc desc = {};
RenderGraphTextureKind kind = RenderGraphTextureKind::Transient;
RHI::RHIResourceView* importedView = nullptr;
RHI::RHITexture* importedTexture = nullptr;
RenderGraphImportedTextureOptions importedOptions = {};
};

View File

@@ -48,6 +48,7 @@ private:
RenderGraphTextureDesc desc = {};
RenderGraphTextureKind kind = RenderGraphTextureKind::Transient;
RHI::RHIResourceView* importedView = nullptr;
RHI::RHITexture* importedTexture = nullptr;
RenderGraphImportedTextureOptions importedOptions = {};
};

View File

@@ -104,7 +104,7 @@ struct RenderGraphTextureTransitionPlan {
struct RenderGraphExecutionContext {
const RenderContext& renderContext;
const RenderGraphRuntimeResources* runtimeResources = nullptr;
RenderGraphRuntimeResources* runtimeResources = nullptr;
RHI::RHIResourceView* ResolveTextureView(
RenderGraphTextureHandle handle,

View File

@@ -3,6 +3,7 @@
#include <XCEngine/Core/Asset/ResourceHandle.h>
#include <XCEngine/Core/Containers/String.h>
#include <XCEngine/Core/Math/Vector4.h>
#include <XCEngine/Rendering/Builtin/BuiltinPassTypes.h>
#include <XCEngine/Rendering/RenderPass.h>
#include <XCEngine/Resources/Shader/Shader.h>
#include <XCEngine/RHI/RHIEnums.h>
@@ -27,6 +28,23 @@ public:
RHI::RHIDescriptorSet* set = nullptr;
};
struct BoundSetState {
RHI::RHIResourceView* sourceColorTextureView = nullptr;
std::vector<RHI::RHIResourceView*> materialTextureViews = {};
};
struct PassResourceLayout {
std::vector<BuiltinPassSetLayoutMetadata> setLayouts = {};
std::vector<OwnedDescriptorSet> descriptorSets = {};
std::vector<BoundSetState> boundSetStates = {};
RHI::RHIPipelineLayout* pipelineLayout = nullptr;
PassResourceBindingLocation passConstants = {};
PassResourceBindingLocation sourceColorTexture = {};
PassResourceBindingLocation linearClampSampler = {};
uint32_t firstDescriptorSet = 0u;
uint32_t descriptorSetCount = 0u;
};
explicit BuiltinVectorFullscreenPass(
const Math::Vector4& vectorPayload = Math::Vector4::One(),
Containers::String shaderPath = {},
@@ -51,7 +69,15 @@ public:
private:
bool EnsureInitialized(const RenderContext& renderContext, const RenderSurface& surface);
bool CreateResources(const RenderContext& renderContext, const RenderSurface& surface);
bool CreateOwnedDescriptorSet(
const BuiltinPassSetLayoutMetadata& setLayout,
OwnedDescriptorSet& descriptorSet);
bool UpdateDescriptorSets(const RenderPassContext& context);
RHI::RHIResourceView* ResolveExtraTextureView(
const RenderPassContext& context,
const BuiltinPassResourceBindingDesc& bindingDesc) const;
void DestroyResources();
void DestroyPassResourceLayout();
void DestroyOwnedDescriptorSet(OwnedDescriptorSet& descriptorSet);
Containers::String m_shaderPath;
@@ -64,12 +90,8 @@ private:
uint32_t m_renderTargetSampleQuality = 0u;
Resources::ResourceHandle<Resources::Shader> m_shader;
RHI::RHISampler* m_sampler = nullptr;
RHI::RHIPipelineLayout* m_pipelineLayout = nullptr;
RHI::RHIPipelineState* m_pipelineState = nullptr;
OwnedDescriptorSet m_constantsSet = {};
OwnedDescriptorSet m_textureSet = {};
OwnedDescriptorSet m_samplerSet = {};
RHI::RHIResourceView* m_boundSourceColorView = nullptr;
PassResourceLayout m_passLayout = {};
};
} // namespace Passes

View File

@@ -104,14 +104,6 @@ public:
GetSharedPipelineBackendAsset() const {
return nullptr;
}
virtual bool UsesNativeCameraFramePlanBaseline() const {
return false;
}
virtual bool UsesNativeCameraFramePlanBaseline(
int32_t rendererIndex) const {
(void)rendererIndex;
return UsesNativeCameraFramePlanBaseline();
}
virtual bool TryGetDefaultFinalColorSettings(FinalColorSettings&) const {
return false;
}

View File

@@ -30,7 +30,7 @@ public:
bool RecordScenePhase(ScenePhase scenePhase);
bool RecordSceneDrawSettings(const DrawSettings& drawSettings);
bool RecordInjectionPoint(SceneRenderInjectionPoint injectionPoint);
bool RecordFeaturePass(const Containers::String& featurePassName);
bool RecordFeaturePass(NativeSceneFeaturePassId featurePassId);
private:
SceneRenderFeaturePassBeginCallback BuildBeginRecordedPassCallback(

View File

@@ -69,6 +69,9 @@ public:
private:
bool EnsureInitialized(const RenderContext& context);
RenderPass* ResolvePipelineBackendStandalonePass(
CameraFrameStage stage,
int32_t rendererIndex) const;
void BindStageRecorderPipelineBackend();
void ShutdownInitializedComponents();
void ResetInitializationState();
@@ -98,7 +101,6 @@ public:
managedAssetRuntime);
std::unique_ptr<RenderPipeline> CreatePipeline() const override;
void ConfigurePipeline(RenderPipeline& pipeline) const override;
FinalColorSettings GetDefaultFinalColorSettings() const override;
private:

View File

@@ -23,12 +23,18 @@ class RenderGraphBuilder;
class RenderGraphBlackboard;
struct RenderPassContext {
struct TextureBindingView {
Containers::String resourceName = {};
RHI::RHIResourceView* resourceView = nullptr;
};
const RenderContext& renderContext;
const RenderSurface& surface;
const RenderSceneData& sceneData;
const RenderSurface* sourceSurface = nullptr;
RHI::RHIResourceView* sourceColorView = nullptr;
RHI::ResourceStates sourceColorState = RHI::ResourceStates::Common;
std::vector<TextureBindingView> textureBindings = {};
};
inline RenderPassContext BuildRenderPassContext(
@@ -39,7 +45,8 @@ inline RenderPassContext BuildRenderPassContext(
executionContext.sceneData,
executionContext.sourceSurface,
executionContext.sourceColorView,
executionContext.sourceColorState
executionContext.sourceColorState,
{}
};
}

View File

@@ -13,6 +13,12 @@ struct RenderPassGraphIO {
bool writeDepth = false;
};
struct RenderPassGraphTextureBindingRequest {
Containers::String resourceName = {};
RenderGraphTextureHandle texture = {};
RenderGraphTextureAspect aspect = RenderGraphTextureAspect::Color;
};
inline RenderPassGraphIO BuildSourceColorFullscreenRasterPassGraphIO() {
return {
true,
@@ -52,7 +58,9 @@ bool RecordCallbackRasterRenderPass(
const RenderPassRenderGraphContext& context,
const RenderPassGraphIO& io,
RenderPassGraphExecutePassCallback executePassCallback,
std::vector<RenderGraphTextureHandle> additionalReadTextures = {});
std::vector<RenderGraphTextureHandle> additionalReadTextures = {},
std::vector<RenderGraphTextureHandle> additionalReadDepthTextures = {},
std::vector<RenderPassGraphTextureBindingRequest> textureBindingRequests = {});
bool RecordRasterRenderPass(
RenderPass& pass,
@@ -100,12 +108,14 @@ inline bool RecordSourceColorFullscreenCallbackRasterPass(
inline bool RecordColorDepthCallbackRasterPass(
const RenderPassRenderGraphContext& context,
RenderPassGraphExecutePassCallback executePassCallback,
std::vector<RenderGraphTextureHandle> additionalReadTextures = {}) {
std::vector<RenderGraphTextureHandle> additionalReadTextures = {},
std::vector<RenderGraphTextureHandle> additionalReadDepthTextures = {}) {
return RecordCallbackRasterRenderPass(
context,
BuildColorDepthRasterPassGraphIO(),
std::move(executePassCallback),
std::move(additionalReadTextures));
std::move(additionalReadTextures),
std::move(additionalReadDepthTextures));
}
} // namespace Rendering

View File

@@ -23,7 +23,7 @@ public:
bool* recordedAnyPass = nullptr) const;
bool RecordFeaturePass(
const SceneRenderFeaturePassRenderGraphContext& context,
const Containers::String& featurePassName,
NativeSceneFeaturePassId featurePassId,
bool* recordedPass = nullptr) const;
bool Execute(
const FrameExecutionContext& executionContext,

View File

@@ -5,6 +5,7 @@
#include <XCEngine/Rendering/Graph/RenderGraphTypes.h>
#include <XCEngine/Rendering/RenderPass.h>
#include <XCEngine/Rendering/RenderSurface.h>
#include <XCEngine/Rendering/SceneRenderFeaturePassId.h>
#include <functional>
@@ -44,6 +45,11 @@ public:
return SceneRenderInjectionPoint::BeforeTransparent;
}
virtual NativeSceneFeaturePassId
GetNativeSceneFeaturePassId() const {
return NativeSceneFeaturePassId::Invalid;
}
bool SupportsInjectionPoint(SceneRenderInjectionPoint injectionPoint) const {
return GetInjectionPoint() == injectionPoint;
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include <cstdint>
namespace XCEngine {
namespace Rendering {
enum class NativeSceneFeaturePassId : uint32_t {
Invalid = 0u,
BuiltinGaussianSplat = 1u,
BuiltinVolumetric = 2u
};
} // namespace Rendering
} // namespace XCEngine

View File

@@ -106,20 +106,43 @@ inline UITabStripLayoutResult ArrangeUITabStrip(
const float gap = (std::max)(0.0f, metrics.tabGap);
const float totalGapWidth = gap * static_cast<float>(desiredHeaderWidths.size() - 1u);
const float availableTabsWidth = (std::max)(0.0f, bounds.width - totalGapWidth);
const float minTabWidth = (std::max)(0.0f, metrics.tabMinWidth);
std::vector<float> resolvedHeaderWidths = {};
resolvedHeaderWidths.reserve(desiredHeaderWidths.size());
float totalDesiredWidth = 0.0f;
float totalMinimumWidth = 0.0f;
for (float width : desiredHeaderWidths) {
totalDesiredWidth += (std::max)(0.0f, width);
const float desiredWidth = (std::max)((std::max)(0.0f, width), minTabWidth);
resolvedHeaderWidths.push_back(desiredWidth);
totalDesiredWidth += desiredWidth;
totalMinimumWidth += minTabWidth;
}
const float scale = totalDesiredWidth > 0.0f && totalDesiredWidth > availableTabsWidth
? availableTabsWidth / totalDesiredWidth
: 1.0f;
if (totalDesiredWidth > availableTabsWidth && totalDesiredWidth > 0.0f) {
if (totalMinimumWidth > 0.0f && totalMinimumWidth >= availableTabsWidth) {
const float minWidthScale = availableTabsWidth / totalMinimumWidth;
for (float& width : resolvedHeaderWidths) {
width = minTabWidth * minWidthScale;
}
} else {
const float totalShrinkableWidth = totalDesiredWidth - totalMinimumWidth;
const float overflowWidth = totalDesiredWidth - availableTabsWidth;
const float excessScale = totalShrinkableWidth > 0.0f
? ((std::max)(totalShrinkableWidth - overflowWidth, 0.0f) / totalShrinkableWidth)
: 0.0f;
for (float& width : resolvedHeaderWidths) {
const float shrinkableWidth = (std::max)(width - minTabWidth, 0.0f);
width = minTabWidth + shrinkableWidth * excessScale;
}
}
}
float cursorX = bounds.x;
for (std::size_t index = 0; index < desiredHeaderWidths.size(); ++index) {
const float width = totalDesiredWidth > 0.0f
? (std::max)(0.0f, desiredHeaderWidths[index]) * scale
? resolvedHeaderWidths[index]
: availableTabsWidth / static_cast<float>(desiredHeaderWidths.size());
result.tabHeaderRects[index] = UIRect(cursorX, bounds.y, width, headerHeight);
cursorX += width + gap;

View File

@@ -1597,6 +1597,7 @@ RHIResourceView* D3D12Device::CreateRenderTargetView(RHITexture* texture, const
}
view->InitializeAsRenderTarget(m_device.Get(), resource, &rtvDesc, heap.get(), 0);
view->SetTextureResource(d3d12Texture);
view->SetOwnedHeap(std::move(heap));
return view;
@@ -1619,6 +1620,7 @@ RHIResourceView* D3D12Device::CreateDepthStencilView(RHITexture* texture, const
}
view->InitializeAsDepthStencil(m_device.Get(), resource, &dsvDesc, heap.get(), 0);
view->SetTextureResource(d3d12Texture);
view->SetOwnedHeap(std::move(heap));
return view;
}
@@ -1738,6 +1740,7 @@ RHIResourceView* D3D12Device::CreateShaderResourceView(RHITexture* texture, cons
}
view->InitializeAsShaderResource(m_device.Get(), resource, &srvDesc, heap.get(), 0);
view->SetTextureResource(d3d12Texture);
if (IsDepthFormat(format)) {
view->SetFormat(format);
}
@@ -1815,6 +1818,7 @@ RHIResourceView* D3D12Device::CreateUnorderedAccessView(RHITexture* texture, con
}
view->InitializeAsUnorderedAccess(m_device.Get(), resource, &uavDesc, heap.get(), 0);
view->SetTextureResource(d3d12Texture);
view->SetOwnedHeap(std::move(heap));
return view;
}

View File

@@ -111,6 +111,7 @@ D3D12ResourceView::D3D12ResourceView()
, m_dimension(ResourceViewDimension::Unknown)
, m_handle({0})
, m_resource(nullptr)
, m_texture(nullptr)
, m_heap(nullptr)
, m_slotIndex(0)
, m_ownedHeap(nullptr)
@@ -127,6 +128,7 @@ D3D12ResourceView::~D3D12ResourceView() {
void D3D12ResourceView::Shutdown() {
m_handle = {};
m_resource = nullptr;
m_texture = nullptr;
if (m_ownedHeap) {
m_ownedHeap->Shutdown();
m_ownedHeap.reset();

View File

@@ -52,7 +52,7 @@ bool GetOpenGLClearTargetExtent(const OpenGLResourceView* view, GLsizei& width,
return false;
}
const OpenGLTexture* texture = view->GetTextureResource();
const OpenGLTexture* texture = view->GetOpenGLTextureResource();
if (texture == nullptr) {
return false;
}
@@ -631,7 +631,7 @@ void OpenGLCommandList::TransitionBarrier(RHIResourceView* resource, ResourceSta
(void)stateBefore;
if (resource != nullptr && resource->IsValid()) {
OpenGLResourceView* view = static_cast<OpenGLResourceView*>(resource);
OpenGLTexture* texture = const_cast<OpenGLTexture*>(view->GetTextureResource());
OpenGLTexture* texture = view->GetOpenGLTextureResource();
if (texture != nullptr) {
texture->SetState(stateAfter);
}
@@ -750,7 +750,7 @@ void OpenGLCommandList::SetRenderTargets(uint32_t count, RHIResourceView** rende
for (uint32_t i = 0; i < count; ++i) {
auto* view = static_cast<OpenGLResourceView*>(renderTargets[i]);
const OpenGLTexture* texture = view != nullptr ? view->GetTextureResource() : nullptr;
const OpenGLTexture* texture = view != nullptr ? view->GetOpenGLTextureResource() : nullptr;
if (texture != nullptr) {
width = texture->GetWidth();
height = texture->GetHeight();
@@ -760,7 +760,7 @@ void OpenGLCommandList::SetRenderTargets(uint32_t count, RHIResourceView** rende
if ((width == 0 || height == 0) && depthStencil != nullptr) {
auto* dsv = static_cast<OpenGLResourceView*>(depthStencil);
const OpenGLTexture* depthTexture = dsv != nullptr ? dsv->GetTextureResource() : nullptr;
const OpenGLTexture* depthTexture = dsv != nullptr ? dsv->GetOpenGLTextureResource() : nullptr;
if (depthTexture != nullptr) {
width = depthTexture->GetWidth();
height = depthTexture->GetHeight();
@@ -782,7 +782,7 @@ void OpenGLCommandList::SetRenderTargets(uint32_t count, RHIResourceView** rende
} else {
ReleaseComposedFramebuffer();
OpenGLResourceView* view = static_cast<OpenGLResourceView*>(renderTargets[0]);
const OpenGLTexture* texture = view != nullptr ? view->GetTextureResource() : nullptr;
const OpenGLTexture* texture = view != nullptr ? view->GetOpenGLTextureResource() : nullptr;
if (texture != nullptr) {
m_currentRenderTargetWidth = texture->GetWidth();
m_currentRenderTargetHeight = texture->GetHeight();
@@ -795,7 +795,7 @@ void OpenGLCommandList::SetRenderTargets(uint32_t count, RHIResourceView** rende
ReleaseComposedFramebuffer();
OpenGLResourceView* dsv = static_cast<OpenGLResourceView*>(depthStencil);
if (dsv && dsv->IsValid()) {
const OpenGLTexture* depthTexture = dsv->GetTextureResource();
const OpenGLTexture* depthTexture = dsv->GetOpenGLTextureResource();
if (depthTexture != nullptr) {
m_currentRenderTargetWidth = depthTexture->GetWidth();
m_currentRenderTargetHeight = depthTexture->GetHeight();
@@ -1056,8 +1056,8 @@ void OpenGLCommandList::CopyResource(RHIResourceView* dst, RHIResourceView* src)
GLuint dstTex = dstView->GetTexture();
GLuint srcTex = srcView->GetTexture();
const OpenGLTexture* dstTexture = dstView->GetTextureResource();
const OpenGLTexture* srcTexture = srcView->GetTextureResource();
const OpenGLTexture* dstTexture = dstView->GetOpenGLTextureResource();
const OpenGLTexture* srcTexture = srcView->GetOpenGLTextureResource();
if (dstTex && srcTex && dstTexture != nullptr && srcTexture != nullptr) {
const GLuint srcTarget = ToOpenGL(srcTexture->GetOpenGLType());
const GLuint dstTarget = ToOpenGL(dstTexture->GetOpenGLType());

View File

@@ -196,7 +196,7 @@ void OpenGLDescriptorSet::Update(uint32_t offset, RHIResourceView* view) {
}
binding->textureIds[0] = glView->GetTexture();
if (const OpenGLTexture* texture = glView->GetTextureResource()) {
if (const OpenGLTexture* texture = glView->GetOpenGLTextureResource()) {
binding->textureTargets[0] = static_cast<uint32_t>(ToOpenGL(texture->GetOpenGLType()));
}
}

View File

@@ -5,6 +5,7 @@
#include "Rendering/Execution/Internal/CameraFrameGraph/Executor.h"
#include "Rendering/GraphicsSettingsState.h"
#include "Rendering/Internal/RenderPipelineFactory.h"
#include "Rendering/Passes/BuiltinObjectIdPass.h"
#include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h"
#include "Rendering/RenderPipelineAsset.h"
#include "Rendering/RenderSurface.h"
@@ -29,6 +30,14 @@ bool IsManagedPipelineAsset(
pipelineAsset.get()) != nullptr;
}
void ConfigureTopLevelToolingPasses(RenderPipeline& pipeline) {
// Object-id is a tooling/editor request. It should live on the
// top-level pipeline used by CameraRenderer, not on a scene backend.
pipeline.SetCameraFrameStandalonePass(
CameraFrameStage::ObjectId,
std::make_unique<Passes::BuiltinObjectIdPass>());
}
RenderPipelineStageSupportContext BuildStageSupportContext(
const CameraFramePlan& plan,
CameraFrameStage stage) {
@@ -124,6 +133,10 @@ void CameraRenderer::ResetPipeline(std::unique_ptr<RenderPipeline> pipeline) {
&m_pipelineAsset);
}
if (m_pipeline != nullptr) {
ConfigureTopLevelToolingPasses(*m_pipeline);
}
m_managedPipelineEnvironmentGeneration =
UsesManagedPipelineBinding()
? GetGraphicsSettingsState().GetEnvironmentGeneration()

View File

@@ -87,6 +87,8 @@ RenderGraphTextureHandle RenderGraphBuilder::ImportTexture(
resource.desc = desc;
resource.kind = RenderGraphTextureKind::Imported;
resource.importedView = importedView;
resource.importedTexture =
importedView != nullptr ? importedView->GetTextureResource() : nullptr;
resource.importedOptions = importedOptions;
m_graph.m_textures.push_back(resource);

View File

@@ -115,9 +115,9 @@ bool RenderGraphCompiler::Compile(
if (texture.kind == RenderGraphTextureKind::Imported &&
texture.importedOptions.graphOwnsTransitions &&
texture.importedView == nullptr) {
texture.importedTexture == nullptr) {
WriteError(
Containers::String("RenderGraph imported texture requires a valid view when graph owns transitions: ") +
Containers::String("RenderGraph imported texture requires a texture-backed view when graph owns transitions: ") +
texture.name,
outErrorMessage);
return false;
@@ -237,6 +237,7 @@ bool RenderGraphCompiler::Compile(
compiledTexture.desc = graph.m_textures[textureIndex].desc;
compiledTexture.kind = graph.m_textures[textureIndex].kind;
compiledTexture.importedView = graph.m_textures[textureIndex].importedView;
compiledTexture.importedTexture = graph.m_textures[textureIndex].importedTexture;
compiledTexture.importedOptions = graph.m_textures[textureIndex].importedOptions;
outCompiledGraph.m_textures.push_back(std::move(compiledTexture));

View File

@@ -40,6 +40,26 @@ RenderGraphTextureViewType ResolveBarrierViewType(RHI::ResourceStates state) {
: RenderGraphTextureViewType::ShaderResource;
}
RHI::ResourceViewType ResolveRequestedResourceViewType(
RenderGraphTextureViewType viewType) {
switch (viewType) {
case RenderGraphTextureViewType::RenderTarget:
return RHI::ResourceViewType::RenderTarget;
case RenderGraphTextureViewType::DepthStencil:
return RHI::ResourceViewType::DepthStencil;
case RenderGraphTextureViewType::UnorderedAccess:
return RHI::ResourceViewType::UnorderedAccess;
case RenderGraphTextureViewType::ShaderResource:
default:
return RHI::ResourceViewType::ShaderResource;
}
}
bool IsTextureViewDimension(RHI::ResourceViewDimension dimension) {
return dimension != RHI::ResourceViewDimension::Unknown &&
!RHI::IsBufferResourceViewDimension(dimension);
}
} // namespace
class RenderGraphRuntimeResources {
@@ -62,7 +82,10 @@ public:
for (size_t textureIndex = 0u; textureIndex < m_graph.m_textures.size(); ++textureIndex) {
const CompiledRenderGraph::CompiledTexture& texture = m_graph.m_textures[textureIndex];
const RenderGraphTextureLifetime& lifetime = m_graph.m_textureLifetimes[textureIndex];
TextureAllocation& allocation = m_textureAllocations[textureIndex];
if (texture.kind == RenderGraphTextureKind::Imported) {
allocation.texture = texture.importedTexture;
allocation.primaryImportedView = texture.importedView;
m_textureStates[textureIndex] = texture.importedOptions.initialState;
}
@@ -105,29 +128,23 @@ public:
RHI::RHIResourceView* ResolveTextureView(
RenderGraphTextureHandle handle,
RenderGraphTextureViewType viewType) const {
RenderGraphTextureViewType viewType,
const RenderContext& renderContext) {
if (!handle.IsValid() || handle.index >= m_graph.m_textures.size()) {
return nullptr;
}
const CompiledRenderGraph::CompiledTexture& texture = m_graph.m_textures[handle.index];
TextureAllocation& allocation = m_textureAllocations[handle.index];
if (texture.kind == RenderGraphTextureKind::Imported) {
return texture.importedView;
return ResolveImportedTextureView(
texture,
allocation,
viewType,
renderContext);
}
const TextureAllocation& allocation = m_textureAllocations[handle.index];
switch (viewType) {
case RenderGraphTextureViewType::RenderTarget:
return allocation.renderTargetView;
case RenderGraphTextureViewType::DepthStencil:
return allocation.depthStencilView;
case RenderGraphTextureViewType::ShaderResource:
return allocation.shaderResourceView;
case RenderGraphTextureViewType::UnorderedAccess:
return allocation.unorderedAccessView;
default:
return nullptr;
}
return ResolveCachedView(allocation, viewType);
}
bool TryGetTextureDesc(
@@ -158,7 +175,6 @@ public:
const CompiledRenderGraph::CompiledTexture& texture = m_graph.m_textures[textureIndex];
if (texture.kind != RenderGraphTextureKind::Imported ||
!texture.importedOptions.graphOwnsTransitions ||
texture.importedView == nullptr ||
textureIndex >= m_graph.m_textureLifetimes.size() ||
!m_graph.m_textureLifetimes[textureIndex].used ||
!IsGraphManagedTransientState(texture.importedOptions.finalState)) {
@@ -208,8 +224,197 @@ private:
RHI::RHIResourceView* depthStencilView = nullptr;
RHI::RHIResourceView* shaderResourceView = nullptr;
RHI::RHIResourceView* unorderedAccessView = nullptr;
RHI::RHIResourceView* primaryImportedView = nullptr;
bool ownsTexture = false;
};
static RHI::RHIResourceView* ResolveCachedView(
const TextureAllocation& allocation,
RenderGraphTextureViewType viewType) {
switch (viewType) {
case RenderGraphTextureViewType::RenderTarget:
return allocation.renderTargetView;
case RenderGraphTextureViewType::DepthStencil:
return allocation.depthStencilView;
case RenderGraphTextureViewType::ShaderResource:
return allocation.shaderResourceView;
case RenderGraphTextureViewType::UnorderedAccess:
return allocation.unorderedAccessView;
default:
return nullptr;
}
}
static RHI::RHIResourceView*& ResolveCachedViewSlot(
TextureAllocation& allocation,
RenderGraphTextureViewType viewType) {
switch (viewType) {
case RenderGraphTextureViewType::RenderTarget:
return allocation.renderTargetView;
case RenderGraphTextureViewType::DepthStencil:
return allocation.depthStencilView;
case RenderGraphTextureViewType::ShaderResource:
return allocation.shaderResourceView;
case RenderGraphTextureViewType::UnorderedAccess:
default:
return allocation.unorderedAccessView;
}
}
static RHI::ResourceViewDimension ResolveDefaultImportedViewDimension(
const CompiledRenderGraph::CompiledTexture& texture) {
const RHI::TextureType textureType =
static_cast<RHI::TextureType>(texture.desc.textureType);
const bool isMultisampled = texture.desc.sampleCount > 1u;
switch (textureType) {
case RHI::TextureType::Texture1D:
return RHI::ResourceViewDimension::Texture1D;
case RHI::TextureType::Texture2DArray:
return isMultisampled
? RHI::ResourceViewDimension::Texture2DMSArray
: RHI::ResourceViewDimension::Texture2DArray;
case RHI::TextureType::Texture3D:
return RHI::ResourceViewDimension::Texture3D;
case RHI::TextureType::TextureCube:
return RHI::ResourceViewDimension::TextureCube;
case RHI::TextureType::TextureCubeArray:
return RHI::ResourceViewDimension::TextureCubeArray;
case RHI::TextureType::Texture2D:
default:
return isMultisampled
? RHI::ResourceViewDimension::Texture2DMS
: RHI::ResourceViewDimension::Texture2D;
}
}
static RHI::Format ResolveImportedViewFormat(
const CompiledRenderGraph::CompiledTexture& texture,
const TextureAllocation& allocation) {
if (allocation.primaryImportedView != nullptr &&
allocation.primaryImportedView->GetFormat() != RHI::Format::Unknown) {
return allocation.primaryImportedView->GetFormat();
}
if (allocation.texture != nullptr &&
allocation.texture->GetFormat() != RHI::Format::Unknown) {
return allocation.texture->GetFormat();
}
return static_cast<RHI::Format>(texture.desc.format);
}
static RHI::ResourceViewDimension ResolveImportedViewDimension(
const CompiledRenderGraph::CompiledTexture& texture,
const TextureAllocation& allocation) {
if (allocation.primaryImportedView != nullptr &&
IsTextureViewDimension(allocation.primaryImportedView->GetDimension())) {
return allocation.primaryImportedView->GetDimension();
}
return ResolveDefaultImportedViewDimension(texture);
}
static bool CanCreateImportedView(
const CompiledRenderGraph::CompiledTexture& texture,
RenderGraphTextureViewType viewType) {
const bool isDepthTexture =
IsDepthFormat(static_cast<RHI::Format>(texture.desc.format));
switch (viewType) {
case RenderGraphTextureViewType::RenderTarget:
return !isDepthTexture;
case RenderGraphTextureViewType::DepthStencil:
return isDepthTexture;
case RenderGraphTextureViewType::ShaderResource:
return true;
case RenderGraphTextureViewType::UnorderedAccess:
return !isDepthTexture;
default:
return false;
}
}
RHI::RHIResourceView* ResolveImportedTextureView(
const CompiledRenderGraph::CompiledTexture& texture,
TextureAllocation& allocation,
RenderGraphTextureViewType viewType,
const RenderContext& renderContext) {
if (allocation.primaryImportedView != nullptr &&
allocation.primaryImportedView->GetViewType() ==
ResolveRequestedResourceViewType(viewType) &&
allocation.primaryImportedView->IsValid()) {
return allocation.primaryImportedView;
}
RHI::RHIResourceView*& cachedView =
ResolveCachedViewSlot(allocation, viewType);
if (cachedView != nullptr) {
return cachedView;
}
if (!CanCreateImportedView(texture, viewType) ||
allocation.texture == nullptr ||
renderContext.device == nullptr) {
return nullptr;
}
cachedView = CreateImportedTextureView(
texture,
allocation,
viewType,
renderContext);
return cachedView;
}
static void DestroyOwnedView(RHI::RHIResourceView*& view) {
if (view == nullptr) {
return;
}
view->Shutdown();
delete view;
view = nullptr;
}
RHI::RHIResourceView* CreateImportedTextureView(
const CompiledRenderGraph::CompiledTexture& texture,
const TextureAllocation& allocation,
RenderGraphTextureViewType viewType,
const RenderContext& renderContext) {
if (renderContext.device == nullptr || allocation.texture == nullptr) {
return nullptr;
}
RHI::ResourceViewDesc viewDesc = {};
const RHI::Format viewFormat =
ResolveImportedViewFormat(texture, allocation);
if (viewFormat != RHI::Format::Unknown) {
viewDesc.format = static_cast<Core::uint32>(viewFormat);
}
viewDesc.dimension = ResolveImportedViewDimension(texture, allocation);
switch (viewType) {
case RenderGraphTextureViewType::RenderTarget:
return renderContext.device->CreateRenderTargetView(
allocation.texture,
viewDesc);
case RenderGraphTextureViewType::DepthStencil:
return renderContext.device->CreateDepthStencilView(
allocation.texture,
viewDesc);
case RenderGraphTextureViewType::ShaderResource:
return renderContext.device->CreateShaderResourceView(
allocation.texture,
viewDesc);
case RenderGraphTextureViewType::UnorderedAccess:
return renderContext.device->CreateUnorderedAccessView(
allocation.texture,
viewDesc);
default:
return nullptr;
}
}
bool ShouldGraphManageTransitions(RenderGraphTextureHandle handle) const {
if (!handle.IsValid() || handle.index >= m_graph.m_textures.size()) {
return false;
@@ -240,8 +445,21 @@ private:
return true;
}
RHI::RHIResourceView* resourceView =
ResolveTextureView(handle, ResolveBarrierViewType(targetState));
const CompiledRenderGraph::CompiledTexture& texture =
m_graph.m_textures[handle.index];
TextureAllocation& allocation = m_textureAllocations[handle.index];
RHI::RHIResourceView* resourceView = nullptr;
if (texture.kind == RenderGraphTextureKind::Imported &&
allocation.primaryImportedView != nullptr &&
allocation.primaryImportedView->GetTextureResource() != nullptr &&
allocation.primaryImportedView->IsValid()) {
resourceView = allocation.primaryImportedView;
} else {
resourceView = ResolveTextureView(
handle,
ResolveBarrierViewType(targetState),
renderContext);
}
if (resourceView == nullptr) {
if (outErrorMessage != nullptr) {
*outErrorMessage =
@@ -260,35 +478,19 @@ private:
}
static void DestroyTextureAllocation(TextureAllocation& allocation) {
if (allocation.renderTargetView != nullptr) {
allocation.renderTargetView->Shutdown();
delete allocation.renderTargetView;
allocation.renderTargetView = nullptr;
}
DestroyOwnedView(allocation.renderTargetView);
DestroyOwnedView(allocation.depthStencilView);
DestroyOwnedView(allocation.shaderResourceView);
DestroyOwnedView(allocation.unorderedAccessView);
if (allocation.depthStencilView != nullptr) {
allocation.depthStencilView->Shutdown();
delete allocation.depthStencilView;
allocation.depthStencilView = nullptr;
}
if (allocation.shaderResourceView != nullptr) {
allocation.shaderResourceView->Shutdown();
delete allocation.shaderResourceView;
allocation.shaderResourceView = nullptr;
}
if (allocation.unorderedAccessView != nullptr) {
allocation.unorderedAccessView->Shutdown();
delete allocation.unorderedAccessView;
allocation.unorderedAccessView = nullptr;
}
if (allocation.texture != nullptr) {
if (allocation.ownsTexture && allocation.texture != nullptr) {
allocation.texture->Shutdown();
delete allocation.texture;
allocation.texture = nullptr;
}
allocation.texture = nullptr;
allocation.primaryImportedView = nullptr;
allocation.ownsTexture = false;
}
bool TextureRequiresUnorderedAccess(Core::uint32 textureIndex) const {
@@ -327,6 +529,7 @@ private:
DestroyTextureAllocation(allocation);
return false;
}
allocation.ownsTexture = true;
RHI::ResourceViewDesc viewDesc = {};
viewDesc.format = texture.desc.format;
@@ -353,22 +556,25 @@ private:
}
}
if (!isDepthTexture) {
allocation.shaderResourceView =
renderContext.device->CreateShaderResourceView(allocation.texture, viewDesc);
if (allocation.shaderResourceView == nullptr) {
allocation.shaderResourceView =
renderContext.device->CreateShaderResourceView(
allocation.texture,
viewDesc);
if (allocation.shaderResourceView == nullptr) {
DestroyTextureAllocation(allocation);
return false;
}
if (!isDepthTexture &&
requiresUnorderedAccess) {
allocation.unorderedAccessView =
renderContext.device->CreateUnorderedAccessView(
allocation.texture,
viewDesc);
if (allocation.unorderedAccessView == nullptr) {
DestroyTextureAllocation(allocation);
return false;
}
if (requiresUnorderedAccess) {
allocation.unorderedAccessView =
renderContext.device->CreateUnorderedAccessView(allocation.texture, viewDesc);
if (allocation.unorderedAccessView == nullptr) {
DestroyTextureAllocation(allocation);
return false;
}
}
}
return true;
@@ -389,7 +595,10 @@ RHI::RHIResourceView* RenderGraphExecutionContext::ResolveTextureView(
RenderGraphTextureHandle handle,
RenderGraphTextureViewType viewType) const {
return runtimeResources != nullptr
? runtimeResources->ResolveTextureView(handle, viewType)
? runtimeResources->ResolveTextureView(
handle,
viewType,
renderContext)
: nullptr;
}

View File

@@ -5,15 +5,9 @@
#include "Rendering/Execution/DirectionalShadowExecutionState.h"
#include "Rendering/Pipelines/BuiltinForwardPipeline.h"
#include "Rendering/Pipelines/Internal/BuiltinForwardSceneSetup.h"
#include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h"
#include "Rendering/Pipelines/ScriptableRenderPipelineHost.h"
#include "Rendering/Passes/BuiltinDepthOnlyPass.h"
#include "Rendering/Passes/BuiltinObjectIdPass.h"
#include "Rendering/Passes/BuiltinShadowCasterPass.h"
#include <mutex>
#include <unordered_map>
#include <unordered_set>
namespace XCEngine {
namespace Rendering {
@@ -29,167 +23,6 @@ CreateBuiltinForwardPipelineRendererAsset() {
return s_builtinForwardPipelineAsset;
}
std::unique_ptr<RenderPass> CreateBuiltinDepthOnlyStandalonePass() {
return std::make_unique<Passes::BuiltinDepthOnlyPass>();
}
std::unique_ptr<RenderPass> CreateBuiltinObjectIdStandalonePass() {
return std::make_unique<Passes::BuiltinObjectIdPass>();
}
std::unique_ptr<RenderPass> CreateBuiltinShadowCasterStandalonePass() {
return std::make_unique<Passes::BuiltinShadowCasterPass>();
}
using PipelineBackendAssetRegistry =
std::unordered_map<std::string, PipelineBackendAssetFactory>;
using CameraFrameStandalonePassRegistry =
std::unordered_map<std::string, CameraFrameStandalonePassFactory>;
using CameraFramePlanPolicyRegistry =
std::unordered_map<std::string, CameraFramePlanPolicy>;
using DirectionalShadowExecutionPolicyRegistry =
std::unordered_map<std::string, DirectionalShadowExecutionPolicy>;
PipelineBackendAssetRegistry& GetPipelineBackendAssetRegistry() {
static PipelineBackendAssetRegistry registry = {};
return registry;
}
CameraFrameStandalonePassRegistry& GetCameraFrameStandalonePassRegistry() {
static CameraFrameStandalonePassRegistry registry = {};
return registry;
}
CameraFramePlanPolicyRegistry& GetCameraFramePlanPolicyRegistry() {
static CameraFramePlanPolicyRegistry registry = {};
return registry;
}
DirectionalShadowExecutionPolicyRegistry&
GetDirectionalShadowExecutionPolicyRegistry() {
static DirectionalShadowExecutionPolicyRegistry registry = {};
return registry;
}
std::unordered_set<std::string>& GetBuiltinPipelineBackendAssetKeys() {
static std::unordered_set<std::string> builtinKeys = {};
return builtinKeys;
}
std::unordered_set<std::string>& GetBuiltinCameraFrameStandalonePassKeys() {
static std::unordered_set<std::string> builtinKeys = {};
return builtinKeys;
}
std::unordered_set<std::string>& GetBuiltinCameraFramePlanPolicyKeys() {
static std::unordered_set<std::string> builtinKeys = {};
return builtinKeys;
}
std::unordered_set<std::string>&
GetBuiltinDirectionalShadowExecutionPolicyKeys() {
static std::unordered_set<std::string> builtinKeys = {};
return builtinKeys;
}
std::mutex& GetPipelineBackendAssetRegistryMutex() {
static std::mutex mutex;
return mutex;
}
std::mutex& GetCameraFrameStandalonePassRegistryMutex() {
static std::mutex mutex;
return mutex;
}
std::mutex& GetCameraFramePlanPolicyRegistryMutex() {
static std::mutex mutex;
return mutex;
}
std::mutex& GetDirectionalShadowExecutionPolicyRegistryMutex() {
static std::mutex mutex;
return mutex;
}
void EnsureBuiltinPipelineBackendAssetRegistryInitialized() {
static const bool initialized = []() {
PipelineBackendAssetRegistry& registry =
GetPipelineBackendAssetRegistry();
registry.emplace(
"BuiltinForward",
&CreateBuiltinForwardPipelineRendererAsset);
GetBuiltinPipelineBackendAssetKeys().insert("BuiltinForward");
return true;
}();
(void)initialized;
}
void EnsureBuiltinCameraFrameStandalonePassRegistryInitialized() {
static const bool initialized = []() {
CameraFrameStandalonePassRegistry& registry =
GetCameraFrameStandalonePassRegistry();
registry.emplace(
"BuiltinDepthOnly",
&CreateBuiltinDepthOnlyStandalonePass);
registry.emplace(
"BuiltinObjectId",
&CreateBuiltinObjectIdStandalonePass);
registry.emplace(
"BuiltinShadowCaster",
&CreateBuiltinShadowCasterStandalonePass);
std::unordered_set<std::string>& builtinKeys =
GetBuiltinCameraFrameStandalonePassKeys();
builtinKeys.insert("BuiltinDepthOnly");
builtinKeys.insert("BuiltinObjectId");
builtinKeys.insert("BuiltinShadowCaster");
return true;
}();
(void)initialized;
}
void EnsureBuiltinCameraFramePlanPolicyRegistryInitialized() {
static const bool initialized = []() {
CameraFramePlanPolicyRegistry& registry =
GetCameraFramePlanPolicyRegistry();
registry.emplace(
"BuiltinDefaultCameraFramePlan",
[](CameraFramePlan& plan,
const FinalColorSettings& defaultFinalColorSettings) {
ApplyDefaultRenderPipelineAssetCameraFramePlanPolicy(
plan,
defaultFinalColorSettings);
});
GetBuiltinCameraFramePlanPolicyKeys().insert(
"BuiltinDefaultCameraFramePlan");
return true;
}();
(void)initialized;
}
void EnsureBuiltinDirectionalShadowExecutionPolicyRegistryInitialized() {
static const bool initialized = []() {
DirectionalShadowExecutionPolicyRegistry& registry =
GetDirectionalShadowExecutionPolicyRegistry();
registry.emplace(
"BuiltinDirectionalShadow",
[](const CameraFramePlan& plan,
const DirectionalShadowSurfaceAllocation& shadowAllocation,
DirectionalShadowExecutionState& shadowState) {
ApplyDefaultRenderPipelineDirectionalShadowExecutionPolicy(
plan,
shadowAllocation,
shadowState);
return shadowState.shadowCasterRequest.IsValid() &&
shadowState.shadowData.IsValid();
});
GetBuiltinDirectionalShadowExecutionPolicyKeys().insert(
"BuiltinDirectionalShadow");
return true;
}();
(void)initialized;
}
std::unique_ptr<SceneDrawBackend> TryCreateSceneDrawBackendFromAsset(
const std::shared_ptr<const RenderPipelineAsset>& asset) {
if (asset == nullptr) {
@@ -221,266 +54,12 @@ std::shared_ptr<const RenderPipelineAsset> CreateFallbackRenderPipelineAsset() {
return std::make_shared<Pipelines::ScriptableRenderPipelineHostAsset>();
}
bool RegisterPipelineBackendAssetFactory(
const std::string& key,
PipelineBackendAssetFactory factory) {
if (key.empty() || !factory) {
return false;
}
EnsureBuiltinPipelineBackendAssetRegistryInitialized();
std::lock_guard<std::mutex> lock(
GetPipelineBackendAssetRegistryMutex());
PipelineBackendAssetRegistry& registry =
GetPipelineBackendAssetRegistry();
if (registry.find(key) != registry.end()) {
return false;
}
registry.emplace(key, std::move(factory));
return true;
}
bool UnregisterPipelineBackendAssetFactory(const std::string& key) {
if (key.empty()) {
return false;
}
EnsureBuiltinPipelineBackendAssetRegistryInitialized();
std::lock_guard<std::mutex> lock(
GetPipelineBackendAssetRegistryMutex());
if (GetBuiltinPipelineBackendAssetKeys().find(key) !=
GetBuiltinPipelineBackendAssetKeys().end()) {
return false;
}
PipelineBackendAssetRegistry& registry =
GetPipelineBackendAssetRegistry();
return registry.erase(key) != 0u;
}
std::shared_ptr<const RenderPipelineAsset> CreateDefaultPipelineBackendAsset() {
static const std::shared_ptr<const RenderPipelineAsset> s_defaultAsset =
CreateBuiltinForwardPipelineRendererAsset();
return s_defaultAsset;
}
std::shared_ptr<const RenderPipelineAsset> CreatePipelineBackendAssetByKey(
const std::string& key) {
if (key.empty()) {
return nullptr;
}
EnsureBuiltinPipelineBackendAssetRegistryInitialized();
std::lock_guard<std::mutex> lock(
GetPipelineBackendAssetRegistryMutex());
const PipelineBackendAssetRegistry& registry =
GetPipelineBackendAssetRegistry();
const auto it = registry.find(key);
if (it == registry.end() || !it->second) {
return nullptr;
}
return it->second();
}
bool RegisterCameraFrameStandalonePassFactory(
const std::string& key,
CameraFrameStandalonePassFactory factory) {
if (key.empty() || !factory) {
return false;
}
EnsureBuiltinCameraFrameStandalonePassRegistryInitialized();
std::lock_guard<std::mutex> lock(
GetCameraFrameStandalonePassRegistryMutex());
CameraFrameStandalonePassRegistry& registry =
GetCameraFrameStandalonePassRegistry();
if (registry.find(key) != registry.end()) {
return false;
}
registry.emplace(key, std::move(factory));
return true;
}
bool UnregisterCameraFrameStandalonePassFactory(
const std::string& key) {
if (key.empty()) {
return false;
}
EnsureBuiltinCameraFrameStandalonePassRegistryInitialized();
std::lock_guard<std::mutex> lock(
GetCameraFrameStandalonePassRegistryMutex());
if (GetBuiltinCameraFrameStandalonePassKeys().find(key) !=
GetBuiltinCameraFrameStandalonePassKeys().end()) {
return false;
}
CameraFrameStandalonePassRegistry& registry =
GetCameraFrameStandalonePassRegistry();
return registry.erase(key) != 0u;
}
std::unique_ptr<RenderPass> CreateCameraFrameStandalonePassByKey(
const std::string& key) {
if (key.empty()) {
return nullptr;
}
EnsureBuiltinCameraFrameStandalonePassRegistryInitialized();
std::lock_guard<std::mutex> lock(
GetCameraFrameStandalonePassRegistryMutex());
const CameraFrameStandalonePassRegistry& registry =
GetCameraFrameStandalonePassRegistry();
const auto it = registry.find(key);
if (it == registry.end() || !it->second) {
return nullptr;
}
return it->second();
}
bool RegisterCameraFramePlanPolicy(
const std::string& key,
CameraFramePlanPolicy policy) {
if (key.empty() || !policy) {
return false;
}
EnsureBuiltinCameraFramePlanPolicyRegistryInitialized();
std::lock_guard<std::mutex> lock(
GetCameraFramePlanPolicyRegistryMutex());
CameraFramePlanPolicyRegistry& registry =
GetCameraFramePlanPolicyRegistry();
if (registry.find(key) != registry.end()) {
return false;
}
registry.emplace(key, std::move(policy));
return true;
}
bool UnregisterCameraFramePlanPolicy(
const std::string& key) {
if (key.empty()) {
return false;
}
EnsureBuiltinCameraFramePlanPolicyRegistryInitialized();
std::lock_guard<std::mutex> lock(
GetCameraFramePlanPolicyRegistryMutex());
if (GetBuiltinCameraFramePlanPolicyKeys().find(key) !=
GetBuiltinCameraFramePlanPolicyKeys().end()) {
return false;
}
CameraFramePlanPolicyRegistry& registry =
GetCameraFramePlanPolicyRegistry();
return registry.erase(key) != 0u;
}
bool ApplyCameraFramePlanPolicyByKey(
const std::string& key,
CameraFramePlan& plan,
const FinalColorSettings& defaultFinalColorSettings) {
if (key.empty()) {
return false;
}
EnsureBuiltinCameraFramePlanPolicyRegistryInitialized();
std::lock_guard<std::mutex> lock(
GetCameraFramePlanPolicyRegistryMutex());
const CameraFramePlanPolicyRegistry& registry =
GetCameraFramePlanPolicyRegistry();
const auto it = registry.find(key);
if (it == registry.end() || !it->second) {
return false;
}
it->second(
plan,
defaultFinalColorSettings);
return true;
}
bool RegisterDirectionalShadowExecutionPolicy(
const std::string& key,
DirectionalShadowExecutionPolicy policy) {
if (key.empty() || !policy) {
return false;
}
EnsureBuiltinDirectionalShadowExecutionPolicyRegistryInitialized();
std::lock_guard<std::mutex> lock(
GetDirectionalShadowExecutionPolicyRegistryMutex());
DirectionalShadowExecutionPolicyRegistry& registry =
GetDirectionalShadowExecutionPolicyRegistry();
if (registry.find(key) != registry.end()) {
return false;
}
registry.emplace(key, std::move(policy));
return true;
}
bool UnregisterDirectionalShadowExecutionPolicy(
const std::string& key) {
if (key.empty()) {
return false;
}
EnsureBuiltinDirectionalShadowExecutionPolicyRegistryInitialized();
std::lock_guard<std::mutex> lock(
GetDirectionalShadowExecutionPolicyRegistryMutex());
if (GetBuiltinDirectionalShadowExecutionPolicyKeys().find(key) !=
GetBuiltinDirectionalShadowExecutionPolicyKeys().end()) {
return false;
}
DirectionalShadowExecutionPolicyRegistry& registry =
GetDirectionalShadowExecutionPolicyRegistry();
return registry.erase(key) != 0u;
}
bool ConfigureDirectionalShadowExecutionStateByKey(
const std::string& key,
const CameraFramePlan& plan,
const DirectionalShadowSurfaceAllocation& shadowAllocation,
DirectionalShadowExecutionState& shadowState) {
if (key.empty()) {
return false;
}
EnsureBuiltinDirectionalShadowExecutionPolicyRegistryInitialized();
std::lock_guard<std::mutex> lock(
GetDirectionalShadowExecutionPolicyRegistryMutex());
const DirectionalShadowExecutionPolicyRegistry& registry =
GetDirectionalShadowExecutionPolicyRegistry();
const auto it = registry.find(key);
if (it == registry.end() || !it->second) {
return false;
}
return it->second(
plan,
shadowAllocation,
shadowState);
}
std::shared_ptr<const RenderPipelineAsset> ResolveRenderPipelineAssetOrDefault(
std::shared_ptr<const RenderPipelineAsset> preferredAsset) {
if (preferredAsset != nullptr) {
@@ -567,7 +146,14 @@ std::unique_ptr<SceneDrawBackend> CreateSceneDrawBackendFromAsset(
}
std::unique_ptr<SceneDrawBackend> CreateDefaultSceneDrawBackend() {
return std::make_unique<Pipelines::BuiltinForwardPipeline>();
if (std::unique_ptr<SceneDrawBackend> sceneDrawBackend =
TryCreateSceneDrawBackendFromAsset(
CreateDefaultPipelineBackendAsset());
sceneDrawBackend != nullptr) {
return sceneDrawBackend;
}
return Pipelines::Internal::CreateConfiguredBuiltinForwardPipeline();
}
} // namespace Internal

View File

@@ -1,8 +1,6 @@
#pragma once
#include <functional>
#include <memory>
#include <string>
namespace XCEngine {
namespace Rendering {
@@ -10,63 +8,12 @@ namespace Rendering {
class SceneDrawBackend;
class RenderPipeline;
class RenderPipelineAsset;
class RenderPass;
struct CameraFramePlan;
struct FinalColorSettings;
struct DirectionalShadowExecutionState;
struct DirectionalShadowSurfaceAllocation;
namespace Internal {
using PipelineBackendAssetFactory =
std::function<std::shared_ptr<const RenderPipelineAsset>()>;
using CameraFrameStandalonePassFactory =
std::function<std::unique_ptr<RenderPass>()>;
using CameraFramePlanPolicy =
std::function<void(
CameraFramePlan&,
const FinalColorSettings&)>;
using DirectionalShadowExecutionPolicy =
std::function<bool(
const CameraFramePlan&,
const DirectionalShadowSurfaceAllocation&,
DirectionalShadowExecutionState&)>;
std::shared_ptr<const RenderPipelineAsset> CreateConfiguredRenderPipelineAsset();
std::shared_ptr<const RenderPipelineAsset> CreateFallbackRenderPipelineAsset();
bool RegisterPipelineBackendAssetFactory(
const std::string& key,
PipelineBackendAssetFactory factory);
bool UnregisterPipelineBackendAssetFactory(const std::string& key);
std::shared_ptr<const RenderPipelineAsset> CreateDefaultPipelineBackendAsset();
std::shared_ptr<const RenderPipelineAsset> CreatePipelineBackendAssetByKey(
const std::string& key);
bool RegisterCameraFrameStandalonePassFactory(
const std::string& key,
CameraFrameStandalonePassFactory factory);
bool UnregisterCameraFrameStandalonePassFactory(
const std::string& key);
std::unique_ptr<RenderPass> CreateCameraFrameStandalonePassByKey(
const std::string& key);
bool RegisterCameraFramePlanPolicy(
const std::string& key,
CameraFramePlanPolicy policy);
bool UnregisterCameraFramePlanPolicy(
const std::string& key);
bool ApplyCameraFramePlanPolicyByKey(
const std::string& key,
CameraFramePlan& plan,
const FinalColorSettings& defaultFinalColorSettings);
bool RegisterDirectionalShadowExecutionPolicy(
const std::string& key,
DirectionalShadowExecutionPolicy policy);
bool UnregisterDirectionalShadowExecutionPolicy(
const std::string& key);
bool ConfigureDirectionalShadowExecutionStateByKey(
const std::string& key,
const CameraFramePlan& plan,
const DirectionalShadowSurfaceAllocation& shadowAllocation,
DirectionalShadowExecutionState& shadowState);
std::shared_ptr<const RenderPipelineAsset> ResolveRenderPipelineAssetOrDefault(
std::shared_ptr<const RenderPipelineAsset> preferredAsset);

View File

@@ -2,10 +2,11 @@
#include "Core/Asset/ResourceManager.h"
#include "Debug/Logger.h"
#include <XCEngine/Rendering/RenderPassGraphContract.h>
#include "Rendering/Builtin/BuiltinPassLayoutUtils.h"
#include "Rendering/Internal/RenderSurfacePipelineUtils.h"
#include "Rendering/Internal/ShaderVariantUtils.h"
#include "Rendering/RenderSurface.h"
#include <XCEngine/Rendering/RenderPassGraphContract.h>
#include "Resources/BuiltinResources.h"
#include "RHI/RHICommandList.h"
#include "RHI/RHIDescriptorPool.h"
@@ -16,7 +17,9 @@
#include "RHI/RHIResourceView.h"
#include "RHI/RHISampler.h"
#include <algorithm>
#include <utility>
#include <vector>
namespace XCEngine {
namespace Rendering {
@@ -45,7 +48,8 @@ const Resources::ShaderPass* FindCompatiblePass(
return nullptr;
}
const Resources::ShaderPass* colorScalePass = shader.FindPass("ColorScale");
const Resources::ShaderPass* colorScalePass =
shader.FindPass("ColorScale");
if (colorScalePass != nullptr &&
::XCEngine::Rendering::Internal::ShaderPassHasGraphicsVariants(
shader,
@@ -55,13 +59,87 @@ const Resources::ShaderPass* FindCompatiblePass(
}
if (shader.GetPassCount() > 0 &&
::XCEngine::Rendering::Internal::ShaderPassHasGraphicsVariants(shader, shader.GetPasses()[0].name, backend)) {
::XCEngine::Rendering::Internal::ShaderPassHasGraphicsVariants(
shader,
shader.GetPasses()[0].name,
backend)) {
return &shader.GetPasses()[0];
}
return nullptr;
}
bool UsesContiguousDescriptorSets(
const BuiltinPassResourceBindingPlan& bindingPlan) {
if (bindingPlan.bindings.Empty()) {
return true;
}
std::vector<bool> usedSets(
static_cast<size_t>(bindingPlan.maxSetIndex) + 1u,
false);
Core::uint32 minSet = UINT32_MAX;
Core::uint32 maxSet = 0u;
for (const BuiltinPassResourceBindingDesc& binding :
bindingPlan.bindings) {
usedSets[binding.location.set] = true;
minSet = std::min(minSet, binding.location.set);
maxSet = std::max(maxSet, binding.location.set);
}
for (Core::uint32 setIndex = minSet;
setIndex <= maxSet;
++setIndex) {
if (!usedSets[setIndex]) {
return false;
}
}
return true;
}
bool IsSupportedFullscreenBindingPlan(
const BuiltinPassResourceBindingPlan& bindingPlan) {
if (!UsesContiguousDescriptorSets(bindingPlan)) {
return false;
}
for (const BuiltinPassResourceBindingDesc& binding :
bindingPlan.bindings) {
switch (binding.semantic) {
case BuiltinPassResourceSemantic::PassConstants:
case BuiltinPassResourceSemantic::SourceColorTexture:
case BuiltinPassResourceSemantic::MaterialTexture:
case BuiltinPassResourceSemantic::LinearClampSampler:
break;
default:
return false;
}
}
return true;
}
const RenderPassContext::TextureBindingView* FindTextureBindingView(
const RenderPassContext& context,
const BuiltinPassResourceBindingDesc& bindingDesc) {
auto matchesName =
[&bindingDesc](
const RenderPassContext::TextureBindingView& bindingView) {
return bindingView.resourceName ==
bindingDesc.name;
};
const auto it =
std::find_if(
context.textureBindings.begin(),
context.textureBindings.end(),
matchesName);
return it != context.textureBindings.end()
? &(*it)
: nullptr;
}
RHI::GraphicsPipelineDesc CreatePipelineDesc(
RHI::RHIType backendType,
RHI::RHIPipelineLayout* pipelineLayout,
@@ -70,34 +148,54 @@ RHI::GraphicsPipelineDesc CreatePipelineDesc(
const RenderSurface& surface) {
RHI::GraphicsPipelineDesc pipelineDesc = {};
pipelineDesc.pipelineLayout = pipelineLayout;
pipelineDesc.topologyType = static_cast<uint32_t>(RHI::PrimitiveTopologyType::Triangle);
::XCEngine::Rendering::Internal::ApplySingleColorAttachmentPropertiesToGraphicsPipelineDesc(
surface,
pipelineDesc);
pipelineDesc.depthStencilFormat = static_cast<uint32_t>(RHI::Format::Unknown);
pipelineDesc.topologyType = static_cast<uint32_t>(
RHI::PrimitiveTopologyType::Triangle);
::XCEngine::Rendering::Internal::
ApplySingleColorAttachmentPropertiesToGraphicsPipelineDesc(
surface,
pipelineDesc);
pipelineDesc.depthStencilFormat = static_cast<uint32_t>(
RHI::Format::Unknown);
pipelineDesc.rasterizerState.fillMode = static_cast<uint32_t>(RHI::FillMode::Solid);
pipelineDesc.rasterizerState.cullMode = static_cast<uint32_t>(RHI::CullMode::None);
pipelineDesc.rasterizerState.frontFace = static_cast<uint32_t>(RHI::FrontFace::CounterClockwise);
pipelineDesc.rasterizerState.fillMode = static_cast<uint32_t>(
RHI::FillMode::Solid);
pipelineDesc.rasterizerState.cullMode = static_cast<uint32_t>(
RHI::CullMode::None);
pipelineDesc.rasterizerState.frontFace =
static_cast<uint32_t>(RHI::FrontFace::CounterClockwise);
pipelineDesc.rasterizerState.depthClipEnable = true;
pipelineDesc.blendState.blendEnable = false;
pipelineDesc.blendState.srcBlend = static_cast<uint32_t>(RHI::BlendFactor::One);
pipelineDesc.blendState.dstBlend = static_cast<uint32_t>(RHI::BlendFactor::Zero);
pipelineDesc.blendState.srcBlendAlpha = static_cast<uint32_t>(RHI::BlendFactor::One);
pipelineDesc.blendState.dstBlendAlpha = static_cast<uint32_t>(RHI::BlendFactor::Zero);
pipelineDesc.blendState.blendOp = static_cast<uint32_t>(RHI::BlendOp::Add);
pipelineDesc.blendState.blendOpAlpha = static_cast<uint32_t>(RHI::BlendOp::Add);
pipelineDesc.blendState.colorWriteMask = static_cast<uint8_t>(RHI::ColorWriteMask::All);
pipelineDesc.blendState.srcBlend = static_cast<uint32_t>(
RHI::BlendFactor::One);
pipelineDesc.blendState.dstBlend = static_cast<uint32_t>(
RHI::BlendFactor::Zero);
pipelineDesc.blendState.srcBlendAlpha =
static_cast<uint32_t>(RHI::BlendFactor::One);
pipelineDesc.blendState.dstBlendAlpha =
static_cast<uint32_t>(RHI::BlendFactor::Zero);
pipelineDesc.blendState.blendOp = static_cast<uint32_t>(
RHI::BlendOp::Add);
pipelineDesc.blendState.blendOpAlpha = static_cast<uint32_t>(
RHI::BlendOp::Add);
pipelineDesc.blendState.colorWriteMask =
static_cast<uint8_t>(RHI::ColorWriteMask::All);
pipelineDesc.depthStencilState.depthTestEnable = false;
pipelineDesc.depthStencilState.depthWriteEnable = false;
pipelineDesc.depthStencilState.depthFunc = static_cast<uint32_t>(RHI::ComparisonFunc::Always);
pipelineDesc.depthStencilState.depthFunc = static_cast<uint32_t>(
RHI::ComparisonFunc::Always);
const Resources::ShaderPass* shaderPass = shader.FindPass(passName);
const Resources::ShaderBackend backend = ::XCEngine::Rendering::Internal::ToShaderBackend(backendType);
const Resources::ShaderPass* shaderPass =
shader.FindPass(passName);
const Resources::ShaderBackend backend =
::XCEngine::Rendering::Internal::ToShaderBackend(
backendType);
if (const Resources::ShaderStageVariant* vertexVariant =
shader.FindVariant(passName, Resources::ShaderType::Vertex, backend)) {
shader.FindVariant(
passName,
Resources::ShaderType::Vertex,
backend)) {
if (shaderPass != nullptr) {
::XCEngine::Rendering::Internal::ApplyShaderStageVariant(
shader.GetPath(),
@@ -108,7 +206,10 @@ RHI::GraphicsPipelineDesc CreatePipelineDesc(
}
}
if (const Resources::ShaderStageVariant* fragmentVariant =
shader.FindVariant(passName, Resources::ShaderType::Fragment, backend)) {
shader.FindVariant(
passName,
Resources::ShaderType::Fragment,
backend)) {
if (shaderPass != nullptr) {
::XCEngine::Rendering::Internal::ApplyShaderStageVariant(
shader.GetPath(),
@@ -132,7 +233,8 @@ BuiltinVectorFullscreenPass::BuiltinVectorFullscreenPass(
, m_preferredPassName(std::move(preferredPassName))
, m_vectorPayload(vectorPayload) {
if (m_shaderPath.Empty()) {
m_shaderPath = Resources::GetBuiltinColorScalePostProcessShaderPath();
m_shaderPath =
Resources::GetBuiltinColorScalePostProcessShaderPath();
}
}
@@ -155,44 +257,56 @@ bool BuiltinVectorFullscreenPass::RecordRenderGraph(
context);
}
bool BuiltinVectorFullscreenPass::Execute(const RenderPassContext& context) {
bool BuiltinVectorFullscreenPass::Execute(
const RenderPassContext& context) {
if (!context.renderContext.IsValid() ||
context.sourceSurface == nullptr ||
context.sourceColorView == nullptr) {
return false;
}
if (!::XCEngine::Rendering::Internal::HasSingleColorAttachment(*context.sourceSurface)) {
!::XCEngine::Rendering::Internal::HasSingleColorAttachment(
context.surface)) {
return false;
}
const std::vector<RHI::RHIResourceView*>& colorAttachments = context.surface.GetColorAttachments();
if (!::XCEngine::Rendering::Internal::HasSingleColorAttachment(context.surface) ||
colorAttachments.empty() ||
const std::vector<RHI::RHIResourceView*>& colorAttachments =
context.surface.GetColorAttachments();
if (colorAttachments.empty() ||
colorAttachments[0] == nullptr) {
return false;
}
const Math::RectInt renderArea = context.surface.GetRenderArea();
if (renderArea.width <= 0 || renderArea.height <= 0) {
const Math::RectInt renderArea =
context.surface.GetRenderArea();
if (renderArea.width <= 0 ||
renderArea.height <= 0) {
return false;
}
if (!EnsureInitialized(context.renderContext, context.surface)) {
if (!EnsureInitialized(
context.renderContext,
context.surface)) {
return false;
}
PostProcessConstants constants = {};
constants.vectorPayload = m_vectorPayload;
m_constantsSet.set->WriteConstant(0, &constants, sizeof(constants));
if (m_boundSourceColorView != context.sourceColorView) {
m_textureSet.set->Update(0, context.sourceColorView);
m_boundSourceColorView = context.sourceColorView;
if (m_passLayout.sourceColorTexture.IsValid() &&
(context.sourceSurface == nullptr ||
context.sourceColorView == nullptr)) {
return false;
}
RHI::RHICommandList* commandList = context.renderContext.commandList;
RHI::RHIResourceView* renderTarget = colorAttachments[0];
const bool autoTransitionSource = context.sourceSurface->IsAutoTransitionEnabled();
if (!UpdateDescriptorSets(context)) {
return false;
}
RHI::RHICommandList* commandList =
context.renderContext.commandList;
if (commandList == nullptr) {
return false;
}
RHI::RHIResourceView* renderTarget =
colorAttachments[0];
const bool autoTransitionSource =
m_passLayout.sourceColorTexture.IsValid() &&
context.sourceSurface != nullptr &&
context.sourceSurface->IsAutoTransitionEnabled();
if (context.surface.IsAutoTransitionEnabled()) {
commandList->TransitionBarrier(
@@ -200,13 +314,16 @@ bool BuiltinVectorFullscreenPass::Execute(const RenderPassContext& context) {
context.surface.GetColorStateBefore(),
RHI::ResourceStates::RenderTarget);
}
if (autoTransitionSource) {
commandList->TransitionBarrier(
context.sourceColorView,
context.sourceColorState,
RHI::ResourceStates::PixelShaderResource);
} else if (context.sourceColorState != RHI::ResourceStates::PixelShaderResource) {
return false;
if (m_passLayout.sourceColorTexture.IsValid()) {
if (autoTransitionSource) {
commandList->TransitionBarrier(
context.sourceColorView,
context.sourceColorState,
RHI::ResourceStates::PixelShaderResource);
} else if (context.sourceColorState !=
RHI::ResourceStates::PixelShaderResource) {
return false;
}
}
commandList->SetRenderTargets(1, &renderTarget, nullptr);
@@ -228,15 +345,38 @@ bool BuiltinVectorFullscreenPass::Execute(const RenderPassContext& context) {
commandList->SetViewport(viewport);
commandList->SetScissorRect(scissorRect);
commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList);
commandList->SetPrimitiveTopology(
RHI::PrimitiveTopology::TriangleList);
commandList->SetPipelineState(m_pipelineState);
RHI::RHIDescriptorSet* descriptorSets[] = {
m_constantsSet.set,
m_textureSet.set,
m_samplerSet.set
};
commandList->SetGraphicsDescriptorSets(0, 3, descriptorSets, m_pipelineLayout);
if (m_passLayout.descriptorSetCount > 0u) {
std::vector<RHI::RHIDescriptorSet*> descriptorSets(
m_passLayout.descriptorSetCount,
nullptr);
for (Core::uint32 descriptorOffset = 0u;
descriptorOffset < m_passLayout.descriptorSetCount;
++descriptorOffset) {
const Core::uint32 setIndex =
m_passLayout.firstDescriptorSet +
descriptorOffset;
if (setIndex >=
m_passLayout.descriptorSets.size() ||
m_passLayout.descriptorSets[setIndex].set ==
nullptr) {
return false;
}
descriptorSets[descriptorOffset] =
m_passLayout.descriptorSets[setIndex].set;
}
commandList->SetGraphicsDescriptorSets(
m_passLayout.firstDescriptorSet,
m_passLayout.descriptorSetCount,
descriptorSets.data(),
m_passLayout.pipelineLayout);
}
commandList->Draw(3, 1, 0, 0);
commandList->EndRenderPass();
@@ -246,7 +386,8 @@ bool BuiltinVectorFullscreenPass::Execute(const RenderPassContext& context) {
RHI::ResourceStates::RenderTarget,
context.surface.GetColorStateAfter());
}
if (autoTransitionSource) {
if (m_passLayout.sourceColorTexture.IsValid() &&
autoTransitionSource) {
commandList->TransitionBarrier(
context.sourceColorView,
RHI::ResourceStates::PixelShaderResource,
@@ -260,7 +401,8 @@ void BuiltinVectorFullscreenPass::Shutdown() {
DestroyResources();
}
void BuiltinVectorFullscreenPass::SetVectorPayload(const Math::Vector4& vectorPayload) {
void BuiltinVectorFullscreenPass::SetVectorPayload(
const Math::Vector4& vectorPayload) {
m_vectorPayload = vectorPayload;
}
@@ -268,7 +410,8 @@ const Math::Vector4& BuiltinVectorFullscreenPass::GetVectorPayload() const {
return m_vectorPayload;
}
void BuiltinVectorFullscreenPass::SetShaderPath(const Containers::String& shaderPath) {
void BuiltinVectorFullscreenPass::SetShaderPath(
const Containers::String& shaderPath) {
if (m_shaderPath == shaderPath) {
return;
}
@@ -291,7 +434,8 @@ void BuiltinVectorFullscreenPass::SetPreferredPassName(
m_preferredPassName = preferredPassName;
}
const Containers::String& BuiltinVectorFullscreenPass::GetPreferredPassName() const {
const Containers::String&
BuiltinVectorFullscreenPass::GetPreferredPassName() const {
return m_preferredPassName;
}
@@ -299,22 +443,25 @@ bool BuiltinVectorFullscreenPass::EnsureInitialized(
const RenderContext& renderContext,
const RenderSurface& surface) {
const RHI::Format renderTargetFormat =
::XCEngine::Rendering::Internal::ResolveSurfaceColorFormat(surface, 0u);
::XCEngine::Rendering::Internal::ResolveSurfaceColorFormat(
surface,
0u);
const uint32_t renderTargetSampleCount =
::XCEngine::Rendering::Internal::ResolveSurfaceSampleCount(surface);
::XCEngine::Rendering::Internal::ResolveSurfaceSampleCount(
surface);
const uint32_t renderTargetSampleQuality =
::XCEngine::Rendering::Internal::ResolveSurfaceSampleQuality(surface);
::XCEngine::Rendering::Internal::ResolveSurfaceSampleQuality(
surface);
if (m_device == renderContext.device &&
m_backendType == renderContext.backendType &&
m_renderTargetFormat == renderTargetFormat &&
m_renderTargetSampleCount == renderTargetSampleCount &&
m_renderTargetSampleQuality == renderTargetSampleQuality &&
m_pipelineLayout != nullptr &&
m_renderTargetSampleCount ==
renderTargetSampleCount &&
m_renderTargetSampleQuality ==
renderTargetSampleQuality &&
m_passLayout.pipelineLayout != nullptr &&
m_pipelineState != nullptr &&
m_sampler != nullptr &&
m_constantsSet.set != nullptr &&
m_textureSet.set != nullptr &&
m_samplerSet.set != nullptr) {
m_sampler != nullptr) {
return true;
}
@@ -330,38 +477,98 @@ bool BuiltinVectorFullscreenPass::CreateResources(
}
RHI::Format renderTargetFormat = RHI::Format::Unknown;
if (!::XCEngine::Rendering::Internal::TryResolveSingleColorAttachmentFormat(surface, renderTargetFormat)) {
if (!::XCEngine::Rendering::Internal::
TryResolveSingleColorAttachmentFormat(
surface,
renderTargetFormat)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinVectorFullscreenPass requires exactly one valid destination color attachment");
"BuiltinVectorFullscreenPass requires exactly one "
"valid destination color attachment");
return false;
}
if (m_shaderPath.Empty()) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinVectorFullscreenPass requires a shader path before resource creation");
"BuiltinVectorFullscreenPass requires a shader path "
"before resource creation");
return false;
}
m_shader = Resources::ResourceManager::Get().Load<Resources::Shader>(m_shaderPath);
m_shader =
Resources::ResourceManager::Get().Load<Resources::Shader>(
m_shaderPath);
if (!m_shader.IsValid()) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinVectorFullscreenPass failed to load configured fullscreen shader resource");
"BuiltinVectorFullscreenPass failed to load "
"configured fullscreen shader resource");
DestroyResources();
return false;
}
const Resources::ShaderBackend backend = ::XCEngine::Rendering::Internal::ToShaderBackend(renderContext.backendType);
const Resources::ShaderBackend backend =
::XCEngine::Rendering::Internal::ToShaderBackend(
renderContext.backendType);
const Resources::ShaderPass* selectedPass =
FindCompatiblePass(*m_shader.Get(), backend, m_preferredPassName);
FindCompatiblePass(
*m_shader.Get(),
backend,
m_preferredPassName);
if (selectedPass == nullptr) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
m_preferredPassName.Empty()
? "BuiltinVectorFullscreenPass could not resolve a compatible fullscreen shader pass"
: "BuiltinVectorFullscreenPass could not resolve the configured fullscreen shader pass");
? "BuiltinVectorFullscreenPass could not resolve "
"a compatible fullscreen shader pass"
: "BuiltinVectorFullscreenPass could not resolve "
"the configured fullscreen shader pass");
DestroyResources();
return false;
}
BuiltinPassResourceBindingPlan bindingPlan = {};
Containers::String bindingPlanError;
if (!TryBuildBuiltinPassResourceBindingPlan(
*selectedPass,
bindingPlan,
&bindingPlanError)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
(Containers::String(
"BuiltinVectorFullscreenPass failed to "
"resolve shader resource bindings: ") +
bindingPlanError)
.CStr());
DestroyResources();
return false;
}
if (!IsSupportedFullscreenBindingPlan(bindingPlan)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"BuiltinVectorFullscreenPass only supports "
"PassConstants, SourceColorTexture, "
"MaterialTexture, and LinearClampSampler "
"resource semantics");
DestroyResources();
return false;
}
std::vector<BuiltinPassSetLayoutMetadata> setLayouts;
Containers::String setLayoutError;
if (!TryBuildBuiltinPassSetLayouts(
bindingPlan,
setLayouts,
&setLayoutError)) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
(Containers::String(
"BuiltinVectorFullscreenPass failed to build "
"descriptor set layouts: ") +
setLayoutError)
.CStr());
DestroyResources();
return false;
}
@@ -369,62 +576,64 @@ bool BuiltinVectorFullscreenPass::CreateResources(
m_device = renderContext.device;
m_backendType = renderContext.backendType;
m_renderTargetFormat = renderTargetFormat;
m_renderTargetSampleCount = ::XCEngine::Rendering::Internal::ResolveSurfaceSampleCount(surface);
m_renderTargetSampleQuality = ::XCEngine::Rendering::Internal::ResolveSurfaceSampleQuality(surface);
m_renderTargetSampleCount =
::XCEngine::Rendering::Internal::ResolveSurfaceSampleCount(
surface);
m_renderTargetSampleQuality =
::XCEngine::Rendering::Internal::
ResolveSurfaceSampleQuality(surface);
RHI::DescriptorSetLayoutBinding constantBinding = {};
constantBinding.binding = 0;
constantBinding.type = static_cast<uint32_t>(RHI::DescriptorType::CBV);
constantBinding.count = 1;
constantBinding.visibility = static_cast<uint32_t>(RHI::ShaderVisibility::All);
m_passLayout.setLayouts = std::move(setLayouts);
m_passLayout.descriptorSets.resize(
m_passLayout.setLayouts.size());
m_passLayout.boundSetStates.resize(
m_passLayout.setLayouts.size());
m_passLayout.passConstants = bindingPlan.passConstants;
m_passLayout.sourceColorTexture =
bindingPlan.sourceColorTexture;
m_passLayout.linearClampSampler =
bindingPlan.linearClampSampler;
m_passLayout.firstDescriptorSet =
bindingPlan.firstDescriptorSet;
m_passLayout.descriptorSetCount =
bindingPlan.descriptorSetCount;
RHI::DescriptorSetLayoutBinding textureBinding = {};
textureBinding.binding = 0;
textureBinding.type = static_cast<uint32_t>(RHI::DescriptorType::SRV);
textureBinding.count = 1;
textureBinding.visibility = static_cast<uint32_t>(RHI::ShaderVisibility::All);
RHI::DescriptorSetLayoutBinding samplerBinding = {};
samplerBinding.binding = 0;
samplerBinding.type = static_cast<uint32_t>(RHI::DescriptorType::Sampler);
samplerBinding.count = 1;
samplerBinding.visibility = static_cast<uint32_t>(RHI::ShaderVisibility::All);
RHI::DescriptorSetLayoutDesc constantLayout = {};
constantLayout.bindings = &constantBinding;
constantLayout.bindingCount = 1;
RHI::DescriptorSetLayoutDesc textureLayout = {};
textureLayout.bindings = &textureBinding;
textureLayout.bindingCount = 1;
RHI::DescriptorSetLayoutDesc samplerLayout = {};
samplerLayout.bindings = &samplerBinding;
samplerLayout.bindingCount = 1;
RHI::DescriptorSetLayoutDesc setLayouts[] = {
constantLayout,
textureLayout,
samplerLayout
};
std::vector<RHI::DescriptorSetLayoutDesc> nativeSetLayouts(
m_passLayout.setLayouts.size());
for (size_t setIndex = 0u;
setIndex < m_passLayout.setLayouts.size();
++setIndex) {
nativeSetLayouts[setIndex] =
m_passLayout.setLayouts[setIndex].layout;
}
RHI::RHIPipelineLayoutDesc pipelineLayoutDesc = {};
pipelineLayoutDesc.setLayouts = setLayouts;
pipelineLayoutDesc.setLayoutCount = 3;
m_pipelineLayout = m_device->CreatePipelineLayout(pipelineLayoutDesc);
if (m_pipelineLayout == nullptr) {
pipelineLayoutDesc.setLayouts =
nativeSetLayouts.empty()
? nullptr
: nativeSetLayouts.data();
pipelineLayoutDesc.setLayoutCount =
static_cast<uint32_t>(nativeSetLayouts.size());
m_passLayout.pipelineLayout =
m_device->CreatePipelineLayout(pipelineLayoutDesc);
if (m_passLayout.pipelineLayout == nullptr) {
DestroyResources();
return false;
}
RHI::SamplerDesc samplerDesc = {};
samplerDesc.filter = static_cast<uint32_t>(RHI::FilterMode::Linear);
samplerDesc.addressU = static_cast<uint32_t>(RHI::TextureAddressMode::Clamp);
samplerDesc.addressV = static_cast<uint32_t>(RHI::TextureAddressMode::Clamp);
samplerDesc.addressW = static_cast<uint32_t>(RHI::TextureAddressMode::Clamp);
samplerDesc.filter =
static_cast<uint32_t>(RHI::FilterMode::Linear);
samplerDesc.addressU = static_cast<uint32_t>(
RHI::TextureAddressMode::Clamp);
samplerDesc.addressV = static_cast<uint32_t>(
RHI::TextureAddressMode::Clamp);
samplerDesc.addressW = static_cast<uint32_t>(
RHI::TextureAddressMode::Clamp);
samplerDesc.mipLodBias = 0.0f;
samplerDesc.maxAnisotropy = 1;
samplerDesc.comparisonFunc = static_cast<uint32_t>(RHI::ComparisonFunc::Always);
samplerDesc.comparisonFunc = static_cast<uint32_t>(
RHI::ComparisonFunc::Always);
samplerDesc.minLod = 0.0f;
samplerDesc.maxLod = 1000.0f;
m_sampler = m_device->CreateSampler(samplerDesc);
@@ -433,58 +642,47 @@ bool BuiltinVectorFullscreenPass::CreateResources(
return false;
}
auto createOwnedDescriptorSet =
[this](const RHI::DescriptorSetLayoutDesc& layout,
RHI::DescriptorHeapType heapType,
bool shaderVisible,
OwnedDescriptorSet& ownedSet) -> bool {
RHI::DescriptorPoolDesc poolDesc = {};
poolDesc.type = heapType;
poolDesc.descriptorCount = 1;
poolDesc.shaderVisible = shaderVisible;
ownedSet.pool = m_device->CreateDescriptorPool(poolDesc);
if (ownedSet.pool == nullptr) {
for (size_t setIndex = 0u;
setIndex < m_passLayout.setLayouts.size();
++setIndex) {
const BuiltinPassSetLayoutMetadata& setLayout =
m_passLayout.setLayouts[setIndex];
if (setLayout.bindings.empty()) {
continue;
}
if (!CreateOwnedDescriptorSet(
setLayout,
m_passLayout.descriptorSets[setIndex])) {
DestroyResources();
return false;
}
if (setLayout.usesSampler) {
if (!setLayout.usesLinearClampSampler ||
!m_passLayout.linearClampSampler.IsValid() ||
m_passLayout.linearClampSampler.set !=
setIndex) {
DestroyResources();
return false;
}
ownedSet.set = ownedSet.pool->AllocateSet(layout);
if (ownedSet.set == nullptr) {
DestroyOwnedDescriptorSet(ownedSet);
return false;
}
return true;
};
if (!createOwnedDescriptorSet(
constantLayout,
RHI::DescriptorHeapType::CBV_SRV_UAV,
false,
m_constantsSet) ||
!createOwnedDescriptorSet(
textureLayout,
RHI::DescriptorHeapType::CBV_SRV_UAV,
true,
m_textureSet) ||
!createOwnedDescriptorSet(
samplerLayout,
RHI::DescriptorHeapType::Sampler,
true,
m_samplerSet)) {
DestroyResources();
return false;
m_passLayout.descriptorSets[setIndex]
.set->UpdateSampler(
m_passLayout.linearClampSampler.binding,
m_sampler);
}
}
m_samplerSet.set->UpdateSampler(0, m_sampler);
m_pipelineState = m_device->CreatePipelineState(
CreatePipelineDesc(
m_backendType,
m_pipelineLayout,
m_passLayout.pipelineLayout,
*m_shader.Get(),
selectedPass->name,
surface));
if (m_pipelineState == nullptr || !m_pipelineState->IsValid()) {
if (m_pipelineState == nullptr ||
!m_pipelineState->IsValid()) {
DestroyResources();
return false;
}
@@ -492,24 +690,149 @@ bool BuiltinVectorFullscreenPass::CreateResources(
return true;
}
void BuiltinVectorFullscreenPass::DestroyResources() {
m_boundSourceColorView = nullptr;
bool BuiltinVectorFullscreenPass::CreateOwnedDescriptorSet(
const BuiltinPassSetLayoutMetadata& setLayout,
OwnedDescriptorSet& descriptorSet) {
RHI::DescriptorPoolDesc poolDesc = {};
poolDesc.type = setLayout.heapType;
poolDesc.descriptorCount =
CountBuiltinPassHeapDescriptors(
setLayout.heapType,
setLayout.bindings);
poolDesc.shaderVisible = setLayout.shaderVisible;
descriptorSet.pool =
m_device->CreateDescriptorPool(poolDesc);
if (descriptorSet.pool == nullptr) {
return false;
}
descriptorSet.set =
descriptorSet.pool->AllocateSet(setLayout.layout);
if (descriptorSet.set == nullptr) {
DestroyOwnedDescriptorSet(descriptorSet);
return false;
}
return true;
}
bool BuiltinVectorFullscreenPass::UpdateDescriptorSets(
const RenderPassContext& context) {
for (size_t setIndex = 0u;
setIndex < m_passLayout.setLayouts.size();
++setIndex) {
const BuiltinPassSetLayoutMetadata& setLayout =
m_passLayout.setLayouts[setIndex];
if (setLayout.bindings.empty()) {
continue;
}
OwnedDescriptorSet& descriptorSet =
m_passLayout.descriptorSets[setIndex];
BoundSetState& boundSetState =
m_passLayout.boundSetStates[setIndex];
if (descriptorSet.set == nullptr) {
return false;
}
if (setLayout.usesPassConstants) {
if (!m_passLayout.passConstants.IsValid() ||
m_passLayout.passConstants.set != setIndex) {
return false;
}
const PostProcessConstants constants = {
m_vectorPayload
};
descriptorSet.set->WriteConstant(
m_passLayout.passConstants.binding,
&constants,
sizeof(constants));
}
if (setLayout.usesSourceColorTexture) {
if (context.sourceColorView == nullptr ||
!m_passLayout.sourceColorTexture.IsValid() ||
m_passLayout.sourceColorTexture.set !=
setIndex) {
return false;
}
if (boundSetState.sourceColorTextureView !=
context.sourceColorView) {
descriptorSet.set->Update(
m_passLayout.sourceColorTexture.binding,
context.sourceColorView);
boundSetState.sourceColorTextureView =
context.sourceColorView;
}
}
if (setLayout.usesMaterialTextures) {
if (boundSetState.materialTextureViews.size() !=
setLayout.materialTextureBindings.size()) {
boundSetState.materialTextureViews.assign(
setLayout.materialTextureBindings.size(),
nullptr);
}
for (size_t bindingIndex = 0u;
bindingIndex <
setLayout.materialTextureBindings.size();
++bindingIndex) {
const BuiltinPassResourceBindingDesc&
textureBinding =
setLayout.materialTextureBindings
[bindingIndex];
RHI::RHIResourceView* resolvedTextureView =
ResolveExtraTextureView(
context,
textureBinding);
if (resolvedTextureView == nullptr) {
return false;
}
if (boundSetState.materialTextureViews
[bindingIndex] !=
resolvedTextureView) {
descriptorSet.set->Update(
textureBinding.location.binding,
resolvedTextureView);
boundSetState.materialTextureViews
[bindingIndex] = resolvedTextureView;
}
}
} else if (!boundSetState.materialTextureViews
.empty()) {
boundSetState.materialTextureViews.clear();
}
}
return true;
}
RHI::RHIResourceView*
BuiltinVectorFullscreenPass::ResolveExtraTextureView(
const RenderPassContext& context,
const BuiltinPassResourceBindingDesc& bindingDesc) const {
const RenderPassContext::TextureBindingView* bindingView =
FindTextureBindingView(
context,
bindingDesc);
return bindingView != nullptr
? bindingView->resourceView
: nullptr;
}
void BuiltinVectorFullscreenPass::DestroyResources() {
if (m_pipelineState != nullptr) {
m_pipelineState->Shutdown();
delete m_pipelineState;
m_pipelineState = nullptr;
}
DestroyOwnedDescriptorSet(m_samplerSet);
DestroyOwnedDescriptorSet(m_textureSet);
DestroyOwnedDescriptorSet(m_constantsSet);
if (m_pipelineLayout != nullptr) {
m_pipelineLayout->Shutdown();
delete m_pipelineLayout;
m_pipelineLayout = nullptr;
}
DestroyPassResourceLayout();
if (m_sampler != nullptr) {
m_sampler->Shutdown();
@@ -525,7 +848,30 @@ void BuiltinVectorFullscreenPass::DestroyResources() {
m_renderTargetSampleQuality = 0u;
}
void BuiltinVectorFullscreenPass::DestroyOwnedDescriptorSet(OwnedDescriptorSet& descriptorSet) {
void BuiltinVectorFullscreenPass::DestroyPassResourceLayout() {
for (OwnedDescriptorSet& descriptorSet :
m_passLayout.descriptorSets) {
DestroyOwnedDescriptorSet(descriptorSet);
}
m_passLayout.descriptorSets.clear();
m_passLayout.boundSetStates.clear();
m_passLayout.setLayouts.clear();
if (m_passLayout.pipelineLayout != nullptr) {
m_passLayout.pipelineLayout->Shutdown();
delete m_passLayout.pipelineLayout;
m_passLayout.pipelineLayout = nullptr;
}
m_passLayout.passConstants = {};
m_passLayout.sourceColorTexture = {};
m_passLayout.linearClampSampler = {};
m_passLayout.firstDescriptorSet = 0u;
m_passLayout.descriptorSetCount = 0u;
}
void BuiltinVectorFullscreenPass::DestroyOwnedDescriptorSet(
OwnedDescriptorSet& descriptorSet) {
if (descriptorSet.set != nullptr) {
descriptorSet.set->Shutdown();
delete descriptorSet.set;

View File

@@ -6,9 +6,7 @@ namespace XCEngine {
namespace Rendering {
namespace Pipelines {
BuiltinForwardPipeline::BuiltinForwardPipeline() {
Internal::RegisterBuiltinForwardSceneFeatures(m_forwardSceneFeatureHost);
}
BuiltinForwardPipeline::BuiltinForwardPipeline() = default;
BuiltinForwardPipeline::~BuiltinForwardPipeline() {
Shutdown();
@@ -28,7 +26,7 @@ SceneRenderFeaturePass* BuiltinForwardPipeline::GetForwardSceneFeaturePass(size_
}
std::unique_ptr<RenderPipeline> BuiltinForwardPipelineAsset::CreatePipeline() const {
return std::make_unique<BuiltinForwardPipeline>();
return Internal::CreateConfiguredBuiltinForwardPipeline();
}
} // namespace Pipelines

View File

@@ -2,7 +2,9 @@
#include "Rendering/Features/BuiltinGaussianSplatPass.h"
#include "Rendering/Features/BuiltinVolumetricPass.h"
#include "Rendering/SceneRenderFeatureHost.h"
#include "Rendering/Passes/BuiltinDepthOnlyPass.h"
#include "Rendering/Passes/BuiltinShadowCasterPass.h"
#include "Rendering/Pipelines/BuiltinForwardPipeline.h"
#include <memory>
@@ -11,9 +13,35 @@ namespace Rendering {
namespace Pipelines {
namespace Internal {
void RegisterBuiltinForwardSceneFeatures(SceneRenderFeatureHost& featureHost) {
featureHost.AddFeaturePass(std::make_unique<Features::BuiltinGaussianSplatPass>());
featureHost.AddFeaturePass(std::make_unique<Features::BuiltinVolumetricPass>());
namespace {
void ConfigureBuiltinForwardStandalonePasses(
BuiltinForwardPipeline& pipeline) {
pipeline.SetCameraFrameStandalonePass(
CameraFrameStage::DepthOnly,
std::make_unique<Passes::BuiltinDepthOnlyPass>());
pipeline.SetCameraFrameStandalonePass(
CameraFrameStage::ShadowCaster,
std::make_unique<Passes::BuiltinShadowCasterPass>());
}
} // namespace
void ConfigureBuiltinForwardPipeline(
BuiltinForwardPipeline& pipeline) {
ConfigureBuiltinForwardStandalonePasses(pipeline);
pipeline.AddForwardSceneFeaturePass(
std::make_unique<Features::BuiltinGaussianSplatPass>());
pipeline.AddForwardSceneFeaturePass(
std::make_unique<Features::BuiltinVolumetricPass>());
}
std::unique_ptr<BuiltinForwardPipeline>
CreateConfiguredBuiltinForwardPipeline() {
std::unique_ptr<BuiltinForwardPipeline> pipeline =
std::make_unique<BuiltinForwardPipeline>();
ConfigureBuiltinForwardPipeline(*pipeline);
return pipeline;
}
} // namespace Internal

View File

@@ -1,14 +1,19 @@
#pragma once
#include <memory>
namespace XCEngine {
namespace Rendering {
class SceneRenderFeatureHost;
namespace Pipelines {
class BuiltinForwardPipeline;
namespace Internal {
void RegisterBuiltinForwardSceneFeatures(SceneRenderFeatureHost& featureHost);
void ConfigureBuiltinForwardPipeline(
BuiltinForwardPipeline& pipeline);
std::unique_ptr<BuiltinForwardPipeline>
CreateConfiguredBuiltinForwardPipeline();
} // namespace Internal
} // namespace Pipelines

View File

@@ -112,12 +112,6 @@ void ManagedScriptableRenderPipelineAsset::ConfigureCameraFramePlan(
if (const std::shared_ptr<const ManagedRenderPipelineAssetRuntime> runtime =
ResolveManagedAssetRuntime();
runtime != nullptr) {
if (runtime->UsesNativeCameraFramePlanBaseline(
plan.request.rendererIndex)) {
ApplyDefaultRenderPipelineAssetCameraFramePlanBaselinePolicy(
plan,
GetDefaultFinalColorSettings());
}
runtime->ConfigureCameraFramePlan(plan);
return;
}

View File

@@ -374,9 +374,10 @@ bool NativeSceneRecorder::RecordInjectionPoint(
}
bool NativeSceneRecorder::RecordFeaturePass(
const Containers::String& featurePassName) {
NativeSceneFeaturePassId featurePassId) {
if (m_context.stage != CameraFrameStage::MainScene ||
featurePassName.Empty()) {
featurePassId ==
NativeSceneFeaturePassId::Invalid) {
return false;
}
@@ -400,7 +401,7 @@ bool NativeSceneRecorder::RecordFeaturePass(
m_clearAttachments,
beginRecordedPass,
endRecordedPass),
featurePassName,
featurePassId,
&recordedPass)) {
return false;
}

View File

@@ -3,10 +3,8 @@
#include "Rendering/Execution/DirectionalShadowExecutionState.h"
#include "Rendering/Internal/RenderPipelineFactory.h"
#include "Rendering/Pipelines/BuiltinForwardPipeline.h"
#include "Rendering/Pipelines/Internal/BuiltinForwardSceneSetup.h"
#include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h"
#include "Rendering/Passes/BuiltinDepthOnlyPass.h"
#include "Rendering/Passes/BuiltinObjectIdPass.h"
#include "Rendering/Passes/BuiltinShadowCasterPass.h"
namespace XCEngine {
namespace Rendering {
@@ -30,7 +28,7 @@ std::unique_ptr<RenderPipelineBackend> CreatePipelineBackendFromAsset(
}
}
return std::make_unique<BuiltinForwardPipeline>();
return Internal::CreateConfiguredBuiltinForwardPipeline();
}
} // namespace
@@ -214,7 +212,15 @@ RenderPass* ScriptableRenderPipelineHost::GetCameraFrameStandalonePass(
return nullptr;
}
return RenderPipeline::GetCameraFrameStandalonePass(stage);
if (RenderPass* const hostPass =
RenderPipeline::GetCameraFrameStandalonePass(stage);
hostPass != nullptr) {
return hostPass;
}
return ResolvePipelineBackendStandalonePass(
stage,
rendererIndex);
}
bool ScriptableRenderPipelineHost::EnsureInitialized(const RenderContext& context) {
@@ -260,6 +266,21 @@ bool ScriptableRenderPipelineHost::EnsureInitialized(const RenderContext& contex
return true;
}
RenderPass* ScriptableRenderPipelineHost::ResolvePipelineBackendStandalonePass(
CameraFrameStage stage,
int32_t rendererIndex) const {
const auto* const backendPipeline =
dynamic_cast<const RenderPipeline*>(m_pipelineBackend.get());
if (backendPipeline == nullptr ||
backendPipeline == this) {
return nullptr;
}
return backendPipeline->GetCameraFrameStandalonePass(
stage,
rendererIndex);
}
void ScriptableRenderPipelineHost::BindStageRecorderPipelineBackend() {
if (m_stageRecorder != nullptr) {
m_stageRecorder->SetPipelineBackend(m_pipelineBackend.get());
@@ -352,28 +373,9 @@ ScriptableRenderPipelineHostAsset::ScriptableRenderPipelineHostAsset(
}
std::unique_ptr<RenderPipeline> ScriptableRenderPipelineHostAsset::CreatePipeline() const {
std::unique_ptr<RenderPipeline> pipeline =
std::make_unique<ScriptableRenderPipelineHost>(
m_pipelineBackendAsset,
m_managedAssetRuntime);
if (pipeline != nullptr) {
ConfigurePipeline(*pipeline);
}
return pipeline;
}
void ScriptableRenderPipelineHostAsset::ConfigurePipeline(
RenderPipeline& pipeline) const {
pipeline.SetCameraFrameStandalonePass(
CameraFrameStage::ObjectId,
std::make_unique<Passes::BuiltinObjectIdPass>());
pipeline.SetCameraFrameStandalonePass(
CameraFrameStage::DepthOnly,
std::make_unique<Passes::BuiltinDepthOnlyPass>());
pipeline.SetCameraFrameStandalonePass(
CameraFrameStage::ShadowCaster,
std::make_unique<Passes::BuiltinShadowCasterPass>());
return std::make_unique<ScriptableRenderPipelineHost>(
m_pipelineBackendAsset,
m_managedAssetRuntime);
}
FinalColorSettings ScriptableRenderPipelineHostAsset::GetDefaultFinalColorSettings() const {

View File

@@ -3,6 +3,7 @@
#include "Rendering/Execution/Internal/CameraFrameGraph/SurfaceUtils.h"
#include "Rendering/FrameData/RenderSceneData.h"
#include "Rendering/Graph/RenderGraph.h"
#include "RHI/RHIResourceView.h"
#include <algorithm>
#include <memory>
@@ -146,13 +147,65 @@ bool ResolveGraphManagedOutputSurface(
return true;
}
bool ResolveGraphManagedTextureBindingViews(
const std::vector<RenderPassGraphTextureBindingRequest>&
textureBindingRequests,
RenderGraphTextureHandle sourceColorTexture,
RHI::RHIResourceView* sourceColorView,
const RenderGraphExecutionContext& graphContext,
std::vector<RenderPassContext::TextureBindingView>&
outTextureBindings) {
outTextureBindings.clear();
outTextureBindings.reserve(textureBindingRequests.size());
for (const RenderPassGraphTextureBindingRequest& bindingRequest :
textureBindingRequests) {
if (bindingRequest.resourceName.Empty() ||
!bindingRequest.texture.IsValid()) {
return false;
}
RHI::RHIResourceView* resolvedView = nullptr;
if (sourceColorTexture.IsValid() &&
bindingRequest.texture.index ==
sourceColorTexture.index) {
resolvedView = sourceColorView;
} else {
resolvedView =
graphContext.ResolveTextureView(
bindingRequest.texture,
RenderGraphTextureViewType::
ShaderResource);
}
if (resolvedView == nullptr ||
resolvedView->GetViewType() !=
RHI::ResourceViewType::ShaderResource) {
return false;
}
RenderPassContext::TextureBindingView
resolvedBinding = {};
resolvedBinding.resourceName =
bindingRequest.resourceName;
resolvedBinding.resourceView = resolvedView;
outTextureBindings.push_back(
std::move(resolvedBinding));
}
return true;
}
} // namespace
bool RecordCallbackRasterRenderPass(
const RenderPassRenderGraphContext& context,
const RenderPassGraphIO& io,
RenderPassGraphExecutePassCallback executePassCallback,
std::vector<RenderGraphTextureHandle> additionalReadTextures) {
std::vector<RenderGraphTextureHandle> additionalReadTextures,
std::vector<RenderGraphTextureHandle> additionalReadDepthTextures,
std::vector<RenderPassGraphTextureBindingRequest>
textureBindingRequests) {
if (!executePassCallback) {
return false;
}
@@ -191,6 +244,8 @@ bool RecordCallbackRasterRenderPass(
endPassCallback,
executePassCallback,
additionalReadTextures,
additionalReadDepthTextures,
textureBindingRequests,
io](
RenderGraphPassBuilder& passBuilder) {
if (io.readSourceColor && sourceColorTexture.IsValid()) {
@@ -203,6 +258,13 @@ bool RecordCallbackRasterRenderPass(
}
}
for (RenderGraphTextureHandle readDepthTexture :
additionalReadDepthTextures) {
if (readDepthTexture.IsValid()) {
passBuilder.ReadDepthTexture(readDepthTexture);
}
}
if (io.writeColor) {
for (RenderGraphTextureHandle colorTarget : colorTargets) {
if (colorTarget.IsValid()) {
@@ -230,6 +292,7 @@ bool RecordCallbackRasterRenderPass(
beginPassCallback,
endPassCallback,
executePassCallback,
textureBindingRequests,
io](
const RenderGraphExecutionContext& executionContext) {
if (executionSucceeded != nullptr && !(*executionSucceeded)) {
@@ -274,13 +337,28 @@ bool RecordCallbackRasterRenderPass(
return;
}
std::vector<RenderPassContext::TextureBindingView>
resolvedTextureBindings = {};
if (!ResolveGraphManagedTextureBindingViews(
textureBindingRequests,
sourceColorTexture,
resolvedSourceColorView,
executionContext,
resolvedTextureBindings)) {
if (executionSucceeded != nullptr) {
*executionSucceeded = false;
}
return;
}
const RenderPassContext passContext = {
renderContext,
*resolvedSurface,
*sceneData,
resolvedSourceSurface,
resolvedSourceColorView,
resolvedSourceColorState
resolvedSourceColorState,
std::move(resolvedTextureBindings)
};
if (beginPassCallback &&
!beginPassCallback(passContext)) {

View File

@@ -48,12 +48,13 @@ Containers::String BuildNamedFeatureGraphPassName(
return Containers::String(name.c_str());
}
bool MatchesFeaturePassName(
bool MatchesFeaturePassId(
const SceneRenderFeaturePass& featurePass,
const Containers::String& featurePassName) {
const char* const passName = featurePass.GetName();
return passName != nullptr &&
featurePassName == Containers::String(passName);
NativeSceneFeaturePassId featurePassId) {
return featurePassId !=
NativeSceneFeaturePassId::Invalid &&
featurePass.GetNativeSceneFeaturePassId() ==
featurePassId;
}
} // namespace
@@ -180,13 +181,14 @@ bool SceneRenderFeatureHost::Record(
bool SceneRenderFeatureHost::RecordFeaturePass(
const SceneRenderFeaturePassRenderGraphContext& context,
const Containers::String& featurePassName,
NativeSceneFeaturePassId featurePassId,
bool* recordedPass) const {
if (recordedPass != nullptr) {
*recordedPass = false;
}
if (featurePassName.Empty()) {
if (featurePassId ==
NativeSceneFeaturePassId::Invalid) {
return false;
}
@@ -196,7 +198,9 @@ bool SceneRenderFeatureHost::RecordFeaturePass(
m_featurePasses[featureIndex];
SceneRenderFeaturePass* const featurePass = featurePassOwner.get();
if (featurePass == nullptr ||
!MatchesFeaturePassName(*featurePass, featurePassName)) {
!MatchesFeaturePassId(
*featurePass,
featurePassId)) {
continue;
}
@@ -217,7 +221,7 @@ bool SceneRenderFeatureHost::RecordFeaturePass(
Debug::LogCategory::Rendering,
(Containers::String(
"SceneRenderFeatureHost record failed for feature pass '") +
featurePassName +
featurePass->GetName() +
"': " +
featurePass->GetName())
.CStr());
@@ -233,8 +237,12 @@ bool SceneRenderFeatureHost::RecordFeaturePass(
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
(Containers::String(
"SceneRenderFeatureHost could not resolve feature pass: ") +
featurePassName)
"SceneRenderFeatureHost could not resolve feature pass id: ") +
Containers::String(
std::to_string(
static_cast<uint32_t>(
featurePassId))
.c_str()))
.CStr());
return false;
}

View File

@@ -118,7 +118,11 @@ struct ManagedScriptableRenderContextState {
Rendering::FullscreenPassDesc passDesc = {};
Rendering::RenderGraphTextureHandle sourceColorTexture = {};
std::vector<Rendering::RenderGraphTextureHandle> readTextures = {};
std::vector<Rendering::RenderGraphTextureHandle> readDepthTextures = {};
std::vector<Rendering::RenderPassGraphTextureBindingRequest>
textureBindings = {};
std::vector<Rendering::RenderGraphTextureHandle> colorTargets = {};
Rendering::RenderGraphTextureHandle depthTarget = {};
};
uint64_t nextPendingRasterPassHandle = 1u;
std::unordered_map<uint64_t, RasterPassRecordRequest>
@@ -420,6 +424,10 @@ bool RecordManagedFullscreenRasterPass(
Rendering::RenderGraphTextureHandle sourceColorTexture,
std::vector<Rendering::RenderGraphTextureHandle> colorTargets,
std::vector<Rendering::RenderGraphTextureHandle> additionalReadTextures,
std::vector<Rendering::RenderGraphTextureHandle> additionalReadDepthTextures,
std::vector<Rendering::RenderPassGraphTextureBindingRequest>
textureBindings,
Rendering::RenderGraphTextureHandle depthTarget,
const Containers::String& passName) {
if (!Rendering::IsCameraFrameFullscreenSequenceStage(stageContext.stage) ||
!sourceColorTexture.IsValid() ||
@@ -442,7 +450,7 @@ bool RecordManagedFullscreenRasterPass(
params.overrideColorTargets = true;
params.colorTargets = std::move(colorTargets);
params.overrideDepthTarget = true;
params.depthTarget = {};
params.depthTarget = depthTarget;
const Rendering::RenderGraphRecordingContext recordingContext =
Rendering::BuildRenderGraphRecordingContext(
@@ -451,14 +459,19 @@ bool RecordManagedFullscreenRasterPass(
const Rendering::RenderPassRenderGraphContext renderGraphContext =
Rendering::BuildRenderPassRenderGraphContext(recordingContext);
Rendering::RenderPass* const passPtr = &pass;
Rendering::RenderPassGraphIO io =
Rendering::BuildSourceColorFullscreenRasterPassGraphIO();
io.writeDepth = depthTarget.IsValid();
return Rendering::RecordCallbackRasterRenderPass(
renderGraphContext,
Rendering::BuildSourceColorFullscreenRasterPassGraphIO(),
io,
[passPtr](const Rendering::RenderPassContext& passContext) {
return passPtr != nullptr &&
passPtr->Execute(passContext);
},
std::move(additionalReadTextures));
std::move(additionalReadTextures),
std::move(additionalReadDepthTextures),
std::move(textureBindings));
}
bool RecordManagedFullscreenPassToTexture(
@@ -473,6 +486,9 @@ bool RecordManagedFullscreenPassToTexture(
sourceColorTexture,
{ outputColorTexture },
{},
{},
{},
{},
passName);
}
@@ -1042,6 +1058,26 @@ static_assert(
sizeof(Rendering::FinalColorSettings),
"Managed final color bridge layout must match native FinalColorSettings.");
struct ManagedFinalColorOverrideSettingsData {
uint8_t overrideOutputTransferMode = 0u;
uint8_t outputTransferMode = 0u;
uint8_t overrideExposureMode = 0u;
uint8_t exposureMode = 0u;
uint8_t overrideExposureValue = 0u;
uint8_t exposureValuePadding[3] = {};
float exposureValue = 1.0f;
uint8_t overrideToneMappingMode = 0u;
uint8_t toneMappingMode = 0u;
uint8_t overrideFinalColorScale = 0u;
uint8_t finalColorScalePadding = 0u;
XCEngine::Math::Vector4 finalColorScale = XCEngine::Math::Vector4::One();
};
static_assert(
sizeof(ManagedFinalColorOverrideSettingsData) ==
sizeof(Rendering::FinalColorOverrideSettings),
"Managed final color override bridge layout must match native FinalColorOverrideSettings.");
struct ManagedRenderGraphTextureDescData {
uint32_t width = 0u;
uint32_t height = 0u;
@@ -1377,6 +1413,42 @@ Rendering::FinalColorSettings BuildManagedFinalColorSettings(
return settings;
}
ManagedFinalColorOverrideSettingsData BuildManagedFinalColorOverrideSettings(
const Rendering::FinalColorOverrideSettings& nativeSettings) {
ManagedFinalColorOverrideSettingsData managedSettings = {};
managedSettings.overrideOutputTransferMode =
nativeSettings.overrideOutputTransferMode
? 1u
: 0u;
managedSettings.outputTransferMode =
static_cast<uint8_t>(nativeSettings.outputTransferMode);
managedSettings.overrideExposureMode =
nativeSettings.overrideExposureMode
? 1u
: 0u;
managedSettings.exposureMode =
static_cast<uint8_t>(nativeSettings.exposureMode);
managedSettings.overrideExposureValue =
nativeSettings.overrideExposureValue
? 1u
: 0u;
managedSettings.exposureValue =
nativeSettings.exposureValue;
managedSettings.overrideToneMappingMode =
nativeSettings.overrideToneMappingMode
? 1u
: 0u;
managedSettings.toneMappingMode =
static_cast<uint8_t>(nativeSettings.toneMappingMode);
managedSettings.overrideFinalColorScale =
nativeSettings.overrideFinalColorScale
? 1u
: 0u;
managedSettings.finalColorScale =
nativeSettings.finalColorScale;
return managedSettings;
}
bool SupportsManagedRenderPipelineStageGraphRecording(
Rendering::CameraFrameStage stage) {
return Rendering::SupportsCameraFramePipelineGraphRecording(stage) ||
@@ -1499,9 +1571,6 @@ public:
Rendering::FinalColorSettings& settings) const override;
std::shared_ptr<const Rendering::RenderPipelineAsset>
GetSharedPipelineBackendAsset() const override;
bool UsesNativeCameraFramePlanBaseline() const override;
bool UsesNativeCameraFramePlanBaseline(
int32_t rendererIndex) const override;
MonoScriptRuntime* GetRuntime() const {
return m_runtime;
@@ -1532,10 +1601,6 @@ private:
MonoObject* assetObject) const;
MonoMethod* ResolveGetRuntimeResourceVersionMethod(
MonoObject* assetObject) const;
MonoMethod* ResolveUsesNativeCameraFramePlanBaselineMethod(
MonoObject* assetObject) const;
MonoMethod* ResolveUsesNativeCameraFramePlanBaselineContextualMethod(
MonoObject* assetObject) const;
MonoMethod* ResolveConfigureRenderSceneSetupMethod(
MonoObject* assetObject) const;
MonoMethod* ResolveConfigureDirectionalShadowExecutionStateMethod(
@@ -1553,11 +1618,6 @@ private:
mutable MonoMethod* m_configureCameraFramePlanMethod = nullptr;
mutable MonoMethod* m_getDefaultFinalColorSettingsMethod = nullptr;
mutable MonoMethod* m_getRuntimeResourceVersionMethod = nullptr;
mutable MonoMethod* m_usesNativeCameraFramePlanBaselineMethod =
nullptr;
mutable MonoMethod*
m_usesNativeCameraFramePlanBaselineContextualMethod =
nullptr;
mutable MonoMethod* m_configureRenderSceneSetupMethod =
nullptr;
mutable MonoMethod*
@@ -1890,6 +1950,9 @@ private:
resolvedSourceColor,
resolvedColorTargets,
request.readTextures,
request.readDepthTextures,
request.textureBindings,
request.depthTarget,
resolvedPassName)) {
return false;
}
@@ -2203,66 +2266,6 @@ MonoManagedRenderPipelineAssetRuntime::GetSharedPipelineBackendAsset() const {
return m_sharedPipelineBackendAsset;
}
bool MonoManagedRenderPipelineAssetRuntime::UsesNativeCameraFramePlanBaseline()
const {
return UsesNativeCameraFramePlanBaseline(-1);
}
bool MonoManagedRenderPipelineAssetRuntime::UsesNativeCameraFramePlanBaseline(
int32_t rendererIndex) const {
if (!SyncManagedAssetRuntimeState()) {
return false;
}
MonoObject* const assetObject = GetManagedAssetObject();
if (assetObject == nullptr) {
return false;
}
MonoMethod* const contextualMethod =
ResolveUsesNativeCameraFramePlanBaselineContextualMethod(
assetObject);
if (contextualMethod != nullptr) {
void* args[1] = { &rendererIndex };
MonoObject* managedValueObject = nullptr;
if (!m_runtime->InvokeManagedMethod(
assetObject,
contextualMethod,
args,
&managedValueObject)) {
return false;
}
bool usesBaseline = false;
return TryUnboxManagedBoolean(
managedValueObject,
usesBaseline) &&
usesBaseline;
}
MonoMethod* const method =
ResolveUsesNativeCameraFramePlanBaselineMethod(
assetObject);
if (method == nullptr) {
return false;
}
MonoObject* managedValueObject = nullptr;
if (!m_runtime->InvokeManagedMethod(
assetObject,
method,
nullptr,
&managedValueObject)) {
return false;
}
bool usesBaseline = false;
return TryUnboxManagedBoolean(
managedValueObject,
usesBaseline) &&
usesBaseline;
}
bool MonoManagedRenderPipelineAssetRuntime::AcquireManagedPipelineHandle(
uint32_t& outPipelineHandle) const {
if (!SyncManagedAssetRuntimeState()) {
@@ -2467,8 +2470,6 @@ void MonoManagedRenderPipelineAssetRuntime::ReleaseManagedAsset() const {
m_configureCameraFramePlanMethod = nullptr;
m_getDefaultFinalColorSettingsMethod = nullptr;
m_getRuntimeResourceVersionMethod = nullptr;
m_usesNativeCameraFramePlanBaselineMethod = nullptr;
m_usesNativeCameraFramePlanBaselineContextualMethod = nullptr;
m_configureRenderSceneSetupMethod = nullptr;
m_configureDirectionalShadowExecutionStateMethod = nullptr;
m_sharedPipelineBackendAsset.reset();
@@ -2590,37 +2591,6 @@ MonoManagedRenderPipelineAssetRuntime::ResolveGetRuntimeResourceVersionMethod(
return m_getRuntimeResourceVersionMethod;
}
MonoMethod*
MonoManagedRenderPipelineAssetRuntime::
ResolveUsesNativeCameraFramePlanBaselineMethod(
MonoObject* assetObject) const {
if (m_usesNativeCameraFramePlanBaselineMethod == nullptr) {
m_usesNativeCameraFramePlanBaselineMethod =
m_runtime->ResolveManagedMethod(
assetObject,
"UsesNativeCameraFramePlanBaseline",
0);
}
return m_usesNativeCameraFramePlanBaselineMethod;
}
MonoMethod*
MonoManagedRenderPipelineAssetRuntime::
ResolveUsesNativeCameraFramePlanBaselineContextualMethod(
MonoObject* assetObject) const {
if (m_usesNativeCameraFramePlanBaselineContextualMethod ==
nullptr) {
m_usesNativeCameraFramePlanBaselineContextualMethod =
m_runtime->ResolveManagedMethod(
assetObject,
"UsesNativeCameraFramePlanBaselineContextual",
1);
}
return m_usesNativeCameraFramePlanBaselineContextualMethod;
}
MonoMethod*
MonoManagedRenderPipelineAssetRuntime::
ResolveConfigureRenderSceneSetupMethod(
@@ -4010,6 +3980,124 @@ void InternalCall_Camera_SetPrimary(uint64_t gameObjectUUID, mono_bool value) {
component->SetPrimary(value != 0);
}
int32_t InternalCall_Camera_GetClearMode(uint64_t gameObjectUUID) {
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
return component != nullptr
? static_cast<int32_t>(component->GetClearMode())
: 0;
}
void InternalCall_Camera_SetClearMode(uint64_t gameObjectUUID, int32_t value) {
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
if (!component) {
return;
}
component->SetClearMode(
static_cast<Components::CameraClearMode>(value));
}
int32_t InternalCall_Camera_GetStackType(uint64_t gameObjectUUID) {
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
return component != nullptr
? static_cast<int32_t>(component->GetStackType())
: 0;
}
void InternalCall_Camera_SetStackType(uint64_t gameObjectUUID, int32_t value) {
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
if (!component) {
return;
}
component->SetStackType(
static_cast<Components::CameraStackType>(value));
}
int32_t InternalCall_Camera_GetProjectionType(uint64_t gameObjectUUID) {
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
return component != nullptr
? static_cast<int32_t>(component->GetProjectionType())
: 0;
}
mono_bool InternalCall_Camera_GetSkyboxEnabled(uint64_t gameObjectUUID) {
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
return (component && component->IsSkyboxEnabled()) ? 1 : 0;
}
mono_bool InternalCall_Camera_GetHasSkyboxMaterial(uint64_t gameObjectUUID) {
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
return (component && component->GetSkyboxMaterial() != nullptr) ? 1 : 0;
}
mono_bool InternalCall_Camera_GetHasFinalColorOverrides(
uint64_t gameObjectUUID) {
Components::CameraComponent* component =
FindCameraComponent(gameObjectUUID);
return (component &&
component->GetFinalColorOverrides().HasOverrides())
? 1
: 0;
}
void InternalCall_Camera_GetFinalColorOverrideSettings(
uint64_t gameObjectUUID,
ManagedFinalColorOverrideSettingsData* outSettings) {
if (outSettings == nullptr) {
return;
}
Components::CameraComponent* component =
FindCameraComponent(gameObjectUUID);
const Rendering::FinalColorOverrideSettings sourceSettings =
component != nullptr
? component->GetFinalColorOverrides()
: Rendering::FinalColorOverrideSettings{};
*outSettings =
BuildManagedFinalColorOverrideSettings(
sourceSettings);
}
void InternalCall_Camera_GetSkyboxTopColor(
uint64_t gameObjectUUID,
XCEngine::Math::Color* outColor) {
if (outColor == nullptr) {
return;
}
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
*outColor = component != nullptr
? component->GetSkyboxTopColor()
: XCEngine::Math::Color();
}
void InternalCall_Camera_GetSkyboxHorizonColor(
uint64_t gameObjectUUID,
XCEngine::Math::Color* outColor) {
if (outColor == nullptr) {
return;
}
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
*outColor = component != nullptr
? component->GetSkyboxHorizonColor()
: XCEngine::Math::Color();
}
void InternalCall_Camera_GetSkyboxBottomColor(
uint64_t gameObjectUUID,
XCEngine::Math::Color* outColor) {
if (outColor == nullptr) {
return;
}
Components::CameraComponent* component = FindCameraComponent(gameObjectUUID);
*outColor = component != nullptr
? component->GetSkyboxBottomColor()
: XCEngine::Math::Color();
}
float InternalCall_Light_GetIntensity(uint64_t gameObjectUUID) {
Components::LightComponent* component = FindLightComponent(gameObjectUUID);
return component ? component->GetIntensity() : 0.0f;
@@ -4622,6 +4710,94 @@ InternalCall_Rendering_ScriptableRenderContext_AddRasterPassReadTexture(
return 1;
}
mono_bool
InternalCall_Rendering_ScriptableRenderContext_AddRasterPassReadDepthTexture(
uint64_t nativeHandle,
uint64_t rasterPassHandle,
int32_t textureHandle) {
ManagedScriptableRenderContextState* const state =
FindManagedScriptableRenderContextState(nativeHandle);
ManagedScriptableRenderContextState::RasterPassRecordRequest*
const request =
FindPendingManagedRasterPassRecordRequest(
state,
rasterPassHandle);
if (request == nullptr) {
return 0;
}
const Rendering::RenderGraphTextureHandle readDepthTexture =
DecodeManagedRenderGraphTextureHandle(
textureHandle);
if (!readDepthTexture.IsValid()) {
return 0;
}
request->readDepthTextures.push_back(readDepthTexture);
return 1;
}
mono_bool
InternalCall_Rendering_ScriptableRenderContext_AddRasterPassTextureBinding(
uint64_t nativeHandle,
uint64_t rasterPassHandle,
MonoString* shaderResourceName,
int32_t textureHandle,
mono_bool isDepth) {
ManagedScriptableRenderContextState* const state =
FindManagedScriptableRenderContextState(nativeHandle);
ManagedScriptableRenderContextState::RasterPassRecordRequest*
const request =
FindPendingManagedRasterPassRecordRequest(
state,
rasterPassHandle);
if (request == nullptr) {
return 0;
}
const Containers::String shaderResourceNameString(
MonoStringToUtf8(shaderResourceName).c_str());
if (shaderResourceNameString.Empty()) {
return 0;
}
const Rendering::RenderGraphTextureHandle texture =
DecodeManagedRenderGraphTextureHandle(
textureHandle);
if (!texture.IsValid()) {
return 0;
}
Rendering::RenderPassGraphTextureBindingRequest
bindingRequest = {};
bindingRequest.resourceName =
shaderResourceNameString;
bindingRequest.texture = texture;
bindingRequest.aspect =
isDepth != 0
? Rendering::RenderGraphTextureAspect::Depth
: Rendering::RenderGraphTextureAspect::Color;
auto existingBinding =
std::find_if(
request->textureBindings.begin(),
request->textureBindings.end(),
[&shaderResourceNameString](
const Rendering::RenderPassGraphTextureBindingRequest&
existingRequest) {
return existingRequest.resourceName ==
shaderResourceNameString;
});
if (existingBinding != request->textureBindings.end()) {
*existingBinding = std::move(bindingRequest);
} else {
request->textureBindings.push_back(
std::move(bindingRequest));
}
return 1;
}
mono_bool
InternalCall_Rendering_ScriptableRenderContext_SetRasterPassColorAttachment(
uint64_t nativeHandle,
@@ -4658,6 +4834,33 @@ InternalCall_Rendering_ScriptableRenderContext_SetRasterPassColorAttachment(
return 1;
}
mono_bool
InternalCall_Rendering_ScriptableRenderContext_SetRasterPassDepthAttachment(
uint64_t nativeHandle,
uint64_t rasterPassHandle,
int32_t textureHandle) {
ManagedScriptableRenderContextState* const state =
FindManagedScriptableRenderContextState(nativeHandle);
ManagedScriptableRenderContextState::RasterPassRecordRequest*
const request =
FindPendingManagedRasterPassRecordRequest(
state,
rasterPassHandle);
if (request == nullptr) {
return 0;
}
const Rendering::RenderGraphTextureHandle depthAttachment =
DecodeManagedRenderGraphTextureHandle(
textureHandle);
if (!depthAttachment.IsValid()) {
return 0;
}
request->depthTarget = depthAttachment;
return 1;
}
mono_bool
InternalCall_Rendering_ScriptableRenderContext_SetRasterPassColorScaleFullscreenExecution(
uint64_t nativeHandle,
@@ -5321,7 +5524,7 @@ InternalCall_Rendering_ScriptableRenderContext_RecordSceneInjectionPoint(
mono_bool
InternalCall_Rendering_ScriptableRenderContext_RecordNativeSceneFeaturePass(
uint64_t nativeHandle,
MonoString* featurePassName) {
int32_t featurePassId) {
ManagedScriptableRenderContextState* const state =
FindManagedScriptableRenderContextState(nativeHandle);
if (state == nullptr ||
@@ -5331,14 +5534,17 @@ InternalCall_Rendering_ScriptableRenderContext_RecordNativeSceneFeaturePass(
return 0;
}
const std::string featurePassNameUtf8 =
MonoStringToUtf8(featurePassName);
if (featurePassNameUtf8.empty()) {
const Rendering::NativeSceneFeaturePassId
resolvedFeaturePassId =
static_cast<Rendering::NativeSceneFeaturePassId>(
featurePassId);
if (resolvedFeaturePassId ==
Rendering::NativeSceneFeaturePassId::Invalid) {
return 0;
}
return state->sceneRecorder->RecordFeaturePass(
Containers::String(featurePassNameUtf8.c_str()))
resolvedFeaturePassId)
? 1
: 0;
}
@@ -5519,6 +5725,74 @@ void InternalCall_Rendering_CameraRenderRequestContext_ClearDirectionalShadow(
state->suppressDirectionalShadow = true;
}
int32_t InternalCall_Rendering_CameraRenderRequestContext_GetClearFlags(
uint64_t nativeHandle) {
const ManagedCameraRenderRequestContextState* const state =
FindManagedCameraRenderRequestContextState(nativeHandle);
return state != nullptr &&
state->request != nullptr
? static_cast<int32_t>(state->request->clearFlags)
: static_cast<int32_t>(Rendering::RenderClearFlags::All);
}
void InternalCall_Rendering_CameraRenderRequestContext_SetClearFlags(
uint64_t nativeHandle,
int32_t clearFlags) {
ManagedCameraRenderRequestContextState* const state =
FindManagedCameraRenderRequestContextState(nativeHandle);
if (state == nullptr || state->request == nullptr) {
return;
}
state->request->clearFlags =
static_cast<Rendering::RenderClearFlags>(clearFlags);
}
void InternalCall_Rendering_CameraRenderRequestContext_SetResolvedFinalColorPolicy(
uint64_t nativeHandle,
ManagedFinalColorSettingsData* settings,
mono_bool hasPipelineDefaults,
mono_bool hasCameraOverrides) {
ManagedCameraRenderRequestContextState* const state =
FindManagedCameraRenderRequestContextState(nativeHandle);
if (state == nullptr ||
state->request == nullptr ||
settings == nullptr) {
return;
}
const Rendering::FinalColorSettings resolvedSettings =
BuildManagedFinalColorSettings(*settings);
Rendering::ResolvedFinalColorPolicy resolvedPolicy = {};
resolvedPolicy.outputTransferMode =
resolvedSettings.outputTransferMode;
resolvedPolicy.exposureMode =
resolvedSettings.exposureMode;
resolvedPolicy.exposureValue =
resolvedSettings.exposureValue;
resolvedPolicy.toneMappingMode =
resolvedSettings.toneMappingMode;
resolvedPolicy.finalColorScale =
resolvedSettings.finalColorScale;
resolvedPolicy.hasPipelineDefaults =
hasPipelineDefaults != 0;
resolvedPolicy.hasCameraOverrides =
hasCameraOverrides != 0;
state->request->finalColorPolicy =
resolvedPolicy;
}
void InternalCall_Rendering_CameraRenderRequestContext_ClearFinalColorPolicy(
uint64_t nativeHandle) {
ManagedCameraRenderRequestContextState* const state =
FindManagedCameraRenderRequestContextState(nativeHandle);
if (state == nullptr || state->request == nullptr) {
return;
}
state->request->finalColorPolicy = {};
}
int32_t
InternalCall_Rendering_RenderSceneSetupContext_GetRendererIndex(
uint64_t nativeHandle) {
@@ -5530,6 +5804,21 @@ InternalCall_Rendering_RenderSceneSetupContext_GetRendererIndex(
: -1;
}
uint64_t
InternalCall_Rendering_RenderSceneSetupContext_GetCameraGameObjectUUID(
uint64_t nativeHandle) {
const ManagedRenderSceneSetupContextState* const state =
FindManagedRenderSceneSetupContextState(nativeHandle);
if (state == nullptr ||
state->plan == nullptr ||
state->plan->request.camera == nullptr ||
state->plan->request.camera->GetGameObject() == nullptr) {
return 0u;
}
return state->plan->request.camera->GetGameObject()->GetUUID();
}
mono_bool
InternalCall_Rendering_RenderSceneSetupContext_GetIsConfigured(
uint64_t nativeHandle) {
@@ -5541,60 +5830,41 @@ InternalCall_Rendering_RenderSceneSetupContext_GetIsConfigured(
: 0;
}
mono_bool
InternalCall_Rendering_RenderSceneSetupContext_UseDefaultSceneSetup(
int32_t InternalCall_Rendering_RenderSceneSetupContext_GetClearFlags(
uint64_t nativeHandle) {
ManagedRenderSceneSetupContextState* const state =
const ManagedRenderSceneSetupContextState* const state =
FindManagedRenderSceneSetupContextState(nativeHandle);
if (state == nullptr ||
state->plan == nullptr ||
state->sceneData == nullptr) {
return 0;
}
Rendering::ApplyDefaultRenderPipelineSceneSetupPolicy(
*state->plan,
*state->sceneData);
state->explicitlyConfigured = true;
return 1;
return state != nullptr &&
state->plan != nullptr
? static_cast<int32_t>(state->plan->request.clearFlags)
: 0;
}
mono_bool
InternalCall_Rendering_RenderSceneSetupContext_UseDefaultEnvironment(
InternalCall_Rendering_RenderSceneSetupContext_GetHasMainSceneDepthAttachment(
uint64_t nativeHandle) {
ManagedRenderSceneSetupContextState* const state =
const ManagedRenderSceneSetupContextState* const state =
FindManagedRenderSceneSetupContextState(nativeHandle);
if (state == nullptr ||
state->plan == nullptr ||
state->sceneData == nullptr) {
return 0;
}
state->sceneData->environment =
Rendering::BuildDefaultRenderPipelineEnvironmentData(
*state->plan);
state->explicitlyConfigured = true;
return 1;
return state != nullptr &&
state->plan != nullptr &&
state->plan->GetMainSceneSurface().GetDepthAttachment() != nullptr
? 1
: 0;
}
mono_bool
InternalCall_Rendering_RenderSceneSetupContext_UseDefaultGlobalShaderKeywords(
InternalCall_Rendering_RenderSceneSetupContext_GetHasMainDirectionalShadow(
uint64_t nativeHandle) {
ManagedRenderSceneSetupContextState* const state =
const ManagedRenderSceneSetupContextState* const state =
FindManagedRenderSceneSetupContextState(nativeHandle);
if (state == nullptr || state->sceneData == nullptr) {
return 0;
}
state->sceneData->globalShaderKeywords =
Rendering::
BuildDefaultRenderPipelineSceneGlobalShaderKeywords(
*state->sceneData);
state->explicitlyConfigured = true;
return 1;
return state != nullptr &&
state->sceneData != nullptr &&
state->sceneData->lighting.HasMainDirectionalShadow()
? 1
: 0;
}
void InternalCall_Rendering_RenderSceneSetupContext_ClearEnvironment(
void InternalCall_Rendering_RenderSceneSetupContext_SetEnvironmentNone(
uint64_t nativeHandle) {
ManagedRenderSceneSetupContextState* const state =
FindManagedRenderSceneSetupContextState(nativeHandle);
@@ -5606,6 +5876,56 @@ void InternalCall_Rendering_RenderSceneSetupContext_ClearEnvironment(
state->explicitlyConfigured = true;
}
mono_bool
InternalCall_Rendering_RenderSceneSetupContext_UseCameraSkyboxMaterial(
uint64_t nativeHandle) {
ManagedRenderSceneSetupContextState* const state =
FindManagedRenderSceneSetupContextState(nativeHandle);
if (state == nullptr ||
state->plan == nullptr ||
state->sceneData == nullptr ||
state->plan->request.camera == nullptr) {
return 0;
}
const Resources::Material* skyboxMaterial =
state->plan->request.camera->GetSkyboxMaterial();
if (skyboxMaterial == nullptr) {
return 0;
}
state->sceneData->environment = {};
state->sceneData->environment.mode =
Rendering::RenderEnvironmentMode::MaterialSkybox;
state->sceneData->environment.materialSkybox.material =
skyboxMaterial;
state->explicitlyConfigured = true;
return 1;
}
void InternalCall_Rendering_RenderSceneSetupContext_SetProceduralSkybox(
uint64_t nativeHandle,
XCEngine::Math::Color* topColor,
XCEngine::Math::Color* horizonColor,
XCEngine::Math::Color* bottomColor) {
ManagedRenderSceneSetupContextState* const state =
FindManagedRenderSceneSetupContextState(nativeHandle);
if (state == nullptr || state->sceneData == nullptr) {
return;
}
state->sceneData->environment = {};
state->sceneData->environment.mode =
Rendering::RenderEnvironmentMode::ProceduralSkybox;
state->sceneData->environment.skybox.topColor =
topColor != nullptr ? *topColor : XCEngine::Math::Color();
state->sceneData->environment.skybox.horizonColor =
horizonColor != nullptr ? *horizonColor : XCEngine::Math::Color();
state->sceneData->environment.skybox.bottomColor =
bottomColor != nullptr ? *bottomColor : XCEngine::Math::Color();
state->explicitlyConfigured = true;
}
void
InternalCall_Rendering_RenderSceneSetupContext_ClearGlobalShaderKeywords(
uint64_t nativeHandle) {
@@ -5619,16 +5939,55 @@ InternalCall_Rendering_RenderSceneSetupContext_ClearGlobalShaderKeywords(
state->explicitlyConfigured = true;
}
void InternalCall_Rendering_RenderSceneSetupContext_ClearSceneSetup(
uint64_t nativeHandle) {
void InternalCall_Rendering_RenderSceneSetupContext_SetGlobalShaderKeyword(
uint64_t nativeHandle,
MonoString* keyword,
mono_bool enabled) {
ManagedRenderSceneSetupContextState* const state =
FindManagedRenderSceneSetupContextState(nativeHandle);
if (state == nullptr || state->sceneData == nullptr) {
return;
}
state->sceneData->environment = {};
state->sceneData->globalShaderKeywords = {};
const XCEngine::Containers::String normalizedKeyword =
Resources::NormalizeShaderKeywordToken(
XCEngine::Containers::String(
MonoStringToUtf8(keyword).c_str()));
if (normalizedKeyword.Empty()) {
state->explicitlyConfigured = true;
return;
}
Resources::ShaderKeywordSet& keywordSet =
state->sceneData->globalShaderKeywords;
bool foundKeyword = false;
size_t foundIndex = 0;
for (size_t keywordIndex = 0;
keywordIndex < keywordSet.enabledKeywords.Size();
++keywordIndex) {
if (keywordSet.enabledKeywords[keywordIndex] ==
normalizedKeyword) {
foundKeyword = true;
foundIndex = keywordIndex;
break;
}
}
if (enabled != 0) {
if (!foundKeyword) {
keywordSet.enabledKeywords.PushBack(normalizedKeyword);
}
} else if (foundKeyword) {
const size_t lastIndex =
keywordSet.enabledKeywords.Size() - 1;
if (foundIndex != lastIndex) {
keywordSet.enabledKeywords[foundIndex] =
keywordSet.enabledKeywords[lastIndex];
}
keywordSet.enabledKeywords.PopBack();
}
Resources::NormalizeShaderKeywordSetInPlace(keywordSet);
state->explicitlyConfigured = true;
}
@@ -6024,6 +6383,18 @@ void RegisterInternalCalls() {
mono_add_internal_call("XCEngine.InternalCalls::Camera_SetDepth", reinterpret_cast<const void*>(&InternalCall_Camera_SetDepth));
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetPrimary", reinterpret_cast<const void*>(&InternalCall_Camera_GetPrimary));
mono_add_internal_call("XCEngine.InternalCalls::Camera_SetPrimary", reinterpret_cast<const void*>(&InternalCall_Camera_SetPrimary));
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetClearMode", reinterpret_cast<const void*>(&InternalCall_Camera_GetClearMode));
mono_add_internal_call("XCEngine.InternalCalls::Camera_SetClearMode", reinterpret_cast<const void*>(&InternalCall_Camera_SetClearMode));
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetStackType", reinterpret_cast<const void*>(&InternalCall_Camera_GetStackType));
mono_add_internal_call("XCEngine.InternalCalls::Camera_SetStackType", reinterpret_cast<const void*>(&InternalCall_Camera_SetStackType));
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetProjectionType", reinterpret_cast<const void*>(&InternalCall_Camera_GetProjectionType));
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetSkyboxEnabled", reinterpret_cast<const void*>(&InternalCall_Camera_GetSkyboxEnabled));
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetHasSkyboxMaterial", reinterpret_cast<const void*>(&InternalCall_Camera_GetHasSkyboxMaterial));
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetHasFinalColorOverrides", reinterpret_cast<const void*>(&InternalCall_Camera_GetHasFinalColorOverrides));
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetFinalColorOverrideSettings", reinterpret_cast<const void*>(&InternalCall_Camera_GetFinalColorOverrideSettings));
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetSkyboxTopColor", reinterpret_cast<const void*>(&InternalCall_Camera_GetSkyboxTopColor));
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetSkyboxHorizonColor", reinterpret_cast<const void*>(&InternalCall_Camera_GetSkyboxHorizonColor));
mono_add_internal_call("XCEngine.InternalCalls::Camera_GetSkyboxBottomColor", reinterpret_cast<const void*>(&InternalCall_Camera_GetSkyboxBottomColor));
mono_add_internal_call("XCEngine.InternalCalls::Light_GetIntensity", reinterpret_cast<const void*>(&InternalCall_Light_GetIntensity));
mono_add_internal_call("XCEngine.InternalCalls::Light_SetIntensity", reinterpret_cast<const void*>(&InternalCall_Light_SetIntensity));
mono_add_internal_call("XCEngine.InternalCalls::Light_GetRange", reinterpret_cast<const void*>(&InternalCall_Light_GetRange));
@@ -6076,7 +6447,10 @@ void RegisterInternalCalls() {
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_BeginRasterPass", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_BeginRasterPass));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassSourceColorTexture", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassSourceColorTexture));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_AddRasterPassReadTexture", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_AddRasterPassReadTexture));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_AddRasterPassReadDepthTexture", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_AddRasterPassReadDepthTexture));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_AddRasterPassTextureBinding", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_AddRasterPassTextureBinding));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassColorAttachment", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassColorAttachment));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassDepthAttachment", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassDepthAttachment));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassColorScaleFullscreenExecution", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassColorScaleFullscreenExecution));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassShaderVectorFullscreenExecution", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassShaderVectorFullscreenExecution));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassFinalColorFullscreenExecution", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassFinalColorFullscreenExecution));
@@ -6158,14 +6532,21 @@ void RegisterInternalCalls() {
mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_GetDirectionalShadowPlanningSettings", reinterpret_cast<const void*>(&InternalCall_Rendering_CameraRenderRequestContext_GetDirectionalShadowPlanningSettings));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_SetDirectionalShadowPlanningSettings", reinterpret_cast<const void*>(&InternalCall_Rendering_CameraRenderRequestContext_SetDirectionalShadowPlanningSettings));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_ClearDirectionalShadow", reinterpret_cast<const void*>(&InternalCall_Rendering_CameraRenderRequestContext_ClearDirectionalShadow));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_GetClearFlags", reinterpret_cast<const void*>(&InternalCall_Rendering_CameraRenderRequestContext_GetClearFlags));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_SetClearFlags", reinterpret_cast<const void*>(&InternalCall_Rendering_CameraRenderRequestContext_SetClearFlags));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_SetResolvedFinalColorPolicy", reinterpret_cast<const void*>(&InternalCall_Rendering_CameraRenderRequestContext_SetResolvedFinalColorPolicy));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_CameraRenderRequestContext_ClearFinalColorPolicy", reinterpret_cast<const void*>(&InternalCall_Rendering_CameraRenderRequestContext_ClearFinalColorPolicy));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_GetRendererIndex", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_GetRendererIndex));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_GetCameraGameObjectUUID", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_GetCameraGameObjectUUID));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_GetIsConfigured", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_GetIsConfigured));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_UseDefaultSceneSetup", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_UseDefaultSceneSetup));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_UseDefaultEnvironment", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_UseDefaultEnvironment));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_UseDefaultGlobalShaderKeywords", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_UseDefaultGlobalShaderKeywords));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_ClearEnvironment", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_ClearEnvironment));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_GetClearFlags", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_GetClearFlags));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_GetHasMainSceneDepthAttachment", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_GetHasMainSceneDepthAttachment));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_GetHasMainDirectionalShadow", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_GetHasMainDirectionalShadow));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_SetEnvironmentNone", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_SetEnvironmentNone));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_UseCameraSkyboxMaterial", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_UseCameraSkyboxMaterial));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_SetProceduralSkybox", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_SetProceduralSkybox));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_ClearGlobalShaderKeywords", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_ClearGlobalShaderKeywords));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_ClearSceneSetup", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_ClearSceneSetup));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_RenderSceneSetupContext_SetGlobalShaderKeyword", reinterpret_cast<const void*>(&InternalCall_Rendering_RenderSceneSetupContext_SetGlobalShaderKeyword));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_DirectionalShadowExecutionContext_GetHasPlannedMainDirectionalShadow", reinterpret_cast<const void*>(&InternalCall_Rendering_DirectionalShadowExecutionContext_GetHasPlannedMainDirectionalShadow));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_DirectionalShadowExecutionContext_GetRendererIndex", reinterpret_cast<const void*>(&InternalCall_Rendering_DirectionalShadowExecutionContext_GetRendererIndex));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_DirectionalShadowExecutionContext_GetIsConfigured", reinterpret_cast<const void*>(&InternalCall_Rendering_DirectionalShadowExecutionContext_GetIsConfigured));

BIN
font.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

View File

@@ -144,6 +144,9 @@ set(XCENGINE_SCRIPT_CORE_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/AssemblyInfo.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Behaviour.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Camera.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/CameraClearMode.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/CameraProjectionType.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/CameraStackType.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Color.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Component.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Debug.cs
@@ -180,13 +183,16 @@ set(XCENGINE_SCRIPT_CORE_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/DirectionalShadowPlanningSettings.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/DrawingSettings.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/FinalColorExposureMode.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/FinalColorOverrideSettings.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/FinalColorOutputTransferMode.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/FinalColorSettings.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/FinalColorToneMappingMode.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/FilteringSettings.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/GraphicsSettings.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/NativeSceneFeaturePassId.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/RenderSceneSetupContext.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/RenderPipelineAsset.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/RenderClearFlags.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/RenderQueueRange.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/RenderStateBlock.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/RenderStateMask.cs
@@ -212,6 +218,7 @@ set(XCENGINE_SCRIPT_CORE_SOURCES
set(XCENGINE_RENDER_PIPELINES_UNIVERSAL_SOURCES
# Universal renderer package
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/CameraData.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/ColorScalePostProcessSettings.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/ColorScalePostProcessRendererFeature.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/BuiltinFinalColorPass.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/BuiltinGaussianSplatRendererFeature.cs
@@ -226,12 +233,14 @@ set(XCENGINE_RENDER_PIPELINES_UNIVERSAL_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/EnvironmentData.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/FinalColorData.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/LightingData.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderClearFlags.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderEnvironmentMode.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsFeatureSettings.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderPassEvent.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsRendererFeature.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/RendererBlock.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/RendererBackedRenderPipeline.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/RendererBackedRenderPipelineAsset.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/RendererBlocks.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/RendererCameraRequestContext.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/RendererDrivenRenderPipeline.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/RendererRecordingContext.cs
@@ -242,15 +251,27 @@ set(XCENGINE_RENDER_PIPELINES_UNIVERSAL_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRenderPass.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRenderer.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRendererData.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRendererDataCollection.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRendererFeatureCollection.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRendererFeature.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/StageColorData.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalAdditionalCameraData.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalDefaultRendererFeatureFactory.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalFinalColorSettings.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalFinalOutputBlock.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalMainSceneData.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalMainSceneBlock.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalMainSceneFeatureUtility.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalNativeSceneFeatureController.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalColorScalePostProcessController.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalDepthPrepassBlock.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalPostProcessBlock.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderObjectsFeatureController.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderPipeline.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderer.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRendererData.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalRenderPipelineAsset.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalShadowCasterBlock.cs
${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.RenderPipelines.Universal/Rendering/Universal/UniversalShadowSettings.cs
)

View File

@@ -59,6 +59,80 @@ namespace Gameplay
}
}
internal static class ProbeScriptableObjectFactory
{
public static T Create<T>()
where T : ScriptableObject
{
T instance =
ScriptableObject.CreateInstance<T>();
if (instance != null)
{
return instance;
}
throw new InvalidOperationException(
"Failed to create ScriptableObject probe instance: " +
typeof(T).FullName);
}
public static ScriptableRendererData[] CreateRendererDataList(
params ScriptableRendererData[] rendererData)
{
return Compact(rendererData);
}
public static ScriptableRendererFeature[] CreateRendererFeatureList(
params ScriptableRendererFeature[] rendererFeatures)
{
return Compact(rendererFeatures);
}
private static T[] Compact<T>(
params T[] items)
where T : class
{
if (items == null ||
items.Length == 0)
{
return Array.Empty<T>();
}
int validCount = 0;
for (int i = 0; i < items.Length; ++i)
{
if (items[i] != null)
{
validCount++;
}
}
if (validCount == items.Length)
{
return items;
}
if (validCount == 0)
{
return Array.Empty<T>();
}
T[] compactItems = new T[validCount];
int writeIndex = 0;
for (int i = 0; i < items.Length; ++i)
{
if (items[i] == null)
{
continue;
}
compactItems[writeIndex++] = items[i];
}
return compactItems;
}
}
internal enum SceneInjectionKind
{
BeforeOpaque,
@@ -345,6 +419,84 @@ namespace Gameplay
renderer.EnqueuePass(renderPass);
}
}
public override void ConfigureCameraFramePlan(
ScriptableRenderPipelinePlanningContext context)
{
if (context == null)
{
return;
}
bool hasPostProcessPass = false;
bool hasFinalOutputPass = false;
for (int i = 0; i < m_passes.Length; ++i)
{
ScriptableRenderPass renderPass = m_passes[i];
if (renderPass == null)
{
continue;
}
if (renderPass.SupportsStage(
CameraFrameStage.PostProcess))
{
hasPostProcessPass = true;
}
if (renderPass.SupportsStage(
CameraFrameStage.FinalOutput))
{
hasFinalOutputPass = true;
}
}
bool needsGraphManagedPostProcessOutput =
context.HasFinalColorProcessing() ||
context.IsStageRequested(
CameraFrameStage.FinalOutput) ||
hasFinalOutputPass;
if (hasPostProcessPass)
{
if (!context.IsStageRequested(
CameraFrameStage.PostProcess))
{
context.RequestFullscreenStage(
CameraFrameStage.PostProcess,
CameraFrameColorSource.MainSceneColor,
needsGraphManagedPostProcessOutput);
}
else if (needsGraphManagedPostProcessOutput &&
context.GetStageColorSource(
CameraFrameStage.PostProcess) !=
CameraFrameColorSource.ExplicitSurface &&
!context.UsesGraphManagedOutputColor(
CameraFrameStage.PostProcess))
{
CameraFrameColorSource source =
context.GetStageColorSource(
CameraFrameStage.PostProcess);
context.ClearFullscreenStage(
CameraFrameStage.PostProcess);
context.RequestFullscreenStage(
CameraFrameStage.PostProcess,
source,
true);
}
}
if (hasFinalOutputPass &&
!context.IsStageRequested(
CameraFrameStage.FinalOutput))
{
context.RequestFullscreenStage(
CameraFrameStage.FinalOutput,
hasPostProcessPass
? CameraFrameColorSource.PostProcessColor
: CameraFrameColorSource.MainSceneColor);
}
}
}
internal class ProbeSceneRenderer : ScriptableRenderer
@@ -484,13 +636,26 @@ namespace Gameplay
internal sealed class ManagedFeaturePassOrderCustomFeature
: ScriptableRendererFeature
{
private readonly ManagedFeaturePassOrderProbePass m_pass;
private ManagedFeaturePassOrderProbePass m_pass;
public ManagedFeaturePassOrderCustomFeature(
string token)
public string token = string.Empty;
protected override int ComputeRuntimeStateHash()
{
int hash =
base.ComputeRuntimeStateHash();
hash =
RuntimeStateHashUtility.Combine(
hash,
token ?? string.Empty);
return hash;
}
public override void Create()
{
m_pass =
new ManagedFeaturePassOrderProbePass(token);
new ManagedFeaturePassOrderProbePass(
token ?? string.Empty);
}
public override void AddRenderPasses(
@@ -504,7 +669,11 @@ namespace Gameplay
return;
}
renderer.EnqueuePass(m_pass);
CreateInstance();
if (m_pass != null)
{
renderer.EnqueuePass(m_pass);
}
}
}
@@ -524,11 +693,19 @@ namespace Gameplay
public ManagedFeaturePassOrderProbeRendererData()
: base(false)
{
rendererFeatures = new ScriptableRendererFeature[]
{
new ManagedFeaturePassOrderCustomFeature("CustomA"),
new ManagedFeaturePassOrderCustomFeature("CustomB")
};
ManagedFeaturePassOrderCustomFeature customA =
ProbeScriptableObjectFactory
.Create<ManagedFeaturePassOrderCustomFeature>();
ManagedFeaturePassOrderCustomFeature customB =
ProbeScriptableObjectFactory
.Create<ManagedFeaturePassOrderCustomFeature>();
customA.token = "CustomA";
customB.token = "CustomB";
rendererFeatures =
ProbeScriptableObjectFactory
.CreateRendererFeatureList(
customA,
customB);
}
protected override ScriptableRenderer CreateProbeRenderer()
@@ -1018,18 +1195,13 @@ namespace Gameplay
internal sealed class ManagedUniversalRenderPipelineProbeRendererData
: ProbeRendererData
{
private readonly Vector4 m_postProcessScale;
public ManagedUniversalRenderPipelineProbeRendererData(
Vector4 postProcessScale)
{
m_postProcessScale = postProcessScale;
}
public Vector4 postProcessScale =
new Vector4(1.03f, 0.98f, 0.94f, 1.0f);
protected override ScriptableRenderer CreateProbeRenderer()
{
return new ManagedUniversalRenderPipelineProbe(
m_postProcessScale);
postProcessScale);
}
}
@@ -1126,10 +1298,11 @@ namespace Gameplay
: base(false)
{
ManagedRendererInvalidationProbeState.CreateFeatureCallCount++;
rendererFeatures = new ScriptableRendererFeature[]
{
new ManagedRendererInvalidationProbeFeature()
};
rendererFeatures =
ProbeScriptableObjectFactory
.CreateRendererFeatureList(
ProbeScriptableObjectFactory
.Create<ManagedRendererInvalidationProbeFeature>());
}
protected override ScriptableRenderer CreateProbeRenderer()
@@ -1205,11 +1378,12 @@ namespace Gameplay
: base(false)
{
m_feature =
new ManagedPersistentFeatureProbeRendererFeature();
rendererFeatures = new ScriptableRendererFeature[]
{
m_feature
};
ProbeScriptableObjectFactory
.Create<ManagedPersistentFeatureProbeRendererFeature>();
rendererFeatures =
ProbeScriptableObjectFactory
.CreateRendererFeatureList(
m_feature);
}
protected override ScriptableRenderer CreateProbeRenderer()
@@ -1260,10 +1434,11 @@ namespace Gameplay
public ManagedFeaturePlannedPostProcessRendererData()
: base(false)
{
rendererFeatures = new ScriptableRendererFeature[]
{
new ManagedFeaturePlannedPostProcessRendererFeature()
};
rendererFeatures =
ProbeScriptableObjectFactory
.CreateRendererFeatureList(
ProbeScriptableObjectFactory
.Create<ManagedFeaturePlannedPostProcessRendererFeature>());
}
protected override ScriptableRenderer CreateProbeRenderer()
@@ -1354,10 +1529,11 @@ namespace Gameplay
: base(false)
{
ManagedLifecycleProbeState.CreateFeatureCallCount++;
rendererFeatures = new ScriptableRendererFeature[]
{
new ManagedLifecycleProbeRendererFeature()
};
rendererFeatures =
ProbeScriptableObjectFactory
.CreateRendererFeatureList(
ProbeScriptableObjectFactory
.Create<ManagedLifecycleProbeRendererFeature>());
}
protected override ScriptableRenderer CreateProbeRenderer()
@@ -1427,10 +1603,11 @@ namespace Gameplay
{
public ManagedUniversalLifecycleProbeAsset()
{
rendererDataList = new ScriptableRendererData[]
{
new ManagedLifecycleProbeRendererData()
};
rendererDataList =
ProbeScriptableObjectFactory
.CreateRendererDataList(
ProbeScriptableObjectFactory
.Create<ManagedLifecycleProbeRendererData>());
}
protected override ScriptableRenderPipeline CreatePipeline()
@@ -1453,10 +1630,11 @@ namespace Gameplay
public ManagedRenderPipelineProbeAsset()
{
rendererDataList = new ScriptableRendererData[]
{
new ManagedRenderPipelineProbeRendererData()
};
rendererDataList =
ProbeScriptableObjectFactory
.CreateRendererDataList(
ProbeScriptableObjectFactory
.Create<ManagedRenderPipelineProbeRendererData>());
}
protected override ScriptableRenderPipeline CreatePipeline()
@@ -1472,10 +1650,10 @@ namespace Gameplay
public ManagedPostProcessRenderPipelineProbeAsset()
{
rendererDataList =
new ScriptableRendererData[]
{
new ManagedPostProcessRenderPipelineProbeRendererData()
};
ProbeScriptableObjectFactory
.CreateRendererDataList(
ProbeScriptableObjectFactory
.Create<ManagedPostProcessRenderPipelineProbeRendererData>());
}
}
@@ -1499,11 +1677,14 @@ namespace Gameplay
private ScriptableRendererData[] CreateRendererDataList()
{
return new ScriptableRendererData[]
{
new ManagedUniversalRenderPipelineProbeRendererData(
postProcessScale)
};
ManagedUniversalRenderPipelineProbeRendererData rendererData =
ProbeScriptableObjectFactory
.Create<ManagedUniversalRenderPipelineProbeRendererData>();
rendererData.postProcessScale =
postProcessScale;
return ProbeScriptableObjectFactory
.CreateRendererDataList(
rendererData);
}
}
@@ -1514,10 +1695,11 @@ namespace Gameplay
{
ManagedRendererReuseProbeRendererData.CreateRendererCallCount = 0;
ManagedRendererReuseProbeRendererData.SetupRendererCallCount = 0;
rendererDataList = new ScriptableRendererData[]
{
new ManagedRendererReuseProbeRendererData()
};
rendererDataList =
ProbeScriptableObjectFactory
.CreateRendererDataList(
ProbeScriptableObjectFactory
.Create<ManagedRendererReuseProbeRendererData>());
}
}
@@ -1530,11 +1712,13 @@ namespace Gameplay
public ManagedRendererInvalidationProbeAsset()
{
ManagedRendererInvalidationProbeState.Reset();
m_rendererData = new ManagedRendererInvalidationProbeRendererData();
rendererDataList = new ScriptableRendererData[]
{
m_rendererData
};
m_rendererData =
ProbeScriptableObjectFactory
.Create<ManagedRendererInvalidationProbeRendererData>();
rendererDataList =
ProbeScriptableObjectFactory
.CreateRendererDataList(
m_rendererData);
}
protected override ScriptableRenderPipeline
@@ -1565,11 +1749,12 @@ namespace Gameplay
{
ManagedPersistentFeatureProbeState.Reset();
m_rendererData =
new ManagedPersistentFeatureProbeRendererData();
rendererDataList = new ScriptableRendererData[]
{
m_rendererData
};
ProbeScriptableObjectFactory
.Create<ManagedPersistentFeatureProbeRendererData>();
rendererDataList =
ProbeScriptableObjectFactory
.CreateRendererDataList(
m_rendererData);
}
public void InvalidateDefaultRendererForTest()
@@ -1589,10 +1774,11 @@ namespace Gameplay
public ManagedFeaturePassOrderProbeAsset()
{
ManagedFeaturePassOrderProbeState.Reset();
rendererDataList = new ScriptableRendererData[]
{
new ManagedFeaturePassOrderProbeRendererData()
};
rendererDataList =
ProbeScriptableObjectFactory
.CreateRendererDataList(
ProbeScriptableObjectFactory
.Create<ManagedFeaturePassOrderProbeRendererData>());
}
}
@@ -1684,10 +1870,10 @@ namespace Gameplay
public ManagedPlannedFullscreenRenderPipelineProbeAsset()
{
rendererDataList =
new ScriptableRendererData[]
{
new ManagedPlannedFullscreenRenderPipelineProbeRendererData()
};
ProbeScriptableObjectFactory
.CreateRendererDataList(
ProbeScriptableObjectFactory
.Create<ManagedPlannedFullscreenRenderPipelineProbeRendererData>());
}
}
@@ -1697,10 +1883,10 @@ namespace Gameplay
public ManagedFeaturePlannedPostProcessProbeAsset()
{
rendererDataList =
new ScriptableRendererData[]
{
new ManagedFeaturePlannedPostProcessRendererData()
};
ProbeScriptableObjectFactory
.CreateRendererDataList(
ProbeScriptableObjectFactory
.Create<ManagedFeaturePlannedPostProcessRendererData>());
}
}
@@ -1710,10 +1896,10 @@ namespace Gameplay
public ManagedClearedPostProcessRenderPipelineProbeAsset()
{
rendererDataList =
new ScriptableRendererData[]
{
new ManagedPlannedFullscreenRenderPipelineProbeRendererData()
};
ProbeScriptableObjectFactory
.CreateRendererDataList(
ProbeScriptableObjectFactory
.Create<ManagedPlannedFullscreenRenderPipelineProbeRendererData>());
}
protected override void ConfigureCameraFramePlan(
@@ -1760,10 +1946,11 @@ namespace Gameplay
{
public ManagedCameraRequestConfiguredRenderPipelineProbeAsset()
{
rendererDataList = new ScriptableRendererData[]
{
new ManagedCameraRequestConfiguredRendererData()
};
rendererDataList =
ProbeScriptableObjectFactory
.CreateRendererDataList(
ProbeScriptableObjectFactory
.Create<ManagedCameraRequestConfiguredRendererData>());
}
}
@@ -1773,10 +1960,10 @@ namespace Gameplay
public ManagedRenderContextCameraDataProbeAsset()
{
rendererDataList =
new ScriptableRendererData[]
{
new ManagedRenderContextCameraDataProbeRendererData()
};
ProbeScriptableObjectFactory
.CreateRendererDataList(
ProbeScriptableObjectFactory
.Create<ManagedRenderContextCameraDataProbeRendererData>());
}
}
@@ -1785,10 +1972,11 @@ namespace Gameplay
{
public ManagedFinalColorRenderPipelineProbeAsset()
{
rendererDataList = new ScriptableRendererData[]
{
new ManagedRenderPipelineProbeRendererData()
};
rendererDataList =
ProbeScriptableObjectFactory
.CreateRendererDataList(
ProbeScriptableObjectFactory
.Create<ManagedRenderPipelineProbeRendererData>());
}
protected override FinalColorSettings GetDefaultFinalColorSettings()
@@ -1803,10 +1991,10 @@ namespace Gameplay
public ManagedRenderContextFinalColorDataProbeAsset()
{
rendererDataList =
new ScriptableRendererData[]
{
new ManagedRenderContextCameraDataProbeRendererData()
};
ProbeScriptableObjectFactory
.CreateRendererDataList(
ProbeScriptableObjectFactory
.Create<ManagedRenderContextCameraDataProbeRendererData>());
}
protected override FinalColorSettings GetDefaultFinalColorSettings()
@@ -1821,10 +2009,10 @@ namespace Gameplay
public ManagedRenderContextStageColorDataProbeAsset()
{
rendererDataList =
new ScriptableRendererData[]
{
new ManagedRenderContextStageColorDataProbeRendererData()
};
ProbeScriptableObjectFactory
.CreateRendererDataList(
ProbeScriptableObjectFactory
.Create<ManagedRenderContextStageColorDataProbeRendererData>());
}
}
@@ -1966,7 +2154,8 @@ namespace Gameplay
public void Start()
{
GraphicsSettings.renderPipelineAsset =
new ManagedRendererInvalidationProbeAsset();
ProbeScriptableObjectFactory
.Create<ManagedRendererInvalidationProbeAsset>();
}
}
@@ -2035,7 +2224,8 @@ namespace Gameplay
public void Start()
{
GraphicsSettings.renderPipelineAsset =
new ManagedPersistentFeatureProbeAsset();
ProbeScriptableObjectFactory
.Create<ManagedPersistentFeatureProbeAsset>();
}
}
@@ -2088,7 +2278,8 @@ namespace Gameplay
public void Start()
{
GraphicsSettings.renderPipelineAsset =
new ManagedFeaturePassOrderProbeAsset();
ProbeScriptableObjectFactory
.Create<ManagedFeaturePassOrderProbeAsset>();
}
}
@@ -2111,7 +2302,8 @@ namespace Gameplay
public void Start()
{
GraphicsSettings.renderPipelineAsset =
new ManagedAssetInvalidationProbeAsset();
ProbeScriptableObjectFactory
.Create<ManagedAssetInvalidationProbeAsset>();
}
}
@@ -2193,7 +2385,8 @@ namespace Gameplay
ManagedRendererReuseProbeRendererData.CreateRendererCallCount = 0;
ManagedRendererReuseProbeRendererData.SetupRendererCallCount = 0;
GraphicsSettings.renderPipelineAsset =
new ManagedRenderPipelineProbeAsset();
ProbeScriptableObjectFactory
.Create<ManagedRenderPipelineProbeAsset>();
}
}
@@ -2273,7 +2466,8 @@ namespace Gameplay
{
ManagedLifecycleProbeState.Reset();
GraphicsSettings.renderPipelineAsset =
new ManagedUniversalLifecycleProbeAsset();
ProbeScriptableObjectFactory
.Create<ManagedUniversalLifecycleProbeAsset>();
}
public void Update()
@@ -2525,11 +2719,13 @@ namespace Gameplay
ManagedUniversalRenderPipelineProbe.RecordPostProcessCallCount = 0;
ManagedUniversalRenderPipelineProbe.LastPostProcessScale =
new Vector4(0.0f, 0.0f, 0.0f, 0.0f);
ManagedUniversalRenderPipelineProbeAsset asset =
ProbeScriptableObjectFactory
.Create<ManagedUniversalRenderPipelineProbeAsset>();
asset.postProcessScale =
new Vector4(1.11f, 0.97f, 0.93f, 1.0f);
GraphicsSettings.renderPipelineAsset =
new ManagedUniversalRenderPipelineProbeAsset
{
postProcessScale = new Vector4(1.11f, 0.97f, 0.93f, 1.0f)
};
asset;
}
public void Update()
@@ -2583,7 +2779,8 @@ namespace Gameplay
{
CameraDataObservationPass.Reset();
GraphicsSettings.renderPipelineAsset =
new ManagedRenderContextCameraDataProbeAsset();
ProbeScriptableObjectFactory
.Create<ManagedRenderContextCameraDataProbeAsset>();
}
public void Update()
@@ -2655,7 +2852,8 @@ namespace Gameplay
{
CameraDataObservationPass.Reset();
GraphicsSettings.renderPipelineAsset =
new ManagedRenderContextCameraDataProbeAsset();
ProbeScriptableObjectFactory
.Create<ManagedRenderContextCameraDataProbeAsset>();
}
public void Update()
@@ -2699,7 +2897,8 @@ namespace Gameplay
{
CameraDataObservationPass.Reset();
GraphicsSettings.renderPipelineAsset =
new ManagedRenderContextCameraDataProbeAsset();
ProbeScriptableObjectFactory
.Create<ManagedRenderContextCameraDataProbeAsset>();
}
public void Update()
@@ -2742,7 +2941,8 @@ namespace Gameplay
{
CameraDataObservationPass.Reset();
GraphicsSettings.renderPipelineAsset =
new ManagedRenderContextCameraDataProbeAsset();
ProbeScriptableObjectFactory
.Create<ManagedRenderContextCameraDataProbeAsset>();
}
public void Update()
@@ -2816,7 +3016,8 @@ namespace Gameplay
{
CameraDataObservationPass.Reset();
GraphicsSettings.renderPipelineAsset =
new ManagedRenderContextFinalColorDataProbeAsset();
ProbeScriptableObjectFactory
.Create<ManagedRenderContextFinalColorDataProbeAsset>();
}
public void Update()
@@ -2867,7 +3068,8 @@ namespace Gameplay
{
StageColorObservationPass.Reset();
GraphicsSettings.renderPipelineAsset =
new ManagedRenderContextStageColorDataProbeAsset();
ProbeScriptableObjectFactory
.Create<ManagedRenderContextStageColorDataProbeAsset>();
}
public void Update()

View File

@@ -8,40 +8,41 @@ namespace XCEngine.Rendering.Universal
{
public RenderPassEvent passEvent =
RenderPassEvent.BeforeRenderingTransparents;
private NativeSceneFeaturePass m_pass;
private readonly UniversalNativeSceneFeatureController m_controller =
new UniversalNativeSceneFeatureController(
NativeSceneFeaturePassId
.BuiltinGaussianSplat);
protected override int ComputeRuntimeStateHash()
{
int hash =
base.ComputeRuntimeStateHash();
hash =
RuntimeStateHashUtility.Combine(
hash,
(int)passEvent);
return hash;
return m_controller.AppendRuntimeStateHash(
hash,
passEvent);
}
public override void Create()
{
m_pass = new NativeSceneFeaturePass(
"BuiltinGaussianSplatPass",
passEvent);
m_controller.Create(passEvent);
}
public override void AddRenderPasses(
ScriptableRenderer renderer,
RenderingData renderingData)
{
if (renderer == null)
if (renderer == null ||
renderingData == null ||
!renderingData.isMainSceneStage)
{
return;
}
CreateInstance();
m_pass.Configure(passEvent);
renderer.EnqueuePass(m_pass);
m_controller.EnqueuePass(
renderer,
renderingData,
passEvent);
}
}
}

View File

@@ -8,40 +8,41 @@ namespace XCEngine.Rendering.Universal
{
public RenderPassEvent passEvent =
RenderPassEvent.BeforeRenderingTransparents;
private NativeSceneFeaturePass m_pass;
private readonly UniversalNativeSceneFeatureController m_controller =
new UniversalNativeSceneFeatureController(
NativeSceneFeaturePassId
.BuiltinVolumetric);
protected override int ComputeRuntimeStateHash()
{
int hash =
base.ComputeRuntimeStateHash();
hash =
RuntimeStateHashUtility.Combine(
hash,
(int)passEvent);
return hash;
return m_controller.AppendRuntimeStateHash(
hash,
passEvent);
}
public override void Create()
{
m_pass = new NativeSceneFeaturePass(
"BuiltinVolumetricPass",
passEvent);
m_controller.Create(passEvent);
}
public override void AddRenderPasses(
ScriptableRenderer renderer,
RenderingData renderingData)
{
if (renderer == null)
if (renderer == null ||
renderingData == null ||
!renderingData.isMainSceneStage)
{
return;
}
CreateInstance();
m_pass.Configure(passEvent);
renderer.EnqueuePass(m_pass);
m_controller.EnqueuePass(
renderer,
renderingData,
passEvent);
}
}
}

View File

@@ -1,4 +1,5 @@
using XCEngine;
using XCEngine.Rendering;
namespace XCEngine.Rendering.Universal
{

View File

@@ -6,24 +6,31 @@ namespace XCEngine.Rendering.Universal
internal sealed class ColorScalePostProcessPass
: ScriptableRenderPass
{
private readonly ColorScalePostProcessRendererFeature m_feature;
private Vector4 m_colorScale = new Vector4(
1.0f,
1.0f,
1.0f,
1.0f);
public ColorScalePostProcessPass(
ColorScalePostProcessRendererFeature feature)
public ColorScalePostProcessPass()
{
m_feature = feature;
renderPassEvent =
RenderPassEvent.BeforeRenderingPostProcessing;
}
public void Configure(
Vector4 colorScale)
{
m_colorScale = colorScale;
}
protected override bool RecordRenderGraph(
ScriptableRenderContext context,
RenderingData renderingData)
{
if (context == null ||
renderingData == null ||
!renderingData.isPostProcessStage ||
m_feature == null)
!renderingData.isPostProcessStage)
{
return false;
}
@@ -32,7 +39,7 @@ namespace XCEngine.Rendering.Universal
context,
context.sourceColorTexture,
context.primaryColorTarget,
m_feature.colorScale,
m_colorScale,
"Universal.ColorScalePostProcess");
}
}
@@ -40,8 +47,9 @@ namespace XCEngine.Rendering.Universal
public sealed class ColorScalePostProcessRendererFeature
: ScriptableRendererFeature
{
private ColorScalePostProcessPass m_pass;
private readonly UniversalColorScalePostProcessController
m_controller =
new UniversalColorScalePostProcessController();
public Vector4 colorScale = new Vector4(
1.0f,
1.0f,
@@ -52,17 +60,22 @@ namespace XCEngine.Rendering.Universal
{
int hash =
base.ComputeRuntimeStateHash();
hash =
RuntimeStateHashUtility.Combine(
hash,
colorScale);
return hash;
return m_controller.AppendRuntimeStateHash(
hash,
BuildSettings());
}
public override void Create()
{
m_pass =
new ColorScalePostProcessPass(this);
m_controller.Create(
BuildSettings());
}
public override void ConfigureCameraFramePlan(
ScriptableRenderPipelinePlanningContext context)
{
m_controller.ConfigureCameraFramePlan(
context);
}
public override void AddRenderPasses(
@@ -70,14 +83,25 @@ namespace XCEngine.Rendering.Universal
RenderingData renderingData)
{
if (renderer == null ||
renderingData == null)
renderingData == null ||
!renderingData.isPostProcessStage)
{
return;
}
CreateInstance();
m_controller.EnqueuePass(
renderer,
renderingData,
BuildSettings());
}
renderer.EnqueuePass(m_pass);
private ColorScalePostProcessSettings BuildSettings()
{
return new ColorScalePostProcessSettings
{
colorScale = colorScale
};
}
}
}

View File

@@ -0,0 +1,21 @@
using XCEngine;
namespace XCEngine.Rendering.Universal
{
internal sealed class ColorScalePostProcessSettings
{
public Vector4 colorScale = new Vector4(
1.0f,
1.0f,
1.0f,
1.0f);
public int AppendRuntimeStateHash(
int hash)
{
return RuntimeStateHashUtility.Combine(
hash,
colorScale);
}
}
}

View File

@@ -6,14 +6,14 @@ namespace XCEngine.Rendering.Universal
internal sealed class NativeSceneFeaturePass
: ScriptableRenderPass
{
private readonly string m_featurePassName;
private readonly NativeSceneFeaturePassId m_featurePassId;
public NativeSceneFeaturePass(
string featurePassName,
NativeSceneFeaturePassId featurePassId,
RenderPassEvent passEvent)
{
m_featurePassName =
featurePassName ?? string.Empty;
m_featurePassId =
featurePassId;
renderPassEvent = passEvent;
}
@@ -31,7 +31,7 @@ namespace XCEngine.Rendering.Universal
renderingData != null &&
renderingData.isMainSceneStage &&
context.RecordNativeSceneFeaturePass(
m_featurePassName);
m_featurePassId);
}
}
}

View File

@@ -0,0 +1,36 @@
using XCEngine;
using XCEngine.Rendering;
namespace XCEngine.Rendering.Universal
{
internal sealed class RenderObjectsFeatureSettings
{
public RenderPassEvent passEvent =
RenderPassEvent.AfterRenderingOpaques;
public SceneRenderPhase scenePhase =
SceneRenderPhase.Opaque;
public RendererListDesc rendererListDesc =
RendererListDesc.CreateDefault(
RendererListType.Opaque);
public DrawingSettings drawingSettings =
DrawingSettings.CreateDefault();
public int AppendRuntimeStateHash(
int hash)
{
hash = RuntimeStateHashUtility.Combine(
hash,
(int)passEvent);
hash = RuntimeStateHashUtility.Combine(
hash,
(int)scenePhase);
hash = RuntimeStateHashUtility.Combine(
hash,
rendererListDesc);
hash = RuntimeStateHashUtility.Combine(
hash,
drawingSettings);
return hash;
}
}
}

View File

@@ -6,7 +6,9 @@ namespace XCEngine.Rendering.Universal
public sealed class RenderObjectsRendererFeature
: ScriptableRendererFeature
{
private DrawObjectsPass m_pass;
private readonly UniversalRenderObjectsFeatureController
m_controller =
new UniversalRenderObjectsFeatureController();
public RenderPassEvent passEvent =
RenderPassEvent.AfterRenderingOpaques;
@@ -32,91 +34,15 @@ namespace XCEngine.Rendering.Universal
{
int hash =
base.ComputeRuntimeStateHash();
hash =
RuntimeStateHashUtility.Combine(
hash,
(int)passEvent);
hash =
RuntimeStateHashUtility.Combine(
hash,
(int)scenePhase);
hash =
RuntimeStateHashUtility.Combine(
hash,
(int)rendererListType);
hash =
RuntimeStateHashUtility.Combine(
hash,
overrideRenderQueueRange);
hash =
RuntimeStateHashUtility.Combine(
hash,
renderQueueRange);
hash =
RuntimeStateHashUtility.Combine(
hash,
overrideRenderLayerMask);
hash =
RuntimeStateHashUtility.Combine(
hash,
renderLayerMask);
hash =
RuntimeStateHashUtility.Combine(
hash,
overrideMaterialPath);
hash =
RuntimeStateHashUtility.Combine(
hash,
shaderPassName);
hash =
RuntimeStateHashUtility.Combine(
hash,
overrideRenderStateBlock);
hash =
RuntimeStateHashUtility.Combine(
hash,
renderStateBlock);
hash =
RuntimeStateHashUtility.Combine(
hash,
overrideFilteringSettings);
hash =
RuntimeStateHashUtility.Combine(
hash,
filteringSettings);
hash =
RuntimeStateHashUtility.Combine(
hash,
overrideSortingSettings);
hash =
RuntimeStateHashUtility.Combine(
hash,
sortingSettings);
return hash;
return m_controller.AppendRuntimeStateHash(
hash,
BuildSettings());
}
public override void Create()
{
RendererListDesc rendererListDesc =
BuildRendererListDesc();
DrawingSettings drawingSettings =
BuildDrawingSettings();
if (m_pass == null)
{
m_pass =
new DrawObjectsPass(
passEvent,
scenePhase,
rendererListDesc,
drawingSettings);
return;
}
m_pass.Configure(
passEvent,
scenePhase,
rendererListDesc,
drawingSettings);
m_controller.Create(
BuildSettings());
}
public override void AddRenderPasses(
@@ -130,13 +56,21 @@ namespace XCEngine.Rendering.Universal
}
CreateInstance();
m_controller.EnqueuePass(
renderer,
renderingData,
BuildSettings());
}
m_pass.Configure(
passEvent,
scenePhase,
BuildRendererListDesc(),
BuildDrawingSettings());
renderer.EnqueuePass(m_pass);
private RenderObjectsFeatureSettings BuildSettings()
{
return new RenderObjectsFeatureSettings
{
passEvent = passEvent,
scenePhase = scenePhase,
rendererListDesc = BuildRendererListDesc(),
drawingSettings = BuildDrawingSettings()
};
}
private RendererListDesc BuildRendererListDesc()

View File

@@ -1,5 +1,4 @@
using System;
using System.Runtime.CompilerServices;
using XCEngine;
using XCEngine.Rendering;
@@ -11,11 +10,15 @@ namespace XCEngine.Rendering.Universal
public ScriptableRendererData[] rendererDataList =
Array.Empty<ScriptableRendererData>();
public int defaultRendererIndex = 0;
private readonly ScriptableRendererDataCollection
m_rendererDataCollection;
private int m_rendererDataRuntimeStateHash;
private bool m_rendererDataRuntimeStateHashResolved;
protected RendererBackedRenderPipelineAsset()
{
m_rendererDataCollection =
new ScriptableRendererDataCollection();
}
protected override ScriptableRenderPipeline CreatePipeline()
@@ -96,30 +99,21 @@ namespace XCEngine.Rendering.Universal
protected override void ReleaseRuntimeResources()
{
ReleaseRendererDataRuntimeResources();
m_rendererDataCollection.ReleaseRuntimeResources(
ref rendererDataList,
ref defaultRendererIndex,
CreateDefaultRendererData);
}
protected override void SynchronizeRuntimeResourceVersion()
{
int runtimeStateHash =
ComputeRendererDataRuntimeStateHash();
if (!m_rendererDataRuntimeStateHashResolved)
{
m_rendererDataRuntimeStateHash =
runtimeStateHash;
m_rendererDataRuntimeStateHashResolved = true;
return;
}
if (runtimeStateHash ==
m_rendererDataRuntimeStateHash)
{
return;
}
m_rendererDataRuntimeStateHash =
runtimeStateHash;
SetDirty();
m_rendererDataCollection.Synchronize(
ref rendererDataList,
ref defaultRendererIndex,
ref m_rendererDataRuntimeStateHash,
ref m_rendererDataRuntimeStateHashResolved,
CreateDefaultRendererData,
SetDirty);
}
protected virtual ScriptableRenderPipeline
@@ -150,15 +144,12 @@ namespace XCEngine.Rendering.Universal
return true;
}
private protected override bool UsesNativeCameraFramePlanBaselineContextual(
int rendererIndex)
{
return UsesExplicitFullscreenStagePlanning();
}
internal ScriptableRendererData GetDefaultRendererData()
{
return ResolveSelectedRendererData();
return m_rendererDataCollection.GetDefaultRendererData(
ref rendererDataList,
ref defaultRendererIndex,
CreateDefaultRendererData);
}
internal ScriptableRenderer GetDefaultRenderer()
@@ -168,8 +159,7 @@ namespace XCEngine.Rendering.Universal
internal ScriptableRendererData ResolveSelectedRendererData()
{
return ResolveRendererDataByResolvedIndex(
ResolveSelectedRendererIndex());
return GetDefaultRendererData();
}
internal ScriptableRenderer ResolveSelectedRenderer()
@@ -184,9 +174,11 @@ namespace XCEngine.Rendering.Universal
internal ScriptableRendererData GetRendererData(
int rendererIndex)
{
return ResolveRendererDataByResolvedIndex(
ResolveRendererIndexWithFallback(
rendererIndex));
return m_rendererDataCollection.GetRendererData(
ref rendererDataList,
ref defaultRendererIndex,
rendererIndex,
CreateDefaultRendererData);
}
internal ScriptableRenderer ResolveRenderer(
@@ -199,113 +191,13 @@ namespace XCEngine.Rendering.Universal
: null;
}
protected internal void ReleaseRendererDataRuntimeResources()
{
EnsureRendererDataList();
for (int i = 0; i < rendererDataList.Length; ++i)
{
ScriptableRendererData rendererData =
rendererDataList[i];
if (rendererData == null ||
WasRendererDataReleasedEarlier(i))
{
continue;
}
rendererData.ReleaseRuntimeResourcesInstance();
}
}
private void EnsureRendererDataList()
{
if (rendererDataList != null &&
rendererDataList.Length > 0)
{
return;
}
ScriptableRendererData defaultRendererData =
CreateDefaultRendererData();
rendererDataList =
defaultRendererData != null
? new ScriptableRendererData[]
{
defaultRendererData
}
: Array.Empty<ScriptableRendererData>();
defaultRendererIndex = 0;
}
private bool WasRendererDataReleasedEarlier(
int rendererDataIndex)
{
ScriptableRendererData rendererData =
rendererDataList[rendererDataIndex];
for (int i = 0; i < rendererDataIndex; ++i)
{
if (object.ReferenceEquals(
rendererDataList[i],
rendererData))
{
return true;
}
}
return false;
}
private int ComputeRendererDataRuntimeStateHash()
{
unchecked
{
int hash = 17;
hash =
(hash * 31) +
ResolveSelectedRendererIndex();
if (rendererDataList == null)
{
return hash;
}
hash = (hash * 31) + rendererDataList.Length;
for (int i = 0; i < rendererDataList.Length; ++i)
{
ScriptableRendererData rendererData =
rendererDataList[i];
if (rendererData != null)
{
hash =
(hash * 31) +
RuntimeHelpers.GetHashCode(
rendererData);
hash =
(hash * 31) +
rendererData
.GetRuntimeStateVersionInstance();
}
}
return hash;
}
}
private ScriptableRendererData ResolveRendererDataByResolvedIndex(
int resolvedRendererIndex)
{
EnsureRendererDataList();
if (resolvedRendererIndex < 0)
{
return null;
}
return rendererDataList[resolvedRendererIndex];
}
private int ResolveSelectedRendererIndex()
{
return ResolveRendererIndexWithFallback(
defaultRendererIndex);
return m_rendererDataCollection
.ResolveDefaultRendererIndex(
ref rendererDataList,
ref defaultRendererIndex,
CreateDefaultRendererData);
}
private ScriptableRendererData ResolveRendererData(
@@ -354,76 +246,12 @@ namespace XCEngine.Rendering.Universal
}
context.rendererIndex =
ResolveRendererIndexWithFallback(
rendererIndex);
}
private int ResolveRendererIndexWithFallback(
int rendererIndex)
{
EnsureRendererDataList();
if (rendererDataList.Length == 0)
{
return -1;
}
if (rendererIndex < 0 ||
rendererIndex >= rendererDataList.Length)
{
return ResolveDefaultRendererIndex();
}
if (rendererDataList[rendererIndex] == null)
{
return ResolveDefaultRendererIndex();
}
return rendererIndex;
}
private int ResolveDefaultRendererIndex()
{
EnsureRendererDataList();
if (rendererDataList.Length == 0)
{
return -1;
}
if (defaultRendererIndex < 0 ||
defaultRendererIndex >= rendererDataList.Length)
{
defaultRendererIndex = 0;
}
if (rendererDataList[defaultRendererIndex] != null)
{
return defaultRendererIndex;
}
int firstValidRendererIndex =
FindFirstValidRendererIndex();
if (firstValidRendererIndex >= 0)
{
defaultRendererIndex = firstValidRendererIndex;
return defaultRendererIndex;
}
rendererDataList[defaultRendererIndex] =
CreateDefaultRendererData();
return defaultRendererIndex;
}
private int FindFirstValidRendererIndex()
{
for (int i = 0; i < rendererDataList.Length; ++i)
{
if (rendererDataList[i] != null)
{
return i;
}
}
return -1;
m_rendererDataCollection
.ResolveRendererIndexWithFallback(
ref rendererDataList,
ref defaultRendererIndex,
rendererIndex,
CreateDefaultRendererData);
}
}
}

View File

@@ -0,0 +1,41 @@
using XCEngine.Rendering;
namespace XCEngine.Rendering.Universal
{
internal enum RendererBlock
{
ShadowCaster = 0,
DepthPrepass = 1,
MainOpaque = 2,
MainSkybox = 3,
MainTransparent = 4,
PostProcess = 5,
FinalOutput = 6,
Count = 7
}
internal static class RendererBlockUtility
{
public static CameraFrameStage GetStage(
RendererBlock block)
{
switch (block)
{
case RendererBlock.ShadowCaster:
return CameraFrameStage.ShadowCaster;
case RendererBlock.DepthPrepass:
return CameraFrameStage.DepthOnly;
case RendererBlock.MainOpaque:
case RendererBlock.MainSkybox:
case RendererBlock.MainTransparent:
return CameraFrameStage.MainScene;
case RendererBlock.PostProcess:
return CameraFrameStage.PostProcess;
case RendererBlock.FinalOutput:
return CameraFrameStage.FinalOutput;
default:
return CameraFrameStage.MainScene;
}
}
}
}

View File

@@ -0,0 +1,89 @@
using System.Collections.Generic;
namespace XCEngine.Rendering.Universal
{
internal sealed class RendererBlocks
{
private struct BlockRange
{
public int firstPassIndex;
public int lastPassIndex;
}
private readonly BlockRange[] m_ranges =
new BlockRange[(int)RendererBlock.Count];
public RendererBlocks()
{
Clear();
}
public void Clear()
{
for (int i = 0; i < m_ranges.Length; ++i)
{
m_ranges[i].firstPassIndex = -1;
m_ranges[i].lastPassIndex = -1;
}
}
public void Build(
IList<ScriptableRenderPass> activePassQueue)
{
Clear();
if (activePassQueue == null)
{
return;
}
for (int i = 0; i < activePassQueue.Count; ++i)
{
ScriptableRenderPass renderPass =
activePassQueue[i];
if (renderPass == null)
{
continue;
}
RendererBlock block;
if (!ScriptableRenderPass.TryResolveRendererBlock(
renderPass.renderPassEvent,
out block))
{
continue;
}
int blockIndex = (int)block;
BlockRange range = m_ranges[blockIndex];
if (range.firstPassIndex < 0)
{
range.firstPassIndex = i;
}
range.lastPassIndex = i;
m_ranges[blockIndex] = range;
}
}
public bool HasPasses(
RendererBlock block)
{
BlockRange range = m_ranges[(int)block];
return range.firstPassIndex >= 0 &&
range.lastPassIndex >= range.firstPassIndex;
}
public bool TryGetPassRange(
RendererBlock block,
out int firstPassIndex,
out int lastPassIndex)
{
BlockRange range = m_ranges[(int)block];
firstPassIndex = range.firstPassIndex;
lastPassIndex = range.lastPassIndex;
return range.firstPassIndex >= 0 &&
range.lastPassIndex >= range.firstPassIndex;
}
}
}

View File

@@ -75,6 +75,44 @@ namespace XCEngine.Rendering.Universal
}
}
public RenderClearFlags clearFlags
{
get =>
m_requestContext != null
? m_requestContext.clearFlags
: RenderClearFlags.All;
set
{
if (m_requestContext != null)
{
m_requestContext.clearFlags = value;
}
}
}
public void SetResolvedFinalColorPolicy(
FinalColorSettings settings,
bool hasPipelineDefaults,
bool hasCameraOverrides)
{
if (m_requestContext != null)
{
m_requestContext
.SetResolvedFinalColorPolicy(
settings,
hasPipelineDefaults,
hasCameraOverrides);
}
}
public void ClearFinalColorPolicy()
{
if (m_requestContext != null)
{
m_requestContext.ClearFinalColorPolicy();
}
}
internal CameraRenderRequestContext requestContext =>
m_requestContext;
}

View File

@@ -23,11 +23,21 @@ namespace XCEngine.Rendering.Universal
public virtual bool SupportsStage(
CameraFrameStage stage)
{
CameraFrameStage resolvedStage;
return TryResolveStage(
RendererBlock block;
return TryResolveRendererBlock(
renderPassEvent,
out resolvedStage) &&
resolvedStage == stage;
out block) &&
RendererBlockUtility.GetStage(block) == stage;
}
internal bool SupportsRendererBlock(
RendererBlock block)
{
RendererBlock resolvedBlock;
return TryResolveRendererBlock(
renderPassEvent,
out resolvedBlock) &&
resolvedBlock == block;
}
internal bool Record(
@@ -209,38 +219,60 @@ namespace XCEngine.Rendering.Universal
internal static bool TryResolveStage(
RenderPassEvent passEvent,
out CameraFrameStage stage)
{
RendererBlock block;
if (TryResolveRendererBlock(
passEvent,
out block))
{
stage =
RendererBlockUtility.GetStage(block);
return true;
}
stage = CameraFrameStage.MainScene;
return false;
}
internal static bool TryResolveRendererBlock(
RenderPassEvent passEvent,
out RendererBlock block)
{
switch (passEvent)
{
case RenderPassEvent.BeforeRenderingShadows:
case RenderPassEvent.AfterRenderingShadows:
stage = CameraFrameStage.ShadowCaster;
block = RendererBlock.ShadowCaster;
return true;
case RenderPassEvent.BeforeRenderingPrePasses:
case RenderPassEvent.AfterRenderingPrePasses:
stage = CameraFrameStage.DepthOnly;
block = RendererBlock.DepthPrepass;
return true;
case RenderPassEvent.BeforeRenderingOpaques:
case RenderPassEvent.RenderOpaques:
case RenderPassEvent.AfterRenderingOpaques:
block = RendererBlock.MainOpaque;
return true;
case RenderPassEvent.BeforeRenderingSkybox:
case RenderPassEvent.RenderSkybox:
case RenderPassEvent.AfterRenderingSkybox:
block = RendererBlock.MainSkybox;
return true;
case RenderPassEvent.BeforeRenderingTransparents:
case RenderPassEvent.RenderTransparents:
case RenderPassEvent.AfterRenderingTransparents:
stage = CameraFrameStage.MainScene;
block = RendererBlock.MainTransparent;
return true;
case RenderPassEvent.BeforeRenderingPostProcessing:
case RenderPassEvent.AfterRenderingPostProcessing:
stage = CameraFrameStage.PostProcess;
block = RendererBlock.PostProcess;
return true;
case RenderPassEvent.BeforeRenderingFinalOutput:
case RenderPassEvent.AfterRenderingFinalOutput:
stage = CameraFrameStage.FinalOutput;
block = RendererBlock.FinalOutput;
return true;
default:
stage = CameraFrameStage.MainScene;
block = RendererBlock.MainOpaque;
return false;
}
}

View File

@@ -10,6 +10,11 @@ namespace XCEngine.Rendering.Universal
new List<ScriptableRendererFeature>();
private readonly List<ScriptableRenderPass> m_activePassQueue =
new List<ScriptableRenderPass>();
private readonly RendererBlocks m_rendererBlocks =
new RendererBlocks();
private bool m_isBuildingPassQueue;
private CameraFrameStage m_passQueueStage =
CameraFrameStage.MainScene;
private bool m_disposed;
protected ScriptableRenderer()
@@ -36,6 +41,7 @@ namespace XCEngine.Rendering.Universal
m_features.Clear();
m_activePassQueue.Clear();
m_rendererBlocks.Clear();
m_disposed = true;
}
@@ -47,6 +53,19 @@ namespace XCEngine.Rendering.Universal
return;
}
if (m_isBuildingPassQueue &&
!renderPass.SupportsStage(m_passQueueStage))
{
return;
}
InsertActivePass(
renderPass);
}
private void InsertActivePass(
ScriptableRenderPass renderPass)
{
int insertIndex = m_activePassQueue.Count;
while (insertIndex > 0 &&
m_activePassQueue[insertIndex - 1].renderPassEvent >
@@ -130,17 +149,7 @@ namespace XCEngine.Rendering.Universal
RenderingData renderingData =
context.renderingData;
BuildPassQueue(renderingData);
for (int i = 0; i < m_activePassQueue.Count; ++i)
{
ScriptableRenderPass renderPass = m_activePassQueue[i];
if (renderPass != null &&
renderPass.SupportsStage(context.stage))
{
return true;
}
}
return false;
return SupportsRendererStage(context);
}
protected virtual bool RecordRenderer(
@@ -155,28 +164,7 @@ namespace XCEngine.Rendering.Universal
RenderingData renderingData =
context.renderingData;
BuildPassQueue(renderingData);
bool recordedAnyPass = false;
for (int i = 0; i < m_activePassQueue.Count; ++i)
{
ScriptableRenderPass renderPass = m_activePassQueue[i];
if (renderPass == null ||
!renderPass.SupportsStage(renderingData.stage))
{
continue;
}
if (!renderPass.Record(
context.renderContext,
renderingData))
{
return false;
}
recordedAnyPass = true;
}
return recordedAnyPass;
return RecordRendererStage(context);
}
protected internal virtual bool SupportsStageRenderGraph(
@@ -202,13 +190,6 @@ namespace XCEngine.Rendering.Universal
protected virtual void FinalizeCameraFramePlan(
ScriptableRenderPipelinePlanningContext context)
{
if (context == null)
{
return;
}
ApplyInferredFullscreenStageRequests(
context);
}
protected virtual void ConfigureRenderSceneSetup(
@@ -221,155 +202,187 @@ namespace XCEngine.Rendering.Universal
{
}
private void BuildPassQueue(
RenderingData renderingData)
private bool HasRendererBlock(
RendererBlock block)
{
m_activePassQueue.Clear();
return m_rendererBlocks.HasPasses(block);
}
for (int i = 0; i < m_features.Count; ++i)
protected virtual bool SupportsRendererStage(
RendererRecordingContext context)
{
if (context == null)
{
ScriptableRendererFeature feature = m_features[i];
if (feature == null || !feature.isActive)
return false;
}
switch (context.stage)
{
case CameraFrameStage.ShadowCaster:
return HasRendererBlock(
RendererBlock.ShadowCaster);
case CameraFrameStage.DepthOnly:
return HasRendererBlock(
RendererBlock.DepthPrepass);
case CameraFrameStage.MainScene:
return HasRendererBlock(
RendererBlock.MainOpaque) ||
HasRendererBlock(
RendererBlock.MainSkybox) ||
HasRendererBlock(
RendererBlock.MainTransparent);
case CameraFrameStage.PostProcess:
return HasRendererBlock(
RendererBlock.PostProcess);
case CameraFrameStage.FinalOutput:
return HasRendererBlock(
RendererBlock.FinalOutput);
default:
return false;
}
}
protected virtual bool RecordRendererStage(
RendererRecordingContext context)
{
if (context == null ||
context.renderContext == null)
{
return false;
}
bool recordedAnyPass = false;
switch (context.stage)
{
case CameraFrameStage.ShadowCaster:
return RecordRendererBlock(
RendererBlock.ShadowCaster,
context,
ref recordedAnyPass) &&
recordedAnyPass;
case CameraFrameStage.DepthOnly:
return RecordRendererBlock(
RendererBlock.DepthPrepass,
context,
ref recordedAnyPass) &&
recordedAnyPass;
case CameraFrameStage.MainScene:
return RecordRendererBlock(
RendererBlock.MainOpaque,
context,
ref recordedAnyPass) &&
RecordRendererBlock(
RendererBlock.MainSkybox,
context,
ref recordedAnyPass) &&
RecordRendererBlock(
RendererBlock.MainTransparent,
context,
ref recordedAnyPass) &&
recordedAnyPass;
case CameraFrameStage.PostProcess:
return RecordRendererBlock(
RendererBlock.PostProcess,
context,
ref recordedAnyPass) &&
recordedAnyPass;
case CameraFrameStage.FinalOutput:
return RecordRendererBlock(
RendererBlock.FinalOutput,
context,
ref recordedAnyPass) &&
recordedAnyPass;
default:
return false;
}
}
private bool RecordRendererBlock(
RendererBlock block,
RendererRecordingContext context,
ref bool recordedAnyPass)
{
if (context == null ||
context.renderContext == null)
{
return false;
}
int firstPassIndex;
int lastPassIndex;
if (!m_rendererBlocks.TryGetPassRange(
block,
out firstPassIndex,
out lastPassIndex))
{
return true;
}
for (int i = firstPassIndex;
i <= lastPassIndex;
++i)
{
ScriptableRenderPass renderPass =
m_activePassQueue[i];
if (renderPass == null ||
!renderPass.SupportsRendererBlock(block))
{
continue;
}
feature.AddRenderPasses(
this,
renderingData);
if (!renderPass.Record(
context.renderContext,
context.renderingData))
{
return false;
}
recordedAnyPass = true;
}
AddRenderPasses(renderingData);
return true;
}
private void BuildPassQueue(
RenderingData renderingData)
{
m_activePassQueue.Clear();
m_rendererBlocks.Clear();
m_isBuildingPassQueue = true;
m_passQueueStage =
renderingData != null
? renderingData.stage
: CameraFrameStage.MainScene;
try
{
for (int i = 0; i < m_features.Count; ++i)
{
ScriptableRendererFeature feature = m_features[i];
if (feature == null || !feature.isActive)
{
continue;
}
feature.AddRenderPasses(
this,
renderingData);
}
AddRenderPasses(renderingData);
m_rendererBlocks.Build(m_activePassQueue);
}
finally
{
m_isBuildingPassQueue = false;
m_passQueueStage =
CameraFrameStage.MainScene;
}
}
protected virtual void ReleaseRuntimeResources()
{
}
protected virtual RenderingData CreatePlanningRenderingData(
ScriptableRenderPipelinePlanningContext context)
{
return context != null
? new RenderingData(
CameraFrameStage.MainScene,
context.rendererIndex)
: null;
}
private void ApplyInferredFullscreenStageRequests(
ScriptableRenderPipelinePlanningContext context)
{
RenderingData planningData =
CreatePlanningRenderingData(context);
if (planningData == null)
{
return;
}
BuildPassQueue(planningData);
ApplyInferredStandaloneStageRequests(
context);
bool hasPostProcessPass =
HasQueuedPassForStage(
CameraFrameStage.PostProcess);
bool hasFinalOutputPass =
HasQueuedPassForStage(
CameraFrameStage.FinalOutput);
bool needsFinalOutputDependency =
context.HasFinalColorProcessing() ||
context.IsStageRequested(
CameraFrameStage.FinalOutput) ||
hasFinalOutputPass;
if (hasPostProcessPass)
{
EnsureInferredPostProcessStage(
context,
needsFinalOutputDependency);
}
if (hasFinalOutputPass &&
!context.IsStageRequested(
CameraFrameStage.FinalOutput))
{
context.RequestFullscreenStage(
CameraFrameStage.FinalOutput,
context.IsStageRequested(
CameraFrameStage.PostProcess)
? CameraFrameColorSource.PostProcessColor
: CameraFrameColorSource.MainSceneColor);
}
}
private void ApplyInferredStandaloneStageRequests(
ScriptableRenderPipelinePlanningContext context)
{
if (!context.HasExplicitShadowCasterStageConfiguration() &&
HasQueuedPassForStage(
CameraFrameStage.ShadowCaster))
{
context.RequestShadowCasterStage();
}
if (!context.HasExplicitDepthOnlyStageConfiguration() &&
HasQueuedPassForStage(
CameraFrameStage.DepthOnly))
{
context.RequestDepthOnlyStage();
}
}
private bool HasQueuedPassForStage(
CameraFrameStage stage)
{
for (int i = 0; i < m_activePassQueue.Count; ++i)
{
ScriptableRenderPass renderPass =
m_activePassQueue[i];
if (renderPass != null &&
renderPass.SupportsStage(stage))
{
return true;
}
}
return false;
}
private static void EnsureInferredPostProcessStage(
ScriptableRenderPipelinePlanningContext context,
bool needsGraphManagedOutputColor)
{
if (!context.IsStageRequested(
CameraFrameStage.PostProcess))
{
context.RequestFullscreenStage(
CameraFrameStage.PostProcess,
CameraFrameColorSource.MainSceneColor,
needsGraphManagedOutputColor);
return;
}
CameraFrameColorSource source =
context.GetStageColorSource(
CameraFrameStage.PostProcess);
if (!needsGraphManagedOutputColor ||
source ==
CameraFrameColorSource.ExplicitSurface ||
context.UsesGraphManagedOutputColor(
CameraFrameStage.PostProcess))
{
return;
}
context.ClearFullscreenStage(
CameraFrameStage.PostProcess);
context.RequestFullscreenStage(
CameraFrameStage.PostProcess,
source,
true);
}
}
}

View File

@@ -9,7 +9,8 @@ namespace XCEngine.Rendering.Universal
: ScriptableObject
{
public ScriptableRendererFeature[] rendererFeatures;
private ScriptableRendererFeature[] m_rendererFeatures;
private readonly ScriptableRendererFeatureCollection
m_featureCollection;
private ScriptableRenderer m_rendererInstance;
private bool m_rendererInvalidated;
private int m_runtimeStateVersion = 1;
@@ -20,6 +21,8 @@ namespace XCEngine.Rendering.Universal
{
rendererFeatures =
Array.Empty<ScriptableRendererFeature>();
m_featureCollection =
new ScriptableRendererFeatureCollection(this);
}
internal ScriptableRenderer CreateRendererInstance()
@@ -60,11 +63,10 @@ namespace XCEngine.Rendering.Universal
internal void InvalidateRendererFeaturesInstance()
{
m_rendererFeatureCollectionHash =
ComputeRendererFeatureCollectionHash(
rendererFeatures ??
Array.Empty<ScriptableRendererFeature>());
m_rendererFeatureCollectionHashResolved = true;
m_featureCollection.Invalidate(
ref rendererFeatures,
ref m_rendererFeatureCollectionHash,
ref m_rendererFeatureCollectionHashResolved);
SetDirty();
}
@@ -85,22 +87,9 @@ namespace XCEngine.Rendering.Universal
CameraRenderRequestContext context)
{
ConfigureCameraRenderRequest(context);
ScriptableRendererFeature[] rendererFeatures =
GetRendererFeatures();
for (int i = 0; i < rendererFeatures.Length; ++i)
{
ScriptableRendererFeature rendererFeature =
rendererFeatures[i];
if (rendererFeature == null ||
!rendererFeature.isActive)
{
continue;
}
rendererFeature.ConfigureCameraRenderRequest(
context);
}
m_featureCollection.ConfigureCameraRenderRequest(
ref rendererFeatures,
context);
}
internal void ConfigureCameraFramePlanInstance(
@@ -116,21 +105,9 @@ namespace XCEngine.Rendering.Universal
context);
}
ScriptableRendererFeature[] rendererFeatures =
GetRendererFeatures();
for (int i = 0; i < rendererFeatures.Length; ++i)
{
ScriptableRendererFeature rendererFeature =
rendererFeatures[i];
if (rendererFeature == null ||
!rendererFeature.isActive)
{
continue;
}
rendererFeature.ConfigureCameraFramePlan(
context);
}
m_featureCollection.ConfigureCameraFramePlan(
ref rendererFeatures,
context);
if (renderer != null)
{
@@ -152,21 +129,9 @@ namespace XCEngine.Rendering.Universal
context);
}
ScriptableRendererFeature[] rendererFeatures =
GetRendererFeatures();
for (int i = 0; i < rendererFeatures.Length; ++i)
{
ScriptableRendererFeature rendererFeature =
rendererFeatures[i];
if (rendererFeature == null ||
!rendererFeature.isActive)
{
continue;
}
rendererFeature.ConfigureRenderSceneSetup(
context);
}
m_featureCollection.ConfigureRenderSceneSetup(
ref rendererFeatures,
context);
return context != null &&
context.isConfigured;
@@ -187,22 +152,10 @@ namespace XCEngine.Rendering.Universal
context);
}
ScriptableRendererFeature[] rendererFeatures =
GetRendererFeatures();
for (int i = 0; i < rendererFeatures.Length; ++i)
{
ScriptableRendererFeature rendererFeature =
rendererFeatures[i];
if (rendererFeature == null ||
!rendererFeature.isActive)
{
continue;
}
rendererFeature
.ConfigureDirectionalShadowExecutionState(
context);
}
m_featureCollection
.ConfigureDirectionalShadowExecutionState(
ref rendererFeatures,
context);
return context != null &&
context.isConfigured;
@@ -329,110 +282,25 @@ namespace XCEngine.Rendering.Universal
protected void ResetRendererFeaturesToDefault()
{
rendererFeatures =
m_featureCollection.Reset(
ref rendererFeatures,
CreateDefaultRendererFeatures() ??
Array.Empty<ScriptableRendererFeature>();
BindRendererFeatureOwners(rendererFeatures);
Array.Empty<ScriptableRendererFeature>());
}
private ScriptableRendererFeature[] GetRendererFeatures()
{
if (m_rendererFeatures == null)
{
ScriptableRendererFeature[]
configuredRendererFeatures =
rendererFeatures ??
Array.Empty<ScriptableRendererFeature>();
rendererFeatures =
configuredRendererFeatures;
m_rendererFeatures =
configuredRendererFeatures;
}
BindRendererFeatureOwners(m_rendererFeatures);
return m_rendererFeatures;
return m_featureCollection.GetFeatures(
ref rendererFeatures);
}
private void SynchronizeRendererFeatureCollectionState()
{
ScriptableRendererFeature[] configuredRendererFeatures =
rendererFeatures ??
Array.Empty<ScriptableRendererFeature>();
BindRendererFeatureOwners(configuredRendererFeatures);
int collectionHash =
ComputeRendererFeatureCollectionHash(
configuredRendererFeatures);
if (!m_rendererFeatureCollectionHashResolved)
{
m_rendererFeatureCollectionHash = collectionHash;
m_rendererFeatureCollectionHashResolved = true;
return;
}
if (collectionHash == m_rendererFeatureCollectionHash)
{
return;
}
m_rendererFeatureCollectionHash = collectionHash;
SetDirty();
}
private void BindRendererFeatureOwners(
ScriptableRendererFeature[] rendererFeatureCollection)
{
if (rendererFeatureCollection == null)
{
return;
}
for (int i = 0; i < rendererFeatureCollection.Length; ++i)
{
ScriptableRendererFeature rendererFeature =
rendererFeatureCollection[i];
if (rendererFeature != null)
{
rendererFeature.BindOwnerInstance(this);
}
}
}
private static int ComputeRendererFeatureCollectionHash(
ScriptableRendererFeature[] rendererFeatureCollection)
{
unchecked
{
int hash = 17;
if (rendererFeatureCollection == null)
{
return hash;
}
hash =
(hash * 31) +
rendererFeatureCollection.Length;
for (int i = 0; i < rendererFeatureCollection.Length; ++i)
{
ScriptableRendererFeature rendererFeature =
rendererFeatureCollection[i];
if (rendererFeature == null)
{
hash = (hash * 31) + 1;
continue;
}
hash =
(hash * 31) +
RuntimeHelpers.GetHashCode(rendererFeature);
hash =
(hash * 31) +
rendererFeature
.GetRuntimeStateVersionInstance();
}
return hash;
}
m_featureCollection.Synchronize(
ref rendererFeatures,
ref m_rendererFeatureCollectionHash,
ref m_rendererFeatureCollectionHashResolved,
SetDirty);
}
private void ReleaseRendererSetupCache()
@@ -441,26 +309,11 @@ namespace XCEngine.Rendering.Universal
{
m_rendererInstance.ReleaseRuntimeResourcesInstance();
m_rendererInstance = null;
m_rendererFeatures = null;
m_featureCollection.ResetResolvedCache();
return;
}
if (m_rendererFeatures == null)
{
return;
}
for (int i = 0; i < m_rendererFeatures.Length; ++i)
{
ScriptableRendererFeature rendererFeature =
m_rendererFeatures[i];
if (rendererFeature != null)
{
rendererFeature.ReleaseRuntimeResourcesInstance();
}
}
m_rendererFeatures = null;
m_featureCollection.ReleaseRuntimeResources();
}
}
}

View File

@@ -0,0 +1,283 @@
using System;
using System.Runtime.CompilerServices;
namespace XCEngine.Rendering.Universal
{
internal sealed class ScriptableRendererDataCollection
{
private ScriptableRendererData[] m_rendererDataList;
public ScriptableRendererDataCollection()
{
m_rendererDataList =
Array.Empty<ScriptableRendererData>();
}
public ScriptableRendererData GetDefaultRendererData(
ref ScriptableRendererData[] configuredRendererDataList,
ref int defaultRendererIndex,
Func<ScriptableRendererData> createDefaultRendererData)
{
return GetRendererData(
ref configuredRendererDataList,
ref defaultRendererIndex,
ResolveDefaultRendererIndex(
ref configuredRendererDataList,
ref defaultRendererIndex,
createDefaultRendererData),
createDefaultRendererData);
}
public ScriptableRendererData GetRendererData(
ref ScriptableRendererData[] configuredRendererDataList,
ref int defaultRendererIndex,
int rendererIndex,
Func<ScriptableRendererData> createDefaultRendererData)
{
int resolvedRendererIndex =
ResolveRendererIndexWithFallback(
ref configuredRendererDataList,
ref defaultRendererIndex,
rendererIndex,
createDefaultRendererData);
if (resolvedRendererIndex < 0)
{
return null;
}
return m_rendererDataList[resolvedRendererIndex];
}
public int ResolveDefaultRendererIndex(
ref ScriptableRendererData[] configuredRendererDataList,
ref int defaultRendererIndex,
Func<ScriptableRendererData> createDefaultRendererData)
{
ScriptableRendererData[] rendererDataList =
ResolveConfiguredRendererDataList(
ref configuredRendererDataList,
createDefaultRendererData);
if (rendererDataList.Length == 0)
{
return -1;
}
if (defaultRendererIndex < 0 ||
defaultRendererIndex >= rendererDataList.Length)
{
defaultRendererIndex = 0;
}
if (rendererDataList[defaultRendererIndex] != null)
{
return defaultRendererIndex;
}
int firstValidRendererIndex =
FindFirstValidRendererIndex(rendererDataList);
if (firstValidRendererIndex >= 0)
{
defaultRendererIndex = firstValidRendererIndex;
return defaultRendererIndex;
}
rendererDataList[defaultRendererIndex] =
createDefaultRendererData != null
? createDefaultRendererData()
: null;
return rendererDataList[defaultRendererIndex] != null
? defaultRendererIndex
: -1;
}
public int ResolveRendererIndexWithFallback(
ref ScriptableRendererData[] configuredRendererDataList,
ref int defaultRendererIndex,
int rendererIndex,
Func<ScriptableRendererData> createDefaultRendererData)
{
ScriptableRendererData[] rendererDataList =
ResolveConfiguredRendererDataList(
ref configuredRendererDataList,
createDefaultRendererData);
if (rendererDataList.Length == 0)
{
return -1;
}
if (rendererIndex < 0 ||
rendererIndex >= rendererDataList.Length)
{
return ResolveDefaultRendererIndex(
ref configuredRendererDataList,
ref defaultRendererIndex,
createDefaultRendererData);
}
if (rendererDataList[rendererIndex] == null)
{
return ResolveDefaultRendererIndex(
ref configuredRendererDataList,
ref defaultRendererIndex,
createDefaultRendererData);
}
return rendererIndex;
}
public void Synchronize(
ref ScriptableRendererData[] configuredRendererDataList,
ref int defaultRendererIndex,
ref int collectionHash,
ref bool collectionHashResolved,
Func<ScriptableRendererData> createDefaultRendererData,
Action onChanged)
{
ScriptableRendererData[] rendererDataList =
ResolveConfiguredRendererDataList(
ref configuredRendererDataList,
createDefaultRendererData);
int resolvedDefaultRendererIndex =
ResolveDefaultRendererIndex(
ref configuredRendererDataList,
ref defaultRendererIndex,
createDefaultRendererData);
int resolvedHash =
ComputeCollectionHash(
rendererDataList,
resolvedDefaultRendererIndex);
if (!collectionHashResolved)
{
collectionHash = resolvedHash;
collectionHashResolved = true;
return;
}
if (resolvedHash == collectionHash)
{
return;
}
collectionHash = resolvedHash;
onChanged?.Invoke();
}
public void ReleaseRuntimeResources(
ref ScriptableRendererData[] configuredRendererDataList,
ref int defaultRendererIndex,
Func<ScriptableRendererData> createDefaultRendererData)
{
ScriptableRendererData[] rendererDataList =
ResolveConfiguredRendererDataList(
ref configuredRendererDataList,
createDefaultRendererData);
for (int i = 0; i < rendererDataList.Length; ++i)
{
ScriptableRendererData rendererData =
rendererDataList[i];
if (rendererData == null ||
WasRendererDataReleasedEarlier(
rendererDataList,
i))
{
continue;
}
rendererData.ReleaseRuntimeResourcesInstance();
}
}
private ScriptableRendererData[] ResolveConfiguredRendererDataList(
ref ScriptableRendererData[] configuredRendererDataList,
Func<ScriptableRendererData> createDefaultRendererData)
{
if (configuredRendererDataList == null ||
configuredRendererDataList.Length == 0)
{
ScriptableRendererData defaultRendererData =
createDefaultRendererData != null
? createDefaultRendererData()
: null;
configuredRendererDataList =
defaultRendererData != null
? new ScriptableRendererData[]
{
defaultRendererData
}
: Array.Empty<ScriptableRendererData>();
}
m_rendererDataList = configuredRendererDataList;
return m_rendererDataList;
}
private static int ComputeCollectionHash(
ScriptableRendererData[] rendererDataList,
int defaultRendererIndex)
{
unchecked
{
int hash = 17;
hash = (hash * 31) + defaultRendererIndex;
if (rendererDataList == null)
{
return hash;
}
hash = (hash * 31) + rendererDataList.Length;
for (int i = 0; i < rendererDataList.Length; ++i)
{
ScriptableRendererData rendererData =
rendererDataList[i];
if (rendererData == null)
{
hash = (hash * 31) + 1;
continue;
}
hash =
(hash * 31) +
RuntimeHelpers.GetHashCode(rendererData);
hash =
(hash * 31) +
rendererData.GetRuntimeStateVersionInstance();
}
return hash;
}
}
private static int FindFirstValidRendererIndex(
ScriptableRendererData[] rendererDataList)
{
for (int i = 0; i < rendererDataList.Length; ++i)
{
if (rendererDataList[i] != null)
{
return i;
}
}
return -1;
}
private static bool WasRendererDataReleasedEarlier(
ScriptableRendererData[] rendererDataList,
int rendererDataIndex)
{
ScriptableRendererData rendererData =
rendererDataList[rendererDataIndex];
for (int i = 0; i < rendererDataIndex; ++i)
{
if (object.ReferenceEquals(
rendererDataList[i],
rendererData))
{
return true;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,262 @@
using System;
using System.Runtime.CompilerServices;
using XCEngine;
using XCEngine.Rendering;
namespace XCEngine.Rendering.Universal
{
internal sealed class ScriptableRendererFeatureCollection
{
private readonly ScriptableRendererData m_owner;
private ScriptableRendererFeature[] m_features;
public ScriptableRendererFeatureCollection(
ScriptableRendererData owner)
{
m_owner = owner;
m_features = Array.Empty<ScriptableRendererFeature>();
}
public ScriptableRendererFeature[] GetFeatures(
ref ScriptableRendererFeature[] configuredFeatures)
{
if (m_features == null)
{
ScriptableRendererFeature[] resolvedFeatures =
configuredFeatures ??
Array.Empty<ScriptableRendererFeature>();
configuredFeatures = resolvedFeatures;
m_features = resolvedFeatures;
}
BindOwners(m_features);
return m_features;
}
public void Reset(
ref ScriptableRendererFeature[] configuredFeatures,
ScriptableRendererFeature[] features)
{
configuredFeatures =
features ??
Array.Empty<ScriptableRendererFeature>();
m_features = configuredFeatures;
BindOwners(m_features);
}
public void Invalidate(
ref ScriptableRendererFeature[] configuredFeatures,
ref int collectionHash,
ref bool collectionHashResolved)
{
ScriptableRendererFeature[] features =
ResolveConfiguredFeatures(
ref configuredFeatures);
collectionHash =
ComputeCollectionHash(features);
collectionHashResolved = true;
}
public void Synchronize(
ref ScriptableRendererFeature[] configuredFeatures,
ref int collectionHash,
ref bool collectionHashResolved,
Action onChanged)
{
ScriptableRendererFeature[] features =
ResolveConfiguredFeatures(
ref configuredFeatures);
int resolvedHash =
ComputeCollectionHash(features);
if (!collectionHashResolved)
{
collectionHash = resolvedHash;
collectionHashResolved = true;
return;
}
if (resolvedHash == collectionHash)
{
return;
}
collectionHash = resolvedHash;
onChanged?.Invoke();
}
public void ConfigureCameraRenderRequest(
ref ScriptableRendererFeature[] configuredFeatures,
CameraRenderRequestContext context)
{
ScriptableRendererFeature[] features =
GetFeatures(ref configuredFeatures);
for (int i = 0; i < features.Length; ++i)
{
ScriptableRendererFeature feature =
features[i];
if (feature == null ||
!feature.isActive)
{
continue;
}
feature.ConfigureCameraRenderRequest(
context);
}
}
public void ConfigureCameraFramePlan(
ref ScriptableRendererFeature[] configuredFeatures,
ScriptableRenderPipelinePlanningContext context)
{
ScriptableRendererFeature[] features =
GetFeatures(ref configuredFeatures);
for (int i = 0; i < features.Length; ++i)
{
ScriptableRendererFeature feature =
features[i];
if (feature == null ||
!feature.isActive)
{
continue;
}
feature.ConfigureCameraFramePlan(
context);
}
}
public void ConfigureRenderSceneSetup(
ref ScriptableRendererFeature[] configuredFeatures,
RenderSceneSetupContext context)
{
ScriptableRendererFeature[] features =
GetFeatures(ref configuredFeatures);
for (int i = 0; i < features.Length; ++i)
{
ScriptableRendererFeature feature =
features[i];
if (feature == null ||
!feature.isActive)
{
continue;
}
feature.ConfigureRenderSceneSetup(
context);
}
}
public void ConfigureDirectionalShadowExecutionState(
ref ScriptableRendererFeature[] configuredFeatures,
DirectionalShadowExecutionContext context)
{
ScriptableRendererFeature[] features =
GetFeatures(ref configuredFeatures);
for (int i = 0; i < features.Length; ++i)
{
ScriptableRendererFeature feature =
features[i];
if (feature == null ||
!feature.isActive)
{
continue;
}
feature
.ConfigureDirectionalShadowExecutionState(
context);
}
}
public void ReleaseRuntimeResources()
{
if (m_features == null)
{
return;
}
for (int i = 0; i < m_features.Length; ++i)
{
ScriptableRendererFeature feature =
m_features[i];
if (feature != null)
{
feature.ReleaseRuntimeResourcesInstance();
}
}
m_features = null;
}
public void ResetResolvedCache()
{
m_features = null;
}
private ScriptableRendererFeature[] ResolveConfiguredFeatures(
ref ScriptableRendererFeature[] configuredFeatures)
{
ScriptableRendererFeature[] features =
configuredFeatures ??
Array.Empty<ScriptableRendererFeature>();
configuredFeatures = features;
m_features = features;
BindOwners(features);
return features;
}
private void BindOwners(
ScriptableRendererFeature[] features)
{
if (features == null)
{
return;
}
for (int i = 0; i < features.Length; ++i)
{
ScriptableRendererFeature feature =
features[i];
if (feature != null)
{
feature.BindOwnerInstance(m_owner);
}
}
}
private static int ComputeCollectionHash(
ScriptableRendererFeature[] features)
{
unchecked
{
int hash = 17;
if (features == null)
{
return hash;
}
hash = (hash * 31) + features.Length;
for (int i = 0; i < features.Length; ++i)
{
ScriptableRendererFeature feature =
features[i];
if (feature == null)
{
hash = (hash * 31) + 1;
continue;
}
hash =
(hash * 31) +
RuntimeHelpers.GetHashCode(feature);
hash =
(hash * 31) +
feature.GetRuntimeStateVersionInstance();
}
return hash;
}
}
}
}

View File

@@ -0,0 +1,59 @@
using XCEngine;
using XCEngine.Rendering;
namespace XCEngine.Rendering.Universal
{
internal sealed class UniversalColorScalePostProcessController
{
private readonly UniversalPostProcessBlock m_postProcessBlock =
new UniversalPostProcessBlock();
private ColorScalePostProcessPass m_pass;
public int AppendRuntimeStateHash(
int hash,
ColorScalePostProcessSettings settings)
{
return settings != null
? settings.AppendRuntimeStateHash(hash)
: hash;
}
public void Create(
ColorScalePostProcessSettings settings)
{
if (m_pass == null)
{
m_pass = new ColorScalePostProcessPass();
}
m_pass.Configure(
settings != null
? settings.colorScale
: new Vector4(
1.0f,
1.0f,
1.0f,
1.0f));
}
public void ConfigureCameraFramePlan(
ScriptableRenderPipelinePlanningContext context)
{
m_postProcessBlock.ConfigureCameraFramePlan(
context,
CameraFrameColorSource.MainSceneColor);
}
public void EnqueuePass(
ScriptableRenderer renderer,
RenderingData renderingData,
ColorScalePostProcessSettings settings)
{
Create(settings);
m_postProcessBlock.EnqueueRenderPass(
renderer,
renderingData,
m_pass);
}
}
}

View File

@@ -0,0 +1,25 @@
using XCEngine;
namespace XCEngine.Rendering.Universal
{
internal static class UniversalDefaultRendererFeatureFactory
{
public static ScriptableRendererFeature[]
CreateDefaultRendererFeatures()
{
BuiltinGaussianSplatRendererFeature gaussianSplatFeature =
ScriptableObject
.CreateInstance<BuiltinGaussianSplatRendererFeature>() ??
new BuiltinGaussianSplatRendererFeature();
BuiltinVolumetricRendererFeature volumetricFeature =
ScriptableObject
.CreateInstance<BuiltinVolumetricRendererFeature>() ??
new BuiltinVolumetricRendererFeature();
return new ScriptableRendererFeature[]
{
gaussianSplatFeature,
volumetricFeature
};
}
}
}

View File

@@ -0,0 +1,53 @@
using XCEngine;
using XCEngine.Rendering;
namespace XCEngine.Rendering.Universal
{
internal sealed class UniversalDepthPrepassBlock
{
private readonly DrawObjectsPass m_drawDepthPrepass =
new DrawObjectsPass(
RenderPassEvent.BeforeRenderingPrePasses,
SceneRenderPhase.Opaque,
RendererListDesc.CreateDefault(
RendererListType.Opaque));
public void ConfigureCameraFramePlan(
ScriptableRenderPipelinePlanningContext context,
DepthPrepassBlockData depthPrepass)
{
if (context == null)
{
return;
}
if (depthPrepass != null &&
depthPrepass.enabled &&
context.RequestCameraDepthOnlyStage())
{
return;
}
context.ClearDepthOnlyStage();
}
public void EnqueueRenderPasses(
ScriptableRenderer renderer,
DepthPrepassBlockData depthPrepass)
{
if (renderer == null ||
depthPrepass == null ||
!depthPrepass.enabled)
{
return;
}
m_drawDepthPrepass.Configure(
depthPrepass.passEvent,
SceneRenderPhase.Opaque,
depthPrepass.rendererListDesc,
depthPrepass.drawingSettings);
renderer.EnqueuePass(m_drawDepthPrepass);
}
}
}

View File

@@ -0,0 +1,54 @@
using XCEngine;
using XCEngine.Rendering;
namespace XCEngine.Rendering.Universal
{
internal sealed class UniversalFinalOutputBlock
{
private readonly BuiltinFinalColorPass m_builtinFinalColorPass =
new BuiltinFinalColorPass();
public void FinalizeCameraFramePlan(
ScriptableRenderPipelinePlanningContext context,
UniversalPostProcessBlock postProcessBlock)
{
if (context == null ||
!context.HasFinalColorProcessing())
{
return;
}
context.ClearFullscreenStage(
CameraFrameStage.FinalOutput);
CameraFrameColorSource finalOutputSource =
postProcessBlock != null
? postProcessBlock.ResolveFinalOutputSource(
context)
: CameraFrameColorSource.MainSceneColor;
context.RequestFullscreenStage(
CameraFrameStage.FinalOutput,
finalOutputSource);
}
public void EnqueueRenderPasses(
ScriptableRenderer renderer,
RenderingData renderingData)
{
if (renderer == null ||
renderingData == null)
{
return;
}
if (!renderingData.isFinalOutputStage &&
!renderingData.finalColorData.requiresProcessing)
{
return;
}
renderer.EnqueuePass(m_builtinFinalColorPass);
}
}
}

View File

@@ -0,0 +1,142 @@
using XCEngine;
using XCEngine.Rendering;
namespace XCEngine.Rendering.Universal
{
internal sealed class UniversalMainSceneBlock
{
private const string kMainLightShadowsKeyword =
"XC_MAIN_LIGHT_SHADOWS";
private readonly DrawObjectsPass m_drawOpaqueObjectsPass =
new DrawObjectsPass(
RenderPassEvent.RenderOpaques,
SceneRenderPhase.Opaque,
RendererListDesc.CreateDefault(
RendererListType.Opaque));
private readonly DrawSkyboxPass m_drawSkyboxPass =
new DrawSkyboxPass();
private readonly DrawObjectsPass m_drawTransparentObjectsPass =
new DrawObjectsPass(
RenderPassEvent.RenderTransparents,
SceneRenderPhase.Transparent,
RendererListDesc.CreateDefault(
RendererListType.Transparent));
public void ConfigureRenderSceneSetup(
RenderSceneSetupContext context)
{
if (context == null)
{
return;
}
context.SetEnvironmentNone();
context.ClearGlobalShaderKeywords();
Camera camera = context.camera;
if (ShouldUseSkyboxEnvironment(
context,
camera))
{
if (camera.hasSkyboxMaterial)
{
context.UseCameraSkyboxMaterial();
}
else
{
context.SetProceduralSkybox(
camera.skyboxTopColor,
camera.skyboxHorizonColor,
camera.skyboxBottomColor);
}
}
context.SetGlobalShaderKeyword(
kMainLightShadowsKeyword,
context.hasMainDirectionalShadow);
}
public void EnqueueRenderPasses(
ScriptableRenderer renderer,
UniversalMainSceneData mainScene)
{
if (renderer == null ||
mainScene == null)
{
return;
}
if (mainScene.renderOpaque)
{
EnqueueOpaquePasses(
renderer,
mainScene);
}
if (mainScene.renderSkybox)
{
EnqueueSkyboxPasses(
renderer,
mainScene);
}
if (mainScene.renderTransparent)
{
EnqueueTransparentPasses(
renderer,
mainScene);
}
}
private void EnqueueOpaquePasses(
ScriptableRenderer renderer,
UniversalMainSceneData mainScene)
{
m_drawOpaqueObjectsPass.Configure(
mainScene.opaquePassEvent,
SceneRenderPhase.Opaque,
mainScene.opaqueRendererListDesc,
mainScene.opaqueDrawingSettings);
renderer.EnqueuePass(m_drawOpaqueObjectsPass);
}
private void EnqueueSkyboxPasses(
ScriptableRenderer renderer,
UniversalMainSceneData mainScene)
{
m_drawSkyboxPass.Configure(
mainScene.skyboxPassEvent);
renderer.EnqueuePass(m_drawSkyboxPass);
}
private void EnqueueTransparentPasses(
ScriptableRenderer renderer,
UniversalMainSceneData mainScene)
{
m_drawTransparentObjectsPass.Configure(
mainScene.transparentPassEvent,
SceneRenderPhase.Transparent,
mainScene.transparentRendererListDesc,
mainScene.transparentDrawingSettings);
renderer.EnqueuePass(
m_drawTransparentObjectsPass);
}
private static bool ShouldUseSkyboxEnvironment(
RenderSceneSetupContext context,
Camera camera)
{
if (context == null ||
camera == null ||
!context.hasMainSceneDepthAttachment ||
(context.clearFlags & RenderClearFlags.Color) == 0 ||
!camera.skyboxEnabled)
{
return false;
}
return camera.projectionType ==
CameraProjectionType.Perspective;
}
}
}

View File

@@ -0,0 +1,42 @@
using XCEngine;
using XCEngine.Rendering;
namespace XCEngine.Rendering.Universal
{
internal static class UniversalMainSceneFeatureUtility
{
public static bool IsActive(
RenderingData renderingData)
{
return renderingData != null &&
renderingData.isMainSceneStage;
}
public static bool SupportsPass(
RenderingData renderingData,
ScriptableRenderPass renderPass)
{
return IsActive(renderingData) &&
renderPass != null &&
renderPass.SupportsStage(
renderingData.stage);
}
public static bool EnqueuePass(
ScriptableRenderer renderer,
RenderingData renderingData,
ScriptableRenderPass renderPass)
{
if (renderer == null ||
!SupportsPass(
renderingData,
renderPass))
{
return false;
}
renderer.EnqueuePass(renderPass);
return true;
}
}
}

View File

@@ -0,0 +1,53 @@
using XCEngine;
using XCEngine.Rendering;
namespace XCEngine.Rendering.Universal
{
internal sealed class UniversalNativeSceneFeatureController
{
private readonly NativeSceneFeaturePassId m_featurePassId;
private NativeSceneFeaturePass m_pass;
public UniversalNativeSceneFeatureController(
NativeSceneFeaturePassId featurePassId)
{
m_featurePassId =
featurePassId;
}
public int AppendRuntimeStateHash(
int hash,
RenderPassEvent passEvent)
{
return RuntimeStateHashUtility.Combine(
hash,
(int)passEvent);
}
public void Create(
RenderPassEvent passEvent)
{
if (m_pass == null)
{
m_pass = new NativeSceneFeaturePass(
m_featurePassId,
passEvent);
return;
}
m_pass.Configure(passEvent);
}
public void EnqueuePass(
ScriptableRenderer renderer,
RenderingData renderingData,
RenderPassEvent passEvent)
{
Create(passEvent);
UniversalMainSceneFeatureUtility.EnqueuePass(
renderer,
renderingData,
m_pass);
}
}
}

View File

@@ -0,0 +1,118 @@
using XCEngine;
using XCEngine.Rendering;
namespace XCEngine.Rendering.Universal
{
internal sealed class UniversalPostProcessBlock
{
public void ConfigureCameraFramePlan(
ScriptableRenderPipelinePlanningContext context,
CameraFrameColorSource sourceColor)
{
if (context == null)
{
return;
}
bool needsGraphManagedOutputColor =
context.HasFinalColorProcessing() ||
context.IsStageRequested(
CameraFrameStage.FinalOutput);
EnsurePostProcessStage(
context,
sourceColor,
needsGraphManagedOutputColor);
}
public CameraFrameColorSource ResolveFinalOutputSource(
ScriptableRenderPipelinePlanningContext context)
{
if (context == null ||
!context.IsStageRequested(
CameraFrameStage.PostProcess))
{
return CameraFrameColorSource.MainSceneColor;
}
CameraFrameColorSource postProcessSource =
context.GetStageColorSource(
CameraFrameStage.PostProcess);
if (postProcessSource ==
CameraFrameColorSource.ExplicitSurface)
{
return CameraFrameColorSource.MainSceneColor;
}
PromoteToGraphManagedOutputColor(
context);
return CameraFrameColorSource.PostProcessColor;
}
public void EnqueueRenderPass(
ScriptableRenderer renderer,
RenderingData renderingData,
ScriptableRenderPass renderPass)
{
if (renderer == null ||
renderingData == null ||
renderPass == null ||
!renderingData.isPostProcessStage)
{
return;
}
renderer.EnqueuePass(renderPass);
}
private static void EnsurePostProcessStage(
ScriptableRenderPipelinePlanningContext context,
CameraFrameColorSource sourceColor,
bool needsGraphManagedOutputColor)
{
if (!context.IsStageRequested(
CameraFrameStage.PostProcess))
{
context.RequestFullscreenStage(
CameraFrameStage.PostProcess,
sourceColor,
needsGraphManagedOutputColor);
return;
}
if (!needsGraphManagedOutputColor)
{
return;
}
PromoteToGraphManagedOutputColor(
context);
}
private static void PromoteToGraphManagedOutputColor(
ScriptableRenderPipelinePlanningContext context)
{
if (context == null)
{
return;
}
CameraFrameColorSource source =
context.GetStageColorSource(
CameraFrameStage.PostProcess);
if (source ==
CameraFrameColorSource.ExplicitSurface ||
context.UsesGraphManagedOutputColor(
CameraFrameStage.PostProcess))
{
return;
}
context.ClearFullscreenStage(
CameraFrameStage.PostProcess);
context.RequestFullscreenStage(
CameraFrameStage.PostProcess,
source,
true);
}
}
}

View File

@@ -0,0 +1,57 @@
using XCEngine;
using XCEngine.Rendering;
namespace XCEngine.Rendering.Universal
{
internal sealed class UniversalRenderObjectsFeatureController
{
private DrawObjectsPass m_pass;
public int AppendRuntimeStateHash(
int hash,
RenderObjectsFeatureSettings settings)
{
return settings != null
? settings.AppendRuntimeStateHash(hash)
: hash;
}
public void Create(
RenderObjectsFeatureSettings settings)
{
if (settings == null)
{
settings = new RenderObjectsFeatureSettings();
}
if (m_pass == null)
{
m_pass =
new DrawObjectsPass(
settings.passEvent,
settings.scenePhase,
settings.rendererListDesc,
settings.drawingSettings);
return;
}
m_pass.Configure(
settings.passEvent,
settings.scenePhase,
settings.rendererListDesc,
settings.drawingSettings);
}
public void EnqueuePass(
ScriptableRenderer renderer,
RenderingData renderingData,
RenderObjectsFeatureSettings settings)
{
Create(settings);
UniversalMainSceneFeatureUtility.EnqueuePass(
renderer,
renderingData,
m_pass);
}
}
}

View File

@@ -37,6 +37,32 @@ namespace XCEngine.Rendering.Universal
return;
}
FinalColorSettings resolvedFinalColorSettings =
GetFinalColorSettingsInstance().settings;
bool hasCameraFinalColorOverrides = false;
Camera camera = context.camera;
if (camera != null &&
camera.hasFinalColorOverrides)
{
FinalColorOverrideSettings overrideSettings =
camera.GetFinalColorOverrideSettings();
if (overrideSettings.HasOverrides())
{
overrideSettings.ApplyTo(
ref resolvedFinalColorSettings);
hasCameraFinalColorOverrides = true;
}
}
context.SetResolvedFinalColorPolicy(
resolvedFinalColorSettings,
true,
hasCameraFinalColorOverrides);
context.clearFlags =
ResolveRequestClearFlags(context);
UniversalShadowSettings shadowSettings =
GetShadowSettingsInstance();
if (!shadowSettings.supportsMainLightShadows)
@@ -87,6 +113,42 @@ namespace XCEngine.Rendering.Universal
return base.ResolveRendererIndex(context);
}
private static RenderClearFlags ResolveRequestClearFlags(
RendererCameraRequestContext context)
{
Camera camera =
context != null
? context.camera
: null;
if (camera == null)
{
return RenderClearFlags.All;
}
switch (camera.clearMode)
{
case CameraClearMode.ColorAndDepth:
return RenderClearFlags.All;
case CameraClearMode.DepthOnly:
return RenderClearFlags.Depth;
case CameraClearMode.None:
return RenderClearFlags.None;
case CameraClearMode.Auto:
default:
if (camera.stackType ==
CameraStackType.Overlay)
{
return context.renderedRequestCount == 0
? RenderClearFlags.All
: RenderClearFlags.Depth;
}
return context.renderedBaseCameraCount == 0
? RenderClearFlags.All
: RenderClearFlags.Depth;
}
}
private UniversalShadowSettings GetShadowSettingsInstance()
{
if (shadows == null)

View File

@@ -6,34 +6,16 @@ namespace XCEngine.Rendering.Universal
public sealed class UniversalRenderer : ScriptableRenderer
{
private readonly UniversalRendererData m_rendererData;
private readonly BuiltinFinalColorPass m_builtinFinalColorPass =
new BuiltinFinalColorPass();
private readonly DrawObjectsPass m_drawShadowCasterPass =
new DrawObjectsPass(
RenderPassEvent.BeforeRenderingShadows,
SceneRenderPhase.Opaque,
RendererListDesc.CreateDefault(
RendererListType.ShadowCaster));
private readonly DrawObjectsPass m_drawDepthPrepass =
new DrawObjectsPass(
RenderPassEvent.BeforeRenderingPrePasses,
SceneRenderPhase.Opaque,
RendererListDesc.CreateDefault(
RendererListType.Opaque));
private readonly DrawObjectsPass m_drawOpaqueObjectsPass =
new DrawObjectsPass(
RenderPassEvent.RenderOpaques,
SceneRenderPhase.Opaque,
RendererListDesc.CreateDefault(
RendererListType.Opaque));
private readonly DrawSkyboxPass m_drawSkyboxPass =
new DrawSkyboxPass();
private readonly DrawObjectsPass m_drawTransparentObjectsPass =
new DrawObjectsPass(
RenderPassEvent.RenderTransparents,
SceneRenderPhase.Transparent,
RendererListDesc.CreateDefault(
RendererListType.Transparent));
private readonly UniversalShadowCasterBlock m_shadowCasterBlock =
new UniversalShadowCasterBlock();
private readonly UniversalDepthPrepassBlock m_depthPrepassBlock =
new UniversalDepthPrepassBlock();
private readonly UniversalMainSceneBlock m_mainSceneBlock =
new UniversalMainSceneBlock();
private readonly UniversalPostProcessBlock m_postProcessBlock =
new UniversalPostProcessBlock();
private readonly UniversalFinalOutputBlock m_finalOutputBlock =
new UniversalFinalOutputBlock();
public UniversalRenderer(
UniversalRendererData rendererData)
@@ -53,10 +35,10 @@ namespace XCEngine.Rendering.Universal
return;
}
ConfigureShadowCasterStage(
m_shadowCasterBlock.ConfigureCameraFramePlan(
context,
m_rendererData.GetShadowCasterBlockInstance());
ConfigureDepthOnlyStage(
m_depthPrepassBlock.ConfigureCameraFramePlan(
context,
m_rendererData.GetDepthPrepassBlockInstance());
}
@@ -70,7 +52,9 @@ namespace XCEngine.Rendering.Universal
}
base.FinalizeCameraFramePlan(context);
ConfigureFinalOutputStage(context);
m_finalOutputBlock.FinalizeCameraFramePlan(
context,
m_postProcessBlock);
}
protected override void ConfigureRenderSceneSetup(
@@ -81,27 +65,22 @@ namespace XCEngine.Rendering.Universal
return;
}
context.UseDefaultSceneSetup();
m_mainSceneBlock.ConfigureRenderSceneSetup(
context);
}
protected override void ConfigureDirectionalShadowExecutionState(
DirectionalShadowExecutionContext context)
{
if (context == null ||
!context.hasPlannedMainDirectionalShadow)
if (context == null)
{
return;
}
ShadowCasterBlockData shadowCaster =
m_rendererData.GetShadowCasterBlockInstance();
if (shadowCaster == null ||
!shadowCaster.enabled)
{
return;
}
context.UseDefaultMainDirectionalShadowExecution();
m_shadowCasterBlock
.ConfigureDirectionalShadowExecutionState(
context,
m_rendererData.GetShadowCasterBlockInstance());
}
protected override void AddRenderPasses(
@@ -112,179 +91,29 @@ namespace XCEngine.Rendering.Universal
return;
}
UniversalMainSceneData mainScene =
m_rendererData.GetMainSceneInstance();
ShadowCasterBlockData shadowCaster =
m_rendererData.GetShadowCasterBlockInstance();
DepthPrepassBlockData depthPrepass =
m_rendererData.GetDepthPrepassBlockInstance();
if (shadowCaster.enabled)
switch (renderingData.stage)
{
EnqueueShadowCasterPasses(shadowCaster);
case CameraFrameStage.ShadowCaster:
m_shadowCasterBlock.EnqueueRenderPasses(
this,
m_rendererData.GetShadowCasterBlockInstance());
break;
case CameraFrameStage.DepthOnly:
m_depthPrepassBlock.EnqueueRenderPasses(
this,
m_rendererData.GetDepthPrepassBlockInstance());
break;
case CameraFrameStage.MainScene:
m_mainSceneBlock.EnqueueRenderPasses(
this,
m_rendererData.GetMainSceneInstance());
break;
case CameraFrameStage.FinalOutput:
m_finalOutputBlock.EnqueueRenderPasses(
this,
renderingData);
break;
}
if (depthPrepass.enabled)
{
EnqueueDepthPrepass(depthPrepass);
}
if (mainScene.renderOpaque)
{
EnqueueOpaquePasses(mainScene);
}
if (mainScene.renderSkybox)
{
EnqueueSkyboxPasses(mainScene);
}
if (mainScene.renderTransparent)
{
EnqueueTransparentPasses(mainScene);
}
EnqueueFinalOutputPasses(renderingData);
}
private void EnqueueShadowCasterPasses(
ShadowCasterBlockData shadowCaster)
{
m_drawShadowCasterPass.Configure(
shadowCaster.passEvent,
SceneRenderPhase.Opaque,
shadowCaster.rendererListDesc,
shadowCaster.drawingSettings);
EnqueuePass(m_drawShadowCasterPass);
}
private void EnqueueDepthPrepass(
DepthPrepassBlockData depthPrepass)
{
m_drawDepthPrepass.Configure(
depthPrepass.passEvent,
SceneRenderPhase.Opaque,
depthPrepass.rendererListDesc,
depthPrepass.drawingSettings);
EnqueuePass(m_drawDepthPrepass);
}
private void EnqueueOpaquePasses(
UniversalMainSceneData mainScene)
{
m_drawOpaqueObjectsPass.Configure(
mainScene.opaquePassEvent,
SceneRenderPhase.Opaque,
mainScene.opaqueRendererListDesc,
mainScene.opaqueDrawingSettings);
EnqueuePass(m_drawOpaqueObjectsPass);
}
private void EnqueueSkyboxPasses(
UniversalMainSceneData mainScene)
{
m_drawSkyboxPass.Configure(
mainScene.skyboxPassEvent);
EnqueuePass(m_drawSkyboxPass);
}
private void EnqueueTransparentPasses(
UniversalMainSceneData mainScene)
{
m_drawTransparentObjectsPass.Configure(
mainScene.transparentPassEvent,
SceneRenderPhase.Transparent,
mainScene.transparentRendererListDesc,
mainScene.transparentDrawingSettings);
EnqueuePass(m_drawTransparentObjectsPass);
}
private static void ConfigureShadowCasterStage(
ScriptableRenderPipelinePlanningContext context,
ShadowCasterBlockData shadowCaster)
{
if (shadowCaster != null &&
shadowCaster.enabled)
{
context.RequestShadowCasterStage();
return;
}
context.ClearShadowCasterStage();
}
private static void ConfigureDepthOnlyStage(
ScriptableRenderPipelinePlanningContext context,
DepthPrepassBlockData depthPrepass)
{
if (depthPrepass != null &&
depthPrepass.enabled &&
context.RequestCameraDepthOnlyStage())
{
return;
}
context.ClearDepthOnlyStage();
}
private static void ConfigureFinalOutputStage(
ScriptableRenderPipelinePlanningContext context)
{
if (!context.HasFinalColorProcessing())
{
return;
}
context.ClearFullscreenStage(
CameraFrameStage.FinalOutput);
CameraFrameColorSource finalOutputSource =
CameraFrameColorSource.MainSceneColor;
if (context.IsStageRequested(
CameraFrameStage.PostProcess))
{
CameraFrameColorSource postProcessSource =
context.GetStageColorSource(
CameraFrameStage.PostProcess);
if (postProcessSource !=
CameraFrameColorSource.ExplicitSurface)
{
if (!context.UsesGraphManagedOutputColor(
CameraFrameStage.PostProcess))
{
context.ClearFullscreenStage(
CameraFrameStage.PostProcess);
context.RequestFullscreenStage(
CameraFrameStage.PostProcess,
postProcessSource,
true);
}
finalOutputSource =
CameraFrameColorSource.PostProcessColor;
}
}
context.RequestFullscreenStage(
CameraFrameStage.FinalOutput,
finalOutputSource);
}
private void EnqueueFinalOutputPasses(
RenderingData renderingData)
{
if (renderingData == null)
{
return;
}
if (!renderingData.isFinalOutputStage &&
!renderingData.finalColorData.requiresProcessing)
{
return;
}
EnqueuePass(m_builtinFinalColorPass);
}
}
}

View File

@@ -35,19 +35,8 @@ namespace XCEngine.Rendering.Universal
protected override ScriptableRendererFeature[]
CreateDefaultRendererFeatures()
{
BuiltinGaussianSplatRendererFeature gaussianSplatFeature =
ScriptableObject
.CreateInstance<BuiltinGaussianSplatRendererFeature>() ??
new BuiltinGaussianSplatRendererFeature();
BuiltinVolumetricRendererFeature volumetricFeature =
ScriptableObject
.CreateInstance<BuiltinVolumetricRendererFeature>() ??
new BuiltinVolumetricRendererFeature();
return new ScriptableRendererFeature[]
{
gaussianSplatFeature,
volumetricFeature
};
return UniversalDefaultRendererFeatureFactory
.CreateDefaultRendererFeatures();
}
internal UniversalMainSceneData GetMainSceneInstance()

Some files were not shown because too many files have changed in this diff Show More