mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 21:11:53 +01:00
Drop 3D engine method calling fast path in GPFIFO
This ended up actually turning out to be a slow path when Maxwell 3D method handling code was inlined.
This commit is contained in:
parent
ded02e3eac
commit
d810619203
@ -6,8 +6,7 @@
|
|||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
#include <soc.h>
|
#include <soc.h>
|
||||||
#include <os.h>
|
#include <os.h>
|
||||||
#include "engines/maxwell_3d.h"
|
#include "channel.h"
|
||||||
#include "engines/fermi_2d.h"
|
|
||||||
|
|
||||||
namespace skyline::soc::gm20b {
|
namespace skyline::soc::gm20b {
|
||||||
/**
|
/**
|
||||||
@ -95,7 +94,7 @@ namespace skyline::soc::gm20b {
|
|||||||
} else {
|
} else {
|
||||||
switch (subChannel) {
|
switch (subChannel) {
|
||||||
case SubchannelId::ThreeD:
|
case SubchannelId::ThreeD:
|
||||||
channelCtx.maxwell3D->HandleMacroCall(method - engine::EngineMethodsEnd, argument, lastCall);
|
channelCtx.maxwell3D.HandleMacroCall(method - engine::EngineMethodsEnd, argument, lastCall);
|
||||||
break;
|
break;
|
||||||
case SubchannelId::TwoD:
|
case SubchannelId::TwoD:
|
||||||
channelCtx.fermi2D.HandleMacroCall(method - engine::EngineMethodsEnd, argument, lastCall);
|
channelCtx.fermi2D.HandleMacroCall(method - engine::EngineMethodsEnd, argument, lastCall);
|
||||||
@ -108,9 +107,14 @@ namespace skyline::soc::gm20b {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ChannelGpfifo::SendPure(u32 method, u32 argument, SubchannelId subChannel) {
|
void ChannelGpfifo::SendPure(u32 method, u32 argument, SubchannelId subChannel) {
|
||||||
|
if (subChannel == SubchannelId::ThreeD) [[likely]] {
|
||||||
|
channelCtx.maxwell3D.CallMethod(method, argument);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (subChannel) {
|
switch (subChannel) {
|
||||||
case SubchannelId::ThreeD:
|
case SubchannelId::ThreeD:
|
||||||
channelCtx.maxwell3D->CallMethod(method, argument);
|
channelCtx.maxwell3D.CallMethod(method, argument);
|
||||||
break;
|
break;
|
||||||
case SubchannelId::Compute:
|
case SubchannelId::Compute:
|
||||||
channelCtx.keplerCompute.CallMethod(method, argument);
|
channelCtx.keplerCompute.CallMethod(method, argument);
|
||||||
@ -132,7 +136,7 @@ namespace skyline::soc::gm20b {
|
|||||||
void ChannelGpfifo::SendPureBatchNonInc(u32 method, span<u32> arguments, SubchannelId subChannel) {
|
void ChannelGpfifo::SendPureBatchNonInc(u32 method, span<u32> arguments, SubchannelId subChannel) {
|
||||||
switch (subChannel) {
|
switch (subChannel) {
|
||||||
case SubchannelId::ThreeD:
|
case SubchannelId::ThreeD:
|
||||||
channelCtx.maxwell3D->CallMethodBatchNonInc(method, arguments);
|
channelCtx.maxwell3D.CallMethodBatchNonInc(method, arguments);
|
||||||
break;
|
break;
|
||||||
case SubchannelId::Compute:
|
case SubchannelId::Compute:
|
||||||
channelCtx.keplerCompute.CallMethodBatchNonInc(method, arguments);
|
channelCtx.keplerCompute.CallMethodBatchNonInc(method, arguments);
|
||||||
@ -237,62 +241,46 @@ namespace skyline::soc::gm20b {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handles execution of a specific method type as specified by the State template parameter
|
* @brief Handles execution of a specific method type as specified by the State template parameter
|
||||||
* @tparam ThreeDOnly Whether to skip subchannel method handling and send all method calls to the 3D engine
|
|
||||||
*/
|
*/
|
||||||
auto dispatchCalls{[&]<bool ThreeDOnly, MethodResumeState::State State> () {
|
auto dispatchCalls{[&]<MethodResumeState::State State> () {
|
||||||
/**
|
/**
|
||||||
* @brief Gets the offset to apply to the method address for a given dispatch loop index
|
* @brief Gets the offset to apply to the method address for a given dispatch loop index
|
||||||
*/
|
*/
|
||||||
auto methodOffset{[] (u32 i) -> u32 {
|
auto methodOffset{[] (u32 i) -> u32 {
|
||||||
switch (State) {
|
if constexpr(State == MethodResumeState::State::Inc)
|
||||||
case MethodResumeState::State::Inc:
|
return i;
|
||||||
return i;
|
else if constexpr (State == MethodResumeState::State::OneInc)
|
||||||
case MethodResumeState::State::OneInc:
|
return i ? 1 : 0;
|
||||||
return i ? 1 : 0;
|
else
|
||||||
case MethodResumeState::State::NonInc:
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
constexpr u32 BatchCutoff{4}; //!< Cutoff needed to send method calls in a batch which is espcially important for UBO updates. This helps to avoid the extra overhead batching for small packets.
|
constexpr u32 BatchCutoff{4}; //!< Cutoff needed to send method calls in a batch which is espcially important for UBO updates. This helps to avoid the extra overhead batching for small packets.
|
||||||
// TODO: Only batch for specific target methods like UBO updates, since normal dispatch is generally cheaper
|
// TODO: Only batch for specific target methods like UBO updates, since normal dispatch is generally cheaper
|
||||||
|
|
||||||
if (remainingEntries >= methodHeader.methodCount) {
|
if (remainingEntries >= methodHeader.methodCount) { [[likely]]
|
||||||
if (methodHeader.Pure()) [[likely]] {
|
if (methodHeader.Pure()) [[likely]] {
|
||||||
if constexpr (State == MethodResumeState::State::NonInc) {
|
if constexpr (State == MethodResumeState::State::NonInc) {
|
||||||
// For pure noninc methods we can send all method calls as a span in one go
|
// For pure noninc methods we can send all method calls as a span in one go
|
||||||
if (methodHeader.methodCount > BatchCutoff) {
|
if (methodHeader.methodCount > BatchCutoff) [[unlikely]] {
|
||||||
if constexpr (ThreeDOnly)
|
SendPureBatchNonInc(methodHeader.methodAddress, span(&(*++entry), methodHeader.methodCount), methodHeader.methodSubChannel);
|
||||||
channelCtx.maxwell3D->CallMethodBatchNonInc(methodHeader.methodAddress, span<u32>(&(*++entry), methodHeader.methodCount));
|
|
||||||
else
|
|
||||||
SendPureBatchNonInc(methodHeader.methodAddress, span(&(*++entry), methodHeader.methodCount), methodHeader.methodSubChannel);
|
|
||||||
|
|
||||||
entry += methodHeader.methodCount - 1;
|
entry += methodHeader.methodCount - 1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if constexpr (State == MethodResumeState::State::OneInc) {
|
} else if constexpr (State == MethodResumeState::State::OneInc) {
|
||||||
// For pure oneinc methods we can send the initial method then send the rest as a span in one go
|
// For pure oneinc methods we can send the initial method then send the rest as a span in one go
|
||||||
if (methodHeader.methodCount > (BatchCutoff + 1)) {
|
if (methodHeader.methodCount > (BatchCutoff + 1)) [[unlikely]] {
|
||||||
if constexpr (ThreeDOnly) {
|
SendPure(methodHeader.methodAddress, *++entry, methodHeader.methodSubChannel);
|
||||||
channelCtx.maxwell3D->CallMethod(methodHeader.methodAddress, *++entry);
|
SendPureBatchNonInc(methodHeader.methodAddress + 1, span(&(*++entry) ,methodHeader.methodCount - 1), methodHeader.methodSubChannel);
|
||||||
channelCtx.maxwell3D->CallMethodBatchNonInc(methodHeader.methodAddress + 1, span(&(*++entry), methodHeader.methodCount - 1));
|
|
||||||
} else {
|
|
||||||
SendPure(methodHeader.methodAddress, *++entry, methodHeader.methodSubChannel);
|
|
||||||
SendPureBatchNonInc(methodHeader.methodAddress + 1, span(&(*++entry) ,methodHeader.methodCount - 1), methodHeader.methodSubChannel);
|
|
||||||
}
|
|
||||||
|
|
||||||
entry += methodHeader.methodCount - 2;
|
entry += methodHeader.methodCount - 2;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (u32 i{}; i < methodHeader.methodCount; i++) {
|
for (u32 i{}; i < methodHeader.methodCount; i++)
|
||||||
if constexpr (ThreeDOnly) {
|
SendPure(methodHeader.methodAddress + methodOffset(i), *++entry, methodHeader.methodSubChannel);
|
||||||
channelCtx.maxwell3D->CallMethod(methodHeader.methodAddress + methodOffset(i), *++entry);
|
|
||||||
} else {
|
|
||||||
SendPure(methodHeader.methodAddress + methodOffset(i), *++entry, methodHeader.methodSubChannel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Slow path for methods that touch GPFIFO or macros
|
// Slow path for methods that touch GPFIFO or macros
|
||||||
for (u32 i{}; i < methodHeader.methodCount; i++)
|
for (u32 i{}; i < methodHeader.methodCount; i++)
|
||||||
@ -308,26 +296,22 @@ namespace skyline::soc::gm20b {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handles execution of a single method
|
* @brief Handles execution of a single method
|
||||||
* @tparam ThreeDOnly Whether to skip subchannel method handling and send all method calls to the 3D engine
|
|
||||||
* @return If the this was the final method in the current GpEntry
|
* @return If the this was the final method in the current GpEntry
|
||||||
*/
|
*/
|
||||||
auto processMethod{[&] <bool ThreeDOnly> () -> bool {
|
auto processMethod{[&] () -> bool {
|
||||||
switch (methodHeader.secOp) {
|
switch (methodHeader.secOp) {
|
||||||
case PushBufferMethodHeader::SecOp::IncMethod:
|
case PushBufferMethodHeader::SecOp::IncMethod:
|
||||||
return dispatchCalls.operator()<ThreeDOnly, MethodResumeState::State::Inc>();
|
return dispatchCalls.operator()<MethodResumeState::State::Inc>();
|
||||||
case PushBufferMethodHeader::SecOp::NonIncMethod:
|
case PushBufferMethodHeader::SecOp::NonIncMethod:
|
||||||
return dispatchCalls.operator()<ThreeDOnly, MethodResumeState::State::NonInc>();
|
return dispatchCalls.operator()<MethodResumeState::State::NonInc>();
|
||||||
case PushBufferMethodHeader::SecOp::OneInc:
|
case PushBufferMethodHeader::SecOp::OneInc:
|
||||||
return dispatchCalls.operator()<ThreeDOnly, MethodResumeState::State::OneInc>();
|
return dispatchCalls.operator()<MethodResumeState::State::OneInc>();
|
||||||
case PushBufferMethodHeader::SecOp::ImmdDataMethod:
|
case PushBufferMethodHeader::SecOp::ImmdDataMethod:
|
||||||
if (methodHeader.Pure()) {
|
if (methodHeader.Pure())
|
||||||
if constexpr (ThreeDOnly)
|
SendPure(methodHeader.methodAddress, methodHeader.immdData, methodHeader.methodSubChannel);
|
||||||
channelCtx.maxwell3D->CallMethod(methodHeader.methodAddress, methodHeader.immdData);
|
else
|
||||||
else
|
|
||||||
SendPure(methodHeader.methodAddress, methodHeader.immdData, methodHeader.methodSubChannel);
|
|
||||||
} else {
|
|
||||||
SendFull(methodHeader.methodAddress, methodHeader.immdData, methodHeader.methodSubChannel, true);
|
SendFull(methodHeader.methodAddress, methodHeader.immdData, methodHeader.methodSubChannel, true);
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
case PushBufferMethodHeader::SecOp::EndPbSegment:
|
case PushBufferMethodHeader::SecOp::EndPbSegment:
|
||||||
return true;
|
return true;
|
||||||
@ -337,12 +321,9 @@ namespace skyline::soc::gm20b {
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
bool hitEnd{[&]() {
|
bool hitEnd{[&]() {
|
||||||
if (methodHeader.methodSubChannel == SubchannelId::ThreeD) { [[likely]]
|
if (methodHeader.methodSubChannel != SubchannelId::ThreeD) [[unlikely]]
|
||||||
return processMethod.operator()<true>();
|
channelCtx.maxwell3D.FlushEngineState(); // Flush the 3D engine state when doing any calls to other engines
|
||||||
} else {
|
return processMethod();
|
||||||
channelCtx.maxwell3D->FlushEngineState(); // Flush the 3D engine state when doing any calls to other engines
|
|
||||||
return processMethod.operator()<false>();
|
|
||||||
}
|
|
||||||
}()};
|
}()};
|
||||||
|
|
||||||
if (hitEnd)
|
if (hitEnd)
|
||||||
|
Loading…
Reference in New Issue
Block a user