mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2024-05-28 17:08:22 -04:00
150 lines
4.5 KiB
C++
150 lines
4.5 KiB
C++
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include "common/debug.h"
|
|
#include "core/PS4/HLE/Graphics/Objects/video_out_ctx.h"
|
|
#include "core/libraries/kernel/time_management.h"
|
|
|
|
namespace HLE::Graphics::Objects {
|
|
|
|
void VideoOutCtx::Init(u32 width, u32 height) {
|
|
m_video_out_ctx.m_resolution.fullWidth = width;
|
|
m_video_out_ctx.m_resolution.fullHeight = height;
|
|
m_video_out_ctx.m_resolution.paneWidth = width;
|
|
m_video_out_ctx.m_resolution.paneHeight = height;
|
|
}
|
|
|
|
int VideoOutCtx::Open() {
|
|
std::scoped_lock lock{m_mutex};
|
|
|
|
int handle = -1;
|
|
|
|
if (!m_video_out_ctx.isOpened) {
|
|
handle = 1; // positive return , should be more than 1 ?
|
|
}
|
|
|
|
m_video_out_ctx.isOpened = true;
|
|
m_video_out_ctx.m_flip_status = SceVideoOutFlipStatus();
|
|
m_video_out_ctx.m_flip_status.flipArg = -1;
|
|
m_video_out_ctx.m_flip_status.currentBuffer = -1;
|
|
m_video_out_ctx.m_flip_status.count = 0;
|
|
m_video_out_ctx.m_vblank_status = SceVideoOutVblankStatus();
|
|
|
|
return handle;
|
|
}
|
|
void VideoOutCtx::Close(s32 handle) {
|
|
std::scoped_lock lock{m_mutex};
|
|
|
|
m_video_out_ctx.isOpened = false;
|
|
|
|
if (m_video_out_ctx.m_flip_evtEq.size() > 0) {
|
|
BREAKPOINT(); // we need to clear all events if they have been created
|
|
}
|
|
|
|
m_video_out_ctx.m_flip_rate = 0;
|
|
|
|
// clear buffers
|
|
for (auto& buffer : m_video_out_ctx.buffers) {
|
|
buffer.buffer = nullptr;
|
|
buffer.buffer_render = nullptr;
|
|
buffer.buffer_size = 0;
|
|
buffer.set_id = 0;
|
|
}
|
|
|
|
m_video_out_ctx.buffers_sets.clear();
|
|
|
|
m_video_out_ctx.buffers_registration_index = 0;
|
|
}
|
|
|
|
void VideoOutCtx::Vblank() {
|
|
std::scoped_lock lock{m_mutex};
|
|
|
|
if (m_video_out_ctx.isOpened) {
|
|
m_video_out_ctx.m_mutex.lock();
|
|
m_video_out_ctx.m_vblank_status.count++;
|
|
m_video_out_ctx.m_vblank_status.processTime = Libraries::Kernel::sceKernelGetProcessTime();
|
|
m_video_out_ctx.m_vblank_status.tsc = Libraries::Kernel::sceKernelReadTsc();
|
|
m_video_out_ctx.m_mutex.unlock();
|
|
}
|
|
}
|
|
VideoConfigInternal* VideoOutCtx::getCtx(int handle) {
|
|
if (handle != 1) [[unlikely]] {
|
|
return nullptr;
|
|
}
|
|
return &m_video_out_ctx; // assuming that it's the only ctx TODO check if we need more
|
|
}
|
|
|
|
void FlipQueue::getFlipStatus(VideoConfigInternal* cfg, SceVideoOutFlipStatus* out) {
|
|
std::scoped_lock lock(m_mutex);
|
|
*out = cfg->m_flip_status;
|
|
}
|
|
|
|
bool FlipQueue::submitFlip(VideoConfigInternal* cfg, s32 index, s64 flip_arg) {
|
|
std::scoped_lock lock{m_mutex};
|
|
|
|
if (m_requests.size() >= 2) {
|
|
return false;
|
|
}
|
|
|
|
Request r{};
|
|
r.cfg = cfg;
|
|
r.index = index;
|
|
r.flip_arg = flip_arg;
|
|
r.submit_tsc = Libraries::Kernel::sceKernelReadTsc();
|
|
|
|
m_requests.push_back(r);
|
|
|
|
cfg->m_flip_status.flipPendingNum = static_cast<int>(m_requests.size());
|
|
cfg->m_flip_status.gcQueueNum = 0;
|
|
|
|
m_submit_cond.notify_one();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool FlipQueue::flip(u32 micros) {
|
|
const auto request = [&]() -> Request* {
|
|
std::unique_lock lock{m_mutex};
|
|
m_submit_cond.wait_for(lock, std::chrono::microseconds(micros),
|
|
[&] { return !m_requests.empty(); });
|
|
if (m_requests.empty()) {
|
|
return nullptr;
|
|
}
|
|
return &m_requests.at(0); // Process first request
|
|
}();
|
|
|
|
if (!request) {
|
|
return false;
|
|
}
|
|
|
|
const auto buffer = request->cfg->buffers[request->index].buffer_render;
|
|
Emu::DrawBuffer(buffer);
|
|
|
|
std::scoped_lock lock{m_mutex};
|
|
|
|
{
|
|
std::scoped_lock cfg_lock{request->cfg->m_mutex};
|
|
for (auto& flip_eq : request->cfg->m_flip_evtEq) {
|
|
if (flip_eq != nullptr) {
|
|
flip_eq->triggerEvent(SCE_VIDEO_OUT_EVENT_FLIP, Libraries::Kernel::EVFILT_VIDEO_OUT,
|
|
reinterpret_cast<void*>(request->flip_arg));
|
|
}
|
|
}
|
|
}
|
|
|
|
m_requests.erase(m_requests.begin());
|
|
m_done_cond.notify_one();
|
|
|
|
request->cfg->m_flip_status.count++;
|
|
request->cfg->m_flip_status.processTime = Libraries::Kernel::sceKernelGetProcessTime();
|
|
request->cfg->m_flip_status.tsc = Libraries::Kernel::sceKernelReadTsc();
|
|
request->cfg->m_flip_status.submitTsc = request->submit_tsc;
|
|
request->cfg->m_flip_status.flipArg = request->flip_arg;
|
|
request->cfg->m_flip_status.currentBuffer = request->index;
|
|
request->cfg->m_flip_status.flipPendingNum = static_cast<int>(m_requests.size());
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace HLE::Graphics::Objects
|