Optimise GPFIFO command processing

GPFIFO code is very high throughput due to the sheer number of commands used for rendering. Adjust some types and switch to a if statement with hints to slightly increase processing speed.
This commit is contained in:
Billy Laws 2022-09-29 20:26:48 +01:00
parent 2cdf6c1fe6
commit bd7eee8e2b

View File

@ -61,7 +61,7 @@ namespace skyline::soc::gm20b {
* @brief Checks if a method is 'pure' i.e. does not touch macro or GPFIFO methods * @brief Checks if a method is 'pure' i.e. does not touch macro or GPFIFO methods
*/ */
bool Pure() const { bool Pure() const {
u16 size{[&]() -> u16 { u32 size{[&]() -> u32 {
switch (secOp) { switch (secOp) {
case SecOp::NonIncMethod: case SecOp::NonIncMethod:
case SecOp::ImmdDataMethod: case SecOp::ImmdDataMethod:
@ -73,7 +73,7 @@ namespace skyline::soc::gm20b {
} }
}()}; }()};
u16 end{static_cast<u16>(methodAddress + size)}; u32 end{static_cast<u32>(methodAddress + size)};
return end < engine::EngineMethodsEnd && methodAddress >= engine::GPFIFO::RegisterCount; return end < engine::EngineMethodsEnd && methodAddress >= engine::GPFIFO::RegisterCount;
} }
}; };
@ -212,12 +212,13 @@ namespace skyline::soc::gm20b {
// Process more methods if the entries are still not all used up after handling resuming // Process more methods if the entries are still not all used up after handling resuming
for (; entry != pushBuffer.end(); entry++) { for (; entry != pushBuffer.end(); entry++) {
if (entry >= pushBuffer.end()) if (entry >= pushBuffer.end()) [[unlikely]]
throw exception("GPFIFO buffer overflow!"); // This should never happen throw exception("GPFIFO buffer overflow!"); // This should never happen
// An entry containing all zeroes is a NOP, skip over it // Entries containing all zeroes is a NOP, skip over them
if (*entry == 0) for (; *entry == 0; entry++)
continue; if (entry == std::prev(pushBuffer.end()))
return;
PushBufferMethodHeader methodHeader{.raw = *entry}; PushBufferMethodHeader methodHeader{.raw = *entry};
@ -279,6 +280,7 @@ namespace skyline::soc::gm20b {
} }
} }
#pragma unroll(2)
for (u32 i{}; i < methodHeader.methodCount; i++) for (u32 i{}; i < methodHeader.methodCount; i++)
SendPure(methodHeader.methodAddress + methodOffset(i), *++entry, methodHeader.methodSubChannel); SendPure(methodHeader.methodAddress + methodOffset(i), *++entry, methodHeader.methodSubChannel);
} else { } else {
@ -299,23 +301,22 @@ namespace skyline::soc::gm20b {
* @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 { auto processMethod{[&] () -> bool {
switch (methodHeader.secOp) { if (methodHeader.secOp == PushBufferMethodHeader::SecOp::IncMethod) [[likely]] {
case PushBufferMethodHeader::SecOp::IncMethod: return dispatchCalls.operator()<MethodResumeState::State::Inc>();
return dispatchCalls.operator()<MethodResumeState::State::Inc>(); } else if (methodHeader.secOp == PushBufferMethodHeader::SecOp::OneInc) [[likely]] {
case PushBufferMethodHeader::SecOp::NonIncMethod: return dispatchCalls.operator()<MethodResumeState::State::OneInc>();
return dispatchCalls.operator()<MethodResumeState::State::NonInc>(); } else if (methodHeader.secOp == PushBufferMethodHeader::SecOp::ImmdDataMethod) {
case PushBufferMethodHeader::SecOp::OneInc: if (methodHeader.Pure())
return dispatchCalls.operator()<MethodResumeState::State::OneInc>(); SendPure(methodHeader.methodAddress, methodHeader.immdData, methodHeader.methodSubChannel);
case PushBufferMethodHeader::SecOp::ImmdDataMethod: else
if (methodHeader.Pure()) SendFull(methodHeader.methodAddress, methodHeader.immdData, methodHeader.methodSubChannel, true);
SendPure(methodHeader.methodAddress, methodHeader.immdData, methodHeader.methodSubChannel);
else
SendFull(methodHeader.methodAddress, methodHeader.immdData, methodHeader.methodSubChannel, true);
return false; return false;
case PushBufferMethodHeader::SecOp::EndPbSegment: } else if (methodHeader.secOp == PushBufferMethodHeader::SecOp::NonIncMethod) [[unlikely]] {
return dispatchCalls.operator()<MethodResumeState::State::NonInc>();
} else if (methodHeader.secOp == PushBufferMethodHeader::SecOp::EndPbSegment) [[unlikely]] {
return true; return true;
default: } else {
throw exception("Unsupported pushbuffer method SecOp: {}", static_cast<u8>(methodHeader.secOp)); throw exception("Unsupported pushbuffer method SecOp: {}", static_cast<u8>(methodHeader.secOp));
} }
}}; }};