AnyPS5/core/libs/prx/libSceVideoOut/include/VideoOutDriver.hpp

149 lines
4.7 KiB
C++

#ifndef CORE_LIBS_PRX_LIBSCEVIDEOUOUT_INCLUDE_VIDEOOUTDRIVER_HPP
#define CORE_LIBS_PRX_LIBSCEVIDEOUOUT_INCLUDE_VIDEOOUTDRIVER_HPP
#include <array>
#include <condition_variable>
#include <cstdint>
#include <list>
#include <mutex>
#include <thread>
#include <vector>
#include "SDL.h"
#include "SceTypes.hpp"
static constexpr int VIDEO_OUT_ERROR_INVALID_VALUE = -2144796671;
static constexpr int VIDEO_OUT_ERROR_INVALID_ADDRESS = -2144796670;
static constexpr int VIDEO_OUT_ERROR_INVALID_HANDLE = -2144796669;
static constexpr int VIDEO_OUT_ERROR_INVALID_EVENT_QUEUE = -2144796668;
static constexpr int VIDEO_OUT_ERROR_INVALID_INDEX = -2144796667;
static constexpr int VIDEO_OUT_ERROR_INVALID_OPTION = -2144796666;
static constexpr int VIDEO_OUT_ERROR_INVALID_CATEGORY = -2144796664;
static constexpr int VIDEO_OUT_ERROR_SLOT_OCCUPIED = -2144796663;
static constexpr int VIDEO_OUT_ERROR_RESOURCE_BUSY = -2144796656;
static constexpr int VIDEO_OUT_ERROR_FLIP_QUEUE_FULL = -2144796654;
static constexpr int VIDEO_OUT_ERROR_UNSUPPORTED_OUTPUT_MODE = -2144796634;
static constexpr int VIDEO_OUT_ERROR_UNAVAILABLE_OUTPUT_MODE = -2144796633;
static constexpr int VIDEO_OUT_ERROR_INVALID_EVENT = -2144796624;
static constexpr int VIDEO_OUT_BUS_TYPE_MAIN = 0;
static constexpr int VIDEO_OUT_BUS_TYPE_OVERLAY = 1;
static constexpr int VIDEO_OUT_BUS_TYPE_SUB = 2;
static constexpr int VIDEO_OUT_BUFFER_NUM_MAX = 16;
static constexpr int VIDEO_OUT_BUFFER_ATTRIBUTE_NUM_MAX = 4;
static constexpr int VIDEO_OUT_NUM_MAX = 4;
static constexpr std::size_t VIDEO_OUT_FLIP_QUEUE_CAPACITY = 16;
static constexpr int VIDEO_OUT_BUFFER_ATTRIBUTE_CATEGORY_UNCOMPRESSED = 0;
static constexpr int VIDEO_OUT_BUFFER_ATTRIBUTE_CATEGORY_COMPRESSED = 1;
static constexpr int VIDEO_OUT_EVENT_FLIP = 0;
static constexpr int VIDEO_OUT_EVENT_VBLANK = 1;
static constexpr int VIDEO_OUT_EVENT_PRE_VBLANK_START = 2;
static constexpr int VIDEO_OUT_EVENT_SET_MODE = 8;
static constexpr int VIDEO_OUT_FLIP_MODE_VSYNC = 1;
static constexpr int VIDEO_OUT_FLIP_MODE_VSYNC_MULTI = 4;
static constexpr int VIDEO_OUT_BUFFER_INDEX_BLACK = -2;
static constexpr int VIDEO_OUT_BUFFER_INDEX_BLANK = -1;
static constexpr uint64_t VIDEO_OUT_OUTPUT_MODE_DEFAULT = 0x0000000000000001ULL;
static constexpr uint64_t VIDEO_OUT_OUTPUT_MODE_119_88HZ = 0x000000000000000FULL;
static constexpr uint64_t VIDEO_OUT_REFRESH_RATE_59_94HZ = 3;
static constexpr uint64_t VIDEO_OUT_REFRESH_RATE_119_88HZ = 13;
struct VideoOutBuffer {
int groupIndex = -1;
uint64_t dataAddress = 0;
uint64_t metadataAddress = 0;
bool Occupied() const { return groupIndex >= 0; }
};
struct BufferAttributeGroup {
VideoOutBufferAttribute2 attribute{};
int category = VIDEO_OUT_BUFFER_ATTRIBUTE_CATEGORY_UNCOMPRESSED;
bool occupied = false;
};
struct EventRegistration {
KernelEqueue eq = 0;
uint64_t generation = 0;
};
struct VideoOutConfig {
std::mutex mutex;
std::condition_variable_any vblankCond;
std::vector<EventRegistration> flipEvents;
std::vector<EventRegistration> vblankEvents;
std::vector<EventRegistration> preVblankEvents;
std::vector<EventRegistration> outputModeEvents;
uint32_t width = 1920;
uint32_t height = 1080;
uint64_t generation = 0;
bool opened = false;
bool closing = false;
int flipRate = 0;
uint64_t outputMode = VIDEO_OUT_OUTPUT_MODE_DEFAULT;
float gamma = 1.0f;
VideoOutFlipStatus flipStatus{};
VideoOutVblankStatus vblankStatus{};
VideoOutVblankStatus preVblankStatus{};
std::array<VideoOutBuffer, VIDEO_OUT_BUFFER_NUM_MAX> buffers{};
std::array<BufferAttributeGroup, VIDEO_OUT_BUFFER_ATTRIBUTE_NUM_MAX> groups{};
};
struct FlipRequest {
VideoOutConfig* cfg = nullptr;
uint64_t generation = 0;
int index = 0;
int flipMode = 0;
int64_t flipArg = 0;
};
class VideoOutDriver {
public:
static VideoOutDriver& Get();
VideoOutDriver();
~VideoOutDriver();
VideoOutDriver(const VideoOutDriver&) = delete;
VideoOutDriver& operator=(const VideoOutDriver&) = delete;
int Open(int busType);
bool Close(int handle);
VideoOutConfig* GetConfig(int handle);
bool IsOpen(int handle);
void SubmitFlip(VideoOutConfig* cfg, int index, int flipMode, int64_t flipArg);
private:
void presentLoop(std::stop_token token);
void vblankBegin();
void vblankEnd();
void processFlip(const FlipRequest& req);
void triggerEvents(VideoOutConfig& cfg, int eventKind, void* triggerData);
std::mutex mutex;
VideoOutConfig contexts[VIDEO_OUT_NUM_MAX];
std::mutex flipMutex;
std::condition_variable flipCond;
std::list<FlipRequest> flipQueue;
SDL_Window* window = nullptr;
SDL_Surface* windowSurface = nullptr;
std::jthread presentThread;
};
#endif