refactor(rendering): formalize pipeline selection and engine asset discovery
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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>();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user