Compare commits

..

10 Commits

Author SHA1 Message Date
b52f26a094 Android 229 2024-02-05 01:00:43 +00:00
e957bc2b4c Merge yuzu-emu#12915 2024-02-05 01:00:43 +00:00
363c96bdc3 Merge yuzu-emu#12905 2024-02-05 01:00:43 +00:00
514c3a75e1 Merge yuzu-emu#12903 2024-02-05 01:00:43 +00:00
bef9ee5000 Merge yuzu-emu#12873 2024-02-05 01:00:43 +00:00
78ce7f00f9 Merge yuzu-emu#12756 2024-02-05 01:00:43 +00:00
9b9634454a Merge yuzu-emu#12749 2024-02-05 01:00:43 +00:00
a5cdf0aed1 Merge yuzu-emu#12461 2024-02-05 01:00:42 +00:00
4cccbe7989 Merge pull request #12892 from liamwhite/serialization-stuff
cmif_serialization: enforce const for references
2024-02-04 09:48:33 -05:00
78f72b3bf5 cmif_serialization: enforce const for references 2024-02-02 09:32:10 -05:00
19 changed files with 262 additions and 98 deletions

View File

@ -2,9 +2,11 @@
|----|----|----|----|----|
| [12461](https://github.com/yuzu-emu/yuzu-android//pull/12461) | [`4c08a0e6d`](https://github.com/yuzu-emu/yuzu-android//pull/12461/files) | Rework Nvdec and VIC to fix out-of-order videos, and speed up decoding. | [Kelebek1](https://github.com/Kelebek1/) | Yes |
| [12749](https://github.com/yuzu-emu/yuzu-android//pull/12749) | [`aad4b0d6f`](https://github.com/yuzu-emu/yuzu-android//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12756](https://github.com/yuzu-emu/yuzu-android//pull/12756) | [`b19285d4f`](https://github.com/yuzu-emu/yuzu-android//pull/12756/files) | general: applet multiprocess | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12892](https://github.com/yuzu-emu/yuzu-android//pull/12892) | [`78f72b3bf`](https://github.com/yuzu-emu/yuzu-android//pull/12892/files) | cmif_serialization: enforce const for references | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12756](https://github.com/yuzu-emu/yuzu-android//pull/12756) | [`cd3de0848`](https://github.com/yuzu-emu/yuzu-android//pull/12756/files) | general: applet multiprocess | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12873](https://github.com/yuzu-emu/yuzu-android//pull/12873) | [`a8488952f`](https://github.com/yuzu-emu/yuzu-android//pull/12873/files) | GPU: Implement channel scheduling. | [FernandoS27](https://github.com/FernandoS27/) | Yes |
| [12903](https://github.com/yuzu-emu/yuzu-android//pull/12903) | [`5be8121af`](https://github.com/yuzu-emu/yuzu-android//pull/12903/files) | shader_recompiler: use only ConstOffset for OpImageFetch | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12905](https://github.com/yuzu-emu/yuzu-android//pull/12905) | [`5eb5c9675`](https://github.com/yuzu-emu/yuzu-android//pull/12905/files) | nvnflinger: release buffers before presentation sleep | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12915](https://github.com/yuzu-emu/yuzu-android//pull/12915) | [`504abbd6e`](https://github.com/yuzu-emu/yuzu-android//pull/12915/files) | dmnt: cheats: Update cheat vm to latest version | [german77](https://github.com/german77/) | Yes |
End of merge log. You can find the original README.md below the break.

View File

@ -118,23 +118,17 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
switch (mode) {
case LibraryAppletMode::AllForeground:
case LibraryAppletMode::NoUi:
applet->focus_state = FocusState::InFocus;
applet->hid_registration.EnableAppletToGetInput(true);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
break;
case LibraryAppletMode::AllForegroundInitiallyHidden:
applet->system_buffer_manager.SetWindowVisibility(false);
applet->focus_state = FocusState::NotInFocus;
applet->hid_registration.EnableAppletToGetInput(false);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
break;
case LibraryAppletMode::PartialForeground:
case LibraryAppletMode::PartialForegroundIndirectDisplay:
default:
applet->focus_state = FocusState::Background;
applet->hid_registration.EnableAppletToGetInput(true);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
applet->focus_state = FocusState::InFocus;
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
break;
case LibraryAppletMode::AllForegroundInitiallyHidden:
applet->hid_registration.EnableAppletToGetInput(false);
applet->focus_state = FocusState::NotInFocus;
applet->system_buffer_manager.SetWindowVisibility(false);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoBackground);
break;
}

View File

@ -38,7 +38,8 @@ bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel:
}
Nvnflinger::LayerBlending blending = Nvnflinger::LayerBlending::None;
if (mode == LibraryAppletMode::PartialForeground) {
if (mode == LibraryAppletMode::PartialForeground ||
mode == LibraryAppletMode::PartialForegroundIndirectDisplay) {
blending = Nvnflinger::LayerBlending::Coverage;
}

View File

@ -62,12 +62,12 @@ void IWindowController::SetAppletWindowVisibility(HLERequestContext& ctx) {
applet->hid_registration.EnableAppletToGetInput(visible);
if (visible) {
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
applet->focus_state = FocusState::InFocus;
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
} else {
applet->focus_state = FocusState::NotInFocus;
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoBackground);
}
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);

View File

@ -7,7 +7,6 @@
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
#include "core/hle/service/nvnflinger/buffer_item.h"
#include "core/hle/service/nvnflinger/buffer_item_consumer.h"
#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
#include "core/hle/service/nvnflinger/hardware_composer.h"
#include "core/hle/service/nvnflinger/hwc_layer.h"
#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
@ -46,31 +45,9 @@ HardwareComposer::HardwareComposer() = default;
HardwareComposer::~HardwareComposer() = default;
u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance) {
Nvidia::Devices::nvdisp_disp0& nvdisp) {
boost::container::small_vector<HwcLayer, 2> composition_stack;
m_frame_number += frame_advance;
// Release any necessary framebuffers.
for (auto& [layer_id, framebuffer] : m_framebuffers) {
if (framebuffer.release_frame_number > m_frame_number) {
// Not yet ready to release this framebuffer.
continue;
}
if (!framebuffer.is_acquired) {
// Already released.
continue;
}
if (auto* layer = display.FindLayer(layer_id); layer != nullptr) {
// TODO: support release fence
// This is needed to prevent screen tearing
layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
framebuffer.is_acquired = false;
}
}
// Set default speed limit to 100%.
*out_speed_scale = 1.0f;
@ -143,7 +120,30 @@ u32 HardwareComposer::ComposeLocked(f32* out_speed_scale, VI::Display& display,
MicroProfileFlip();
// Advance by at least one frame.
return swap_interval.value_or(1);
const u32 frame_advance = swap_interval.value_or(1);
m_frame_number += frame_advance;
// Release any necessary framebuffers.
for (auto& [layer_id, framebuffer] : m_framebuffers) {
if (framebuffer.release_frame_number > m_frame_number) {
// Not yet ready to release this framebuffer.
continue;
}
if (!framebuffer.is_acquired) {
// Already released.
continue;
}
if (auto* layer = display.FindLayer(layer_id); layer != nullptr) {
// TODO: support release fence
// This is needed to prevent screen tearing
layer->GetConsumer().ReleaseBuffer(framebuffer.item, android::Fence::NoFence());
framebuffer.is_acquired = false;
}
}
return frame_advance;
}
void HardwareComposer::RemoveLayerLocked(VI::Display& display, LayerId layer_id) {

View File

@ -27,7 +27,7 @@ public:
~HardwareComposer();
u32 ComposeLocked(f32* out_speed_scale, VI::Display& display,
Nvidia::Devices::nvdisp_disp0& nvdisp, u32 frame_advance);
Nvidia::Devices::nvdisp_disp0& nvdisp);
void RemoveLayerLocked(VI::Display& display, LayerId layer_id);
private:

View File

@ -292,8 +292,7 @@ void Nvnflinger::Compose() {
auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd);
ASSERT(nvdisp);
swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp,
swap_interval);
swap_interval = display.GetComposer().ComposeLocked(&compose_speed_scale, display, *nvdisp);
}
}

View File

@ -9,6 +9,7 @@
#include "core/core_timing.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_process_page_table.h"
#include "core/hle/service/hid/hid_server.h"
#include "core/hle/service/sm/sm.h"
#include "core/memory.h"
@ -85,8 +86,12 @@ VAddr StandardVmCallbacks::SanitizeAddress(VAddr in) const {
if ((in < metadata.main_nso_extents.base ||
in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) &&
(in < metadata.heap_extents.base ||
in >= metadata.heap_extents.base + metadata.heap_extents.size)) {
LOG_ERROR(CheatEngine,
in >= metadata.heap_extents.base + metadata.heap_extents.size) &&
(in < metadata.alias_extents.base ||
in >= metadata.heap_extents.base + metadata.alias_extents.size) &&
(in < metadata.aslr_extents.base ||
in >= metadata.heap_extents.base + metadata.aslr_extents.size)) {
LOG_DEBUG(CheatEngine,
"Cheat attempting to access memory at invalid address={:016X}, if this "
"persists, "
"the cheat may be incorrect. However, this may be normal early in execution if "
@ -211,16 +216,14 @@ void CheatEngine::Initialize() {
.base = GetInteger(page_table.GetHeapRegionStart()),
.size = page_table.GetHeapRegionSize(),
};
metadata.address_space_extents = {
.base = GetInteger(page_table.GetAddressSpaceStart()),
.size = page_table.GetAddressSpaceSize(),
};
metadata.alias_extents = {
metadata.aslr_extents = {
.base = GetInteger(page_table.GetAliasCodeRegionStart()),
.size = page_table.GetAliasCodeRegionSize(),
};
metadata.alias_extents = {
.base = GetInteger(page_table.GetAliasRegionStart()),
.size = page_table.GetAliasRegionSize(),
};
is_pending_reload.exchange(true);
}

View File

@ -37,7 +37,7 @@ private:
VAddr SanitizeAddress(VAddr address) const;
const CheatProcessMetadata& metadata;
System& system;
Core::System& system;
};
// Intermediary class that parses a text file or other disk format for storing cheats into a

View File

@ -18,7 +18,7 @@ struct CheatProcessMetadata {
MemoryRegionExtents main_nso_extents{};
MemoryRegionExtents heap_extents{};
MemoryRegionExtents alias_extents{};
MemoryRegionExtents address_space_extents{};
MemoryRegionExtents aslr_extents{};
std::array<u8, 0x20> main_nso_build_id{};
};

View File

@ -322,8 +322,9 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
} break;
case CheatVmOpcodeType::EndConditionalBlock: {
// 20000000
// There's actually nothing left to process here!
opcode.opcode = EndConditionalOpcode{};
opcode.opcode = EndConditionalOpcode{
.is_else = ((first_dword >> 24) & 0xf) == 1,
};
} break;
case CheatVmOpcodeType::ControlLoop: {
// 300R0000 VVVVVVVV
@ -555,6 +556,18 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
.idx = first_dword & 0xF,
};
} break;
case CheatVmOpcodeType::PauseProcess: {
/* FF0????? */
/* FF0 = opcode 0xFF0 */
/* Pauses the current process. */
opcode.opcode = PauseProcessOpcode{};
} break;
case CheatVmOpcodeType::ResumeProcess: {
/* FF0????? */
/* FF0 = opcode 0xFF0 */
/* Pauses the current process. */
opcode.opcode = ResumeProcessOpcode{};
} break;
case CheatVmOpcodeType::DebugLog: {
// FFFTIX##
// FFFTI0Ma aaaaaaaa
@ -621,7 +634,7 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
return valid;
}
void DmntCheatVm::SkipConditionalBlock() {
void DmntCheatVm::SkipConditionalBlock(bool is_if) {
if (condition_depth > 0) {
// We want to continue until we're out of the current block.
const std::size_t desired_depth = condition_depth - 1;
@ -637,8 +650,12 @@ void DmntCheatVm::SkipConditionalBlock() {
// We also support nesting of conditional blocks, and Gateway does not.
if (skip_opcode.begin_conditional_block) {
condition_depth++;
} else if (std::holds_alternative<EndConditionalOpcode>(skip_opcode.opcode)) {
condition_depth--;
} else if (auto end_cond = std::get_if<EndConditionalOpcode>(&skip_opcode.opcode)) {
if (!end_cond->is_else) {
condition_depth--;
} else if (is_if && condition_depth - 1 == desired_depth) {
break;
}
}
}
} else {
@ -675,6 +692,10 @@ u64 DmntCheatVm::GetCheatProcessAddress(const CheatProcessMetadata& metadata,
return metadata.main_nso_extents.base + rel_address;
case MemoryAccessType::Heap:
return metadata.heap_extents.base + rel_address;
case MemoryAccessType::Alias:
return metadata.alias_extents.base + rel_address;
case MemoryAccessType::Aslr:
return metadata.aslr_extents.base + rel_address;
}
}
@ -682,7 +703,6 @@ void DmntCheatVm::ResetState() {
registers.fill(0);
saved_values.fill(0);
loop_tops.fill(0);
static_registers.fill(0);
instruction_ptr = 0;
condition_depth = 0;
decode_success = true;
@ -794,13 +814,18 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
}
// Skip conditional block if condition not met.
if (!cond_met) {
SkipConditionalBlock();
SkipConditionalBlock(true);
}
} else if (std::holds_alternative<EndConditionalOpcode>(cur_opcode.opcode)) {
// Decrement the condition depth.
// We will assume, graciously, that mismatched conditional block ends are a nop.
if (condition_depth > 0) {
condition_depth--;
} else if (auto end_cond = std::get_if<EndConditionalOpcode>(&cur_opcode.opcode)) {
if (end_cond->is_else) {
/* Skip to the end of the conditional block. */
this->SkipConditionalBlock(false);
} else {
/* Decrement the condition depth. */
/* We will assume, graciously, that mismatched conditional block ends are a nop. */
if (condition_depth > 0) {
condition_depth--;
}
}
} else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&cur_opcode.opcode)) {
if (ctrl_loop->start_loop) {
@ -908,7 +933,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
// Check for keypress.
if ((begin_keypress_cond->key_mask & kDown) != begin_keypress_cond->key_mask) {
// Keys not pressed. Skip conditional block.
SkipConditionalBlock();
SkipConditionalBlock(true);
}
} else if (auto perform_math_reg =
std::get_if<PerformArithmeticRegisterOpcode>(&cur_opcode.opcode)) {
@ -1116,7 +1141,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
// Skip conditional block if condition not met.
if (!cond_met) {
SkipConditionalBlock();
SkipConditionalBlock(true);
}
} else if (auto save_restore_reg =
std::get_if<SaveRestoreRegisterOpcode>(&cur_opcode.opcode)) {
@ -1178,6 +1203,10 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
// Store a register to a static register.
static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx];
}
} else if (std::holds_alternative<PauseProcessOpcode>(cur_opcode.opcode)) {
// TODO: Pause cheat process
} else if (std::holds_alternative<ResumeProcessOpcode>(cur_opcode.opcode)) {
// TODO: Resume cheat process
} else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) {
// Read value from memory.
u64 log_value = 0;

View File

@ -42,12 +42,16 @@ enum class CheatVmOpcodeType : u32 {
DoubleExtendedWidth = 0xF0,
// Double-extended width opcodes.
PauseProcess = 0xFF0,
ResumeProcess = 0xFF1,
DebugLog = 0xFFF,
};
enum class MemoryAccessType : u32 {
MainNso = 0,
Heap = 1,
Alias = 2,
Aslr = 3,
};
enum class ConditionalComparisonType : u32 {
@ -131,7 +135,9 @@ struct BeginConditionalOpcode {
VmInt value{};
};
struct EndConditionalOpcode {};
struct EndConditionalOpcode {
bool is_else;
};
struct ControlLoopOpcode {
bool start_loop{};
@ -222,6 +228,10 @@ struct ReadWriteStaticRegisterOpcode {
u32 idx{};
};
struct PauseProcessOpcode {};
struct ResumeProcessOpcode {};
struct DebugLogOpcode {
u32 bit_width{};
u32 log_id{};
@ -244,8 +254,8 @@ struct CheatVmOpcode {
PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, DebugLogOpcode,
UnrecognizedInstruction>
SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, PauseProcessOpcode,
ResumeProcessOpcode, DebugLogOpcode, UnrecognizedInstruction>
opcode{};
};
@ -296,7 +306,7 @@ private:
std::array<std::size_t, NumRegisters> loop_tops{};
bool DecodeNextOpcode(CheatVmOpcode& out);
void SkipConditionalBlock();
void SkipConditionalBlock(bool is_if);
void ResetState();
// For implementing the DebugLog opcode.

View File

@ -13,20 +13,101 @@ Scheduler::Scheduler(GPU& gpu_) : gpu{gpu_} {}
Scheduler::~Scheduler() = default;
void Scheduler::Init() {
master_control = Common::Fiber::ThreadToFiber();
}
void Scheduler::Resume() {
bool nothing_pending;
do {
nothing_pending = true;
current_fifo = nullptr;
{
std::unique_lock lk(scheduling_guard);
size_t num_iters = gpfifos.size();
for (size_t i = 0; i < num_iters; i++) {
size_t current_id = (current_fifo_rotation_id + i) % gpfifos.size();
auto& fifo = gpfifos[current_id];
if (!fifo.is_active) {
continue;
}
std::scoped_lock lk2(fifo.guard);
if (!fifo.pending_work.empty() || fifo.working.load(std::memory_order_acquire)) {
current_fifo = &fifo;
current_fifo_rotation_id = current_id;
nothing_pending = false;
break;
}
}
}
if (current_fifo) {
Common::Fiber::YieldTo(master_control, *current_fifo->context);
current_fifo = nullptr;
}
} while (!nothing_pending);
}
void Scheduler::Yield() {
ASSERT(current_fifo != nullptr);
Common::Fiber::YieldTo(current_fifo->context, *master_control);
}
void Scheduler::Push(s32 channel, CommandList&& entries) {
std::unique_lock lk(scheduling_guard);
auto it = channels.find(channel);
ASSERT(it != channels.end());
auto channel_state = it->second;
gpu.BindChannel(channel_state->bind_id);
channel_state->dma_pusher->Push(std::move(entries));
channel_state->dma_pusher->DispatchCalls();
auto it = channel_gpfifo_ids.find(channel);
ASSERT(it != channel_gpfifo_ids.end());
auto gpfifo_id = it->second;
auto& fifo = gpfifos[gpfifo_id];
{
std::scoped_lock lk2(fifo.guard);
fifo.pending_work.emplace_back(std::move(entries));
}
}
void Scheduler::ChannelLoop(size_t gpfifo_id, s32 channel_id) {
gpu.BindChannel(channel_id);
auto& fifo = gpfifos[gpfifo_id];
while (true) {
auto* channel_state = channels[channel_id].get();
fifo.guard.lock();
while (!fifo.pending_work.empty()) {
{
fifo.working.store(true, std::memory_order_release);
CommandList&& entries = std::move(fifo.pending_work.front());
channel_state->dma_pusher->Push(std::move(entries));
fifo.pending_work.pop_front();
}
fifo.guard.unlock();
channel_state->dma_pusher->DispatchCalls();
fifo.guard.lock();
}
fifo.working.store(false, std::memory_order_relaxed);
fifo.guard.unlock();
Common::Fiber::YieldTo(fifo.context, *master_control);
gpu.BindChannel(channel_id);
}
}
void Scheduler::DeclareChannel(std::shared_ptr<ChannelState> new_channel) {
s32 channel = new_channel->bind_id;
std::unique_lock lk(scheduling_guard);
channels.emplace(channel, new_channel);
size_t new_fifo_id;
if (!free_fifos.empty()) {
new_fifo_id = free_fifos.front();
free_fifos.pop_front();
} else {
new_fifo_id = gpfifos.size();
gpfifos.emplace_back();
}
auto& new_fifo = gpfifos[new_fifo_id];
channel_gpfifo_ids[channel] = new_fifo_id;
new_fifo.is_active = true;
new_fifo.bind_id = channel;
new_fifo.pending_work.clear();
std::function<void()> callback = std::bind(&Scheduler::ChannelLoop, this, new_fifo_id, channel);
new_fifo.context = std::make_shared<Common::Fiber>(std::move(callback));
}
} // namespace Tegra::Control

View File

@ -3,10 +3,13 @@
#pragma once
#include <atomic>
#include <deque>
#include <memory>
#include <mutex>
#include <unordered_map>
#include "common/fiber.h"
#include "video_core/dma_pusher.h"
namespace Tegra {
@ -22,14 +25,36 @@ public:
explicit Scheduler(GPU& gpu_);
~Scheduler();
void Init();
void Resume();
void Yield();
void Push(s32 channel, CommandList&& entries);
void DeclareChannel(std::shared_ptr<ChannelState> new_channel);
private:
void ChannelLoop(size_t gpfifo_id, s32 channel_id);
std::unordered_map<s32, std::shared_ptr<ChannelState>> channels;
std::unordered_map<s32, size_t> channel_gpfifo_ids;
std::mutex scheduling_guard;
std::shared_ptr<Common::Fiber> master_control;
struct GPFifoContext {
bool is_active;
std::shared_ptr<Common::Fiber> context;
std::deque<CommandList> pending_work;
std::atomic<bool> working{};
std::mutex guard;
s32 bind_id;
};
std::deque<GPFifoContext> gpfifos;
std::deque<size_t> free_fifos;
GPU& gpu;
size_t current_fifo_rotation_id{};
GPFifoContext* current_fifo{};
};
} // namespace Control

View File

@ -6,6 +6,7 @@
#include "common/settings.h"
#include "core/core.h"
#include "video_core/control/channel_state.h"
#include "video_core/control/scheduler.h"
#include "video_core/dma_pusher.h"
#include "video_core/engines/fermi_2d.h"
#include "video_core/engines/kepler_compute.h"
@ -14,6 +15,8 @@
#include "video_core/engines/maxwell_dma.h"
#include "video_core/engines/puller.h"
#include "video_core/gpu.h"
#include "video_core/host1x/host1x.h"
#include "video_core/host1x/syncpoint_manager.h"
#include "video_core/memory_manager.h"
#include "video_core/rasterizer_interface.h"
@ -60,11 +63,14 @@ void Puller::ProcessBindMethod(const MethodCall& method_call) {
}
void Puller::ProcessFenceActionMethod() {
auto& syncpoint_manager = gpu.Host1x().GetSyncpointManager();
switch (regs.fence_action.op) {
case Puller::FenceOperation::Acquire:
// UNIMPLEMENTED_MSG("Channel Scheduling pending.");
// WaitFence(regs.fence_action.syncpoint_id, regs.fence_value);
rasterizer->ReleaseFences();
while (regs.fence_value >
syncpoint_manager.GetGuestSyncpointValue(regs.fence_action.syncpoint_id)) {
rasterizer->ReleaseFences();
gpu.Scheduler().Yield();
}
break;
case Puller::FenceOperation::Increment:
rasterizer->SignalSyncPoint(regs.fence_action.syncpoint_id);

View File

@ -387,6 +387,14 @@ std::shared_ptr<Control::ChannelState> GPU::AllocateChannel() {
return impl->AllocateChannel();
}
Tegra::Control::Scheduler& GPU::Scheduler() {
return *impl->scheduler;
}
const Tegra::Control::Scheduler& GPU::Scheduler() const {
return *impl->scheduler;
}
void GPU::InitChannel(Control::ChannelState& to_init) {
impl->InitChannel(to_init);
}

View File

@ -124,7 +124,8 @@ class KeplerCompute;
namespace Control {
struct ChannelState;
}
class Scheduler;
} // namespace Control
namespace Host1x {
class Host1x;
@ -204,6 +205,12 @@ public:
/// Returns a const reference to the shader notifier.
[[nodiscard]] const VideoCore::ShaderNotify& ShaderNotify() const;
/// Returns GPU Channel Scheduler.
[[nodiscard]] Tegra::Control::Scheduler& Scheduler();
/// Returns GPU Channel Scheduler.
[[nodiscard]] const Tegra::Control::Scheduler& Scheduler() const;
[[nodiscard]] u64 GetTicks() const;
[[nodiscard]] bool IsAsync() const;

View File

@ -34,13 +34,15 @@ static void RunThread(std::stop_token stop_token, Core::System& system,
CommandDataContainer next;
scheduler.Init();
while (!stop_token.stop_requested()) {
state.queue.PopWait(next, stop_token);
if (stop_token.stop_requested()) {
break;
}
if (auto* submit_list = std::get_if<SubmitListCommand>(&next.data)) {
scheduler.Push(submit_list->channel, std::move(submit_list->entries));
if (std::holds_alternative<SubmitListCommand>(next.data)) {
scheduler.Resume();
} else if (std::holds_alternative<GPUTickCommand>(next.data)) {
system.GPU().TickWork();
} else if (const auto* flush = std::get_if<FlushRegionCommand>(&next.data)) {
@ -67,14 +69,16 @@ ThreadManager::~ThreadManager() = default;
void ThreadManager::StartThread(VideoCore::RendererBase& renderer,
Core::Frontend::GraphicsContext& context,
Tegra::Control::Scheduler& scheduler) {
Tegra::Control::Scheduler& scheduler_) {
rasterizer = renderer.ReadRasterizer();
scheduler = &scheduler_;
thread = std::jthread(RunThread, std::ref(system), std::ref(renderer), std::ref(context),
std::ref(scheduler), std::ref(state));
std::ref(scheduler_), std::ref(state));
}
void ThreadManager::SubmitList(s32 channel, Tegra::CommandList&& entries) {
PushCommand(SubmitListCommand(channel, std::move(entries)));
scheduler->Push(channel, std::move(entries));
PushCommand(SubmitListCommand());
}
void ThreadManager::FlushRegion(DAddr addr, u64 size) {

View File

@ -36,13 +36,7 @@ class RendererBase;
namespace VideoCommon::GPUThread {
/// Command to signal to the GPU thread that a command list is ready for processing
struct SubmitListCommand final {
explicit SubmitListCommand(s32 channel_, Tegra::CommandList&& entries_)
: channel{channel_}, entries{std::move(entries_)} {}
s32 channel;
Tegra::CommandList entries;
};
struct SubmitListCommand final {};
/// Command to signal to the GPU thread to flush a region
struct FlushRegionCommand final {
@ -124,6 +118,7 @@ public:
private:
/// Pushes a command to be executed by the GPU thread
u64 PushCommand(CommandData&& command_data, bool block = false);
Tegra::Control::Scheduler* scheduler;
Core::System& system;
const bool is_async;