refactor(srp): let universal assets declare native backend keys
This commit is contained in:
202
docs/used/SRP_Universal原生后端Key接缝计划_完成归档_2026-04-19.md
Normal file
202
docs/used/SRP_Universal原生后端Key接缝计划_完成归档_2026-04-19.md
Normal file
@@ -0,0 +1,202 @@
|
||||
# SRP Universal 原生后端 Key 接缝计划 2026-04-19
|
||||
|
||||
## 1. 阶段目标
|
||||
|
||||
上一阶段已经把 Mono managed SRP 的:
|
||||
|
||||
1. host renderer
|
||||
2. stage recorder
|
||||
|
||||
收到了同一条 native backend ownership 上。
|
||||
|
||||
但当前仍然有一个关键问题没有解决:
|
||||
|
||||
`MonoManagedRenderPipelineAssetRuntime`
|
||||
现在还是统一硬编码返回:
|
||||
|
||||
`BuiltinForwardPipelineAsset`
|
||||
|
||||
这意味着:
|
||||
|
||||
1. managed asset 自己并没有显式声明“我要哪个 native backend”
|
||||
2. first-party `UniversalRenderPipelineAsset` 和普通 `ScriptableRenderPipelineAsset`
|
||||
在 native backend 选择上没有语义区别
|
||||
3. 未来想让不同 SRP/renderer data 走不同 native backend 时,
|
||||
还会继续卡在 Mono runtime 的类型外部硬编码
|
||||
|
||||
本阶段目标就是把这件事改成:
|
||||
|
||||
`ScriptableRenderPipelineAsset`
|
||||
-> 返回 native backend key
|
||||
-> Mono runtime 解析 key
|
||||
-> native factory 映射到 `RenderPipelineAsset`
|
||||
|
||||
先把“谁声明 backend”这件事正式落到 managed asset 自己身上。
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前问题
|
||||
|
||||
### 2.1 Universal 虽然已经有 `rendererData`,但还没有 native backend 声明权
|
||||
|
||||
当前 `UniversalRenderPipelineAsset` 已经拥有:
|
||||
|
||||
1. `rendererData`
|
||||
2. `CreatePipeline()`
|
||||
3. `ConfigureCameraRenderRequest()`
|
||||
|
||||
这些都说明 managed package 侧已经在承担“渲染管线组织”责任。
|
||||
|
||||
但 native backend 选择仍然没有经过它,而是 Mono runtime 统一硬编码。
|
||||
|
||||
这不符合我们要的方向:
|
||||
|
||||
1. first-party Universal 应该先成为第一个显式声明 backend 的包
|
||||
2. Mono runtime 只负责桥接,不负责替 asset 做产品决策
|
||||
|
||||
### 2.2 当前 `CreateNativeSceneRendererFromAsset(nullptr)` 语义不干净
|
||||
|
||||
上一阶段新补的:
|
||||
|
||||
`CreateNativeSceneRendererFromAsset(...)`
|
||||
|
||||
内部现在仍然会走:
|
||||
|
||||
`ResolveRenderPipelineAssetOrDefault(...)`
|
||||
|
||||
这对于“从一个明确 backend asset 创建 native scene renderer”这件事来说语义过重了。
|
||||
|
||||
如果传入 `nullptr`,它不该再去全局查询 configured render pipeline asset,
|
||||
更不该重新把当前 managed pipeline asset 自己绕回来。
|
||||
|
||||
这个点如果不修,后面 backend key seam 加上去以后,
|
||||
scene recorder 的 fallback 仍然有可能偷偷回到全局 configured asset,
|
||||
会把 ownership 再次搞脏。
|
||||
|
||||
### 2.3 当前还缺一组“unknown backend key 也不会崩”的测试
|
||||
|
||||
我们不仅要验证:
|
||||
|
||||
1. Universal 显式声明 builtin forward key 能被解析
|
||||
|
||||
还要验证:
|
||||
|
||||
1. key 不存在时 runtime 返回空 asset
|
||||
2. recorder 仍然能本地 fallback 到默认 native scene renderer
|
||||
3. 不会因为 unknown key 让 managed stage graph 录制回归
|
||||
|
||||
---
|
||||
|
||||
## 3. 本阶段方案
|
||||
|
||||
### 方案核心
|
||||
|
||||
新增一条受控的 managed seam:
|
||||
|
||||
`ScriptableRenderPipelineAsset`
|
||||
-> `GetPipelineRendererAssetKey()`
|
||||
-> Mono runtime
|
||||
-> native factory key mapping
|
||||
-> `RenderPipelineAsset`
|
||||
|
||||
### 第一阶段只落 first-party Universal
|
||||
|
||||
本阶段只让:
|
||||
|
||||
`UniversalRenderPipelineAsset`
|
||||
|
||||
显式返回:
|
||||
|
||||
`BuiltinForward`
|
||||
|
||||
也就是说:
|
||||
|
||||
1. Universal 成为第一个正式声明 native backend 的 managed package
|
||||
2. 普通 `ScriptableRenderPipelineAsset` 先保持默认不声明
|
||||
3. Mono runtime 对“未声明 key”的 asset 返回 `nullptr`
|
||||
4. host / recorder 再按本地 fallback 兜底
|
||||
|
||||
### 这样做的原因
|
||||
|
||||
这样能同时保证两件事:
|
||||
|
||||
1. 我们正式建立了面向未来的 backend key seam
|
||||
2. 又不会一次性把所有 custom SRP 公共 API 扩太大
|
||||
|
||||
---
|
||||
|
||||
## 4. 实施步骤
|
||||
|
||||
### Step 1:给 managed asset 加 backend key seam
|
||||
|
||||
目标:
|
||||
|
||||
1. 在 `ScriptableRenderPipelineAsset` 新增受保护虚方法
|
||||
2. 默认返回空 key
|
||||
3. `UniversalRenderPipelineAsset` override 返回 `BuiltinForward`
|
||||
|
||||
### Step 2:补 native key -> asset 工厂映射
|
||||
|
||||
目标:
|
||||
|
||||
1. 在 native factory 层新增统一的 key 解析入口
|
||||
2. 当前先支持 `BuiltinForward`
|
||||
3. 保证未来增加更多 native backend 时,不需要把 if/switch 散落到 Mono runtime
|
||||
|
||||
### Step 3:重构 Mono runtime 的 backend asset 解析
|
||||
|
||||
目标:
|
||||
|
||||
1. `MonoManagedRenderPipelineAssetRuntime::GetPipelineRendererAsset()`
|
||||
不再硬编码 builtin forward
|
||||
2. 改为调用 managed asset 的 backend key 方法
|
||||
3. 按 key 去 native factory 解析 asset
|
||||
4. 未声明或未知 key 时返回空 asset
|
||||
|
||||
### Step 4:修正 recorder fallback 语义
|
||||
|
||||
目标:
|
||||
|
||||
1. `CreateNativeSceneRendererFromAsset(nullptr)` 不再回查全局 configured pipeline asset
|
||||
2. recorder fallback 只在“本地 asset 解析失败”后回到默认 native scene renderer
|
||||
3. 避免 native backend 选择再次绕回全局 configured managed asset
|
||||
|
||||
### Step 5:补测试并完整验证
|
||||
|
||||
目标:
|
||||
|
||||
1. 增加 scripting tests,验证 Universal backend key -> builtin forward asset
|
||||
2. 增加 unknown key fallback 回归测试
|
||||
3. 编译 `rendering_unit_tests`、`scripting_tests`、`XCEditor`
|
||||
4. 旧版 editor 10s 冒烟
|
||||
5. 归档 plan、提交、推送
|
||||
|
||||
---
|
||||
|
||||
## 5. 验收标准
|
||||
|
||||
本阶段完成后应满足:
|
||||
|
||||
1. native backend 的声明责任开始落到 managed asset 自己
|
||||
2. first-party Universal 是第一个显式声明 native backend 的包
|
||||
3. Mono runtime 不再统一硬编码 builtin forward backend
|
||||
4. recorder fallback 不再回查全局 configured managed asset
|
||||
5. unknown backend key 不会导致 managed stage recording 崩坏
|
||||
|
||||
---
|
||||
|
||||
## 6. 本阶段不做的事
|
||||
|
||||
本阶段明确不做:
|
||||
|
||||
1. 不开放完整用户自定义 backend key 注册系统
|
||||
2. 不做 deferred
|
||||
3. 不做 lightmap / baking
|
||||
4. 不做 renderer data 到 native renderer asset 的复杂序列化桥
|
||||
5. 不做 editor workflow 扩展
|
||||
|
||||
这一刀只建立:
|
||||
|
||||
`managed asset -> backend key -> native asset`
|
||||
|
||||
这条正式接缝。
|
||||
@@ -41,6 +41,18 @@ std::shared_ptr<const RenderPipelineAsset> CreateFallbackRenderPipelineAsset() {
|
||||
return std::make_shared<Pipelines::ScriptableRenderPipelineHostAsset>();
|
||||
}
|
||||
|
||||
std::shared_ptr<const RenderPipelineAsset> CreatePipelineRendererAssetByKey(
|
||||
const std::string& key) {
|
||||
if (key == "BuiltinForward") {
|
||||
static const std::shared_ptr<const RenderPipelineAsset>
|
||||
s_builtinForwardPipelineAsset =
|
||||
std::make_shared<Pipelines::BuiltinForwardPipelineAsset>();
|
||||
return s_builtinForwardPipelineAsset;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<const RenderPipelineAsset> ResolveRenderPipelineAssetOrDefault(
|
||||
std::shared_ptr<const RenderPipelineAsset> preferredAsset) {
|
||||
if (preferredAsset != nullptr) {
|
||||
@@ -112,12 +124,10 @@ std::unique_ptr<RenderPipeline> CreateRenderPipelineOrDefault(
|
||||
std::unique_ptr<NativeSceneRenderer> CreateNativeSceneRendererFromAsset(
|
||||
const std::shared_ptr<const RenderPipelineAsset>& preferredAsset,
|
||||
std::shared_ptr<const RenderPipelineAsset>* outResolvedAsset) {
|
||||
const std::shared_ptr<const RenderPipelineAsset> resolvedAsset =
|
||||
ResolveRenderPipelineAssetOrDefault(preferredAsset);
|
||||
if (std::unique_ptr<NativeSceneRenderer> sceneRenderer =
|
||||
TryCreateNativeSceneRendererFromAsset(resolvedAsset)) {
|
||||
TryCreateNativeSceneRendererFromAsset(preferredAsset)) {
|
||||
if (outResolvedAsset != nullptr) {
|
||||
*outResolvedAsset = resolvedAsset;
|
||||
*outResolvedAsset = preferredAsset;
|
||||
}
|
||||
return sceneRenderer;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace XCEngine {
|
||||
@@ -13,6 +14,8 @@ namespace Internal {
|
||||
|
||||
std::shared_ptr<const RenderPipelineAsset> CreateConfiguredRenderPipelineAsset();
|
||||
std::shared_ptr<const RenderPipelineAsset> CreateFallbackRenderPipelineAsset();
|
||||
std::shared_ptr<const RenderPipelineAsset> CreatePipelineRendererAssetByKey(
|
||||
const std::string& key);
|
||||
|
||||
std::shared_ptr<const RenderPipelineAsset> ResolveRenderPipelineAssetOrDefault(
|
||||
std::shared_ptr<const RenderPipelineAsset> preferredAsset);
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "Rendering/Internal/RenderPipelineFactory.h"
|
||||
#include "Rendering/Passes/BuiltinVectorFullscreenPass.h"
|
||||
#include "Rendering/Planning/FullscreenPassDesc.h"
|
||||
#include "Rendering/Pipelines/BuiltinForwardPipeline.h"
|
||||
#include "Rendering/Pipelines/NativeSceneRecorder.h"
|
||||
#include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h"
|
||||
#include "Rendering/RenderPipelineStageGraphContract.h"
|
||||
@@ -743,6 +742,8 @@ private:
|
||||
MonoObject* assetObject) const;
|
||||
MonoMethod* ResolveGetDefaultFinalColorSettingsMethod(
|
||||
MonoObject* assetObject) const;
|
||||
MonoMethod* ResolveGetPipelineRendererAssetKeyMethod(
|
||||
MonoObject* assetObject) const;
|
||||
|
||||
MonoScriptRuntime* m_runtime = nullptr;
|
||||
std::weak_ptr<void> m_runtimeLifetime;
|
||||
@@ -751,8 +752,12 @@ private:
|
||||
mutable MonoMethod* m_createPipelineMethod = nullptr;
|
||||
mutable MonoMethod* m_configureCameraRenderRequestMethod = nullptr;
|
||||
mutable MonoMethod* m_getDefaultFinalColorSettingsMethod = nullptr;
|
||||
mutable MonoMethod* m_getPipelineRendererAssetKeyMethod = nullptr;
|
||||
mutable bool m_ownsManagedAssetHandle = false;
|
||||
mutable bool m_assetCreationAttempted = false;
|
||||
mutable bool m_pipelineRendererAssetResolved = false;
|
||||
mutable std::shared_ptr<const Rendering::RenderPipelineAsset>
|
||||
m_pipelineRendererAsset = nullptr;
|
||||
};
|
||||
|
||||
class MonoManagedRenderPipelineStageRecorder final
|
||||
@@ -1088,10 +1093,42 @@ bool MonoManagedRenderPipelineAssetRuntime::TryGetDefaultFinalColorSettings(
|
||||
|
||||
std::shared_ptr<const Rendering::RenderPipelineAsset>
|
||||
MonoManagedRenderPipelineAssetRuntime::GetPipelineRendererAsset() const {
|
||||
static const std::shared_ptr<const Rendering::RenderPipelineAsset>
|
||||
s_builtinForwardPipelineAsset =
|
||||
std::make_shared<Rendering::Pipelines::BuiltinForwardPipelineAsset>();
|
||||
return s_builtinForwardPipelineAsset;
|
||||
if (m_pipelineRendererAssetResolved) {
|
||||
return m_pipelineRendererAsset;
|
||||
}
|
||||
|
||||
m_pipelineRendererAssetResolved = true;
|
||||
m_pipelineRendererAsset.reset();
|
||||
if (!EnsureManagedAsset()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MonoObject* const assetObject = GetManagedAssetObject();
|
||||
MonoMethod* const method =
|
||||
ResolveGetPipelineRendererAssetKeyMethod(assetObject);
|
||||
if (assetObject == nullptr || method == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MonoObject* managedKeyObject = nullptr;
|
||||
if (!m_runtime->InvokeManagedMethod(
|
||||
assetObject,
|
||||
method,
|
||||
nullptr,
|
||||
&managedKeyObject)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::string pipelineRendererAssetKey =
|
||||
MonoStringToUtf8(reinterpret_cast<MonoString*>(managedKeyObject));
|
||||
if (pipelineRendererAssetKey.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_pipelineRendererAsset =
|
||||
Rendering::Internal::CreatePipelineRendererAssetByKey(
|
||||
pipelineRendererAssetKey);
|
||||
return m_pipelineRendererAsset;
|
||||
}
|
||||
|
||||
bool MonoManagedRenderPipelineAssetRuntime::CreateManagedPipeline(
|
||||
@@ -1199,6 +1236,9 @@ void MonoManagedRenderPipelineAssetRuntime::ReleaseManagedAsset() const {
|
||||
m_createPipelineMethod = nullptr;
|
||||
m_configureCameraRenderRequestMethod = nullptr;
|
||||
m_getDefaultFinalColorSettingsMethod = nullptr;
|
||||
m_getPipelineRendererAssetKeyMethod = nullptr;
|
||||
m_pipelineRendererAsset.reset();
|
||||
m_pipelineRendererAssetResolved = false;
|
||||
const bool ownsManagedAssetHandle = m_ownsManagedAssetHandle;
|
||||
m_ownsManagedAssetHandle = false;
|
||||
m_assetCreationAttempted = false;
|
||||
@@ -1262,6 +1302,20 @@ MonoManagedRenderPipelineAssetRuntime::ResolveGetDefaultFinalColorSettingsMethod
|
||||
return m_getDefaultFinalColorSettingsMethod;
|
||||
}
|
||||
|
||||
MonoMethod*
|
||||
MonoManagedRenderPipelineAssetRuntime::ResolveGetPipelineRendererAssetKeyMethod(
|
||||
MonoObject* assetObject) const {
|
||||
if (m_getPipelineRendererAssetKeyMethod == nullptr) {
|
||||
m_getPipelineRendererAssetKeyMethod =
|
||||
m_runtime->ResolveManagedMethod(
|
||||
assetObject,
|
||||
"GetPipelineRendererAssetKey",
|
||||
0);
|
||||
}
|
||||
|
||||
return m_getPipelineRendererAssetKeyMethod;
|
||||
}
|
||||
|
||||
class MonoManagedRenderPipelineBridge final
|
||||
: public Rendering::Pipelines::ManagedRenderPipelineBridge {
|
||||
public:
|
||||
|
||||
@@ -926,6 +926,20 @@ namespace Gameplay
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ManagedUnknownBackendRenderPipelineProbeAsset
|
||||
: UniversalRenderPipelineAsset
|
||||
{
|
||||
public ManagedUnknownBackendRenderPipelineProbeAsset()
|
||||
{
|
||||
rendererData = new ManagedRenderPipelineProbeRendererData();
|
||||
}
|
||||
|
||||
protected override string GetPipelineRendererAssetKey()
|
||||
{
|
||||
return "MissingBackend";
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ManagedUniversalRenderPipelineProbeAsset
|
||||
: UniversalRenderPipelineAsset
|
||||
{
|
||||
|
||||
@@ -22,6 +22,11 @@ namespace XCEngine.Rendering
|
||||
{
|
||||
return FinalColorSettings.CreateDefault();
|
||||
}
|
||||
|
||||
protected virtual string GetPipelineRendererAssetKey()
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,11 @@ namespace XCEngine.Rendering.Universal
|
||||
}
|
||||
}
|
||||
|
||||
protected override string GetPipelineRendererAssetKey()
|
||||
{
|
||||
return "BuiltinForward";
|
||||
}
|
||||
|
||||
private ScriptableRendererData ResolveRendererData()
|
||||
{
|
||||
if (rendererData == null)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <XCEngine/Rendering/Execution/CameraRenderer.h>
|
||||
#include <XCEngine/Rendering/Execution/RenderPipelineHost.h>
|
||||
#include <XCEngine/Rendering/Graph/RenderGraph.h>
|
||||
#include <XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h>
|
||||
#include <XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h>
|
||||
#include <XCEngine/Rendering/Pipelines/ScriptableRenderPipelineHost.h>
|
||||
#include <XCEngine/Rendering/RenderPassGraphContract.h>
|
||||
@@ -22,6 +23,7 @@
|
||||
#include <XCEngine/Scene/Scene.h>
|
||||
|
||||
#include "Rendering/Execution/Internal/CameraFrameGraph/SurfaceResolver.h"
|
||||
#include "Rendering/Internal/RenderPipelineFactory.h"
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -4508,6 +4510,39 @@ TEST(ScriptableRenderPipelineHost_Test, BindsCurrentPipelineRendererIntoStageRec
|
||||
host.GetPipelineRenderer());
|
||||
}
|
||||
|
||||
TEST(
|
||||
RenderPipelineFactory_Test,
|
||||
NullPreferredAssetSkipsConfiguredManagedPipelineAssetWhenCreatingNativeSceneRenderer) {
|
||||
Pipelines::ClearManagedRenderPipelineBridge();
|
||||
Pipelines::ClearConfiguredManagedRenderPipelineAssetDescriptor();
|
||||
|
||||
const Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = {
|
||||
"GameScripts",
|
||||
"Gameplay",
|
||||
"ManagedRenderPipelineProbeAsset"
|
||||
};
|
||||
auto bridgeState = std::make_shared<MockManagedRenderPipelineBridgeState>();
|
||||
Pipelines::SetManagedRenderPipelineBridge(
|
||||
std::make_shared<MockManagedRenderPipelineBridge>(bridgeState));
|
||||
Pipelines::SetConfiguredManagedRenderPipelineAssetDescriptor(descriptor);
|
||||
|
||||
std::shared_ptr<const RenderPipelineAsset> resolvedAsset = nullptr;
|
||||
std::unique_ptr<NativeSceneRenderer> sceneRenderer =
|
||||
Internal::CreateNativeSceneRendererFromAsset(
|
||||
nullptr,
|
||||
&resolvedAsset);
|
||||
|
||||
ASSERT_NE(sceneRenderer, nullptr);
|
||||
EXPECT_EQ(resolvedAsset, nullptr);
|
||||
EXPECT_NE(
|
||||
dynamic_cast<Pipelines::BuiltinForwardPipeline*>(sceneRenderer.get()),
|
||||
nullptr);
|
||||
EXPECT_EQ(bridgeState->createAssetRuntimeCalls, 0);
|
||||
|
||||
Pipelines::ClearConfiguredManagedRenderPipelineAssetDescriptor();
|
||||
Pipelines::ClearManagedRenderPipelineBridge();
|
||||
}
|
||||
|
||||
TEST(
|
||||
ScriptableRenderPipelineHost_Test,
|
||||
FallsBackToRendererWhenStageRecorderDeclinesRecording) {
|
||||
|
||||
@@ -2462,6 +2462,127 @@ TEST_F(
|
||||
nullptr);
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
MonoScriptRuntimeTest,
|
||||
ScriptCoreUniversalRenderPipelineAssetExposesBuiltinForwardRendererAsset) {
|
||||
const auto bridge =
|
||||
XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge();
|
||||
ASSERT_NE(bridge, nullptr);
|
||||
|
||||
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = {
|
||||
"XCEngine.RenderPipelines.Universal",
|
||||
"XCEngine.Rendering.Universal",
|
||||
"UniversalRenderPipelineAsset"
|
||||
};
|
||||
|
||||
std::shared_ptr<const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetRuntime>
|
||||
assetRuntime = bridge->CreateAssetRuntime(descriptor);
|
||||
ASSERT_NE(assetRuntime, nullptr);
|
||||
|
||||
const std::shared_ptr<const XCEngine::Rendering::RenderPipelineAsset>
|
||||
rendererAsset = assetRuntime->GetPipelineRendererAsset();
|
||||
ASSERT_NE(rendererAsset, nullptr);
|
||||
|
||||
std::unique_ptr<XCEngine::Rendering::RenderPipeline> pipeline =
|
||||
rendererAsset->CreatePipeline();
|
||||
ASSERT_NE(pipeline, nullptr);
|
||||
EXPECT_NE(
|
||||
dynamic_cast<XCEngine::Rendering::Pipelines::BuiltinForwardPipeline*>(
|
||||
pipeline.get()),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
MonoScriptRuntimeTest,
|
||||
ManagedRenderPipelineBridgeFallsBackToDefaultSceneRecorderWhenBackendKeyIsUnknown) {
|
||||
const auto bridge =
|
||||
XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge();
|
||||
ASSERT_NE(bridge, nullptr);
|
||||
|
||||
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = {
|
||||
"GameScripts",
|
||||
"Gameplay",
|
||||
"ManagedUnknownBackendRenderPipelineProbeAsset"
|
||||
};
|
||||
|
||||
std::shared_ptr<const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetRuntime>
|
||||
assetRuntime = bridge->CreateAssetRuntime(descriptor);
|
||||
ASSERT_NE(assetRuntime, nullptr);
|
||||
EXPECT_EQ(assetRuntime->GetPipelineRendererAsset(), nullptr);
|
||||
|
||||
std::unique_ptr<XCEngine::Rendering::RenderPipelineStageRecorder> recorder =
|
||||
assetRuntime->CreateStageRecorder();
|
||||
ASSERT_NE(recorder, nullptr);
|
||||
|
||||
const XCEngine::Rendering::RenderContext renderContext = {};
|
||||
ASSERT_TRUE(recorder->Initialize(renderContext));
|
||||
ASSERT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
|
||||
XCEngine::Rendering::RenderGraph graph;
|
||||
XCEngine::Rendering::RenderGraphBuilder graphBuilder(graph);
|
||||
XCEngine::Rendering::RenderGraphTextureDesc colorDesc = {};
|
||||
colorDesc.width = 64u;
|
||||
colorDesc.height = 64u;
|
||||
colorDesc.format =
|
||||
static_cast<XCEngine::Core::uint32>(
|
||||
XCEngine::RHI::Format::R8G8B8A8_UNorm);
|
||||
XCEngine::Rendering::RenderGraphTextureDesc depthDesc = colorDesc;
|
||||
depthDesc.format =
|
||||
static_cast<XCEngine::Core::uint32>(
|
||||
XCEngine::RHI::Format::D32_Float);
|
||||
const XCEngine::Rendering::RenderGraphTextureHandle colorTarget =
|
||||
graphBuilder.CreateTransientTexture("ManagedUnknownBackendColor", colorDesc);
|
||||
const XCEngine::Rendering::RenderGraphTextureHandle depthTarget =
|
||||
graphBuilder.CreateTransientTexture("ManagedUnknownBackendDepth", depthDesc);
|
||||
|
||||
const XCEngine::Rendering::RenderSceneData sceneData = {};
|
||||
const XCEngine::Rendering::RenderSurface surface(64u, 64u);
|
||||
bool executionSucceeded = true;
|
||||
XCEngine::Rendering::RenderGraphBlackboard blackboard = {};
|
||||
const XCEngine::Rendering::RenderPipelineStageRenderGraphContext graphContext = {
|
||||
graphBuilder,
|
||||
"ManagedUnknownBackendMainScene",
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene,
|
||||
renderContext,
|
||||
sceneData,
|
||||
surface,
|
||||
nullptr,
|
||||
nullptr,
|
||||
XCEngine::RHI::ResourceStates::Common,
|
||||
{},
|
||||
{ colorTarget },
|
||||
depthTarget,
|
||||
{},
|
||||
&executionSucceeded,
|
||||
&blackboard
|
||||
};
|
||||
|
||||
EXPECT_TRUE(recorder->RecordStageRenderGraph(graphContext));
|
||||
|
||||
XCEngine::Rendering::CompiledRenderGraph compiledGraph = {};
|
||||
XCEngine::Containers::String errorMessage;
|
||||
ASSERT_TRUE(
|
||||
XCEngine::Rendering::RenderGraphCompiler::Compile(
|
||||
graph,
|
||||
compiledGraph,
|
||||
&errorMessage))
|
||||
<< errorMessage.CStr();
|
||||
ASSERT_EQ(compiledGraph.GetPassCount(), 3u);
|
||||
EXPECT_STREQ(
|
||||
compiledGraph.GetPassName(0).CStr(),
|
||||
"ManagedUnknownBackendMainScene.Opaque");
|
||||
EXPECT_STREQ(
|
||||
compiledGraph.GetPassName(1).CStr(),
|
||||
"ManagedUnknownBackendMainScene.Skybox");
|
||||
EXPECT_STREQ(
|
||||
compiledGraph.GetPassName(2).CStr(),
|
||||
"ManagedUnknownBackendMainScene.Transparent");
|
||||
|
||||
recorder->Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
MonoScriptRuntimeTest,
|
||||
ManagedStageRecorderRecordsMainSceneThroughScriptableRenderContext) {
|
||||
|
||||
Reference in New Issue
Block a user