Bridge managed render funcs to command buffers
This commit is contained in:
@@ -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 &&
|
||||
|
||||
Reference in New Issue
Block a user