Add support for batched method sending

Important for constbuf updates which would be very slow if done one at a
time.
This commit is contained in:
Billy Laws 2022-03-04 19:41:22 +00:00 committed by PixelyIon
parent 43879e2476
commit a5dd961f01
4 changed files with 57 additions and 0 deletions

View File

@ -691,6 +691,12 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
#undef MAXWELL3D_ARRAY_STRUCT_STRUCT_CASE
}
void Maxwell3D::CallMethodBatchNonInc(u32 method, span<u32> arguments) {
for (u32 argument : arguments) {
CallMethod(method, argument);
}
}
void Maxwell3D::WriteSemaphoreResult(u64 result) {
struct FourWordResult {
u64 value;

View File

@ -329,6 +329,8 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
void CallMethod(u32 method, u32 argument);
void CallMethodBatchNonInc(u32 method, span<u32> arguments);
void CallMethodFromMacro(u32 method, u32 argument) override;
u32 ReadMethodFromMacro(u32 method) override;

View File

@ -118,6 +118,17 @@ namespace skyline::soc::gm20b {
}
}
void ChannelGpfifo::SendPureBatchNonInc(u32 method, span<u32> arguments, SubchannelId subChannel) {
switch (subChannel) {
case SubchannelId::ThreeD:
channelCtx.maxwell3D->CallMethodBatchNonInc(method, arguments);
break;
default:
Logger::Warn("Called method 0x{:X} in unimplemented engine 0x{:X} with batch args", method, subChannel);
break;
}
}
void ChannelGpfifo::Process(GpEntry gpEntry) {
if (!gpEntry.size) {
// This is a GPFIFO control entry, all control entries have a zero length and contain no pushbuffers
@ -164,6 +175,9 @@ namespace skyline::soc::gm20b {
// Process more methods if the entries are still not all used up after handling resuming
for (; entry != pushBufferData.end(); entry++) {
if (entry >= pushBufferData.end())
throw exception("GPFIFO buffer overflow!"); // This should never happen
// An entry containing all zeroes is a NOP, skip over it
if (*entry == 0)
continue;
@ -207,8 +221,38 @@ namespace skyline::soc::gm20b {
}
}};
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
if (remainingEntries >= methodHeader.methodCount) {
if (methodHeader.Pure()) [[likely]] {
if constexpr (State == MethodResumeState::State::NonInc) {
// For pure noninc methods we can send all method calls as a span in one go
if (methodHeader.methodCount > BatchCutoff) {
if constexpr (ThreeDOnly)
channelCtx.maxwell3D->CallMethodBatchNonInc(methodHeader.methodAddress, span<u32>(&(*++entry), methodHeader.methodCount));
else
SendPureBatchNonInc(methodHeader.methodAddress, span(&(*++entry), methodHeader.methodCount), methodHeader.methodSubChannel);
entry += methodHeader.methodCount - 1;
return false;
}
} 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
if (methodHeader.methodCount > (BatchCutoff + 1)) {
if constexpr (ThreeDOnly) {
channelCtx.maxwell3D->CallMethod(methodHeader.methodAddress, *++entry);
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;
return false;
}
}
for (u32 i{}; i < methodHeader.methodCount; i++) {
if constexpr (ThreeDOnly) {
channelCtx.maxwell3D->CallMethod(methodHeader.methodAddress + methodOffset(i), *++entry);

View File

@ -139,6 +139,11 @@ namespace skyline::soc::gm20b {
*/
void SendPure(u32 method, u32 argument, SubchannelId subchannel);
/**
* @brief Sends a batch of method calls all directed at the same method to the appropriate subchannel, macro and GPFIFO methods are not handled
*/
void SendPureBatchNonInc(u32 method, span<u32> arguments, SubchannelId subChannel);
/**
* @brief Processes the pushbuffer contained within the given GpEntry, calling methods as needed
*/