feat(rendering): add scriptable render context v1

This commit is contained in:
2026-04-17 21:53:52 +08:00
parent 4e2261ad37
commit 9026aff881
8 changed files with 290 additions and 7 deletions

View File

@@ -10,6 +10,7 @@
#include "Debug/Logger.h"
#include "Input/InputManager.h"
#include "Physics/PhysicsWorld.h"
#include "Rendering/Pipelines/BuiltinForwardPipeline.h"
#include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h"
#include "Scene/Scene.h"
#include "Scripting/ScriptComponent.h"
@@ -83,6 +84,52 @@ bool& GetInternalCallRegistrationState() {
return registered;
}
struct ManagedScriptableRenderContextState {
uint64_t handle = 0;
Rendering::CameraFrameStage stage = Rendering::CameraFrameStage::MainScene;
const Rendering::RenderPipelineStageRenderGraphContext* graphContext = nullptr;
Rendering::Pipelines::BuiltinForwardPipeline builtinForwardPipeline;
};
uint64_t& GetManagedScriptableRenderContextNextHandle() {
static uint64_t nextHandle = 1;
return nextHandle;
}
std::unordered_map<uint64_t, ManagedScriptableRenderContextState*>&
GetManagedScriptableRenderContextRegistry() {
static std::unordered_map<uint64_t, ManagedScriptableRenderContextState*> registry;
return registry;
}
ManagedScriptableRenderContextState* FindManagedScriptableRenderContextState(
uint64_t handle) {
const auto it = GetManagedScriptableRenderContextRegistry().find(handle);
return it != GetManagedScriptableRenderContextRegistry().end()
? it->second
: nullptr;
}
uint64_t RegisterManagedScriptableRenderContextState(
ManagedScriptableRenderContextState& state) {
uint64_t handle = GetManagedScriptableRenderContextNextHandle()++;
if (handle == 0) {
handle = GetManagedScriptableRenderContextNextHandle()++;
}
state.handle = handle;
GetManagedScriptableRenderContextRegistry()[handle] = &state;
return handle;
}
void UnregisterManagedScriptableRenderContextState(uint64_t handle) {
if (handle == 0) {
return;
}
GetManagedScriptableRenderContextRegistry().erase(handle);
}
void CleanupMonoRootDomainAtExit() {
MonoRootState& rootState = GetMonoRootState();
if (!rootState.rootDomain) {
@@ -233,14 +280,27 @@ public:
return false;
}
int32_t managedStage = static_cast<int32_t>(context.stage);
void* args[1] = { &managedStage };
ManagedScriptableRenderContextState managedContextState = {};
managedContextState.stage = context.stage;
managedContextState.graphContext = &context;
const uint64_t managedContextHandle =
RegisterManagedScriptableRenderContextState(managedContextState);
MonoObject* const managedContextObject =
m_runtime->CreateManagedScriptableRenderContext(managedContextHandle);
if (managedContextObject == nullptr) {
UnregisterManagedScriptableRenderContextState(managedContextHandle);
return false;
}
void* args[1] = { managedContextObject };
MonoObject* result = nullptr;
if (!m_runtime->InvokeManagedMethod(
const bool invokeSucceeded = m_runtime->InvokeManagedMethod(
pipelineObject,
method,
args,
&result)) {
&result);
UnregisterManagedScriptableRenderContextState(managedContextHandle);
if (!invokeSucceeded) {
return false;
}
@@ -2100,6 +2160,31 @@ MonoString* InternalCall_Rendering_GetRenderPipelineAssetTypeName() {
return mono_string_new(mono_domain_get(), assemblyQualifiedName.c_str());
}
int32_t InternalCall_Rendering_ScriptableRenderContext_GetStage(
uint64_t nativeHandle) {
const ManagedScriptableRenderContextState* const state =
FindManagedScriptableRenderContextState(nativeHandle);
return state != nullptr
? static_cast<int32_t>(state->stage)
: static_cast<int32_t>(Rendering::CameraFrameStage::MainScene);
}
mono_bool InternalCall_Rendering_ScriptableRenderContext_RenderBuiltinForwardMainScene(
uint64_t nativeHandle) {
ManagedScriptableRenderContextState* const state =
FindManagedScriptableRenderContextState(nativeHandle);
if (state == nullptr ||
state->graphContext == nullptr ||
state->stage != Rendering::CameraFrameStage::MainScene) {
return 0;
}
return state->builtinForwardPipeline.RecordStageRenderGraph(
*state->graphContext)
? 1
: 0;
}
void RegisterInternalCalls() {
if (GetInternalCallRegistrationState()) {
return;
@@ -2228,6 +2313,8 @@ void RegisterInternalCalls() {
mono_add_internal_call("XCEngine.InternalCalls::Physics_Raycast", reinterpret_cast<const void*>(&InternalCall_Physics_Raycast));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_SetRenderPipelineAssetType", reinterpret_cast<const void*>(&InternalCall_Rendering_SetRenderPipelineAssetType));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_GetRenderPipelineAssetTypeName", reinterpret_cast<const void*>(&InternalCall_Rendering_GetRenderPipelineAssetTypeName));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetStage", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_GetStage));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_RenderBuiltinForwardMainScene", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_RenderBuiltinForwardMainScene));
GetInternalCallRegistrationState() = true;
}
@@ -2280,6 +2367,8 @@ bool MonoScriptRuntime::Initialize() {
void MonoScriptRuntime::Shutdown() {
Rendering::Pipelines::ClearManagedRenderPipelineBridge();
GetManagedScriptableRenderContextRegistry().clear();
GetManagedScriptableRenderContextNextHandle() = 1;
ClearManagedInstances();
ClearExternalManagedObjects();
ClearClassCache();
@@ -2294,8 +2383,10 @@ void MonoScriptRuntime::Shutdown() {
m_monoBehaviourClass = nullptr;
m_scriptableRenderPipelineAssetClass = nullptr;
m_scriptableRenderPipelineClass = nullptr;
m_scriptableRenderContextClass = nullptr;
m_serializeFieldAttributeClass = nullptr;
m_gameObjectConstructor = nullptr;
m_scriptableRenderContextConstructor = nullptr;
m_managedGameObjectUUIDField = nullptr;
m_gameObjectUUIDField = nullptr;
m_scriptComponentUUIDField = nullptr;
@@ -2908,6 +2999,25 @@ bool MonoScriptRuntime::DiscoverScriptClasses() {
return false;
}
m_scriptableRenderContextClass = mono_class_from_name(
m_coreImage,
m_settings.baseNamespace.c_str(),
"ScriptableRenderContext");
if (!m_scriptableRenderContextClass) {
SetError("Failed to locate the managed ScriptableRenderContext type.");
return false;
}
m_scriptableRenderContextConstructor = mono_class_get_method_from_name(
m_scriptableRenderContextClass,
".ctor",
1);
if (!m_scriptableRenderContextConstructor) {
SetError(
"Failed to locate the managed ScriptableRenderContext constructor.");
return false;
}
m_serializeFieldAttributeClass = mono_class_from_name(
m_coreImage,
m_settings.baseNamespace.c_str(),
@@ -3322,6 +3432,43 @@ void MonoScriptRuntime::DestroyExternalManagedObject(uint32_t gcHandle) {
m_externalManagedObjects.erase(it);
}
MonoObject* MonoScriptRuntime::CreateManagedScriptableRenderContext(
uint64_t nativeHandle) {
if (!m_initialized ||
nativeHandle == 0 ||
m_scriptableRenderContextClass == nullptr ||
m_scriptableRenderContextConstructor == nullptr) {
return nullptr;
}
SetCurrentDomain();
MonoObject* const contextObject =
mono_object_new(m_appDomain, m_scriptableRenderContextClass);
if (contextObject == nullptr) {
SetError(
"Mono failed to allocate a managed ScriptableRenderContext.");
return nullptr;
}
void* args[1];
uint64_t nativeHandleArgument = nativeHandle;
args[0] = &nativeHandleArgument;
MonoObject* exception = nullptr;
mono_runtime_invoke(
m_scriptableRenderContextConstructor,
contextObject,
args,
&exception);
if (exception != nullptr) {
RecordException(exception);
return nullptr;
}
return contextObject;
}
MonoScriptRuntime::InstanceData* MonoScriptRuntime::FindInstance(const ScriptRuntimeContext& context) {
const auto it = m_instances.find(InstanceKey{context.gameObjectUUID, context.scriptComponentUUID});
return it != m_instances.end() ? &it->second : nullptr;