2024-08-24 13:18:12 +00:00
|
|
|
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
2024-04-14 14:09:51 +00:00
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
2024-07-28 13:54:09 +00:00
|
|
|
|
#include "common/debug.h"
|
|
|
|
|
#include "common/polyfill_thread.h"
|
|
|
|
|
#include "core/libraries/videoout/video_out.h"
|
|
|
|
|
|
2024-04-14 14:09:51 +00:00
|
|
|
|
#include <condition_variable>
|
|
|
|
|
#include <mutex>
|
|
|
|
|
#include <queue>
|
|
|
|
|
|
|
|
|
|
namespace Vulkan {
|
|
|
|
|
struct Frame;
|
2024-05-21 22:35:12 +00:00
|
|
|
|
}
|
2024-04-14 14:09:51 +00:00
|
|
|
|
|
|
|
|
|
namespace Libraries::VideoOut {
|
|
|
|
|
|
|
|
|
|
struct VideoOutPort {
|
|
|
|
|
bool is_open = false;
|
|
|
|
|
SceVideoOutResolutionStatus resolution;
|
|
|
|
|
std::array<VideoOutBuffer, MaxDisplayBuffers> buffer_slots;
|
2024-05-29 10:48:21 +00:00
|
|
|
|
std::array<u64, MaxDisplayBuffers> buffer_labels; // should be contiguous in memory
|
2024-05-08 05:35:10 +00:00
|
|
|
|
static_assert(sizeof(buffer_labels[0]) == 8u);
|
2024-04-14 14:09:51 +00:00
|
|
|
|
std::array<BufferAttributeGroup, MaxDisplayBufferGroups> groups;
|
|
|
|
|
FlipStatus flip_status;
|
|
|
|
|
SceVideoOutVblankStatus vblank_status;
|
|
|
|
|
std::vector<Kernel::SceKernelEqueue> flip_events;
|
2024-05-17 21:31:55 +00:00
|
|
|
|
std::vector<Kernel::SceKernelEqueue> vblank_events;
|
2024-07-28 13:54:09 +00:00
|
|
|
|
std::mutex vo_mutex;
|
2024-08-14 09:36:11 +00:00
|
|
|
|
std::mutex port_mutex;
|
2024-07-28 13:54:09 +00:00
|
|
|
|
std::condition_variable vo_cv;
|
|
|
|
|
std::condition_variable vblank_cv;
|
2024-04-14 14:09:51 +00:00
|
|
|
|
int flip_rate = 0;
|
|
|
|
|
|
|
|
|
|
s32 FindFreeGroup() const {
|
|
|
|
|
s32 index = 0;
|
|
|
|
|
while (index < groups.size() && groups[index].is_occupied) {
|
|
|
|
|
index++;
|
|
|
|
|
}
|
|
|
|
|
return index;
|
|
|
|
|
}
|
2024-05-10 19:48:01 +00:00
|
|
|
|
|
2024-07-28 13:54:09 +00:00
|
|
|
|
bool IsVoLabel(const u64* address) const {
|
|
|
|
|
const u64* start = &buffer_labels[0];
|
|
|
|
|
const u64* end = &buffer_labels[MaxDisplayBuffers - 1];
|
|
|
|
|
return address >= start && address <= end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WaitVoLabel(auto&& pred) {
|
|
|
|
|
std::unique_lock lk{vo_mutex};
|
|
|
|
|
vo_cv.wait(lk, pred);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SignalVoLabel() {
|
|
|
|
|
std::scoped_lock lk{vo_mutex};
|
|
|
|
|
vo_cv.notify_one();
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-10 19:48:01 +00:00
|
|
|
|
[[nodiscard]] int NumRegisteredBuffers() const {
|
|
|
|
|
return std::count_if(buffer_slots.cbegin(), buffer_slots.cend(),
|
|
|
|
|
[](auto& buffer) { return buffer.group_index != -1; });
|
|
|
|
|
}
|
2024-04-14 14:09:51 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct ServiceThreadParams {
|
|
|
|
|
u32 unknown;
|
|
|
|
|
bool set_priority;
|
|
|
|
|
u32 priority;
|
|
|
|
|
bool set_affinity;
|
|
|
|
|
u64 affinity;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class VideoOutDriver {
|
|
|
|
|
public:
|
|
|
|
|
explicit VideoOutDriver(u32 width, u32 height);
|
|
|
|
|
~VideoOutDriver();
|
|
|
|
|
|
|
|
|
|
int Open(const ServiceThreadParams* params);
|
|
|
|
|
void Close(s32 handle);
|
|
|
|
|
|
|
|
|
|
VideoOutPort* GetPort(s32 handle);
|
|
|
|
|
|
|
|
|
|
int RegisterBuffers(VideoOutPort* port, s32 startIndex, void* const* addresses, s32 bufferNum,
|
|
|
|
|
const BufferAttribute* attribute);
|
|
|
|
|
int UnregisterBuffers(VideoOutPort* port, s32 attributeIndex);
|
|
|
|
|
|
2024-05-10 19:48:01 +00:00
|
|
|
|
bool SubmitFlip(VideoOutPort* port, s32 index, s64 flip_arg, bool is_eop = false);
|
2024-04-14 14:09:51 +00:00
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
struct Request {
|
|
|
|
|
Vulkan::Frame* frame;
|
|
|
|
|
VideoOutPort* port;
|
|
|
|
|
s64 flip_arg;
|
2024-08-24 13:18:12 +00:00
|
|
|
|
s32 index;
|
2024-05-10 19:48:01 +00:00
|
|
|
|
bool eop;
|
2024-07-28 13:54:09 +00:00
|
|
|
|
|
|
|
|
|
operator bool() const noexcept {
|
|
|
|
|
return frame != nullptr;
|
|
|
|
|
}
|
2024-04-14 14:09:51 +00:00
|
|
|
|
};
|
|
|
|
|
|
2024-07-28 13:54:09 +00:00
|
|
|
|
std::chrono::microseconds Flip(const Request& req);
|
2024-08-14 09:36:11 +00:00
|
|
|
|
void SubmitFlipInternal(VideoOutPort* port, s32 index, s64 flip_arg, bool is_eop = false);
|
2024-07-28 13:54:09 +00:00
|
|
|
|
void PresentThread(std::stop_token token);
|
|
|
|
|
|
2024-04-14 14:09:51 +00:00
|
|
|
|
std::mutex mutex;
|
|
|
|
|
VideoOutPort main_port{};
|
2024-07-28 13:54:09 +00:00
|
|
|
|
std::jthread present_thread;
|
2024-04-14 14:09:51 +00:00
|
|
|
|
std::queue<Request> requests;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace Libraries::VideoOut
|