mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-21 03:54:45 +00:00
video_out: Move presentation to separate thread
This commit is contained in:
parent
bc28ed66e8
commit
cc81ba6793
11 changed files with 66 additions and 45 deletions
|
@ -2131,6 +2131,7 @@ int PS4_SYSV_ABI sceGnmSubmitDone() {
|
|||
if (!liverpool->IsGpuIdle()) {
|
||||
submission_lock = true;
|
||||
}
|
||||
liverpool->SubmitDone();
|
||||
send_init_packet = true;
|
||||
++frames_submitted;
|
||||
return ORBIS_OK;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <pthread.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/debug.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/time_management.h"
|
||||
#include "core/libraries/videoout/driver.h"
|
||||
|
@ -41,6 +42,7 @@ VideoOutDriver::VideoOutDriver(u32 width, u32 height) {
|
|||
main_port.resolution.fullHeight = height;
|
||||
main_port.resolution.paneWidth = width;
|
||||
main_port.resolution.paneHeight = height;
|
||||
present_thread = std::jthread([&](std::stop_token token) { PresentThread(token); });
|
||||
}
|
||||
|
||||
VideoOutDriver::~VideoOutDriver() = default;
|
||||
|
@ -158,27 +160,7 @@ int VideoOutDriver::UnregisterBuffers(VideoOutPort* port, s32 attributeIndex) {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void VideoOutDriver::Flip(std::chrono::microseconds timeout) {
|
||||
Request req;
|
||||
{
|
||||
std::unique_lock lock{mutex};
|
||||
submit_cond.wait_for(lock, timeout, [&] { return !requests.empty(); });
|
||||
if (requests.empty()) {
|
||||
renderer->ShowSplash();
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the request.
|
||||
req = requests.front();
|
||||
requests.pop();
|
||||
}
|
||||
|
||||
// Whatever the game is rendering show splash if it is active
|
||||
if (!renderer->ShowSplash(req.frame)) {
|
||||
// Present the frame.
|
||||
renderer->Present(req.frame);
|
||||
}
|
||||
|
||||
void VideoOutDriver::Flip(const Request& req) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
// Update flip status.
|
||||
|
@ -256,4 +238,33 @@ void VideoOutDriver::Vblank() {
|
|||
}
|
||||
}
|
||||
|
||||
void VideoOutDriver::PresentThread(std::stop_token token) {
|
||||
static constexpr std::chrono::milliseconds FlipPeriod{16};
|
||||
while (!token.stop_requested()) {
|
||||
Request req;
|
||||
{
|
||||
std::unique_lock lock{mutex};
|
||||
submit_cond.wait_for(lock, FlipPeriod, [&] { return !requests.empty(); });
|
||||
if (requests.empty()) {
|
||||
renderer->ShowSplash();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Retrieve the request.
|
||||
req = requests.front();
|
||||
requests.pop();
|
||||
}
|
||||
|
||||
// Whatever the game is rendering show splash if it is active
|
||||
if (!renderer->ShowSplash(req.frame)) {
|
||||
// Present the frame.
|
||||
renderer->Present(req.frame);
|
||||
}
|
||||
|
||||
Flip(req);
|
||||
Vblank();
|
||||
FRAME_END;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Libraries::VideoOut
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include "common/polyfill_thread.h"
|
||||
#include "core/libraries/videoout/video_out.h"
|
||||
|
||||
namespace Vulkan {
|
||||
|
@ -63,7 +64,6 @@ public:
|
|||
const BufferAttribute* attribute);
|
||||
int UnregisterBuffers(VideoOutPort* port, s32 attributeIndex);
|
||||
|
||||
void Flip(std::chrono::microseconds timeout);
|
||||
bool SubmitFlip(VideoOutPort* port, s32 index, s64 flip_arg, bool is_eop = false);
|
||||
|
||||
void Vblank();
|
||||
|
@ -78,10 +78,14 @@ private:
|
|||
bool eop;
|
||||
};
|
||||
|
||||
void Flip(const Request& req);
|
||||
void PresentThread(std::stop_token token);
|
||||
|
||||
std::mutex mutex;
|
||||
VideoOutPort main_port{};
|
||||
std::condition_variable_any submit_cond;
|
||||
std::condition_variable done_cond;
|
||||
std::jthread present_thread;
|
||||
std::queue<Request> requests;
|
||||
bool is_neo{};
|
||||
};
|
||||
|
|
|
@ -141,10 +141,12 @@ s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode
|
|||
LOG_INFO(Lib_VideoOut, "bufferIndex = {}, flipMode = {}, flipArg = {}", bufferIndex, flipMode,
|
||||
flipArg);
|
||||
|
||||
if (!driver->SubmitFlip(port, bufferIndex, flipArg)) {
|
||||
LOG_ERROR(Lib_VideoOut, "Flip queue is full");
|
||||
return ORBIS_VIDEO_OUT_ERROR_FLIP_QUEUE_FULL;
|
||||
}
|
||||
// Next time the gpu enters idle state, submit the flip
|
||||
Platform::IrqC::Instance()->RegisterOnce(
|
||||
Platform::InterruptId::GpuIdle, [=](Platform::InterruptId irq) {
|
||||
const auto result = driver->SubmitFlip(port, bufferIndex, flipArg);
|
||||
ASSERT_MSG(result, "Flip submission failed");
|
||||
});
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
@ -229,14 +231,6 @@ s32 PS4_SYSV_ABI sceVideoOutUnregisterBuffers(s32 handle, s32 attributeIndex) {
|
|||
return driver->UnregisterBuffers(port, attributeIndex);
|
||||
}
|
||||
|
||||
void Flip(std::chrono::microseconds micros) {
|
||||
return driver->Flip(micros);
|
||||
}
|
||||
|
||||
void Vblank() {
|
||||
return driver->Vblank();
|
||||
}
|
||||
|
||||
void sceVideoOutGetBufferLabelAddress(s32 handle, uintptr_t* label_addr) {
|
||||
auto* port = driver->GetPort(handle);
|
||||
ASSERT(port);
|
||||
|
|
|
@ -104,9 +104,6 @@ s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 i
|
|||
const void* param);
|
||||
s32 PS4_SYSV_ABI sceVideoOutClose(s32 handle);
|
||||
|
||||
void Flip(std::chrono::microseconds micros);
|
||||
void Vblank();
|
||||
|
||||
// Internal system functions
|
||||
void sceVideoOutGetBufferLabelAddress(s32 handle, uintptr_t* label_addr);
|
||||
s32 sceVideoOutSubmitEopFlip(s32 handle, u32 buf_id, u32 mode, u32 arg, void** unk);
|
||||
|
|
|
@ -136,14 +136,8 @@ void Emulator::Run(const std::filesystem::path& file) {
|
|||
std::jthread mainthread =
|
||||
std::jthread([this](std::stop_token stop_token) { linker->Execute(); });
|
||||
|
||||
// Begin main window loop until the application exits
|
||||
static constexpr std::chrono::milliseconds FlipPeriod{16};
|
||||
|
||||
while (window->isOpen()) {
|
||||
window->waitEvent();
|
||||
Libraries::VideoOut::Flip(FlipPeriod);
|
||||
Libraries::VideoOut::Vblank();
|
||||
FRAME_END;
|
||||
}
|
||||
|
||||
std::exit(0);
|
||||
|
|
|
@ -71,7 +71,7 @@ void WindowSDL::waitEvent() {
|
|||
// Called on main thread
|
||||
SDL_Event event;
|
||||
|
||||
if (!SDL_PollEvent(&event)) {
|
||||
if (!SDL_WaitEvent(&event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ void Liverpool::Process(std::stop_token stoken) {
|
|||
while (!stoken.stop_requested()) {
|
||||
{
|
||||
std::unique_lock lk{submit_mutex};
|
||||
Common::CondvarWait(submit_cv, lk, stoken, [this] { return num_submits != 0; });
|
||||
Common::CondvarWait(submit_cv, lk, stoken, [this] { return num_submits != 0 || submit_done; });
|
||||
}
|
||||
if (stoken.stop_requested()) {
|
||||
break;
|
||||
|
@ -67,6 +67,13 @@ void Liverpool::Process(std::stop_token stoken) {
|
|||
}
|
||||
}
|
||||
|
||||
if (submit_done) {
|
||||
if (rasterizer) {
|
||||
rasterizer->Flush();
|
||||
}
|
||||
submit_done = false;
|
||||
}
|
||||
|
||||
Platform::IrqC::Instance()->Signal(Platform::InterruptId::GpuIdle);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -991,6 +991,12 @@ public:
|
|||
void SubmitGfx(std::span<const u32> dcb, std::span<const u32> ccb);
|
||||
void SubmitAsc(u32 vqid, std::span<const u32> acb);
|
||||
|
||||
void SubmitDone() noexcept {
|
||||
std::scoped_lock lk{submit_mutex};
|
||||
submit_done = true;
|
||||
submit_cv.notify_one();
|
||||
}
|
||||
|
||||
bool IsGpuIdle() const {
|
||||
return num_submits == 0;
|
||||
}
|
||||
|
@ -1061,6 +1067,7 @@ private:
|
|||
Vulkan::Rasterizer* rasterizer{};
|
||||
std::jthread process_thread{};
|
||||
std::atomic<u32> num_submits{};
|
||||
std::atomic<bool> submit_done{};
|
||||
std::mutex submit_mutex;
|
||||
std::condition_variable_any submit_cv;
|
||||
};
|
||||
|
|
|
@ -96,6 +96,10 @@ void Rasterizer::DispatchDirect() {
|
|||
cmdbuf.dispatch(cs_program.dim_x, cs_program.dim_y, cs_program.dim_z);
|
||||
}
|
||||
|
||||
void Rasterizer::Flush() {
|
||||
scheduler.Flush();
|
||||
}
|
||||
|
||||
void Rasterizer::BeginRendering() {
|
||||
const auto& regs = liverpool->regs;
|
||||
RenderState state;
|
||||
|
|
|
@ -35,6 +35,8 @@ public:
|
|||
|
||||
void ScopeMarkerBegin(const std::string& str);
|
||||
void ScopeMarkerEnd();
|
||||
|
||||
void Flush();
|
||||
|
||||
private:
|
||||
u32 SetupIndexBuffer(bool& is_indexed, u32 index_offset);
|
||||
|
|
Loading…
Add table
Reference in a new issue