Bridge managed render funcs to command buffers

This commit is contained in:
2026-04-27 16:11:54 +08:00
parent 2e6643b4d1
commit 048ca7b362
10 changed files with 697 additions and 27 deletions

View File

@@ -31,6 +31,7 @@
#include "Rendering/RenderPipelineStageGraphContract.h"
#include "Resources/BuiltinResources.h"
#include "Core/Asset/ResourceManager.h"
#include "RHI/RHICommandList.h"
#include "Scene/Scene.h"
#include "Scripting/ScriptComponent.h"
#include "Scripting/ScriptEngine.h"
@@ -63,6 +64,8 @@ namespace {
constexpr const char* kManagedRenderingNamespace = "XCEngine.Rendering";
MonoScriptRuntime* GetActiveMonoScriptRuntime();
struct MonoRootState {
MonoDomain* rootDomain = nullptr;
bool initialized = false;
@@ -117,6 +120,7 @@ struct ManagedScriptableRenderContextState {
Containers::String passName = {};
Rendering::FullscreenPassDesc passDesc = {};
bool usesManagedRenderFuncExecution = false;
uint32_t managedRenderFuncHandle = 0u;
Rendering::RenderGraphTextureHandle sourceColorTexture = {};
std::vector<Rendering::RenderGraphTextureHandle> readTextures = {};
std::vector<Rendering::RenderGraphTextureHandle> readDepthTextures = {};
@@ -163,6 +167,21 @@ struct ManagedScriptableRenderPipelinePlanningContextState {
Rendering::CameraFramePlan* plan = nullptr;
};
struct ManagedCommandBufferCommand {
enum class Kind {
ClearRenderTarget
};
Kind kind = Kind::ClearRenderTarget;
float color[4] = {};
};
struct ManagedCommandBufferState {
uint64_t handle = 0;
const Rendering::RenderPassContext* passContext = nullptr;
std::vector<ManagedCommandBufferCommand> commands = {};
};
uint64_t& GetManagedScriptableRenderContextNextHandle() {
static uint64_t nextHandle = 1;
return nextHandle;
@@ -217,6 +236,108 @@ void UnregisterManagedScriptableRenderContextState(uint64_t handle) {
GetManagedScriptableRenderContextRegistry().erase(handle);
}
uint64_t& GetManagedCommandBufferNextHandle() {
static uint64_t nextHandle = 1;
return nextHandle;
}
std::unordered_map<uint64_t, ManagedCommandBufferState*>&
GetManagedCommandBufferRegistry() {
static std::unordered_map<uint64_t, ManagedCommandBufferState*> registry;
return registry;
}
uint64_t RegisterManagedCommandBufferState(
ManagedCommandBufferState& state) {
uint64_t handle = GetManagedCommandBufferNextHandle()++;
if (handle == 0u) {
handle = GetManagedCommandBufferNextHandle()++;
}
state.handle = handle;
GetManagedCommandBufferRegistry()[handle] = &state;
return handle;
}
ManagedCommandBufferState* FindManagedCommandBufferState(
uint64_t handle) {
if (handle == 0u) {
return nullptr;
}
const auto it = GetManagedCommandBufferRegistry().find(handle);
return it != GetManagedCommandBufferRegistry().end()
? it->second
: nullptr;
}
void UnregisterManagedCommandBufferState(uint64_t handle) {
if (handle == 0u) {
return;
}
GetManagedCommandBufferRegistry().erase(handle);
}
void ReleaseManagedRenderFuncHandle(uint32_t& gcHandle) {
if (gcHandle == 0u) {
return;
}
MonoScriptRuntime* const runtime =
GetActiveMonoScriptRuntime();
if (runtime != nullptr) {
runtime->ReleaseExternalManagedObject(gcHandle);
}
gcHandle = 0u;
}
void ReleaseManagedScriptableRenderContextRenderFuncHandles(
ManagedScriptableRenderContextState& state) {
for (auto& [rasterPassHandle, request] :
state.pendingRasterPassRequests) {
(void)rasterPassHandle;
ReleaseManagedRenderFuncHandle(request.managedRenderFuncHandle);
}
for (ManagedScriptableRenderContextState::RasterPassRecordRequest&
request : state.rasterPassRequests) {
ReleaseManagedRenderFuncHandle(request.managedRenderFuncHandle);
}
}
bool FlushManagedCommandBufferState(
const ManagedCommandBufferState& state) {
if (state.passContext == nullptr ||
state.passContext->renderContext.commandList == nullptr) {
return false;
}
RHI::RHICommandList* const commandList =
state.passContext->renderContext.commandList;
const std::vector<RHI::RHIResourceView*>& colorAttachments =
state.passContext->surface.GetColorAttachments();
for (const ManagedCommandBufferCommand& command : state.commands) {
switch (command.kind) {
case ManagedCommandBufferCommand::Kind::ClearRenderTarget:
if (colorAttachments.empty() ||
colorAttachments[0] == nullptr) {
return false;
}
commandList->ClearRenderTarget(
colorAttachments[0],
command.color);
break;
default:
return false;
}
}
return true;
}
const Rendering::RenderCameraData& ResolveManagedScriptableRenderContextCameraData(
const ManagedScriptableRenderContextState* state) {
if (state != nullptr &&
@@ -491,9 +612,11 @@ bool RecordManagedRenderFuncRasterPass(
std::vector<Rendering::RenderPassGraphTextureBindingRequest>
textureBindings,
Rendering::RenderGraphTextureHandle depthTarget,
const Containers::String& passName) {
const Containers::String& passName,
Rendering::RenderPassGraphBeginCallback executeCallback) {
if (!ResolveManagedPrimaryColorTarget(colorTargets).IsValid() &&
!depthTarget.IsValid()) {
!depthTarget.IsValid() ||
!executeCallback) {
return false;
}
@@ -526,9 +649,7 @@ bool RecordManagedRenderFuncRasterPass(
return Rendering::RecordCallbackRasterRenderPass(
renderGraphContext,
io,
[](const Rendering::RenderPassContext&) {
return true;
},
std::move(executeCallback),
std::move(additionalReadTextures),
std::move(additionalReadDepthTextures),
std::move(textureBindings));
@@ -1964,20 +2085,91 @@ public:
&result);
UnregisterManagedScriptableRenderContextState(managedContextHandle);
if (!invokeSucceeded) {
ReleaseManagedScriptableRenderContextRenderFuncHandles(
managedContextState);
return false;
}
bool recorded = false;
if (!(TryUnboxManagedBoolean(result, recorded) && recorded)) {
ReleaseManagedScriptableRenderContextRenderFuncHandles(
managedContextState);
return false;
}
return FlushManagedRasterPasses(
context,
managedContextState);
const bool flushed =
FlushManagedRasterPasses(
context,
managedContextState);
if (!flushed) {
ReleaseManagedScriptableRenderContextRenderFuncHandles(
managedContextState);
}
return flushed;
}
private:
struct ManagedRenderFuncExecutionState {
std::shared_ptr<const MonoManagedRenderPipelineAssetRuntime>
assetRuntime = nullptr;
uint32_t renderFuncHandle = 0u;
Containers::String passName = {};
~ManagedRenderFuncExecutionState() {
ReleaseRenderFunc();
}
bool Execute(const Rendering::RenderPassContext& passContext) {
if (assetRuntime == nullptr ||
!assetRuntime->IsRuntimeAlive() ||
renderFuncHandle == 0u) {
return false;
}
MonoScriptRuntime* const runtime =
assetRuntime->GetRuntime();
if (runtime == nullptr) {
return false;
}
ManagedCommandBufferState commandBufferState = {};
commandBufferState.passContext = &passContext;
const uint64_t commandBufferHandle =
RegisterManagedCommandBufferState(
commandBufferState);
const bool invoked =
runtime->InvokeManagedRenderGraphRasterFunc(
renderFuncHandle,
passName.CStr(),
commandBufferHandle);
UnregisterManagedCommandBufferState(
commandBufferHandle);
return invoked &&
FlushManagedCommandBufferState(
commandBufferState);
}
void ReleaseRenderFunc() {
if (renderFuncHandle == 0u) {
return;
}
if (assetRuntime != nullptr &&
assetRuntime->IsRuntimeAlive()) {
MonoScriptRuntime* const runtime =
assetRuntime->GetRuntime();
if (runtime != nullptr) {
runtime->ReleaseRetainedManagedRenderFunc(
renderFuncHandle);
}
}
renderFuncHandle = 0u;
}
};
bool IsRuntimeAlive() const {
return m_assetRuntime != nullptr &&
m_assetRuntime->IsRuntimeAlive() &&
@@ -2058,7 +2250,7 @@ private:
bool FlushManagedRasterPasses(
const Rendering::RenderPipelineStageRenderGraphContext& context,
const ManagedScriptableRenderContextState& managedContextState) {
ManagedScriptableRenderContextState& managedContextState) {
if (managedContextState.rasterPassRequests.empty()) {
return true;
}
@@ -2073,7 +2265,7 @@ private:
for (size_t passIndex = 0u;
passIndex < managedContextState.rasterPassRequests.size();
++passIndex) {
const ManagedScriptableRenderContextState::RasterPassRecordRequest&
ManagedScriptableRenderContextState::RasterPassRecordRequest&
request = managedContextState.rasterPassRequests[passIndex];
const Containers::String resolvedPassName =
!request.passName.Empty()
@@ -2084,6 +2276,25 @@ private:
context.passName,
passIndex);
if (request.usesManagedRenderFuncExecution) {
const uint32_t renderFuncHandle =
std::exchange(
request.managedRenderFuncHandle,
0u);
if (renderFuncHandle == 0u) {
return false;
}
auto executionState =
std::make_shared<ManagedRenderFuncExecutionState>();
executionState->assetRuntime = m_assetRuntime;
executionState->renderFuncHandle = renderFuncHandle;
executionState->passName = resolvedPassName;
Rendering::RenderPassGraphBeginCallback executeCallback =
[executionState](
const Rendering::RenderPassContext& passContext) {
return executionState != nullptr &&
executionState->Execute(passContext);
};
if (!RecordManagedRenderFuncRasterPass(
context,
request.sourceColorTexture,
@@ -2092,7 +2303,8 @@ private:
request.readDepthTextures,
request.textureBindings,
request.depthTarget,
resolvedPassName)) {
resolvedPassName,
std::move(executeCallback))) {
return false;
}
@@ -5106,6 +5318,8 @@ InternalCall_Rendering_ScriptableRenderContext_SetRasterPassColorScaleFullscreen
return 0;
}
ReleaseManagedRenderFuncHandle(
request->managedRenderFuncHandle);
request->usesManagedRenderFuncExecution = false;
request->passDesc =
Rendering::FullscreenPassDesc::MakeColorScale(
@@ -5140,6 +5354,8 @@ InternalCall_Rendering_ScriptableRenderContext_SetRasterPassShaderVectorFullscre
return 0;
}
ReleaseManagedRenderFuncHandle(
request->managedRenderFuncHandle);
request->usesManagedRenderFuncExecution = false;
request->passDesc =
Rendering::FullscreenPassDesc::MakeShaderVector(
@@ -5170,6 +5386,8 @@ InternalCall_Rendering_ScriptableRenderContext_SetRasterPassFinalColorFullscreen
return 0;
}
ReleaseManagedRenderFuncHandle(
request->managedRenderFuncHandle);
request->usesManagedRenderFuncExecution = false;
request->passDesc =
Rendering::FullscreenPassDesc::MakeFinalColor(
@@ -5183,7 +5401,8 @@ InternalCall_Rendering_ScriptableRenderContext_SetRasterPassFinalColorFullscreen
mono_bool
InternalCall_Rendering_ScriptableRenderContext_SetRasterPassManagedRenderFuncExecution(
uint64_t nativeHandle,
uint64_t rasterPassHandle) {
uint64_t rasterPassHandle,
MonoObject* renderFunc) {
ManagedScriptableRenderContextState* const state =
FindManagedScriptableRenderContextState(nativeHandle);
ManagedScriptableRenderContextState::RasterPassRecordRequest*
@@ -5191,11 +5410,27 @@ InternalCall_Rendering_ScriptableRenderContext_SetRasterPassManagedRenderFuncExe
FindPendingManagedRasterPassRecordRequest(
state,
rasterPassHandle);
if (request == nullptr) {
if (request == nullptr ||
renderFunc == nullptr) {
return 0;
}
MonoScriptRuntime* const runtime =
GetActiveMonoScriptRuntime();
if (runtime == nullptr) {
return 0;
}
uint32_t renderFuncHandle =
runtime->RetainExternalManagedObjectReference(renderFunc);
if (renderFuncHandle == 0u) {
return 0;
}
ReleaseManagedRenderFuncHandle(
request->managedRenderFuncHandle);
request->usesManagedRenderFuncExecution = true;
request->managedRenderFuncHandle = renderFuncHandle;
request->passDesc = {};
return 1;
}
@@ -5222,11 +5457,15 @@ mono_bool InternalCall_Rendering_ScriptableRenderContext_CommitRasterPass(
state->pendingRasterPassRequests.erase(it);
if (request.usesManagedRenderFuncExecution) {
if (!HasManagedRasterWriteTarget(request)) {
ReleaseManagedRenderFuncHandle(
request.managedRenderFuncHandle);
return 0;
}
} else if (!request.passDesc.IsValid() ||
!ResolveManagedPrimaryColorTarget(request.colorTargets)
.IsValid()) {
ReleaseManagedRenderFuncHandle(
request.managedRenderFuncHandle);
return 0;
}
@@ -5234,6 +5473,27 @@ mono_bool InternalCall_Rendering_ScriptableRenderContext_CommitRasterPass(
return 1;
}
mono_bool InternalCall_Rendering_CommandBuffer_ClearRenderTarget(
uint64_t nativeHandle,
XCEngine::Math::Color* color) {
ManagedCommandBufferState* const state =
FindManagedCommandBufferState(nativeHandle);
if (state == nullptr ||
color == nullptr) {
return 0;
}
ManagedCommandBufferCommand command = {};
command.kind =
ManagedCommandBufferCommand::Kind::ClearRenderTarget;
command.color[0] = color->r;
command.color[1] = color->g;
command.color[2] = color->b;
command.color[3] = color->a;
state->commands.push_back(command);
return 1;
}
int32_t InternalCall_Rendering_ScriptableRenderContext_GetStageColorSource(
uint64_t nativeHandle) {
const ManagedScriptableRenderContextState* const state =
@@ -6684,6 +6944,7 @@ void RegisterInternalCalls() {
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassFinalColorFullscreenExecution", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassFinalColorFullscreenExecution));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_SetRasterPassManagedRenderFuncExecution", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_SetRasterPassManagedRenderFuncExecution));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_CommitRasterPass", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_CommitRasterPass));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_CommandBuffer_ClearRenderTarget", reinterpret_cast<const void*>(&InternalCall_Rendering_CommandBuffer_ClearRenderTarget));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetStageColorSource", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_GetStageColorSource));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetStageUsesGraphManagedOutputColor", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_GetStageUsesGraphManagedOutputColor));
mono_add_internal_call("XCEngine.InternalCalls::Rendering_ScriptableRenderContext_GetMainDirectionalShadowEnabled", reinterpret_cast<const void*>(&InternalCall_Rendering_ScriptableRenderContext_GetMainDirectionalShadowEnabled));
@@ -8189,6 +8450,78 @@ void MonoScriptRuntime::ReleaseExternalManagedObject(uint32_t gcHandle) {
DestroyExternalManagedObject(gcHandle);
}
void MonoScriptRuntime::ReleaseRetainedManagedRenderFunc(uint32_t gcHandle) {
ReleaseExternalManagedObject(gcHandle);
}
bool MonoScriptRuntime::InvokeManagedRenderGraphRasterFunc(
uint32_t gcHandle,
const char* passName,
uint64_t commandBufferHandle) {
if (!m_initialized ||
gcHandle == 0u ||
commandBufferHandle == 0u) {
return false;
}
MonoObject* const renderFunc =
GetExternalManagedObject(gcHandle);
if (renderFunc == nullptr) {
return false;
}
MonoClass* builderClass = nullptr;
if (!ResolveManagedClass(
m_settings.coreAssemblyName,
kManagedRenderingNamespace,
"RenderGraphRasterPassBuilder",
builderClass)) {
SetError(
"Managed class was not found: " +
m_settings.coreAssemblyName + "|" +
BuildFullClassName(
kManagedRenderingNamespace,
"RenderGraphRasterPassBuilder"));
return false;
}
MonoMethod* const invokeMethod =
ResolveManagedMethod(
builderClass,
"InvokeManagedRenderFunc",
3);
if (invokeMethod == nullptr) {
SetError(
"Managed RenderGraphRasterPassBuilder.InvokeManagedRenderFunc was not found.");
return false;
}
MonoString* const managedPassName =
mono_string_new(
m_appDomain,
passName != nullptr ? passName : "");
void* args[3] = {
renderFunc,
managedPassName,
&commandBufferHandle
};
MonoObject* exception = nullptr;
MonoObject* const result =
mono_runtime_invoke(
invokeMethod,
nullptr,
args,
&exception);
if (exception != nullptr) {
RecordException(exception);
return false;
}
bool invoked = false;
return TryUnboxManagedBoolean(result, invoked) && invoked;
}
bool MonoScriptRuntime::IsScriptableRenderPipelineAssetObject(
MonoObject* managedObject) const {
return managedObject != nullptr &&