refactor(rendering): formalize pipeline selection and engine asset discovery

This commit is contained in:
2026-04-19 04:31:48 +08:00
parent 78bcd2e9ca
commit 48bfde28e3
17 changed files with 294 additions and 121 deletions

View File

@@ -23,14 +23,14 @@ void GraphicsSettingsState::ClearManagedRenderPipelineBridge() {
BumpEnvironmentGeneration();
}
void GraphicsSettingsState::SetRenderPipelineAssetDescriptor(
void GraphicsSettingsState::SetConfiguredRenderPipelineAssetDescriptor(
const Pipelines::ManagedRenderPipelineAssetDescriptor& descriptor) {
m_renderPipelineAssetDescriptor = descriptor;
m_configuredRenderPipelineAssetDescriptor = descriptor;
BumpEnvironmentGeneration();
}
void GraphicsSettingsState::ClearRenderPipelineAssetDescriptor() {
m_renderPipelineAssetDescriptor = {};
void GraphicsSettingsState::ClearConfiguredRenderPipelineAssetDescriptor() {
m_configuredRenderPipelineAssetDescriptor = {};
BumpEnvironmentGeneration();
}

View File

@@ -8,15 +8,27 @@ namespace XCEngine {
namespace Rendering {
namespace Internal {
std::shared_ptr<const RenderPipelineAsset> CreateDefaultRenderPipelineAsset() {
return Pipelines::CreateManagedOrDefaultScriptableRenderPipelineAsset();
std::shared_ptr<const RenderPipelineAsset> CreateConfiguredRenderPipelineAsset() {
return Pipelines::CreateConfiguredManagedRenderPipelineAsset();
}
std::shared_ptr<const RenderPipelineAsset> CreateFallbackRenderPipelineAsset() {
return std::make_shared<Pipelines::ScriptableRenderPipelineHostAsset>();
}
std::shared_ptr<const RenderPipelineAsset> ResolveRenderPipelineAssetOrDefault(
std::shared_ptr<const RenderPipelineAsset> preferredAsset) {
return preferredAsset != nullptr
? std::move(preferredAsset)
: CreateDefaultRenderPipelineAsset();
if (preferredAsset != nullptr) {
return std::move(preferredAsset);
}
if (std::shared_ptr<const RenderPipelineAsset> configuredAsset =
CreateConfiguredRenderPipelineAsset();
configuredAsset != nullptr) {
return configuredAsset;
}
return CreateFallbackRenderPipelineAsset();
}
std::unique_ptr<RenderPipeline> CreateRenderPipelineOrDefault(
@@ -34,10 +46,24 @@ std::unique_ptr<RenderPipeline> CreateRenderPipelineOrDefault(
}
}
const std::shared_ptr<const RenderPipelineAsset> defaultAsset =
ResolveRenderPipelineAssetOrDefault(nullptr);
if (defaultAsset != nullptr &&
defaultAsset != resolvedAsset) {
if (std::unique_ptr<RenderPipeline> pipeline =
defaultAsset->CreatePipeline()) {
if (outResolvedAsset != nullptr) {
*outResolvedAsset = defaultAsset;
}
return pipeline;
}
}
const std::shared_ptr<const RenderPipelineAsset> fallbackAsset =
CreateDefaultRenderPipelineAsset();
CreateFallbackRenderPipelineAsset();
if (fallbackAsset != nullptr &&
fallbackAsset != resolvedAsset) {
fallbackAsset != resolvedAsset &&
fallbackAsset != defaultAsset) {
if (std::unique_ptr<RenderPipeline> pipeline =
fallbackAsset->CreatePipeline()) {
if (outResolvedAsset != nullptr) {
@@ -51,7 +77,9 @@ std::unique_ptr<RenderPipeline> CreateRenderPipelineOrDefault(
*outResolvedAsset =
fallbackAsset != nullptr
? fallbackAsset
: resolvedAsset;
: (defaultAsset != nullptr
? defaultAsset
: resolvedAsset);
}
return std::make_unique<Pipelines::ScriptableRenderPipelineHost>();
}

View File

@@ -11,7 +11,8 @@ class RenderPipelineAsset;
namespace Internal {
std::shared_ptr<const RenderPipelineAsset> CreateDefaultRenderPipelineAsset();
std::shared_ptr<const RenderPipelineAsset> CreateConfiguredRenderPipelineAsset();
std::shared_ptr<const RenderPipelineAsset> CreateFallbackRenderPipelineAsset();
std::shared_ptr<const RenderPipelineAsset> ResolveRenderPipelineAssetOrDefault(
std::shared_ptr<const RenderPipelineAsset> preferredAsset);

View File

@@ -38,7 +38,8 @@ ManagedScriptableRenderPipelineAsset::ResolveManagedAssetRuntime() const {
}
std::unique_ptr<RenderPipeline> ManagedScriptableRenderPipelineAsset::CreatePipeline() const {
std::unique_ptr<RenderPipeline> pipeline = m_fallbackAsset.CreatePipeline();
std::unique_ptr<RenderPipeline> pipeline =
m_executionHostAsset.CreatePipeline();
auto* host = dynamic_cast<ScriptableRenderPipelineHost*>(pipeline.get());
if (host == nullptr) {
return pipeline;
@@ -85,7 +86,7 @@ FinalColorSettings ManagedScriptableRenderPipelineAsset::GetDefaultFinalColorSet
}
}
return m_fallbackAsset.GetDefaultFinalColorSettings();
return m_executionHostAsset.GetDefaultFinalColorSettings();
}
void ManagedScriptableRenderPipelineAsset::ConfigureCameraFramePlan(
@@ -118,29 +119,31 @@ size_t GetManagedRenderPipelineEnvironmentGeneration() {
return GetGraphicsSettingsState().GetEnvironmentGeneration();
}
void SetManagedRenderPipelineAssetDescriptor(
void SetConfiguredManagedRenderPipelineAssetDescriptor(
const ManagedRenderPipelineAssetDescriptor& descriptor) {
GetGraphicsSettingsState().SetRenderPipelineAssetDescriptor(
GetGraphicsSettingsState().SetConfiguredRenderPipelineAssetDescriptor(
descriptor);
}
void ClearManagedRenderPipelineAssetDescriptor() {
GetGraphicsSettingsState().ClearRenderPipelineAssetDescriptor();
void ClearConfiguredManagedRenderPipelineAssetDescriptor() {
GetGraphicsSettingsState().ClearConfiguredRenderPipelineAssetDescriptor();
}
ManagedRenderPipelineAssetDescriptor GetManagedRenderPipelineAssetDescriptor() {
return GetGraphicsSettingsState().GetRenderPipelineAssetDescriptor();
ManagedRenderPipelineAssetDescriptor
GetConfiguredManagedRenderPipelineAssetDescriptor() {
return GetGraphicsSettingsState()
.GetConfiguredRenderPipelineAssetDescriptor();
}
std::shared_ptr<const RenderPipelineAsset>
CreateManagedOrDefaultScriptableRenderPipelineAsset() {
CreateConfiguredManagedRenderPipelineAsset() {
const ManagedRenderPipelineAssetDescriptor descriptor =
GetGraphicsSettingsState().GetRenderPipelineAssetDescriptor();
GetGraphicsSettingsState().GetConfiguredRenderPipelineAssetDescriptor();
if (descriptor.IsValid()) {
return std::make_shared<ManagedScriptableRenderPipelineAsset>(descriptor);
}
return std::make_shared<ScriptableRenderPipelineHostAsset>();
return nullptr;
}
} // namespace Pipelines

View File

@@ -357,6 +357,14 @@ std::string TrimAssemblyName(const std::string& assemblyName) {
return assemblyName;
}
MonoScriptRuntime::ManagedAssemblyDescriptor BuildManagedAssemblyDescriptor(
const std::string& assemblyName,
const std::filesystem::path& assemblyPath) {
return MonoScriptRuntime::ManagedAssemblyDescriptor{
assemblyName,
assemblyPath};
}
bool IsMonoClassOrSubclass(MonoClass* monoClass, MonoClass* potentialBaseClass) {
if (!monoClass || !potentialBaseClass) {
return false;
@@ -386,12 +394,14 @@ MonoScriptRuntime* GetActiveMonoScriptRuntime() {
void ClearManagedRenderPipelineSelection(MonoScriptRuntime* runtime) {
const Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor =
Rendering::GetGraphicsSettingsState().GetRenderPipelineAssetDescriptor();
Rendering::GetGraphicsSettingsState()
.GetConfiguredRenderPipelineAssetDescriptor();
if (runtime != nullptr && descriptor.managedAssetHandle != 0u) {
runtime->ReleaseExternalManagedObject(descriptor.managedAssetHandle);
}
Rendering::GetGraphicsSettingsState().ClearRenderPipelineAssetDescriptor();
Rendering::GetGraphicsSettingsState()
.ClearConfiguredRenderPipelineAssetDescriptor();
}
bool TryUnboxManagedBoolean(MonoObject* boxedValue, bool& outValue) {
@@ -2812,7 +2822,8 @@ mono_bool InternalCall_Physics_Raycast(
void InternalCall_Rendering_SetRenderPipelineAsset(MonoObject* assetObject) {
MonoScriptRuntime* const runtime = GetActiveMonoScriptRuntime();
const Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor currentDescriptor =
Rendering::GetGraphicsSettingsState().GetRenderPipelineAssetDescriptor();
Rendering::GetGraphicsSettingsState()
.GetConfiguredRenderPipelineAssetDescriptor();
if (assetObject == nullptr) {
ClearManagedRenderPipelineSelection(runtime);
@@ -2856,8 +2867,8 @@ void InternalCall_Rendering_SetRenderPipelineAsset(MonoObject* assetObject) {
currentDescriptor.managedAssetHandle);
}
Rendering::GetGraphicsSettingsState().SetRenderPipelineAssetDescriptor(
descriptor);
Rendering::GetGraphicsSettingsState()
.SetConfiguredRenderPipelineAssetDescriptor(descriptor);
}
MonoObject* InternalCall_Rendering_GetRenderPipelineAsset() {
@@ -2867,7 +2878,8 @@ MonoObject* InternalCall_Rendering_GetRenderPipelineAsset() {
}
Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor descriptor =
Rendering::GetGraphicsSettingsState().GetRenderPipelineAssetDescriptor();
Rendering::GetGraphicsSettingsState()
.GetConfiguredRenderPipelineAssetDescriptor();
if (!descriptor.IsValid()) {
return nullptr;
}
@@ -2877,8 +2889,8 @@ MonoObject* InternalCall_Rendering_GetRenderPipelineAsset() {
return nullptr;
}
Rendering::GetGraphicsSettingsState().SetRenderPipelineAssetDescriptor(
descriptor);
Rendering::GetGraphicsSettingsState()
.SetConfiguredRenderPipelineAssetDescriptor(descriptor);
}
return runtime->GetExternalManagedObject(
@@ -3838,6 +3850,7 @@ void MonoScriptRuntime::Shutdown() {
m_appAssembly = nullptr;
m_coreImage = nullptr;
m_appImage = nullptr;
m_loadedManagedAssemblies.clear();
m_componentClass = nullptr;
m_behaviourClass = nullptr;
m_gameObjectClass = nullptr;
@@ -4304,6 +4317,19 @@ void MonoScriptRuntime::ResolveSettings() {
m_settings.corlibDirectory = m_settings.coreAssemblyPath.parent_path();
}
}
for (ManagedAssemblyDescriptor& assembly : m_settings.engineAssemblies) {
if (assembly.name.empty() && !assembly.path.empty()) {
assembly.name = assembly.path.stem().string();
}
if (assembly.path.empty() &&
!m_settings.assemblyDirectory.empty() &&
!assembly.name.empty()) {
assembly.path =
m_settings.assemblyDirectory / (assembly.name + ".dll");
}
}
}
bool MonoScriptRuntime::InitializeRootDomain() {
@@ -4387,42 +4413,95 @@ bool MonoScriptRuntime::LoadAssemblies() {
return false;
}
if (!std::filesystem::exists(m_settings.coreAssemblyPath)) {
SetError("Script core assembly does not exist: " + m_settings.coreAssemblyPath.string());
return false;
}
if (!std::filesystem::exists(m_settings.appAssemblyPath)) {
SetError("Game scripts assembly does not exist: " + m_settings.appAssemblyPath.string());
return false;
}
SetCurrentDomain();
m_loadedManagedAssemblies.clear();
m_coreAssembly = mono_domain_assembly_open(m_appDomain, m_settings.coreAssemblyPath.string().c_str());
if (!m_coreAssembly) {
SetError("Failed to load script core assembly: " + m_settings.coreAssemblyPath.string());
if (!LoadAssemblyImage(
BuildManagedAssemblyDescriptor(
m_settings.coreAssemblyName,
m_settings.coreAssemblyPath),
"script core",
m_coreAssembly,
m_coreImage)) {
return false;
}
m_coreImage = mono_assembly_get_image(m_coreAssembly);
if (!m_coreImage) {
SetError("Failed to access the script core image.");
for (const ManagedAssemblyDescriptor& assembly :
m_settings.engineAssemblies) {
MonoAssembly* loadedAssembly = nullptr;
MonoImage* loadedImage = nullptr;
if (!LoadAssemblyImage(
assembly,
"engine",
loadedAssembly,
loadedImage)) {
return false;
}
}
if (!LoadAssemblyImage(
BuildManagedAssemblyDescriptor(
m_settings.appAssemblyName,
m_settings.appAssemblyPath),
"game scripts",
m_appAssembly,
m_appImage)) {
return false;
}
m_appAssembly = mono_domain_assembly_open(m_appDomain, m_settings.appAssemblyPath.string().c_str());
if (!m_appAssembly) {
SetError("Failed to load game scripts assembly: " + m_settings.appAssemblyPath.string());
return true;
}
bool MonoScriptRuntime::LoadAssemblyImage(
const ManagedAssemblyDescriptor& descriptor,
const char* roleLabel,
MonoAssembly*& outAssembly,
MonoImage*& outImage) {
outAssembly = nullptr;
outImage = nullptr;
if (descriptor.name.empty() || descriptor.path.empty()) {
SetError(
"Managed " + std::string(roleLabel) +
" assembly descriptor is incomplete.");
return false;
}
m_appImage = mono_assembly_get_image(m_appAssembly);
if (!m_appImage) {
SetError("Failed to access the game scripts image.");
if (!std::filesystem::exists(descriptor.path)) {
SetError(
"Managed " + std::string(roleLabel) +
" assembly does not exist: " + descriptor.path.string());
return false;
}
if (m_loadedManagedAssemblies.contains(descriptor.name)) {
SetError(
"Managed assembly name is loaded more than once: " +
descriptor.name);
return false;
}
outAssembly = mono_domain_assembly_open(
m_appDomain,
descriptor.path.string().c_str());
if (!outAssembly) {
SetError(
"Failed to load managed " + std::string(roleLabel) +
" assembly: " + descriptor.path.string());
return false;
}
outImage = mono_assembly_get_image(outAssembly);
if (!outImage) {
SetError(
"Failed to access the managed " + std::string(roleLabel) +
" image: " + descriptor.path.string());
return false;
}
m_loadedManagedAssemblies.emplace(
descriptor.name,
LoadedManagedAssemblyData{outAssembly, outImage});
return true;
}
@@ -4568,6 +4647,15 @@ bool MonoScriptRuntime::DiscoverScriptClasses() {
}
DiscoverScriptClassesInImage(m_settings.appAssemblyName, m_appImage);
DiscoverRenderPipelineAssetClassesInImage(
m_settings.coreAssemblyName,
m_coreImage);
for (const ManagedAssemblyDescriptor& assembly :
m_settings.engineAssemblies) {
DiscoverRenderPipelineAssetClassesInImage(
assembly.name,
FindLoadedAssemblyImage(assembly.name));
}
DiscoverRenderPipelineAssetClassesInImage(
m_settings.appAssemblyName,
m_appImage);
@@ -4669,11 +4757,16 @@ void MonoScriptRuntime::DiscoverRenderPipelineAssetClassesInImage(
continue;
}
m_renderPipelineAssetClasses.push_back(
ScriptClassDescriptor{
assemblyName,
SafeString(mono_class_get_namespace(monoClass)),
SafeString(mono_class_get_name(monoClass))});
const ScriptClassDescriptor descriptor{
assemblyName,
SafeString(mono_class_get_namespace(monoClass)),
SafeString(mono_class_get_name(monoClass))};
if (std::find(
m_renderPipelineAssetClasses.begin(),
m_renderPipelineAssetClasses.end(),
descriptor) == m_renderPipelineAssetClasses.end()) {
m_renderPipelineAssetClasses.push_back(descriptor);
}
}
}
@@ -4899,13 +4992,7 @@ bool MonoScriptRuntime::ResolveManagedClass(
return false;
}
MonoImage* image = nullptr;
if (assemblyName == m_settings.coreAssemblyName) {
image = m_coreImage;
} else if (assemblyName == m_settings.appAssemblyName) {
image = m_appImage;
}
MonoImage* image = FindLoadedAssemblyImage(assemblyName);
if (!image) {
return false;
}
@@ -5875,6 +5962,14 @@ void MonoScriptRuntime::ClearClassCache() {
m_renderPipelineAssetClasses.clear();
}
MonoImage* MonoScriptRuntime::FindLoadedAssemblyImage(
const std::string& assemblyName) const {
const auto it = m_loadedManagedAssemblies.find(assemblyName);
return it != m_loadedManagedAssemblies.end()
? it->second.image
: nullptr;
}
bool MonoScriptRuntime::InvokeManagedMethod(
MonoObject* instance,
MonoMethod* method,