shadPS4/src/core/libraries/videoout/driver.h
Herman Semenov 243fd0be78
core,shader_recompiler: align structures for 64-bit platforms (#447)
Decreased sizes:
 * TextureDefinition 32 bytes -> 24 bytes
 * PortOut 72 bytes -> 64 bytes
 * Request 48 bytes -> 40 bytes
 * WindowSystemInfo 32 bytes -> 24 bytes
2024-08-24 16:18:12 +03:00

115 lines
3.1 KiB
C++

// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/debug.h"
#include "common/polyfill_thread.h"
#include "core/libraries/videoout/video_out.h"
#include <condition_variable>
#include <mutex>
#include <queue>
namespace Vulkan {
struct Frame;
}
namespace Libraries::VideoOut {
struct VideoOutPort {
bool is_open = false;
SceVideoOutResolutionStatus resolution;
std::array<VideoOutBuffer, MaxDisplayBuffers> buffer_slots;
std::array<u64, MaxDisplayBuffers> buffer_labels; // should be contiguous in memory
static_assert(sizeof(buffer_labels[0]) == 8u);
std::array<BufferAttributeGroup, MaxDisplayBufferGroups> groups;
FlipStatus flip_status;
SceVideoOutVblankStatus vblank_status;
std::vector<Kernel::SceKernelEqueue> flip_events;
std::vector<Kernel::SceKernelEqueue> vblank_events;
std::mutex vo_mutex;
std::mutex port_mutex;
std::condition_variable vo_cv;
std::condition_variable vblank_cv;
int flip_rate = 0;
s32 FindFreeGroup() const {
s32 index = 0;
while (index < groups.size() && groups[index].is_occupied) {
index++;
}
return index;
}
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();
}
[[nodiscard]] int NumRegisteredBuffers() const {
return std::count_if(buffer_slots.cbegin(), buffer_slots.cend(),
[](auto& buffer) { return buffer.group_index != -1; });
}
};
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);
bool SubmitFlip(VideoOutPort* port, s32 index, s64 flip_arg, bool is_eop = false);
private:
struct Request {
Vulkan::Frame* frame;
VideoOutPort* port;
s64 flip_arg;
s32 index;
bool eop;
operator bool() const noexcept {
return frame != nullptr;
}
};
std::chrono::microseconds Flip(const Request& req);
void SubmitFlipInternal(VideoOutPort* port, s32 index, s64 flip_arg, bool is_eop = false);
void PresentThread(std::stop_token token);
std::mutex mutex;
VideoOutPort main_port{};
std::jthread present_thread;
std::queue<Request> requests;
};
} // namespace Libraries::VideoOut