chore: snapshot editor work and restore tests
Key points:\n- restore the tests tree removed by bc47e6e\n- capture current editor workspace, scene, and docs reshuffle changes\n- keep local cloud.nvdb resources ignored from this commit
This commit is contained in:
746
tests/scripting/test_project_script_assembly.cpp
Normal file
746
tests/scripting/test_project_script_assembly.cpp
Normal file
@@ -0,0 +1,746 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <XCEngine/Core/Asset/ResourceManager.h>
|
||||
#include <XCEngine/Input/InputManager.h>
|
||||
#include <XCEngine/Rendering/Execution/CameraFrameRenderGraphFrameData.h>
|
||||
#include <XCEngine/Rendering/Graph/RenderGraph.h>
|
||||
#include <XCEngine/Rendering/Graph/RenderGraphCompiler.h>
|
||||
#include <XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h>
|
||||
#include <XCEngine/Rendering/RenderSurface.h>
|
||||
#include <XCEngine/RHI/RHIResourceView.h>
|
||||
#include <XCEngine/Scene/Scene.h>
|
||||
#include <XCEngine/Scripting/Mono/MonoScriptRuntime.h>
|
||||
#include <XCEngine/Scripting/ScriptComponent.h>
|
||||
#include <XCEngine/Scripting/ScriptEngine.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
using namespace XCEngine::Components;
|
||||
using namespace XCEngine::Scripting;
|
||||
|
||||
namespace {
|
||||
|
||||
std::filesystem::path GetExecutableDirectory() {
|
||||
#ifdef _WIN32
|
||||
std::wstring buffer(MAX_PATH, L'\0');
|
||||
const DWORD length = GetModuleFileNameW(nullptr, buffer.data(), static_cast<DWORD>(buffer.size()));
|
||||
if (length == 0 || length >= buffer.size()) {
|
||||
return std::filesystem::current_path();
|
||||
}
|
||||
|
||||
buffer.resize(length);
|
||||
return std::filesystem::path(buffer).parent_path();
|
||||
#else
|
||||
return std::filesystem::current_path();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::filesystem::path ResolveProjectManagedOutputDirectory() {
|
||||
constexpr const char* configuredDirectory = XCENGINE_TEST_PROJECT_MANAGED_OUTPUT_DIR;
|
||||
if (configuredDirectory[0] != '\0') {
|
||||
return std::filesystem::path(configuredDirectory);
|
||||
}
|
||||
|
||||
return (GetExecutableDirectory() / ".." / ".." / "managed" / "ProjectScriptAssemblies").lexically_normal();
|
||||
}
|
||||
|
||||
std::filesystem::path ResolveProjectScriptCoreDllPath() {
|
||||
constexpr const char* configuredPath = XCENGINE_TEST_PROJECT_SCRIPT_CORE_DLL;
|
||||
if (configuredPath[0] != '\0') {
|
||||
return std::filesystem::path(configuredPath);
|
||||
}
|
||||
|
||||
return ResolveProjectManagedOutputDirectory() / "XCEngine.ScriptCore.dll";
|
||||
}
|
||||
|
||||
std::filesystem::path ResolveProjectGameScriptsDllPath() {
|
||||
constexpr const char* configuredPath = XCENGINE_TEST_PROJECT_GAME_SCRIPTS_DLL;
|
||||
if (configuredPath[0] != '\0') {
|
||||
return std::filesystem::path(configuredPath);
|
||||
}
|
||||
|
||||
return ResolveProjectManagedOutputDirectory() / "GameScripts.dll";
|
||||
}
|
||||
|
||||
MonoScriptRuntime::Settings CreateProjectMonoSettings() {
|
||||
MonoScriptRuntime::Settings settings;
|
||||
settings.assemblyDirectory = ResolveProjectManagedOutputDirectory();
|
||||
settings.corlibDirectory = settings.assemblyDirectory;
|
||||
settings.coreAssemblyPath = ResolveProjectScriptCoreDllPath();
|
||||
settings.appAssemblyPath = ResolveProjectGameScriptsDllPath();
|
||||
return settings;
|
||||
}
|
||||
|
||||
class ProjectScriptAssemblyTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
engine = &ScriptEngine::Get();
|
||||
engine->OnRuntimeStop();
|
||||
engine->SetRuntimeFixedDeltaTime(
|
||||
ScriptEngine::DefaultFixedDeltaTime);
|
||||
XCEngine::Input::InputManager::Get().Shutdown();
|
||||
XCEngine::Resources::ResourceManager::Get().Shutdown();
|
||||
XCEngine::Rendering::Pipelines::
|
||||
ClearConfiguredManagedRenderPipelineAssetDescriptor();
|
||||
|
||||
ASSERT_TRUE(std::filesystem::exists(ResolveProjectScriptCoreDllPath()));
|
||||
ASSERT_TRUE(std::filesystem::exists(ResolveProjectGameScriptsDllPath()));
|
||||
|
||||
MonoScriptRuntime::Settings settings =
|
||||
CreateProjectMonoSettings();
|
||||
std::string engineAssemblyError;
|
||||
ASSERT_TRUE(
|
||||
MonoScriptRuntime::DiscoverEngineAssemblies(
|
||||
settings,
|
||||
&engineAssemblyError))
|
||||
<< engineAssemblyError;
|
||||
ASSERT_FALSE(settings.engineAssemblies.empty());
|
||||
for (const MonoScriptRuntime::ManagedAssemblyDescriptor& assembly :
|
||||
settings.engineAssemblies) {
|
||||
ASSERT_TRUE(std::filesystem::exists(assembly.path))
|
||||
<< assembly.path.string();
|
||||
}
|
||||
|
||||
runtime = std::make_unique<MonoScriptRuntime>(std::move(settings));
|
||||
ASSERT_TRUE(runtime->Initialize()) << runtime->GetLastError();
|
||||
engine->SetRuntime(runtime.get());
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
if (engine != nullptr) {
|
||||
engine->OnRuntimeStop();
|
||||
engine->SetRuntime(nullptr);
|
||||
}
|
||||
|
||||
XCEngine::Input::InputManager::Get().Shutdown();
|
||||
XCEngine::Rendering::Pipelines::
|
||||
ClearConfiguredManagedRenderPipelineAssetDescriptor();
|
||||
runtime.reset();
|
||||
scene.reset();
|
||||
XCEngine::Resources::ResourceManager::Get().Shutdown();
|
||||
}
|
||||
|
||||
Scene* CreateScene(const std::string& sceneName) {
|
||||
scene = std::make_unique<Scene>(sceneName);
|
||||
return scene.get();
|
||||
}
|
||||
|
||||
ScriptComponent* AddProjectScript(
|
||||
GameObject* gameObject,
|
||||
const std::string& className) {
|
||||
ScriptComponent* component =
|
||||
gameObject->AddComponent<ScriptComponent>();
|
||||
component->SetScriptClass(
|
||||
"GameScripts",
|
||||
"ProjectScripts",
|
||||
className);
|
||||
return component;
|
||||
}
|
||||
|
||||
ScriptEngine* engine = nullptr;
|
||||
std::unique_ptr<MonoScriptRuntime> runtime;
|
||||
std::unique_ptr<Scene> scene;
|
||||
};
|
||||
|
||||
TEST_F(ProjectScriptAssemblyTest, InitializesFromProjectScriptAssemblyDirectory) {
|
||||
EXPECT_TRUE(runtime->IsInitialized());
|
||||
EXPECT_EQ(runtime->GetSettings().assemblyDirectory, ResolveProjectManagedOutputDirectory());
|
||||
EXPECT_EQ(runtime->GetSettings().appAssemblyPath, ResolveProjectGameScriptsDllPath());
|
||||
}
|
||||
|
||||
TEST_F(ProjectScriptAssemblyTest, DiscoversProjectAssetMonoBehaviourClassesAndFieldMetadata) {
|
||||
const std::vector<std::string> classNames = runtime->GetScriptClassNames("GameScripts");
|
||||
std::vector<ScriptClassDescriptor> classDescriptors;
|
||||
ASSERT_TRUE(runtime->TryGetAvailableScriptClasses(classDescriptors));
|
||||
|
||||
EXPECT_TRUE(runtime->IsClassAvailable("GameScripts", "ProjectScripts", "ProjectScriptProbe"));
|
||||
EXPECT_NE(
|
||||
std::find(classNames.begin(), classNames.end(), "ProjectScripts.ProjectScriptProbe"),
|
||||
classNames.end());
|
||||
EXPECT_NE(
|
||||
std::find(
|
||||
classDescriptors.begin(),
|
||||
classDescriptors.end(),
|
||||
ScriptClassDescriptor{"GameScripts", "ProjectScripts", "ProjectScriptProbe"}),
|
||||
classDescriptors.end());
|
||||
|
||||
std::vector<ScriptFieldMetadata> fields;
|
||||
ASSERT_TRUE(runtime->TryGetClassFieldMetadata("GameScripts", "ProjectScripts", "ProjectScriptProbe", fields));
|
||||
|
||||
const std::vector<ScriptFieldMetadata> expectedFields = {
|
||||
{"EnabledOnBoot", ScriptFieldType::Bool},
|
||||
{"Label", ScriptFieldType::String},
|
||||
{"Speed", ScriptFieldType::Float},
|
||||
};
|
||||
|
||||
EXPECT_EQ(fields, expectedFields);
|
||||
|
||||
std::vector<ScriptFieldDefaultValue> defaultValues;
|
||||
ASSERT_TRUE(runtime->TryGetClassFieldDefaultValues("GameScripts", "ProjectScripts", "ProjectScriptProbe", defaultValues));
|
||||
ASSERT_EQ(defaultValues.size(), 3u);
|
||||
|
||||
EXPECT_EQ(defaultValues[0].fieldName, "EnabledOnBoot");
|
||||
EXPECT_EQ(defaultValues[0].type, ScriptFieldType::Bool);
|
||||
EXPECT_EQ(std::get<bool>(defaultValues[0].value), true);
|
||||
|
||||
EXPECT_EQ(defaultValues[1].fieldName, "Label");
|
||||
EXPECT_EQ(defaultValues[1].type, ScriptFieldType::String);
|
||||
EXPECT_EQ(std::get<std::string>(defaultValues[1].value), "ProjectScriptProbe");
|
||||
|
||||
EXPECT_EQ(defaultValues[2].fieldName, "Speed");
|
||||
EXPECT_EQ(defaultValues[2].type, ScriptFieldType::Float);
|
||||
EXPECT_FLOAT_EQ(std::get<float>(defaultValues[2].value), 2.5f);
|
||||
}
|
||||
|
||||
TEST_F(ProjectScriptAssemblyTest, DiscoversProjectAssetRenderPipelineAssetClasses) {
|
||||
std::vector<ScriptClassDescriptor> classes;
|
||||
ASSERT_TRUE(runtime->TryGetAvailableRenderPipelineAssetClasses(classes));
|
||||
|
||||
EXPECT_NE(
|
||||
std::find(
|
||||
classes.begin(),
|
||||
classes.end(),
|
||||
ScriptClassDescriptor{
|
||||
"GameScripts",
|
||||
"ProjectScripts",
|
||||
"ProjectUniversalFeaturePipelineAsset"}),
|
||||
classes.end());
|
||||
EXPECT_NE(
|
||||
std::find(
|
||||
classes.begin(),
|
||||
classes.end(),
|
||||
ScriptClassDescriptor{
|
||||
"GameScripts",
|
||||
"ProjectScripts",
|
||||
"ProjectCustomRendererPipelineAsset"}),
|
||||
classes.end());
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ProjectScriptAssemblyTest,
|
||||
CreatesProjectAssetUniversalFeatureRuntimeThroughManagedBridge) {
|
||||
const auto bridge =
|
||||
XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge();
|
||||
ASSERT_NE(bridge, nullptr);
|
||||
|
||||
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = {
|
||||
"GameScripts",
|
||||
"ProjectScripts",
|
||||
"ProjectUniversalFeaturePipelineAsset"
|
||||
};
|
||||
|
||||
std::shared_ptr<const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetRuntime>
|
||||
assetRuntime = bridge->CreateAssetRuntime(descriptor);
|
||||
ASSERT_NE(assetRuntime, nullptr);
|
||||
EXPECT_NE(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));
|
||||
EXPECT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
EXPECT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::PostProcess));
|
||||
|
||||
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);
|
||||
const XCEngine::Rendering::RenderGraphTextureHandle sourceColor =
|
||||
graphBuilder.ImportTexture(
|
||||
"ProjectManagedPostProcessSource",
|
||||
colorDesc,
|
||||
reinterpret_cast<XCEngine::RHI::RHIResourceView*>(901),
|
||||
{});
|
||||
const XCEngine::Rendering::RenderGraphTextureHandle outputColor =
|
||||
graphBuilder.CreateTransientTexture(
|
||||
"ProjectManagedPostProcessOutput",
|
||||
colorDesc);
|
||||
|
||||
const XCEngine::Rendering::RenderSceneData sceneData = {};
|
||||
const XCEngine::Rendering::RenderSurface surface(64u, 64u);
|
||||
bool executionSucceeded = true;
|
||||
XCEngine::Rendering::RenderGraphBlackboard blackboard = {};
|
||||
XCEngine::Rendering::EmplaceCameraFrameRenderGraphFrameData(blackboard)
|
||||
.resources.mainScene.color = sourceColor;
|
||||
const XCEngine::Rendering::RenderPipelineStageRenderGraphContext graphContext = {
|
||||
graphBuilder,
|
||||
"ProjectManagedPostProcess",
|
||||
XCEngine::Rendering::CameraFrameStage::PostProcess,
|
||||
renderContext,
|
||||
sceneData,
|
||||
surface,
|
||||
nullptr,
|
||||
nullptr,
|
||||
XCEngine::RHI::ResourceStates::Common,
|
||||
{},
|
||||
{ outputColor },
|
||||
{},
|
||||
{},
|
||||
&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(), 1u);
|
||||
EXPECT_STREQ(
|
||||
compiledGraph.GetPassName(0).CStr(),
|
||||
"ProjectManagedPostProcess");
|
||||
|
||||
recorder->Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ProjectScriptAssemblyTest,
|
||||
CreatesProjectCustomRendererPipelineAssetThroughManagedBridge) {
|
||||
const auto bridge =
|
||||
XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge();
|
||||
ASSERT_NE(bridge, nullptr);
|
||||
|
||||
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor = {
|
||||
"GameScripts",
|
||||
"ProjectScripts",
|
||||
"ProjectCustomRendererPipelineAsset"
|
||||
};
|
||||
|
||||
std::shared_ptr<const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetRuntime>
|
||||
assetRuntime = bridge->CreateAssetRuntime(descriptor);
|
||||
ASSERT_NE(assetRuntime, nullptr);
|
||||
EXPECT_NE(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));
|
||||
EXPECT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
EXPECT_FALSE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::PostProcess));
|
||||
|
||||
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(
|
||||
"ProjectCustomMainSceneColor",
|
||||
colorDesc);
|
||||
const XCEngine::Rendering::RenderGraphTextureHandle depthTarget =
|
||||
graphBuilder.CreateTransientTexture(
|
||||
"ProjectCustomMainSceneDepth",
|
||||
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,
|
||||
"ProjectCustomMainScene",
|
||||
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(), 1u);
|
||||
EXPECT_STREQ(
|
||||
compiledGraph.GetPassName(0).CStr(),
|
||||
"ProjectCustomMainScene.Opaque");
|
||||
|
||||
recorder->Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ProjectScriptAssemblyTest,
|
||||
ProjectManagedBridgeRebuildsRendererAfterProjectRendererDataInvalidation) {
|
||||
Scene* runtimeScene =
|
||||
CreateScene("ProjectRendererInvalidationScene");
|
||||
GameObject* selectionObject =
|
||||
runtimeScene->CreateGameObject(
|
||||
"ProjectRendererInvalidationSelection");
|
||||
ScriptComponent* selectionScript =
|
||||
AddProjectScript(
|
||||
selectionObject,
|
||||
"ProjectRendererInvalidationRuntimeSelectionProbe");
|
||||
ASSERT_NE(selectionScript, nullptr);
|
||||
GameObject* observationObject =
|
||||
runtimeScene->CreateGameObject(
|
||||
"ProjectRendererInvalidationObservation");
|
||||
ScriptComponent* observationScript =
|
||||
AddProjectScript(
|
||||
observationObject,
|
||||
"ProjectRendererInvalidationObservationProbe");
|
||||
ASSERT_NE(observationScript, nullptr);
|
||||
|
||||
engine->OnRuntimeStart(runtimeScene);
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor
|
||||
descriptor =
|
||||
XCEngine::Rendering::Pipelines::
|
||||
GetConfiguredManagedRenderPipelineAssetDescriptor();
|
||||
ASSERT_TRUE(descriptor.IsValid());
|
||||
ASSERT_NE(descriptor.managedAssetHandle, 0u);
|
||||
EXPECT_EQ(descriptor.assemblyName, "GameScripts");
|
||||
EXPECT_EQ(descriptor.namespaceName, "ProjectScripts");
|
||||
EXPECT_EQ(
|
||||
descriptor.className,
|
||||
"ProjectRendererInvalidationProbeAsset");
|
||||
|
||||
const auto bridge =
|
||||
XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge();
|
||||
ASSERT_NE(bridge, nullptr);
|
||||
|
||||
std::shared_ptr<const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetRuntime>
|
||||
assetRuntime = bridge->CreateAssetRuntime(descriptor);
|
||||
ASSERT_NE(assetRuntime, nullptr);
|
||||
|
||||
std::unique_ptr<XCEngine::Rendering::RenderPipelineStageRecorder>
|
||||
recorder = assetRuntime->CreateStageRecorder();
|
||||
ASSERT_NE(recorder, nullptr);
|
||||
|
||||
const XCEngine::Rendering::RenderContext context = {};
|
||||
ASSERT_TRUE(recorder->Initialize(context));
|
||||
ASSERT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
ASSERT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
EXPECT_TRUE(runtime->GetLastError().empty()) << runtime->GetLastError();
|
||||
|
||||
int observedCreatePipelineCallCount = 0;
|
||||
int observedDisposePipelineCallCount = 0;
|
||||
int observedCreateRendererCallCount = 0;
|
||||
int observedSetupRendererCallCount = 0;
|
||||
int observedCreateFeatureCallCount = 0;
|
||||
int observedDisposeRendererCallCount = 0;
|
||||
int observedDisposeFeatureCallCount = 0;
|
||||
int observedInvalidateRendererCallCount = 0;
|
||||
int observedRuntimeResourceVersionBeforeInvalidation = 0;
|
||||
int observedRuntimeResourceVersionAfterInvalidation = 0;
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedCreatePipelineCallCount",
|
||||
observedCreatePipelineCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedDisposePipelineCallCount",
|
||||
observedDisposePipelineCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedCreateRendererCallCount",
|
||||
observedCreateRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedSetupRendererCallCount",
|
||||
observedSetupRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedCreateFeatureCallCount",
|
||||
observedCreateFeatureCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedDisposeRendererCallCount",
|
||||
observedDisposeRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedDisposeFeatureCallCount",
|
||||
observedDisposeFeatureCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedInvalidateRendererCallCount",
|
||||
observedInvalidateRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedRuntimeResourceVersionBeforeInvalidation",
|
||||
observedRuntimeResourceVersionBeforeInvalidation));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedRuntimeResourceVersionAfterInvalidation",
|
||||
observedRuntimeResourceVersionAfterInvalidation));
|
||||
|
||||
EXPECT_EQ(observedCreatePipelineCallCount, 2);
|
||||
EXPECT_EQ(observedDisposePipelineCallCount, 1);
|
||||
EXPECT_EQ(observedCreateRendererCallCount, 2);
|
||||
EXPECT_EQ(observedSetupRendererCallCount, 2);
|
||||
EXPECT_EQ(observedCreateFeatureCallCount, 2);
|
||||
EXPECT_EQ(observedDisposeRendererCallCount, 1);
|
||||
EXPECT_EQ(observedDisposeFeatureCallCount, 1);
|
||||
EXPECT_EQ(observedInvalidateRendererCallCount, 1);
|
||||
EXPECT_GT(observedRuntimeResourceVersionBeforeInvalidation, 0);
|
||||
EXPECT_EQ(
|
||||
observedRuntimeResourceVersionAfterInvalidation,
|
||||
observedRuntimeResourceVersionBeforeInvalidation + 1);
|
||||
|
||||
recorder->Shutdown();
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ProjectScriptAssemblyTest,
|
||||
ProjectManagedBridgeReleasesProjectRendererCachesAcrossInvalidationAndAssetRuntimeRelease) {
|
||||
Scene* runtimeScene =
|
||||
CreateScene("ProjectPersistentFeatureLifecycleScene");
|
||||
GameObject* selectionObject =
|
||||
runtimeScene->CreateGameObject(
|
||||
"ProjectPersistentFeatureSelection");
|
||||
ScriptComponent* selectionScript =
|
||||
AddProjectScript(
|
||||
selectionObject,
|
||||
"ProjectPersistentFeatureRuntimeSelectionProbe");
|
||||
ASSERT_NE(selectionScript, nullptr);
|
||||
GameObject* observationObject =
|
||||
runtimeScene->CreateGameObject(
|
||||
"ProjectPersistentFeatureObservation");
|
||||
ScriptComponent* observationScript =
|
||||
AddProjectScript(
|
||||
observationObject,
|
||||
"ProjectPersistentFeatureObservationProbe");
|
||||
ASSERT_NE(observationScript, nullptr);
|
||||
|
||||
engine->OnRuntimeStart(runtimeScene);
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor
|
||||
descriptor =
|
||||
XCEngine::Rendering::Pipelines::
|
||||
GetConfiguredManagedRenderPipelineAssetDescriptor();
|
||||
ASSERT_TRUE(descriptor.IsValid());
|
||||
ASSERT_NE(descriptor.managedAssetHandle, 0u);
|
||||
EXPECT_EQ(descriptor.assemblyName, "GameScripts");
|
||||
EXPECT_EQ(descriptor.namespaceName, "ProjectScripts");
|
||||
EXPECT_EQ(
|
||||
descriptor.className,
|
||||
"ProjectPersistentFeatureProbeAsset");
|
||||
|
||||
{
|
||||
const auto bridge =
|
||||
XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge();
|
||||
ASSERT_NE(bridge, nullptr);
|
||||
|
||||
std::shared_ptr<const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetRuntime>
|
||||
assetRuntime = bridge->CreateAssetRuntime(descriptor);
|
||||
ASSERT_NE(assetRuntime, nullptr);
|
||||
|
||||
std::unique_ptr<XCEngine::Rendering::RenderPipelineStageRecorder>
|
||||
recorder = assetRuntime->CreateStageRecorder();
|
||||
ASSERT_NE(recorder, nullptr);
|
||||
|
||||
const XCEngine::Rendering::RenderContext context = {};
|
||||
ASSERT_TRUE(recorder->Initialize(context));
|
||||
ASSERT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
ASSERT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
|
||||
recorder->Shutdown();
|
||||
}
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
EXPECT_TRUE(runtime->GetLastError().empty()) << runtime->GetLastError();
|
||||
|
||||
int observedCreateRendererCallCount = 0;
|
||||
int observedCreateFeatureRuntimeCallCount = 0;
|
||||
int observedDisposeRendererCallCount = 0;
|
||||
int observedDisposeFeatureCallCount = 0;
|
||||
int observedInvalidateRendererCallCount = 0;
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedCreateRendererCallCount",
|
||||
observedCreateRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedCreateFeatureRuntimeCallCount",
|
||||
observedCreateFeatureRuntimeCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedDisposeRendererCallCount",
|
||||
observedDisposeRendererCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedDisposeFeatureCallCount",
|
||||
observedDisposeFeatureCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedInvalidateRendererCallCount",
|
||||
observedInvalidateRendererCallCount));
|
||||
|
||||
EXPECT_EQ(observedCreateRendererCallCount, 2);
|
||||
EXPECT_EQ(observedCreateFeatureRuntimeCallCount, 2);
|
||||
EXPECT_EQ(observedDisposeRendererCallCount, 2);
|
||||
EXPECT_EQ(observedDisposeFeatureCallCount, 2);
|
||||
EXPECT_EQ(observedInvalidateRendererCallCount, 1);
|
||||
}
|
||||
|
||||
TEST_F(
|
||||
ProjectScriptAssemblyTest,
|
||||
ProjectManagedBridgeRebuildsPipelineAfterProjectAssetInvalidation) {
|
||||
Scene* runtimeScene =
|
||||
CreateScene("ProjectAssetInvalidationScene");
|
||||
GameObject* selectionObject =
|
||||
runtimeScene->CreateGameObject(
|
||||
"ProjectAssetInvalidationSelection");
|
||||
ScriptComponent* selectionScript =
|
||||
AddProjectScript(
|
||||
selectionObject,
|
||||
"ProjectAssetInvalidationRuntimeSelectionProbe");
|
||||
ASSERT_NE(selectionScript, nullptr);
|
||||
GameObject* observationObject =
|
||||
runtimeScene->CreateGameObject(
|
||||
"ProjectAssetInvalidationObservation");
|
||||
ScriptComponent* observationScript =
|
||||
AddProjectScript(
|
||||
observationObject,
|
||||
"ProjectAssetInvalidationObservationProbe");
|
||||
ASSERT_NE(observationScript, nullptr);
|
||||
|
||||
engine->OnRuntimeStart(runtimeScene);
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor
|
||||
descriptor =
|
||||
XCEngine::Rendering::Pipelines::
|
||||
GetConfiguredManagedRenderPipelineAssetDescriptor();
|
||||
ASSERT_TRUE(descriptor.IsValid());
|
||||
ASSERT_NE(descriptor.managedAssetHandle, 0u);
|
||||
EXPECT_EQ(descriptor.assemblyName, "GameScripts");
|
||||
EXPECT_EQ(descriptor.namespaceName, "ProjectScripts");
|
||||
EXPECT_EQ(
|
||||
descriptor.className,
|
||||
"ProjectAssetInvalidationProbeAsset");
|
||||
|
||||
const auto bridge =
|
||||
XCEngine::Rendering::Pipelines::GetManagedRenderPipelineBridge();
|
||||
ASSERT_NE(bridge, nullptr);
|
||||
|
||||
std::shared_ptr<const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetRuntime>
|
||||
assetRuntime = bridge->CreateAssetRuntime(descriptor);
|
||||
ASSERT_NE(assetRuntime, nullptr);
|
||||
|
||||
std::unique_ptr<XCEngine::Rendering::RenderPipelineStageRecorder>
|
||||
recorder = assetRuntime->CreateStageRecorder();
|
||||
ASSERT_NE(recorder, nullptr);
|
||||
|
||||
const XCEngine::Rendering::RenderContext context = {};
|
||||
ASSERT_TRUE(recorder->Initialize(context));
|
||||
ASSERT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
ASSERT_FALSE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::PostProcess));
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
|
||||
ASSERT_FALSE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::MainScene));
|
||||
ASSERT_TRUE(
|
||||
recorder->SupportsStageRenderGraph(
|
||||
XCEngine::Rendering::CameraFrameStage::PostProcess));
|
||||
|
||||
engine->OnUpdate(0.016f);
|
||||
EXPECT_TRUE(runtime->GetLastError().empty()) << runtime->GetLastError();
|
||||
|
||||
int observedCreatePipelineCallCount = 0;
|
||||
int observedDisposePipelineCallCount = 0;
|
||||
int observedInvalidateAssetCallCount = 0;
|
||||
int observedLastCreatedSupportedStage = 0;
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedCreatePipelineCallCount",
|
||||
observedCreatePipelineCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedDisposePipelineCallCount",
|
||||
observedDisposePipelineCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedInvalidateAssetCallCount",
|
||||
observedInvalidateAssetCallCount));
|
||||
EXPECT_TRUE(runtime->TryGetFieldValue(
|
||||
observationScript,
|
||||
"ObservedLastCreatedSupportedStage",
|
||||
observedLastCreatedSupportedStage));
|
||||
|
||||
EXPECT_EQ(observedCreatePipelineCallCount, 2);
|
||||
EXPECT_EQ(observedDisposePipelineCallCount, 1);
|
||||
EXPECT_EQ(observedInvalidateAssetCallCount, 1);
|
||||
EXPECT_EQ(
|
||||
observedLastCreatedSupportedStage,
|
||||
static_cast<int>(
|
||||
XCEngine::Rendering::CameraFrameStage::PostProcess));
|
||||
|
||||
recorder->Shutdown();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user