mirror of
https://github.com/skyline-emu/skyline.git
synced 2025-01-01 07:55:29 +03:00
Use GPFIFO pushbuffer contents in-place if possible
The memcpy within `Read()` was taking up a fair amount of time, avoid this by using the mapped range in-place when the mapping isn't split.
This commit is contained in:
parent
be825b7aad
commit
30ec844a1b
@ -165,17 +165,26 @@ namespace skyline::soc::gm20b {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pushBufferData.resize(gpEntry.size);
|
auto pushBufferMappedRanges{channelCtx.asCtx->gmmu.TranslateRange(gpEntry.Address(), gpEntry.size * sizeof(u32))};
|
||||||
channelCtx.asCtx->gmmu.Read<u32>(pushBufferData, gpEntry.Address());
|
auto pushBuffer{[&]() -> span<u32> {
|
||||||
|
if (pushBufferMappedRanges.size() == 1) {
|
||||||
|
return pushBufferMappedRanges.front().cast<u32>();
|
||||||
|
} else {
|
||||||
|
// Create an intermediate copy of pushbuffer data if it's split across multiple mappings
|
||||||
|
pushBufferData.resize(gpEntry.size);
|
||||||
|
channelCtx.asCtx->gmmu.Read<u32>(pushBufferData, gpEntry.Address());
|
||||||
|
return span(pushBufferData);
|
||||||
|
}
|
||||||
|
}()};
|
||||||
|
|
||||||
// There will be at least one entry here
|
// There will be at least one entry here
|
||||||
auto entry{pushBufferData.begin()};
|
auto entry{pushBuffer.begin()};
|
||||||
|
|
||||||
// Executes the current split method, returning once execution is finished or the current GpEntry has reached its end
|
// Executes the current split method, returning once execution is finished or the current GpEntry has reached its end
|
||||||
auto resumeSplitMethod{[&](){
|
auto resumeSplitMethod{[&](){
|
||||||
switch (resumeState.state) {
|
switch (resumeState.state) {
|
||||||
case MethodResumeState::State::Inc:
|
case MethodResumeState::State::Inc:
|
||||||
while (entry != pushBufferData.end() && resumeState.remaining)
|
while (entry != pushBuffer.end() && resumeState.remaining)
|
||||||
SendFull(resumeState.address++, *(entry++), resumeState.subChannel, --resumeState.remaining == 0);
|
SendFull(resumeState.address++, *(entry++), resumeState.subChannel, --resumeState.remaining == 0);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -186,7 +195,7 @@ namespace skyline::soc::gm20b {
|
|||||||
resumeState.state = MethodResumeState::State::NonInc;
|
resumeState.state = MethodResumeState::State::NonInc;
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case MethodResumeState::State::NonInc:
|
case MethodResumeState::State::NonInc:
|
||||||
while (entry != pushBufferData.end() && resumeState.remaining)
|
while (entry != pushBuffer.end() && resumeState.remaining)
|
||||||
SendFull(resumeState.address, *(entry++), resumeState.subChannel, --resumeState.remaining == 0);
|
SendFull(resumeState.address, *(entry++), resumeState.subChannel, --resumeState.remaining == 0);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -198,8 +207,8 @@ namespace skyline::soc::gm20b {
|
|||||||
resumeSplitMethod();
|
resumeSplitMethod();
|
||||||
|
|
||||||
// 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 != pushBufferData.end(); entry++) {
|
for (; entry != pushBuffer.end(); entry++) {
|
||||||
if (entry >= pushBufferData.end())
|
if (entry >= pushBuffer.end())
|
||||||
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
|
// An entry containing all zeroes is a NOP, skip over it
|
||||||
@ -209,7 +218,7 @@ namespace skyline::soc::gm20b {
|
|||||||
PushBufferMethodHeader methodHeader{.raw = *entry};
|
PushBufferMethodHeader methodHeader{.raw = *entry};
|
||||||
|
|
||||||
// Needed in order to check for methods split across multiple GpEntries
|
// Needed in order to check for methods split across multiple GpEntries
|
||||||
ssize_t remainingEntries{std::distance(entry, pushBufferData.end()) - 1};
|
ssize_t remainingEntries{std::distance(entry, pushBuffer.end()) - 1};
|
||||||
|
|
||||||
// Handles storing state and initial execution for methods that are split across multiple GpEntries
|
// Handles storing state and initial execution for methods that are split across multiple GpEntries
|
||||||
auto startSplitMethod{[&](auto methodState) {
|
auto startSplitMethod{[&](auto methodState) {
|
||||||
|
Loading…
Reference in New Issue
Block a user