diff --git a/app/src/main/cpp/skyline/gpu/interconnect/command_executor.cpp b/app/src/main/cpp/skyline/gpu/interconnect/command_executor.cpp index dc22993a..200eb1f2 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/command_executor.cpp +++ b/app/src/main/cpp/skyline/gpu/interconnect/command_executor.cpp @@ -164,6 +164,10 @@ namespace skyline::gpu::interconnect { } } + void CommandExecutor::AddFlushCallback(std::function &&callback) { + flushCallbacks.emplace_back(std::forward(callback)); + } + void CommandExecutor::Execute() { if (!nodes.empty()) { TRACE_EVENT("gpu", "CommandExecutor::Execute"); diff --git a/app/src/main/cpp/skyline/gpu/interconnect/command_executor.h b/app/src/main/cpp/skyline/gpu/interconnect/command_executor.h index 474bd4c7..5ea03ccf 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/command_executor.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/command_executor.h @@ -29,6 +29,8 @@ namespace skyline::gpu::interconnect { span lastSubpassColorAttachments; //!< The set of color attachments used in the last subpass TextureView *lastSubpassDepthStencilAttachment{}; //!< The depth stencil attachment used in the last subpass + std::vector> flushCallbacks; //!< Set of persistent callbacks that will be called at the start of Execute in order to flush data required for recording + /** * @brief Create a new render pass and subpass with the specified attachments, if one doesn't already exist or the current one isn't compatible * @note This also checks for subpass coalescing and will merge the new subpass with the previous one when possible @@ -91,6 +93,11 @@ namespace skyline::gpu::interconnect { */ void AddOutsideRpCommand(std::function &, GPU &)> &&function); + /** + * @brief Adds a persistent callback that will be called at the start of Execute in order to flush data required for recording + */ + void AddFlushCallback(std::function &&callback); + /** * @brief Execute all the nodes and submit the resulting command buffer to the GPU */ diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp index 88dd5733..e68d14c2 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp @@ -13,23 +13,10 @@ namespace skyline::soc::gm20b::engine::maxwell3d { context(*state.gpu, channelCtx, executor), i2m(channelCtx.asCtx), channelCtx(channelCtx) { + executor.AddFlushCallback([this]() { FlushEngineState(); }); InitializeRegisters(); } - void Maxwell3D::CallMethodFromMacro(u32 method, u32 argument) { - HandleMethod(method, argument); - } - - u32 Maxwell3D::ReadMethodFromMacro(u32 method) { - return registers.raw[method]; - } - - __attribute__((always_inline)) void Maxwell3D::CallMethod(u32 method, u32 argument) { - Logger::Verbose("Called method in Maxwell 3D: 0x{:X} args: 0x{:X}", method, argument); - - HandleMethod(method, argument); - } - void Maxwell3D::HandleMethod(u32 method, u32 argument) { if (method != ENGINE_STRUCT_OFFSET(mme, shadowRamControl)) { if (shadowRegisters.mme->shadowRamControl == type::MmeShadowRamControl::MethodTrack || shadowRegisters.mme->shadowRamControl == type::MmeShadowRamControl::MethodTrackWithFilter) @@ -707,19 +694,6 @@ namespace skyline::soc::gm20b::engine::maxwell3d { } } - void Maxwell3D::CallMethodBatchNonInc(u32 method, span arguments) { - switch (method) { - case ENGINE_STRUCT_OFFSET(i2m, loadInlineData): - i2m.LoadInlineData(*registers.i2m, arguments); - return; - default: - break; - } - - for (u32 argument : arguments) - HandleMethod(method, argument); - } - void Maxwell3D::WriteSemaphoreResult(u64 result) { struct FourWordResult { u64 value; @@ -745,4 +719,38 @@ namespace skyline::soc::gm20b::engine::maxwell3d { } } } + + void Maxwell3D::FlushEngineState() { + if (batchConstantBufferUpdate.Active()) { + context.ConstantBufferUpdate(std::move(batchConstantBufferUpdate.buffer), batchConstantBufferUpdate.startOffset); + batchConstantBufferUpdate.Reset(); + } + } + + __attribute__((always_inline)) void Maxwell3D::CallMethod(u32 method, u32 argument) { + Logger::Verbose("Called method in Maxwell 3D: 0x{:X} args: 0x{:X}", method, argument); + + HandleMethod(method, argument); + } + + void Maxwell3D::CallMethodBatchNonInc(u32 method, span arguments) { + switch (method) { + case ENGINE_STRUCT_OFFSET(i2m, loadInlineData): + i2m.LoadInlineData(*registers.i2m, arguments); + return; + default: + break; + } + + for (u32 argument : arguments) + HandleMethod(method, argument); + } + + void Maxwell3D::CallMethodFromMacro(u32 method, u32 argument) { + HandleMethod(method, argument); + } + + u32 Maxwell3D::ReadMethodFromMacro(u32 method) { + return registers.raw[method]; + } } diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h index 27900fe8..a1ea1310 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h @@ -356,7 +356,6 @@ namespace skyline::soc::gm20b::engine::maxwell3d { ChannelContext &channelCtx; - Maxwell3D(const DeviceState &state, ChannelContext &channelCtx, MacroState ¯oState, gpu::interconnect::CommandExecutor &executor); /** @@ -364,6 +363,11 @@ namespace skyline::soc::gm20b::engine::maxwell3d { */ void InitializeRegisters(); + /** + * @brief Flushes any batched constant buffer update or instanced draw state + */ + void FlushEngineState(); + void CallMethod(u32 method, u32 argument); void CallMethodBatchNonInc(u32 method, span arguments); diff --git a/app/src/main/cpp/skyline/soc/gm20b/gpfifo.cpp b/app/src/main/cpp/skyline/soc/gm20b/gpfifo.cpp index b7a63f00..a3fe68a0 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/gpfifo.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/gpfifo.cpp @@ -322,15 +322,19 @@ namespace skyline::soc::gm20b { }}; bool hitEnd{[&]() { - if (methodHeader.methodSubChannel == SubchannelId::ThreeD) [[likely]] + if (methodHeader.methodSubChannel == SubchannelId::ThreeD) { [[likely]] return processMethod.operator()(); - else + } else { + channelCtx.maxwell3D->FlushEngineState(); // Flush the 3D engine state when doing any calls to other engines return processMethod.operator()(); + } }()}; if (hitEnd) - return; + break; } + + channelCtx.maxwell3D->FlushEngineState(); } void ChannelGpfifo::Run() {