mirror of
https://git.suyu.dev/suyu/suyu
synced 2025-01-09 16:03:21 +00:00
206 lines
5.4 KiB
C++
206 lines
5.4 KiB
C++
// SPDX-FileCopyrightText: 2021 yuzu Emulator Project
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
#pragma once
|
|
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
#include <queue>
|
|
|
|
#include "common/common_types.h"
|
|
|
|
#include "common/address_space.h"
|
|
#include "video_core/cdma_pusher.h"
|
|
#include "video_core/host1x/gpu_device_memory_manager.h"
|
|
#include "video_core/host1x/syncpoint_manager.h"
|
|
#include "video_core/memory_manager.h"
|
|
|
|
namespace Core {
|
|
class System;
|
|
} // namespace Core
|
|
|
|
namespace FFmpeg {
|
|
class Frame;
|
|
} // namespace FFmpeg
|
|
|
|
namespace Tegra::Host1x {
|
|
class Nvdec;
|
|
|
|
class FrameQueue {
|
|
public:
|
|
void Open(s32 fd) {
|
|
std::scoped_lock l{m_mutex};
|
|
m_presentation_order.insert({fd, {}});
|
|
m_decode_order.insert({fd, {}});
|
|
}
|
|
|
|
void Close(s32 fd) {
|
|
std::scoped_lock l{m_mutex};
|
|
m_presentation_order.erase(fd);
|
|
m_decode_order.erase(fd);
|
|
}
|
|
|
|
s32 VicFindNvdecFdFromOffset(u64 search_offset) {
|
|
std::scoped_lock l{m_mutex};
|
|
// Vic does not know which nvdec is producing frames for it, so search all the fds here for
|
|
// the given offset.
|
|
for (auto& map : m_presentation_order) {
|
|
for (auto& [offset, _] : map.second) {
|
|
if (offset == search_offset) {
|
|
return map.first;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto& map : m_decode_order) {
|
|
for (auto& [offset, _] : map.second) {
|
|
if (offset == search_offset) {
|
|
return map.first;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void PushPresentOrder(s32 fd, u64 offset, std::shared_ptr<FFmpeg::Frame>&& frame) {
|
|
std::scoped_lock l{m_mutex};
|
|
auto map = m_presentation_order.find(fd);
|
|
if (map == m_presentation_order.end()) {
|
|
return;
|
|
}
|
|
map->second.emplace_back(offset, std::move(frame));
|
|
}
|
|
|
|
void PushDecodeOrder(s32 fd, u64 offset, std::shared_ptr<FFmpeg::Frame>&& frame) {
|
|
std::scoped_lock l{m_mutex};
|
|
auto map = m_decode_order.find(fd);
|
|
if (map == m_decode_order.end()) {
|
|
return;
|
|
}
|
|
map->second.insert_or_assign(offset, std::move(frame));
|
|
}
|
|
|
|
std::shared_ptr<FFmpeg::Frame> GetFrame(s32 fd, u64 offset) {
|
|
if (fd == -1) {
|
|
return {};
|
|
}
|
|
|
|
std::scoped_lock l{m_mutex};
|
|
auto present_map = m_presentation_order.find(fd);
|
|
if (present_map != m_presentation_order.end() && present_map->second.size() > 0) {
|
|
return GetPresentOrderLocked(fd);
|
|
}
|
|
|
|
auto decode_map = m_decode_order.find(fd);
|
|
if (decode_map != m_decode_order.end() && decode_map->second.size() > 0) {
|
|
return GetDecodeOrderLocked(fd, offset);
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
private:
|
|
std::shared_ptr<FFmpeg::Frame> GetPresentOrderLocked(s32 fd) {
|
|
auto map = m_presentation_order.find(fd);
|
|
if (map == m_presentation_order.end() || map->second.size() == 0) {
|
|
return {};
|
|
}
|
|
auto frame = std::move(map->second.front().second);
|
|
map->second.pop_front();
|
|
return frame;
|
|
}
|
|
|
|
std::shared_ptr<FFmpeg::Frame> GetDecodeOrderLocked(s32 fd, u64 offset) {
|
|
auto map = m_decode_order.find(fd);
|
|
if (map == m_decode_order.end() || map->second.size() == 0) {
|
|
return {};
|
|
}
|
|
auto it = map->second.find(offset);
|
|
if (it == map->second.end()) {
|
|
return {};
|
|
}
|
|
return std::move(map->second.extract(it).mapped());
|
|
}
|
|
|
|
using FramePtr = std::shared_ptr<FFmpeg::Frame>;
|
|
|
|
std::mutex m_mutex{};
|
|
std::unordered_map<s32, std::deque<std::pair<u64, FramePtr>>> m_presentation_order;
|
|
std::unordered_map<s32, std::unordered_map<u64, FramePtr>> m_decode_order;
|
|
};
|
|
|
|
enum class ChannelType : u32 {
|
|
MsEnc = 0,
|
|
VIC = 1,
|
|
GPU = 2,
|
|
NvDec = 3,
|
|
Display = 4,
|
|
NvJpg = 5,
|
|
TSec = 6,
|
|
Max = 7,
|
|
};
|
|
|
|
class Host1x {
|
|
public:
|
|
explicit Host1x(Core::System& system);
|
|
~Host1x();
|
|
|
|
Core::System& System() {
|
|
return system;
|
|
}
|
|
|
|
SyncpointManager& GetSyncpointManager() {
|
|
return syncpoint_manager;
|
|
}
|
|
|
|
const SyncpointManager& GetSyncpointManager() const {
|
|
return syncpoint_manager;
|
|
}
|
|
|
|
Tegra::MaxwellDeviceMemoryManager& MemoryManager() {
|
|
return memory_manager;
|
|
}
|
|
|
|
const Tegra::MaxwellDeviceMemoryManager& MemoryManager() const {
|
|
return memory_manager;
|
|
}
|
|
|
|
Tegra::MemoryManager& GMMU() {
|
|
return gmmu_manager;
|
|
}
|
|
|
|
const Tegra::MemoryManager& GMMU() const {
|
|
return gmmu_manager;
|
|
}
|
|
|
|
Common::FlatAllocator<u32, 0, 32>& Allocator() {
|
|
return *allocator;
|
|
}
|
|
|
|
const Common::FlatAllocator<u32, 0, 32>& Allocator() const {
|
|
return *allocator;
|
|
}
|
|
|
|
void StartDevice(s32 fd, ChannelType type, u32 syncpt);
|
|
void StopDevice(s32 fd, ChannelType type);
|
|
|
|
void PushEntries(s32 fd, ChCommandHeaderList&& entries) {
|
|
auto it = devices.find(fd);
|
|
if (it == devices.end()) {
|
|
return;
|
|
}
|
|
it->second->PushEntries(std::move(entries));
|
|
}
|
|
|
|
private:
|
|
Core::System& system;
|
|
SyncpointManager syncpoint_manager;
|
|
Tegra::MaxwellDeviceMemoryManager memory_manager;
|
|
Tegra::MemoryManager gmmu_manager;
|
|
std::unique_ptr<Common::FlatAllocator<u32, 0, 32>> allocator;
|
|
FrameQueue frame_queue;
|
|
std::unordered_map<s32, std::unique_ptr<CDmaPusher>> devices;
|
|
};
|
|
|
|
} // namespace Tegra::Host1x
|