diff --git a/rpcsx/gpu/DeviceCtl.cpp b/rpcsx/gpu/DeviceCtl.cpp index 1c3c9de..ddc3c0d 100644 --- a/rpcsx/gpu/DeviceCtl.cpp +++ b/rpcsx/gpu/DeviceCtl.cpp @@ -60,6 +60,29 @@ void DeviceCtl::submitFlip(int gfxPipe, std::uint32_t pid, int bufferIndex, flipArg >> 32, pid)); } +orbis::ErrorCode DeviceCtl::submitFlipOnEop(int gfxPipe, std::uint32_t pid, + int bufferIndex, + std::uint64_t flipArg) { + int index; + auto &pipe = mDevice->graphicsPipes[gfxPipe]; + { + std::lock_guard lock(pipe.eopFlipMtx); + if (pipe.eopFlipRequestCount >= GraphicsPipe::kEopFlipRequestMax) { + return orbis::ErrorCode::AGAIN; + } + + index = pipe.eopFlipRequestCount++; + + pipe.eopFlipRequests[index] = { + .pid = pid, + .bufferIndex = bufferIndex, + .arg = flipArg, + }; + } + + return {}; +} + void DeviceCtl::submitMapMemory(int gfxPipe, std::uint32_t pid, std::uint64_t address, std::uint64_t size, int memoryType, int dmemIndex, int prot, diff --git a/rpcsx/gpu/DeviceCtl.hpp b/rpcsx/gpu/DeviceCtl.hpp index d8ea308..3f6c842 100644 --- a/rpcsx/gpu/DeviceCtl.hpp +++ b/rpcsx/gpu/DeviceCtl.hpp @@ -30,6 +30,8 @@ class DeviceCtl { void submitSwitchBuffer(int gfxPipe); void submitFlip(int gfxPipe, std::uint32_t pid, int bufferIndex, std::uint64_t flipArg); + orbis::ErrorCode submitFlipOnEop(int gfxPipe, std::uint32_t pid, + int bufferIndex, std::uint64_t flipArg); void submitMapMemory(int gfxPipe, std::uint32_t pid, std::uint64_t address, std::uint64_t size, int memoryType, int dmemIndex, int prot, std::int64_t offset); @@ -48,7 +50,7 @@ class DeviceCtl { orbis::uint64_t readPtrAddress, orbis::uint64_t doorbell, orbis::uint64_t ringSize); void submitComputeQueue(std::uint32_t meId, std::uint32_t pipeId, - std::uint32_t queueId, std::uint64_t offset); + std::uint32_t queueId, std::uint64_t offset); void start(); void waitForIdle(); diff --git a/rpcsx/gpu/Pipe.cpp b/rpcsx/gpu/Pipe.cpp index 4d63495..2023ac3 100644 --- a/rpcsx/gpu/Pipe.cpp +++ b/rpcsx/gpu/Pipe.cpp @@ -1190,6 +1190,23 @@ bool GraphicsPipe::eventWriteEop(Ring &ring) { kGcEventGfxEop); } + if (intSel == 2) { + std::optional request; + int index; + { + std::lock_guard lock(eopFlipMtx); + + if (eopFlipRequestCount > 0) { + index = --eopFlipRequestCount; + request = eopFlipRequests[index]; + } + } + + if (request) { + device->flip(request->pid, request->bufferIndex, request->arg); + } + } + return true; } diff --git a/rpcsx/gpu/Pipe.hpp b/rpcsx/gpu/Pipe.hpp index d4a17ce..8351c3b 100644 --- a/rpcsx/gpu/Pipe.hpp +++ b/rpcsx/gpu/Pipe.hpp @@ -51,7 +51,8 @@ struct ComputePipe { bool processAllRings(); bool processRing(Ring &ring); void setIndirectRing(int queueId, int level, Ring ring); - void mapQueue(int queueId, Ring ring, std::unique_lock &lock); + void mapQueue(int queueId, Ring ring, + std::unique_lock &lock); void waitForIdle(int queueId, std::unique_lock &lock); void submit(int queueId, std::uint32_t offset); @@ -73,7 +74,14 @@ struct ComputePipe { std::uint32_t *getMmRegister(Ring &ring, std::uint32_t dwAddress); }; +struct EopFlipRequest { + std::uint32_t pid; + int bufferIndex; + std::uint64_t arg; +}; + struct GraphicsPipe { + static constexpr auto kEopFlipRequestMax = 0x10; Device *device; Scheduler scheduler; @@ -95,6 +103,10 @@ struct GraphicsPipe { Ring deQueues[3]; Ring ceQueue; + orbis::shared_mutex eopFlipMtx; + std::uint32_t eopFlipRequestCount{0}; + EopFlipRequest eopFlipRequests[kEopFlipRequestMax]; + using CommandHandler = bool (GraphicsPipe::*)(Ring &); CommandHandler commandHandlers[4][255]; diff --git a/rpcsx/iodev/dce.cpp b/rpcsx/iodev/dce.cpp index 3e91a46..9ca7f7c 100644 --- a/rpcsx/iodev/dce.cpp +++ b/rpcsx/iodev/dce.cpp @@ -392,15 +392,17 @@ static orbis::ErrorCode dce_ioctl(orbis::File *file, std::uint64_t request, // flip request auto args = reinterpret_cast(argp); - // ORBIS_LOG_ERROR("dce: FlipRequestArgs", args->canary, - // args->displayBufferIndex, args->flipMode, args->unk1, - // args->flipArg, args->flipArg2, args->eop_nz, args->unk2, - // args->eop_val, args->unk3, args->unk4, args->rout); - gpu.submitFlip(thread->tproc->gfxRing, thread->tproc->pid, - args->displayBufferIndex, - /*args->flipMode,*/ args->flipArg); - - // *args->rout = 0; + if (args->eop_nz == 0) { + gpu.submitFlip(thread->tproc->gfxRing, thread->tproc->pid, + args->displayBufferIndex, args->flipArg); + } else if (args->eop_nz == 1) { + ORBIS_RET_ON_ERROR( + gpu.submitFlipOnEop(thread->tproc->gfxRing, thread->tproc->pid, + args->displayBufferIndex, args->flipArg)); + *args->eop_val = args->canary; + } + + *args->rout = 0; return {}; }