From b521616e27d5bac397f85db114fcca7ba71cd0db Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Mon, 20 Apr 2026 18:26:47 +0800 Subject: [PATCH] refactor(rendering/srp): unify managed fullscreen raster recording --- ...een旧桥清理与Builder统一计划_2026-04-20.md | 167 +++++ ...nagedRenderGraph_v1计划_阶段归档_2026-04-20.md | 216 ++++++ .../src/Scripting/Mono/MonoScriptRuntime.cpp | 679 ++++++++++++++++-- .../Universal/ScriptableRenderPass.cs | 338 +++++++++ managed/XCEngine.ScriptCore/InternalCalls.cs | 93 ++- 5 files changed, 1426 insertions(+), 67 deletions(-) create mode 100644 docs/plan/SRP_ManagedFullscreen旧桥清理与Builder统一计划_2026-04-20.md create mode 100644 docs/used/SRP_Universal包边界与ManagedRenderGraph_v1计划_阶段归档_2026-04-20.md create mode 100644 managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRenderPass.cs diff --git a/docs/plan/SRP_ManagedFullscreen旧桥清理与Builder统一计划_2026-04-20.md b/docs/plan/SRP_ManagedFullscreen旧桥清理与Builder统一计划_2026-04-20.md new file mode 100644 index 00000000..6d5d5c8e --- /dev/null +++ b/docs/plan/SRP_ManagedFullscreen旧桥清理与Builder统一计划_2026-04-20.md @@ -0,0 +1,167 @@ +# SRP Managed Fullscreen 旧桥清理与 Builder 统一计划 2026-04-20 + +## 1. 阶段目标 + +上一阶段已经完成两件关键工作: + +1. `ScriptCore` 与 `XCEngine.RenderPipelines.Universal` 的包边界拆开 +2. managed 侧最小 `RenderGraphRasterPassBuilder` 打通,并且首个 Universal feature 已经开始走 builder + +当前还剩最后一条明显的旧接缝没有收干净: + +1. `ScriptableRenderPass` 里无 handle 的 fullscreen 录制重载仍然在走旧的 `RecordFullscreenPass` internal call +2. C# probe 仍然能间接命中这条旧路径 +3. native 侧仍然保留了专门给这条旧路径服务的 internal call 注册和实现 + +这一阶段的目标很明确: + +1. Universal fullscreen pass 录制统一走 managed raster builder +2. 删除 `Rendering_ScriptableRenderContext_RecordFullscreenPass` 这条废弃桥 +3. 保持现有 `editor` 主链可编译、可启动、可冒烟 + +--- + +## 2. 当前问题 + +### 2.1 `ScriptableRenderPass` 仍然保留双轨制 + +当前 `ScriptableRenderPass` 已经有基于: + +1. `RenderGraphTextureHandle` +2. `RenderGraphRasterPassBuilder` + +的正式录制接口。 + +但无 handle 的两个重载: + +1. `RecordColorScaleFullscreenPass(context, Vector4)` +2. `RecordShaderVectorFullscreenPass(context, string, Vector4, string)` + +仍然通过旧 internal call 直接把“fullscreen pass 描述”扔回 native。 + +这会导致: + +1. Universal pass API 表面上已经 graph 化,内部却仍然夹着旧录制桥 +2. probe 和样例代码继续依赖旧路径,阻碍后续 SRP API 收口 +3. native 侧保留多余桥接逻辑,增加维护成本 + +### 2.2 这条旧桥已经不再合理 + +现在 `ScriptableRenderContext` 已经直接暴露: + +1. `sourceColorTexture` +2. `primaryColorTarget` +3. `AddRasterPass(...)` + +也就是说,fullscreen pass 已经具备从 managed 侧完整声明: + +1. 输入纹理 +2. 输出 attachment +3. 执行类型 + +的最小能力。继续保留旧桥,只会让 SRP host 看起来“像 Unity”,但实现上仍然是半旧半新。 + +--- + +## 3. 本阶段范围 + +本阶段只做下面四件事: + +1. 归档上一阶段 `ManagedRenderGraph v1` 计划 +2. 新增本阶段计划并开始执行 +3. 清理 Universal fullscreen 旧录制桥 +4. 重编 `editor` 并完成至少 10 秒冒烟验证 + +本阶段明确不做: + +1. 新的 SRP API 扩展 +2. compute pass 接口扩展 +3. renderer feature 编辑器适配 +4. shadow / volume / deferred 内容迁移 + +--- + +## 4. 实施步骤 + +### Step 1:统一 `ScriptableRenderPass` fullscreen 录制入口 + +目标: + +让无 handle 的 fullscreen 重载内部自动解析: + +1. `context.sourceColorTexture` +2. `context.primaryColorTarget` + +然后直接复用现有 builder 版本的正式录制路径。 + +完成标准: + +1. `ScriptableRenderPass` 不再出现 `RecordedFullscreenPassType` +2. `RecordFullscreenPassInternal(...)` 被删除 +3. fullscreen pass 的所有 managed 入口都统一汇入 builder + +### Step 2:移除废弃 internal call + +目标: + +删除已经不再需要的: + +1. `InternalCalls.Rendering_ScriptableRenderContext_RecordFullscreenPass` +2. native 对应实现 +3. native 对应注册 + +完成标准: + +1. 全仓搜索不再出现 `Rendering_ScriptableRenderContext_RecordFullscreenPass` +2. managed/native 不再保留 fullscreen 旧桥专用代码 + +### Step 3:校正 probe 与调用面 + +目标: + +确认现有 probe 通过无 handle 重载时,已经自动命中 builder 路径,而不是继续依赖旧桥。 + +完成标准: + +1. probe 不需要特殊兼容逻辑 +2. API surface 仍然满足现有验证脚本使用方式 + +### Step 4:编译与冒烟 + +固定验证: + +1. 编译旧版 `editor` +2. 启动 `editor/bin/Debug/XCEngine.exe` +3. 冒烟运行至少 10 秒 +4. 检查 `editor/bin/Debug/editor.log` 中新的 `SceneReady` + +--- + +## 5. 验收标准 + +这一阶段收口后应满足: + +1. Universal fullscreen pass 录制完全统一到 managed builder +2. managed 到 native 的 fullscreen 旧桥彻底删除 +3. 现有 probe / Universal feature 不需要回退到旧 API +4. `editor` 编译通过,旧 editor 冒烟通过 + +--- + +## 6. 阶段意义 + +这一步做完以后,SRP 主线会从: + +`已有 RenderGraph builder,但 fullscreen 仍残留旧录制桥` + +推进到: + +`Universal 已经开始真正以 managed graph producer 的方式录制 pass` + +这样下一阶段继续扩: + +1. 更多 Universal 官方式 pass +2. 更清晰的 renderer feature authoring +3. 更接近 Unity 风格的 SRP/URP API 面 + +时,就不需要再回头清理历史接缝。 diff --git a/docs/used/SRP_Universal包边界与ManagedRenderGraph_v1计划_阶段归档_2026-04-20.md b/docs/used/SRP_Universal包边界与ManagedRenderGraph_v1计划_阶段归档_2026-04-20.md new file mode 100644 index 00000000..38014cc1 --- /dev/null +++ b/docs/used/SRP_Universal包边界与ManagedRenderGraph_v1计划_阶段归档_2026-04-20.md @@ -0,0 +1,216 @@ +# SRP Universal 包边界与 Managed RenderGraph v1 计划 2026-04-20 + +## 1. 阶段目标 + +上一阶段已经完成了: + +1. `ScriptableRenderPipelineAsset -> RendererBackedRenderPipelineAsset -> ScriptableRendererData -> ScriptableRenderer -> Feature -> Pass` +2. project 侧自定义 SRP/URP 风格资源、feature、pass 的主链打通 +3. renderer data / asset invalidation、runtime rebuild、runtime release 契约锁定 + +当前下一阶段不再继续补 lifecycle 接缝,而是正式进入两个面向长期演进的基础工作: + +1. 把首方 Universal 包的物理边界收干净 +2. 给 managed 层补上最小可用的 RenderGraph API v1 + +这一步是后续继续做 Unity 风格 `SRP + URP` 的真正起点。 + +--- + +## 2. 当前问题 + +### 2.1 包边界逻辑正确,但物理结构不干净 + +虽然 `XCEngine.RenderPipelines.Universal.dll` 已经是独立 assembly, +但是源码物理上仍然放在: + +`managed/XCEngine.ScriptCore/Rendering/Universal/*` + +这会造成几个问题: + +1. 目录结构误导,难以分辨哪些属于 ScriptCore,哪些属于首方管线包 +2. 后续继续扩 Universal 内容时,容易把 package code 和 core API 混写 +3. 不利于未来继续拆 `Core / Universal / HDRP-like / user package` + +### 2.2 现在的 Universal 还只是“薄骨架” + +当前 Universal 主要完成了: + +1. renderer data / renderer / feature / pass 的 managed 组织 +2. main scene / post process / final output 的阶段录制入口 +3. 少量 feature 级能力验证 + +但它还没有真正进入“官方默认渲染管线内容层”的状态。 + +### 2.3 Managed 侧还没有真正的 RenderGraph API + +当前 managed pass 主要还是依赖: + +1. `RecordScene` +2. `RecordScenePhase` +3. `RecordSceneInjectionPoint` +4. `RecordFullscreenPass` + +这意味着: + +1. C# 侧还不能明确声明纹理资源依赖 +2. C# 侧还不能真正创建 transient 资源 +3. C# 侧还不能录制通用 raster / compute pass + +如果继续在这个基础上堆功能,最终会变成“可脚本化的 builtin pipeline”,而不是真正的 SRP/URP。 + +--- + +## 3. 本阶段范围 + +本阶段只做下面两件事: + +1. `Universal 包边界正式化` +2. `Managed RenderGraph API v1` + +本阶段明确不做: + +1. deferred renderer +2. lightmap / GI / probe +3. HDRP 风格分支 +4. 编辑器 inspector/资源面板适配 + +--- + +## 4. 实施步骤 + +### Step 1:Universal 包物理拆层 + +目标: + +把当前 `managed/XCEngine.ScriptCore/Rendering/Universal/*` +迁移到独立目录,例如: + +`managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/*` + +同时修正构建脚本,让 assembly 名、目录名、源码归属三者一致。 + +完成标准: + +1. Universal 源码不再物理挂在 ScriptCore 目录下 +2. `managed/CMakeLists.txt` 仍然稳定产出 `XCEngine.RenderPipelines.Universal.dll` +3. 所有现有 scripting/rendering/editor 验证通过 + +### Step 2:梳理 managed SRP core 和 Universal package 的边界 + +目标: + +明确哪些类型应该留在 core,哪些应该留在 Universal: + +保留在 core: + +1. `RenderPipelineAsset` +2. `ScriptableRenderPipelineAsset` +3. `ScriptableRenderPipeline` +4. `ScriptableRenderContext` +5. `ScriptableRenderPipelinePlanningContext` +6. `CameraRenderRequestContext` + +保留在 Universal: + +1. `RendererBackedRenderPipelineAsset` +2. `RendererDrivenRenderPipeline` +3. `ScriptableRendererData` +4. `ScriptableRenderer` +5. `ScriptableRendererFeature` +6. `ScriptableRenderPass` +7. `RenderingData*` +8. `UniversalRenderPipelineAsset / UniversalRendererData / UniversalRenderer` + +完成标准: + +1. 不再出现 core/package 边界混乱的命名与落位 +2. C# API 表意清晰,后续用户可以理解“引擎 core”和“首方管线包”的区别 + +### Step 3:设计 Managed RenderGraph API v1 + +目标: + +在不推翻当前 native RenderGraph 的前提下,给 managed 层补最小可用 graph API。 + +v1 只做最小闭环: + +1. graph texture handle +2. 导入主场景/后处理阶段颜色输入 +3. 创建 transient color/depth texture +4. 添加 raster pass +5. 添加 compute pass +6. 在 pass setup 中声明 read/write 依赖 + +v1 暂不做: + +1. 完整 builder 泛型体系 +2. 复杂 blackboard typed API +3. 跨帧历史资源 +4. async compute / pass culling / alias 可视化 + +完成标准: + +1. managed pass 能不依赖固定 helper,直接声明 graph 资源和 pass +2. native graph compile/execute 仍由 C++ 层负责 +3. API 能支撑后续做首方 URP feature + +### Step 4:用 v1 API 改造 Universal 的官方默认内容层 + +目标: + +先挑最小路径做首个正式化样板: + +1. 保留主场景几何后端仍走 native builtin forward +2. 把 managed Universal 的 post process / final output 录制逐步改到 graph API +3. 保证 feature/pass 是真正的 graph producer,而不是固定 internal call 包装 + +完成标准: + +1. Universal 包不再只是“阶段调用壳” +2. feature/pass 能开始承载真实官方默认管线内容 + +### Step 5:阶段验证与收口 + +固定验证流程: + +1. 编译 `rendering_unit_tests` +2. 编译 `scripting_tests` +3. 编译 `XCEditor` +4. 运行 `rendering_unit_tests` +5. 运行 `scripting_tests` +6. 启动旧版 `editor/bin/Debug/XCEngine.exe` 至少 10 秒 +7. 检查新鲜 `editor/bin/Debug/editor.log` 中出现 `SceneReady` +8. 阶段完成后归档 plan +9. 使用规范 conventional commit 提交并推送 + +--- + +## 5. 验收标准 + +本阶段收口后应满足: + +1. `ScriptCore` 和 `Universal package` 的边界在目录、构建、职责三层一致 +2. managed 层拥有最小可用的 graph 录制能力 +3. Universal 开始从“验证骨架”进入“官方默认管线内容层” +4. 下一阶段可以继续做更像 URP 的 renderer feature / renderer data / 官方 pass 体系,而不是继续补接缝 + +--- + +## 6. 阶段意义 + +这一步做完后,渲染架构会从: + +`SRP bridge 已打通,但 Universal 还是薄封装` + +推进到: + +`SRP core + 首方 Universal package + managed graph authoring 基础成立` + +只有到这一步,后面继续做: + +1. Unity 风格官方 URP renderer feature +2. 更复杂的官方 post process +3. deferred / lightmap / volume 等后续内容 + +才不会再回头重写主结构。 diff --git a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp index 5cc20fdd..99ee7d1b 100644 --- a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp +++ b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp @@ -11,12 +11,17 @@ #include "Input/InputManager.h" #include "Physics/PhysicsWorld.h" #include "Rendering/Execution/CameraFramePlan.h" +#include "Rendering/Execution/CameraFrameRenderGraphFrameData.h" +#include "Rendering/Execution/Internal/CameraFrameGraph/SurfaceUtils.h" +#include "Rendering/Graph/RenderGraph.h" +#include "Rendering/Graph/RenderGraphRecordingContext.h" #include "Rendering/GraphicsSettingsState.h" #include "Rendering/Internal/RenderPipelineFactory.h" #include "Rendering/Passes/BuiltinVectorFullscreenPass.h" #include "Rendering/Planning/FullscreenPassDesc.h" #include "Rendering/Pipelines/NativeSceneRecorder.h" #include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h" +#include "Rendering/RenderPassGraphContract.h" #include "Rendering/RenderPipelineStageGraphContract.h" #include "Resources/BuiltinResources.h" #include "Scene/Scene.h" @@ -101,7 +106,17 @@ struct ManagedScriptableRenderContextState { Rendering::CameraFrameStage stage = Rendering::CameraFrameStage::MainScene; const Rendering::RenderPipelineStageRenderGraphContext* graphContext = nullptr; Rendering::Pipelines::NativeSceneRecorder* sceneRecorder = nullptr; - std::vector queuedFullscreenPasses = {}; + struct RasterPassRecordRequest { + Containers::String passName = {}; + Rendering::FullscreenPassDesc passDesc = {}; + Rendering::RenderGraphTextureHandle sourceColorTexture = {}; + std::vector readTextures = {}; + std::vector colorTargets = {}; + }; + uint64_t nextPendingRasterPassHandle = 1u; + std::unordered_map + pendingRasterPassRequests = {}; + std::vector rasterPassRequests = {}; }; struct ManagedCameraRenderRequestContextState { @@ -135,6 +150,21 @@ ManagedScriptableRenderContextState* FindManagedScriptableRenderContextState( : nullptr; } +ManagedScriptableRenderContextState::RasterPassRecordRequest* +FindPendingManagedRasterPassRecordRequest( + ManagedScriptableRenderContextState* state, + uint64_t rasterPassHandle) { + if (state == nullptr || rasterPassHandle == 0u) { + return nullptr; + } + + const auto it = + state->pendingRasterPassRequests.find(rasterPassHandle); + return it != state->pendingRasterPassRequests.end() + ? &it->second + : nullptr; +} + uint64_t RegisterManagedScriptableRenderContextState( ManagedScriptableRenderContextState& state) { uint64_t handle = GetManagedScriptableRenderContextNextHandle()++; @@ -220,6 +250,205 @@ bool ResolveManagedScriptableRenderContextUsesGraphManagedOutputColor( state->graphContext->usesGraphManagedOutputColor; } +int32_t EncodeManagedRenderGraphTextureHandle( + Rendering::RenderGraphTextureHandle handle) { + return handle.IsValid() + ? static_cast(handle.index) + : -1; +} + +Rendering::RenderGraphTextureHandle +DecodeManagedRenderGraphTextureHandle( + int32_t handleValue) { + Rendering::RenderGraphTextureHandle handle = {}; + if (handleValue < 0) { + return handle; + } + + handle.index = static_cast(handleValue); + return handle; +} + +Rendering::RenderGraphTextureHandle +ResolveManagedScriptableRenderContextSourceColorTexture( + const ManagedScriptableRenderContextState* state) { + if (state == nullptr || + state->graphContext == nullptr) { + return {}; + } + + if (state->graphContext->sourceColorTexture.IsValid()) { + return state->graphContext->sourceColorTexture; + } + + const Rendering::CameraFrameRenderGraphResources* const resources = + Rendering::TryGetCameraFrameRenderGraphResources( + state->graphContext->blackboard); + if (resources == nullptr) { + return {}; + } + + switch (state->stage) { + case Rendering::CameraFrameStage::PostProcess: + return resources->mainScene.color; + case Rendering::CameraFrameStage::FinalOutput: + return resources->postProcess.color.IsValid() + ? resources->postProcess.color + : resources->mainScene.color; + default: + return {}; + } +} + +Rendering::RenderGraphTextureHandle +ResolveManagedPrimaryColorTarget( + const std::vector& colorTargets) { + const auto it = + std::find_if( + colorTargets.begin(), + colorTargets.end(), + [](Rendering::RenderGraphTextureHandle handle) { + return handle.IsValid(); + }); + return it != colorTargets.end() + ? *it + : Rendering::RenderGraphTextureHandle{}; +} + +Rendering::RenderGraphTextureHandle +ResolveManagedScriptableRenderContextPrimaryColorTarget( + const ManagedScriptableRenderContextState* state) { + if (state == nullptr || + state->graphContext == nullptr) { + return {}; + } + + return ResolveManagedPrimaryColorTarget( + state->graphContext->colorTargets); +} + +Rendering::RenderGraphTextureHandle +ResolveManagedScriptableRenderContextDepthTarget( + const ManagedScriptableRenderContextState* state) { + return state != nullptr && + state->graphContext != nullptr + ? state->graphContext->depthTarget + : Rendering::RenderGraphTextureHandle{}; +} + +Rendering::RenderGraphTextureDesc +BuildManagedFullscreenTransientDepthTextureDesc( + const Rendering::RenderSurface& surface) { + Rendering::RenderGraphTextureDesc desc = {}; + desc.width = + surface.GetWidth() > 0u + ? surface.GetWidth() + : surface.GetRenderAreaWidth(); + desc.height = + surface.GetHeight() > 0u + ? surface.GetHeight() + : surface.GetRenderAreaHeight(); + desc.format = static_cast( + RHI::Format::D24_UNorm_S8_UInt); + desc.textureType = static_cast( + RHI::TextureType::Texture2D); + desc.sampleCount = 1u; + desc.sampleQuality = 0u; + return desc; +} + +Rendering::RenderGraphRecordingSourceBinding +BuildManagedScriptableRenderContextSourceBinding( + const Rendering::RenderPipelineStageRenderGraphContext& context, + Rendering::RenderGraphTextureHandle sourceColorTexture) { + if (!sourceColorTexture.IsValid()) { + return {}; + } + + Rendering::RenderGraphRecordingSourceBinding binding = + Rendering::MakeRenderGraphRecordingSourceBinding( + context.sourceSurface, + context.sourceColorView, + context.sourceColorState, + sourceColorTexture); + const bool usesContextSource = + context.sourceColorTexture.IsValid() && + context.sourceColorTexture.index == sourceColorTexture.index; + if (!usesContextSource) { + binding.sourceColorView = nullptr; + binding.sourceColorState = + RHI::ResourceStates::PixelShaderResource; + } + + if (binding.sourceSurface == nullptr) { + binding.sourceSurface = &context.surfaceTemplate; + } + + return binding; +} + +bool RecordManagedFullscreenRasterPass( + const Rendering::RenderPipelineStageRenderGraphContext& stageContext, + Rendering::RenderPass& pass, + Rendering::RenderGraphTextureHandle sourceColorTexture, + std::vector colorTargets, + std::vector additionalReadTextures, + const Containers::String& passName) { + if (!Rendering::IsCameraFrameFullscreenSequenceStage(stageContext.stage) || + !sourceColorTexture.IsValid() || + !ResolveManagedPrimaryColorTarget(colorTargets).IsValid()) { + return false; + } + + const Rendering::RenderGraphRecordingContext baseContext = + Rendering::BuildRenderGraphRecordingContext( + stageContext); + Rendering::RenderGraphRecordingContextBuildParams params = {}; + if (!passName.Empty()) { + params.passName = &passName; + } + params.overrideSourceBinding = true; + params.sourceBinding = + BuildManagedScriptableRenderContextSourceBinding( + stageContext, + sourceColorTexture); + params.overrideColorTargets = true; + params.colorTargets = std::move(colorTargets); + params.overrideDepthTarget = true; + params.depthTarget = {}; + + const Rendering::RenderGraphRecordingContext recordingContext = + Rendering::BuildRenderGraphRecordingContext( + baseContext, + std::move(params)); + const Rendering::RenderPassRenderGraphContext renderGraphContext = + Rendering::BuildRenderPassRenderGraphContext(recordingContext); + Rendering::RenderPass* const passPtr = &pass; + return Rendering::RecordCallbackRasterRenderPass( + renderGraphContext, + Rendering::BuildSourceColorFullscreenRasterPassGraphIO(), + [passPtr](const Rendering::RenderPassContext& passContext) { + return passPtr != nullptr && + passPtr->Execute(passContext); + }, + std::move(additionalReadTextures)); +} + +bool RecordManagedFullscreenPassToTexture( + const Rendering::RenderPipelineStageRenderGraphContext& stageContext, + Rendering::RenderPass& pass, + Rendering::RenderGraphTextureHandle sourceColorTexture, + Rendering::RenderGraphTextureHandle outputColorTexture, + const Containers::String& passName) { + return RecordManagedFullscreenRasterPass( + stageContext, + pass, + sourceColorTexture, + { outputColorTexture }, + {}, + passName); +} + const Rendering::DirectionalShadowRenderPlan& ResolveManagedScriptableRenderContextDirectionalShadowPlan( const ManagedScriptableRenderContextState* state) { @@ -686,6 +915,20 @@ static_assert( sizeof(Rendering::FinalColorSettings), "Managed final color bridge layout must match native FinalColorSettings."); +struct ManagedRenderGraphTextureDescData { + uint32_t width = 0u; + uint32_t height = 0u; + uint32_t format = 0u; + uint32_t textureType = 0u; + uint32_t sampleCount = 0u; + uint32_t sampleQuality = 0u; +}; + +static_assert( + sizeof(ManagedRenderGraphTextureDescData) == + sizeof(Rendering::RenderGraphTextureDesc), + "Managed render graph texture desc bridge layout must match native RenderGraphTextureDesc."); + Rendering::FinalColorOutputTransferMode ResolveManagedFinalColorOutputTransferMode( uint8_t value) { switch (value) { @@ -1007,7 +1250,7 @@ public: return false; } - return FlushManagedFullscreenPasses( + return FlushManagedRasterPasses( context, managedContextState); } @@ -1063,36 +1306,86 @@ private: return m_recordStageMethod; } - bool FlushManagedFullscreenPasses( + bool FlushManagedRasterPasses( const Rendering::RenderPipelineStageRenderGraphContext& context, const ManagedScriptableRenderContextState& managedContextState) { - if (managedContextState.queuedFullscreenPasses.empty()) { + if (managedContextState.rasterPassRequests.empty()) { return true; } if (!Rendering::IsCameraFrameFullscreenSequenceStage(context.stage)) { return false; } - std::vector passes = {}; - passes.reserve( - managedContextState.queuedFullscreenPasses.size()); + Rendering::RenderGraphTextureHandle currentSourceColor = + ResolveManagedScriptableRenderContextSourceColorTexture( + &managedContextState); + const Rendering::RenderGraphTextureHandle finalOutputColor = + ResolveManagedScriptableRenderContextPrimaryColorTarget( + &managedContextState); + if (!currentSourceColor.IsValid() || + !finalOutputColor.IsValid()) { + return false; + } + for (size_t passIndex = 0u; - passIndex < managedContextState.queuedFullscreenPasses.size(); + passIndex < managedContextState.rasterPassRequests.size(); ++passIndex) { + const ManagedScriptableRenderContextState::RasterPassRecordRequest& + request = managedContextState.rasterPassRequests[passIndex]; Rendering::RenderPass* const pass = ConfigureManagedFullscreenPass( m_fullscreenPassPool, passIndex, - managedContextState.queuedFullscreenPasses[passIndex]); + request.passDesc); if (pass == nullptr) { return false; } - passes.push_back(pass); + + const Containers::String resolvedPassName = + !request.passName.Empty() + ? request.passName + : managedContextState.rasterPassRequests.size() == 1u + ? context.passName + : Rendering::BuildRenderGraphSequencePassName( + context.passName, + passIndex); + const Rendering::RenderGraphTextureHandle resolvedSourceColor = + request.sourceColorTexture.IsValid() + ? request.sourceColorTexture + : currentSourceColor; + std::vector + resolvedColorTargets = + request.colorTargets; + if (!ResolveManagedPrimaryColorTarget(resolvedColorTargets) + .IsValid()) { + const bool isLastPass = + passIndex + 1u == + managedContextState.rasterPassRequests.size(); + const Rendering::RenderGraphTextureHandle resolvedOutputColor = + isLastPass + ? finalOutputColor + : context.graphBuilder.CreateTransientTexture( + resolvedPassName + ".Color", + Rendering::BuildFullscreenTransientTextureDesc( + context.surfaceTemplate)); + resolvedColorTargets = { resolvedOutputColor }; + } + if (!RecordManagedFullscreenRasterPass( + context, + *pass, + resolvedSourceColor, + resolvedColorTargets, + request.readTextures, + resolvedPassName)) { + return false; + } + + currentSourceColor = + ResolveManagedPrimaryColorTarget( + resolvedColorTargets); } - return Rendering::RecordRenderPipelineStageFullscreenPassSequence( - context, - passes); + return true; } Rendering::NativeSceneRenderer* ResolveSceneRenderer() { @@ -3414,6 +3707,308 @@ int32_t InternalCall_Rendering_ScriptableRenderContext_GetStage( : static_cast(Rendering::CameraFrameStage::MainScene); } +int32_t InternalCall_Rendering_ScriptableRenderContext_GetSourceColorTextureHandle( + uint64_t nativeHandle) { + const ManagedScriptableRenderContextState* const state = + FindManagedScriptableRenderContextState(nativeHandle); + return EncodeManagedRenderGraphTextureHandle( + ResolveManagedScriptableRenderContextSourceColorTexture( + state)); +} + +int32_t InternalCall_Rendering_ScriptableRenderContext_GetPrimaryColorTargetHandle( + uint64_t nativeHandle) { + const ManagedScriptableRenderContextState* const state = + FindManagedScriptableRenderContextState(nativeHandle); + return EncodeManagedRenderGraphTextureHandle( + ResolveManagedScriptableRenderContextPrimaryColorTarget( + state)); +} + +int32_t InternalCall_Rendering_ScriptableRenderContext_GetDepthTargetHandle( + uint64_t nativeHandle) { + const ManagedScriptableRenderContextState* const state = + FindManagedScriptableRenderContextState(nativeHandle); + return EncodeManagedRenderGraphTextureHandle( + ResolveManagedScriptableRenderContextDepthTarget( + state)); +} + +int32_t InternalCall_Rendering_ScriptableRenderContext_CreateTransientTexture( + uint64_t nativeHandle, + MonoString* name, + ManagedRenderGraphTextureDescData* descData) { + ManagedScriptableRenderContextState* const state = + FindManagedScriptableRenderContextState(nativeHandle); + if (state == nullptr || + state->graphContext == nullptr || + descData == nullptr) { + return -1; + } + + const auto* const desc = + reinterpret_cast( + descData); + if (!desc->IsValid()) { + return -1; + } + + const Rendering::RenderGraphTextureHandle handle = + state->graphContext->graphBuilder.CreateTransientTexture( + Containers::String(MonoStringToUtf8(name).c_str()), + *desc); + return EncodeManagedRenderGraphTextureHandle(handle); +} + +int32_t +InternalCall_Rendering_ScriptableRenderContext_CreateFullscreenTransientColorTexture( + uint64_t nativeHandle, + MonoString* name) { + ManagedScriptableRenderContextState* const state = + FindManagedScriptableRenderContextState(nativeHandle); + if (state == nullptr || + state->graphContext == nullptr) { + return -1; + } + + const Rendering::RenderGraphTextureHandle handle = + state->graphContext->graphBuilder.CreateTransientTexture( + Containers::String(MonoStringToUtf8(name).c_str()), + Rendering::BuildFullscreenTransientTextureDesc( + state->graphContext->surfaceTemplate)); + return EncodeManagedRenderGraphTextureHandle(handle); +} + +int32_t +InternalCall_Rendering_ScriptableRenderContext_CreateFullscreenTransientDepthTexture( + uint64_t nativeHandle, + MonoString* name) { + ManagedScriptableRenderContextState* const state = + FindManagedScriptableRenderContextState(nativeHandle); + if (state == nullptr || + state->graphContext == nullptr) { + return -1; + } + + const Rendering::RenderGraphTextureHandle handle = + state->graphContext->graphBuilder.CreateTransientTexture( + Containers::String(MonoStringToUtf8(name).c_str()), + BuildManagedFullscreenTransientDepthTextureDesc( + state->graphContext->surfaceTemplate)); + return EncodeManagedRenderGraphTextureHandle(handle); +} + +uint64_t InternalCall_Rendering_ScriptableRenderContext_BeginRasterPass( + uint64_t nativeHandle, + MonoString* passName) { + ManagedScriptableRenderContextState* const state = + FindManagedScriptableRenderContextState(nativeHandle); + if (state == nullptr || + state->graphContext == nullptr || + !Rendering::IsCameraFrameFullscreenSequenceStage(state->stage)) { + return 0u; + } + + const Containers::String passNameString( + MonoStringToUtf8(passName).c_str()); + if (passNameString.Empty()) { + return 0u; + } + + uint64_t rasterPassHandle = + state->nextPendingRasterPassHandle++; + if (rasterPassHandle == 0u) { + rasterPassHandle = + state->nextPendingRasterPassHandle++; + } + + ManagedScriptableRenderContextState::RasterPassRecordRequest + request = {}; + request.passName = passNameString; + state->pendingRasterPassRequests[rasterPassHandle] = + std::move(request); + return rasterPassHandle; +} + +mono_bool +InternalCall_Rendering_ScriptableRenderContext_SetRasterPassSourceColorTexture( + uint64_t nativeHandle, + uint64_t rasterPassHandle, + int32_t sourceTextureHandle) { + ManagedScriptableRenderContextState* const state = + FindManagedScriptableRenderContextState(nativeHandle); + ManagedScriptableRenderContextState::RasterPassRecordRequest* + const request = + FindPendingManagedRasterPassRecordRequest( + state, + rasterPassHandle); + if (request == nullptr) { + return 0; + } + + const Rendering::RenderGraphTextureHandle sourceColorTexture = + DecodeManagedRenderGraphTextureHandle( + sourceTextureHandle); + if (!sourceColorTexture.IsValid()) { + return 0; + } + + request->sourceColorTexture = sourceColorTexture; + return 1; +} + +mono_bool +InternalCall_Rendering_ScriptableRenderContext_AddRasterPassReadTexture( + 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 readTexture = + DecodeManagedRenderGraphTextureHandle( + textureHandle); + if (!readTexture.IsValid()) { + return 0; + } + + request->readTextures.push_back(readTexture); + return 1; +} + +mono_bool +InternalCall_Rendering_ScriptableRenderContext_SetRasterPassColorAttachment( + uint64_t nativeHandle, + uint64_t rasterPassHandle, + int32_t colorAttachmentIndex, + int32_t textureHandle) { + ManagedScriptableRenderContextState* const state = + FindManagedScriptableRenderContextState(nativeHandle); + ManagedScriptableRenderContextState::RasterPassRecordRequest* + const request = + FindPendingManagedRasterPassRecordRequest( + state, + rasterPassHandle); + if (request == nullptr || + colorAttachmentIndex < 0) { + return 0; + } + + const Rendering::RenderGraphTextureHandle colorAttachment = + DecodeManagedRenderGraphTextureHandle( + textureHandle); + if (!colorAttachment.IsValid()) { + return 0; + } + + if (request->colorTargets.size() <= + static_cast(colorAttachmentIndex)) { + request->colorTargets.resize( + static_cast(colorAttachmentIndex) + 1u); + } + + request->colorTargets[static_cast(colorAttachmentIndex)] = + colorAttachment; + return 1; +} + +mono_bool +InternalCall_Rendering_ScriptableRenderContext_SetRasterPassColorScaleFullscreenExecution( + uint64_t nativeHandle, + uint64_t rasterPassHandle, + XCEngine::Math::Vector4* vectorPayload) { + ManagedScriptableRenderContextState* const state = + FindManagedScriptableRenderContextState(nativeHandle); + ManagedScriptableRenderContextState::RasterPassRecordRequest* + const request = + FindPendingManagedRasterPassRecordRequest( + state, + rasterPassHandle); + if (request == nullptr || + vectorPayload == nullptr) { + return 0; + } + + request->passDesc = + Rendering::FullscreenPassDesc::MakeColorScale( + *vectorPayload); + return 1; +} + +mono_bool +InternalCall_Rendering_ScriptableRenderContext_SetRasterPassShaderVectorFullscreenExecution( + uint64_t nativeHandle, + uint64_t rasterPassHandle, + MonoString* shaderPath, + MonoString* shaderPassName, + XCEngine::Math::Vector4* vectorPayload) { + ManagedScriptableRenderContextState* const state = + FindManagedScriptableRenderContextState(nativeHandle); + ManagedScriptableRenderContextState::RasterPassRecordRequest* + const request = + FindPendingManagedRasterPassRecordRequest( + state, + rasterPassHandle); + if (request == nullptr || + vectorPayload == nullptr) { + return 0; + } + + const Containers::String shaderPathString( + MonoStringToUtf8(shaderPath).c_str()); + if (shaderPathString.Empty()) { + return 0; + } + + request->passDesc = + Rendering::FullscreenPassDesc::MakeShaderVector( + shaderPathString, + *vectorPayload, + Containers::String(MonoStringToUtf8(shaderPassName).c_str())); + return request->passDesc.IsValid() + ? 1 + : 0; +} + +mono_bool InternalCall_Rendering_ScriptableRenderContext_CommitRasterPass( + uint64_t nativeHandle, + uint64_t rasterPassHandle) { + ManagedScriptableRenderContextState* const state = + FindManagedScriptableRenderContextState(nativeHandle); + if (state == nullptr || + state->graphContext == nullptr || + !Rendering::IsCameraFrameFullscreenSequenceStage(state->stage)) { + return 0; + } + + auto it = + state->pendingRasterPassRequests.find( + rasterPassHandle); + if (it == state->pendingRasterPassRequests.end()) { + return 0; + } + + ManagedScriptableRenderContextState::RasterPassRecordRequest + request = std::move(it->second); + state->pendingRasterPassRequests.erase(it); + if (!request.passDesc.IsValid() || + !ResolveManagedPrimaryColorTarget(request.colorTargets) + .IsValid()) { + return 0; + } + + state->rasterPassRequests.push_back(std::move(request)); + return 1; +} + int32_t InternalCall_Rendering_ScriptableRenderContext_GetStageColorSource( uint64_t nativeHandle) { const ManagedScriptableRenderContextState* const state = @@ -3974,50 +4569,6 @@ InternalCall_Rendering_ScriptableRenderContext_RecordSceneInjectionPoint( : 0; } -mono_bool -InternalCall_Rendering_ScriptableRenderContext_RecordFullscreenPass( - uint64_t nativeHandle, - int32_t passType, - MonoString* shaderPath, - MonoString* passName, - XCEngine::Math::Vector4* vectorPayload) { - ManagedScriptableRenderContextState* const state = - FindManagedScriptableRenderContextState(nativeHandle); - if (state == nullptr || - state->graphContext == nullptr || - !Rendering::IsCameraFrameFullscreenSequenceStage(state->stage)) { - return 0; - } - - Rendering::FullscreenPassDesc passDesc = {}; - switch (static_cast(passType)) { - case Rendering::FullscreenPassType::ColorScale: - if (vectorPayload == nullptr) { - return 0; - } - passDesc = - Rendering::FullscreenPassDesc::MakeColorScale(*vectorPayload); - break; - case Rendering::FullscreenPassType::ShaderVector: - if (vectorPayload == nullptr) { - return 0; - } - passDesc = Rendering::FullscreenPassDesc::MakeShaderVector( - Containers::String(MonoStringToUtf8(shaderPath).c_str()), - *vectorPayload, - Containers::String(MonoStringToUtf8(passName).c_str())); - if (!passDesc.IsValid()) { - return 0; - } - break; - default: - return 0; - } - - state->queuedFullscreenPasses.push_back(passDesc); - return 1; -} - int32_t InternalCall_Rendering_CameraRenderRequestContext_GetRenderedBaseCameraCount( uint64_t nativeHandle) { @@ -4299,6 +4850,19 @@ void RegisterInternalCalls() { mono_add_internal_call("XCEngine.InternalCalls::Rendering_SetRenderPipelineAsset", reinterpret_cast(&InternalCall_Rendering_SetRenderPipelineAsset)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_GetRenderPipelineAsset", reinterpret_cast(&InternalCall_Rendering_GetRenderPipelineAsset)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetStage", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetStage)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetSourceColorTextureHandle", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetSourceColorTextureHandle)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetPrimaryColorTargetHandle", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetPrimaryColorTargetHandle)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetDepthTargetHandle", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetDepthTargetHandle)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_CreateTransientTexture", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_CreateTransientTexture)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_CreateFullscreenTransientColorTexture", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_CreateFullscreenTransientColorTexture)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_CreateFullscreenTransientDepthTexture", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_CreateFullscreenTransientDepthTexture)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_BeginRasterPass", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_BeginRasterPass)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassSourceColorTexture", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassSourceColorTexture)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_AddRasterPassReadTexture", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_AddRasterPassReadTexture)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassColorAttachment", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassColorAttachment)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassColorScaleFullscreenExecution", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassColorScaleFullscreenExecution)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassShaderVectorFullscreenExecution", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassShaderVectorFullscreenExecution)); + mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_CommitRasterPass", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_CommitRasterPass)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetStageColorSource", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetStageColorSource)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetStageUsesGraphManagedOutputColor", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetStageUsesGraphManagedOutputColor)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalShadowEnabled", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowEnabled)); @@ -4352,7 +4916,6 @@ void RegisterInternalCalls() { mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_RecordScene", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_RecordScene)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_RecordScenePhase", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_RecordScenePhase)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_RecordSceneInjectionPoint", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_RecordSceneInjectionPoint)); - mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_RecordFullscreenPass", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderContext_RecordFullscreenPass)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_IsStageRequested", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_IsStageRequested)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_GetStageColorSource", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetStageColorSource)); mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderPipelinePlanningContext_GetStageUsesGraphManagedOutputColor", reinterpret_cast(&InternalCall_Rendering_ScriptableRenderPipelinePlanningContext_GetStageUsesGraphManagedOutputColor)); diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRenderPass.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRenderPass.cs new file mode 100644 index 00000000..e5db6fa9 --- /dev/null +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/ScriptableRenderPass.cs @@ -0,0 +1,338 @@ +using System; +using XCEngine; +using XCEngine.Rendering; + +namespace XCEngine.Rendering.Universal +{ + public abstract class ScriptableRenderPass + { + private const string kColorScaleFullscreenPassName = + "Universal.ColorScaleFullscreen"; + private const string kShaderVectorFullscreenPassName = + "Universal.ShaderVectorFullscreen"; + + private enum RecordedScenePhase + { + Opaque = 0, + Skybox = 1, + Transparent = 3 + } + + private enum RecordedSceneInjectionPoint + { + BeforeOpaque = 0, + AfterOpaque = 1, + BeforeSkybox = 2, + AfterSkybox = 3, + BeforeTransparent = 4, + AfterTransparent = 5 + } + + protected ScriptableRenderPass() + { + } + + public RenderPassEvent renderPassEvent { get; protected set; } = + RenderPassEvent.BeforeRenderingOpaques; + + public virtual bool SupportsStage( + CameraFrameStage stage) + { + CameraFrameStage resolvedStage; + return TryResolveStage( + renderPassEvent, + out resolvedStage) && + resolvedStage == stage; + } + + internal bool Record( + ScriptableRenderContext context, + RenderingData renderingData) + { + return RecordRenderGraph( + context, + renderingData); + } + + protected abstract bool RecordRenderGraph( + ScriptableRenderContext context, + RenderingData renderingData); + + protected bool RecordScene( + ScriptableRenderContext context) + { + return context != null && + InternalCalls + .Rendering_ScriptableRenderContext_RecordScene( + context.nativeHandle); + } + + protected bool RecordOpaqueScenePhase( + ScriptableRenderContext context) + { + return RecordScenePhaseInternal( + context, + RecordedScenePhase.Opaque); + } + + protected bool RecordSkyboxScenePhase( + ScriptableRenderContext context) + { + return RecordScenePhaseInternal( + context, + RecordedScenePhase.Skybox); + } + + protected bool RecordTransparentScenePhase( + ScriptableRenderContext context) + { + return RecordScenePhaseInternal( + context, + RecordedScenePhase.Transparent); + } + + protected bool RecordBeforeOpaqueInjection( + ScriptableRenderContext context) + { + return RecordSceneInjectionPointInternal( + context, + RecordedSceneInjectionPoint.BeforeOpaque); + } + + protected bool RecordAfterOpaqueInjection( + ScriptableRenderContext context) + { + return RecordSceneInjectionPointInternal( + context, + RecordedSceneInjectionPoint.AfterOpaque); + } + + protected bool RecordBeforeSkyboxInjection( + ScriptableRenderContext context) + { + return RecordSceneInjectionPointInternal( + context, + RecordedSceneInjectionPoint.BeforeSkybox); + } + + protected bool RecordAfterSkyboxInjection( + ScriptableRenderContext context) + { + return RecordSceneInjectionPointInternal( + context, + RecordedSceneInjectionPoint.AfterSkybox); + } + + protected bool RecordBeforeTransparentInjection( + ScriptableRenderContext context) + { + return RecordSceneInjectionPointInternal( + context, + RecordedSceneInjectionPoint.BeforeTransparent); + } + + protected bool RecordAfterTransparentInjection( + ScriptableRenderContext context) + { + return RecordSceneInjectionPointInternal( + context, + RecordedSceneInjectionPoint.AfterTransparent); + } + + protected bool RecordColorScaleFullscreenPass( + ScriptableRenderContext context, + Vector4 colorScale) + { + RenderGraphTextureHandle sourceColor; + RenderGraphTextureHandle outputColor; + return TryResolveDefaultFullscreenTargets( + context, + out sourceColor, + out outputColor) && + RecordColorScaleFullscreenPass( + context, + sourceColor, + outputColor, + colorScale); + } + + protected bool RecordColorScaleFullscreenPass( + ScriptableRenderContext context, + RenderGraphTextureHandle sourceColor, + RenderGraphTextureHandle outputColor, + Vector4 colorScale, + string passName = null) + { + if (context == null || + !outputColor.isValid) + { + return false; + } + + RenderGraphRasterPassBuilder passBuilder = + context.AddRasterPass( + ResolveFullscreenPassName( + passName, + kColorScaleFullscreenPassName)); + if (sourceColor.isValid) + { + passBuilder.UseColorSource(sourceColor); + } + + return passBuilder + .SetColorAttachment(outputColor) + .SetColorScaleFullscreenExecution(colorScale) + .Commit(); + } + + protected bool RecordShaderVectorFullscreenPass( + ScriptableRenderContext context, + string shaderPath, + Vector4 vectorPayload, + string passName = null) + { + if (string.IsNullOrEmpty(shaderPath)) + { + throw new ArgumentException( + "Fullscreen shader path cannot be null or empty.", + nameof(shaderPath)); + } + + RenderGraphTextureHandle sourceColor; + RenderGraphTextureHandle outputColor; + return TryResolveDefaultFullscreenTargets( + context, + out sourceColor, + out outputColor) && + RecordShaderVectorFullscreenPass( + context, + sourceColor, + outputColor, + shaderPath, + vectorPayload, + passName: passName); + } + + protected bool RecordShaderVectorFullscreenPass( + ScriptableRenderContext context, + RenderGraphTextureHandle sourceColor, + RenderGraphTextureHandle outputColor, + string shaderPath, + Vector4 vectorPayload, + string shaderPassName = null, + string passName = null) + { + if (string.IsNullOrEmpty(shaderPath)) + { + throw new ArgumentException( + "Fullscreen shader path cannot be null or empty.", + nameof(shaderPath)); + } + + if (context == null || + !outputColor.isValid) + { + return false; + } + + RenderGraphRasterPassBuilder passBuilder = + context.AddRasterPass( + ResolveFullscreenPassName( + passName, + kShaderVectorFullscreenPassName)); + if (sourceColor.isValid) + { + passBuilder.UseColorSource(sourceColor); + } + + return passBuilder + .SetColorAttachment(outputColor) + .SetShaderVectorFullscreenExecution( + shaderPath, + vectorPayload, + shaderPassName) + .Commit(); + } + + internal static bool TryResolveStage( + RenderPassEvent passEvent, + out CameraFrameStage stage) + { + switch (passEvent) + { + case RenderPassEvent.BeforeRenderingOpaques: + case RenderPassEvent.RenderOpaques: + case RenderPassEvent.AfterRenderingOpaques: + case RenderPassEvent.BeforeRenderingSkybox: + case RenderPassEvent.RenderSkybox: + case RenderPassEvent.AfterRenderingSkybox: + case RenderPassEvent.BeforeRenderingTransparents: + case RenderPassEvent.RenderTransparents: + case RenderPassEvent.AfterRenderingTransparents: + stage = CameraFrameStage.MainScene; + return true; + case RenderPassEvent.BeforeRenderingPostProcessing: + case RenderPassEvent.AfterRenderingPostProcessing: + stage = CameraFrameStage.PostProcess; + return true; + case RenderPassEvent.BeforeRenderingFinalOutput: + case RenderPassEvent.AfterRenderingFinalOutput: + stage = CameraFrameStage.FinalOutput; + return true; + default: + stage = CameraFrameStage.MainScene; + return false; + } + } + + private bool RecordScenePhaseInternal( + ScriptableRenderContext context, + RecordedScenePhase scenePhase) + { + return context != null && + InternalCalls + .Rendering_ScriptableRenderContext_RecordScenePhase( + context.nativeHandle, + (int)scenePhase); + } + + private bool RecordSceneInjectionPointInternal( + ScriptableRenderContext context, + RecordedSceneInjectionPoint injectionPoint) + { + return context != null && + InternalCalls + .Rendering_ScriptableRenderContext_RecordSceneInjectionPoint( + context.nativeHandle, + (int)injectionPoint); + } + + private static bool TryResolveDefaultFullscreenTargets( + ScriptableRenderContext context, + out RenderGraphTextureHandle sourceColor, + out RenderGraphTextureHandle outputColor) + { + sourceColor = new RenderGraphTextureHandle(); + outputColor = new RenderGraphTextureHandle(); + if (context == null) + { + return false; + } + + sourceColor = context.sourceColorTexture; + outputColor = context.primaryColorTarget; + return sourceColor.isValid && + outputColor.isValid; + } + + private static string ResolveFullscreenPassName( + string passName, + string defaultPassName) + { + return string.IsNullOrEmpty(passName) + ? defaultPassName + : passName; + } + } +} + diff --git a/managed/XCEngine.ScriptCore/InternalCalls.cs b/managed/XCEngine.ScriptCore/InternalCalls.cs index 0ed74740..039d52b3 100644 --- a/managed/XCEngine.ScriptCore/InternalCalls.cs +++ b/managed/XCEngine.ScriptCore/InternalCalls.cs @@ -389,6 +389,90 @@ namespace XCEngine internal static extern int Rendering_ScriptableRenderContext_GetStage( ulong nativeHandle); + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern int + Rendering_ScriptableRenderContext_GetSourceColorTextureHandle( + ulong nativeHandle); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern int + Rendering_ScriptableRenderContext_GetPrimaryColorTargetHandle( + ulong nativeHandle); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern int + Rendering_ScriptableRenderContext_GetDepthTargetHandle( + ulong nativeHandle); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern int + Rendering_ScriptableRenderContext_CreateTransientTexture( + ulong nativeHandle, + string name, + ref Rendering.RenderGraphTextureDesc desc); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern int + Rendering_ScriptableRenderContext_CreateFullscreenTransientColorTexture( + ulong nativeHandle, + string name); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern int + Rendering_ScriptableRenderContext_CreateFullscreenTransientDepthTexture( + ulong nativeHandle, + string name); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern ulong + Rendering_ScriptableRenderContext_BeginRasterPass( + ulong nativeHandle, + string passName); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern bool + Rendering_ScriptableRenderContext_SetRasterPassSourceColorTexture( + ulong nativeHandle, + ulong rasterPassHandle, + int sourceTextureHandle); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern bool + Rendering_ScriptableRenderContext_AddRasterPassReadTexture( + ulong nativeHandle, + ulong rasterPassHandle, + int textureHandle); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern bool + Rendering_ScriptableRenderContext_SetRasterPassColorAttachment( + ulong nativeHandle, + ulong rasterPassHandle, + int colorAttachmentIndex, + int textureHandle); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern bool + Rendering_ScriptableRenderContext_SetRasterPassColorScaleFullscreenExecution( + ulong nativeHandle, + ulong rasterPassHandle, + ref Vector4 vectorPayload); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern bool + Rendering_ScriptableRenderContext_SetRasterPassShaderVectorFullscreenExecution( + ulong nativeHandle, + ulong rasterPassHandle, + string shaderPath, + string shaderPassName, + ref Vector4 vectorPayload); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern bool + Rendering_ScriptableRenderContext_CommitRasterPass( + ulong nativeHandle, + ulong rasterPassHandle); + [MethodImpl(MethodImplOptions.InternalCall)] internal static extern bool Rendering_ScriptableRenderPipelinePlanningContext_IsStageRequested( @@ -703,15 +787,6 @@ namespace XCEngine ulong nativeHandle, int injectionPoint); - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool - Rendering_ScriptableRenderContext_RecordFullscreenPass( - ulong nativeHandle, - int passType, - string shaderPath, - string passName, - ref Vector4 vectorPayload); - [MethodImpl(MethodImplOptions.InternalCall)] internal static extern int Rendering_CameraRenderRequestContext_GetRenderedBaseCameraCount(