early-access version 1258
This commit is contained in:
parent
78b48028e1
commit
c7d8d0947d
18 changed files with 73 additions and 159 deletions
|
@ -1,7 +1,7 @@
|
||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 1255.
|
This is the source code for early-access 1258.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include "audio_core/info_updater.h"
|
#include "audio_core/info_updater.h"
|
||||||
#include "audio_core/voice_context.h"
|
#include "audio_core/voice_context.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/hle/kernel/writable_event.h"
|
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
|
|
||||||
|
@ -71,10 +70,9 @@ namespace {
|
||||||
namespace AudioCore {
|
namespace AudioCore {
|
||||||
AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
|
AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
|
||||||
AudioCommon::AudioRendererParameter params,
|
AudioCommon::AudioRendererParameter params,
|
||||||
std::shared_ptr<Kernel::WritableEvent> buffer_event_,
|
Stream::ReleaseCallback&& release_callback,
|
||||||
std::size_t instance_number)
|
std::size_t instance_number)
|
||||||
: worker_params{params}, buffer_event{buffer_event_},
|
: worker_params{params}, memory_pool_info(params.effect_count + params.voice_count * 4),
|
||||||
memory_pool_info(params.effect_count + params.voice_count * 4),
|
|
||||||
voice_context(params.voice_count), effect_context(params.effect_count), mix_context(),
|
voice_context(params.voice_count), effect_context(params.effect_count), mix_context(),
|
||||||
sink_context(params.sink_count), splitter_context(),
|
sink_context(params.sink_count), splitter_context(),
|
||||||
voices(params.voice_count), memory{memory_},
|
voices(params.voice_count), memory{memory_},
|
||||||
|
@ -85,10 +83,9 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory
|
||||||
params.num_splitter_send_channels);
|
params.num_splitter_send_channels);
|
||||||
mix_context.Initialize(behavior_info, params.submix_count + 1, params.effect_count);
|
mix_context.Initialize(behavior_info, params.submix_count + 1, params.effect_count);
|
||||||
audio_out = std::make_unique<AudioCore::AudioOut>();
|
audio_out = std::make_unique<AudioCore::AudioOut>();
|
||||||
stream =
|
stream = audio_out->OpenStream(
|
||||||
audio_out->OpenStream(core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
|
core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
|
||||||
fmt::format("AudioRenderer-Instance{}", instance_number),
|
fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback));
|
||||||
[=]() { buffer_event_->Signal(); });
|
|
||||||
audio_out->StartStream(stream);
|
audio_out->StartStream(stream);
|
||||||
|
|
||||||
QueueMixedBuffer(0);
|
QueueMixedBuffer(0);
|
||||||
|
|
|
@ -27,10 +27,6 @@ namespace Core::Timing {
|
||||||
class CoreTiming;
|
class CoreTiming;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Kernel {
|
|
||||||
class WritableEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Core::Memory {
|
namespace Core::Memory {
|
||||||
class Memory;
|
class Memory;
|
||||||
}
|
}
|
||||||
|
@ -44,8 +40,7 @@ class AudioRenderer {
|
||||||
public:
|
public:
|
||||||
AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
|
AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
|
||||||
AudioCommon::AudioRendererParameter params,
|
AudioCommon::AudioRendererParameter params,
|
||||||
std::shared_ptr<Kernel::WritableEvent> buffer_event_,
|
Stream::ReleaseCallback&& release_callback, std::size_t instance_number);
|
||||||
std::size_t instance_number);
|
|
||||||
~AudioRenderer();
|
~AudioRenderer();
|
||||||
|
|
||||||
[[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
|
[[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
|
||||||
|
@ -61,7 +56,6 @@ private:
|
||||||
BehaviorInfo behavior_info{};
|
BehaviorInfo behavior_info{};
|
||||||
|
|
||||||
AudioCommon::AudioRendererParameter worker_params;
|
AudioCommon::AudioRendererParameter worker_params;
|
||||||
std::shared_ptr<Kernel::WritableEvent> buffer_event;
|
|
||||||
std::vector<ServerMemoryPoolInfo> memory_pool_info;
|
std::vector<ServerMemoryPoolInfo> memory_pool_info;
|
||||||
VoiceContext voice_context;
|
VoiceContext voice_context;
|
||||||
EffectContext effect_context;
|
EffectContext effect_context;
|
||||||
|
|
|
@ -132,6 +132,8 @@ std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(std::size_t max_count)
|
||||||
for (std::size_t count = 0; count < max_count && !released_buffers.empty(); ++count) {
|
for (std::size_t count = 0; count < max_count && !released_buffers.empty(); ++count) {
|
||||||
if (released_buffers.front()) {
|
if (released_buffers.front()) {
|
||||||
tags.push_back(released_buffers.front()->GetTag());
|
tags.push_back(released_buffers.front()->GetTag());
|
||||||
|
} else {
|
||||||
|
ASSERT_MSG(false, "Invalid tag in released_buffers!");
|
||||||
}
|
}
|
||||||
released_buffers.pop();
|
released_buffers.pop();
|
||||||
}
|
}
|
||||||
|
@ -144,6 +146,8 @@ std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers() {
|
||||||
while (!released_buffers.empty()) {
|
while (!released_buffers.empty()) {
|
||||||
if (released_buffers.front()) {
|
if (released_buffers.front()) {
|
||||||
tags.push_back(released_buffers.front()->GetTag());
|
tags.push_back(released_buffers.front()->GetTag());
|
||||||
|
} else {
|
||||||
|
ASSERT_MSG(false, "Invalid tag in released_buffers!");
|
||||||
}
|
}
|
||||||
released_buffers.pop();
|
released_buffers.pop();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unordered_set>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
@ -35,7 +35,6 @@
|
||||||
#include "core/hle/kernel/physical_core.h"
|
#include "core/hle/kernel/physical_core.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/kernel/resource_limit.h"
|
#include "core/hle/kernel/resource_limit.h"
|
||||||
#include "core/hle/kernel/service_thread.h"
|
|
||||||
#include "core/hle/kernel/shared_memory.h"
|
#include "core/hle/kernel/shared_memory.h"
|
||||||
#include "core/hle/kernel/synchronization.h"
|
#include "core/hle/kernel/synchronization.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
@ -108,9 +107,6 @@ struct KernelCore::Impl {
|
||||||
std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(),
|
std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(),
|
||||||
std::thread::id{});
|
std::thread::id{});
|
||||||
std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0);
|
std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0);
|
||||||
|
|
||||||
// Ensures all service threads gracefully shutdown
|
|
||||||
service_threads.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializePhysicalCores() {
|
void InitializePhysicalCores() {
|
||||||
|
@ -349,9 +345,6 @@ struct KernelCore::Impl {
|
||||||
std::shared_ptr<Kernel::SharedMemory> irs_shared_mem;
|
std::shared_ptr<Kernel::SharedMemory> irs_shared_mem;
|
||||||
std::shared_ptr<Kernel::SharedMemory> time_shared_mem;
|
std::shared_ptr<Kernel::SharedMemory> time_shared_mem;
|
||||||
|
|
||||||
// Threads used for services
|
|
||||||
std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads;
|
|
||||||
|
|
||||||
std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
|
std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
|
||||||
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
|
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
|
||||||
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
|
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
|
||||||
|
@ -646,16 +639,4 @@ void KernelCore::ExitSVCProfile() {
|
||||||
MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]);
|
MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) {
|
|
||||||
auto service_thread = std::make_shared<Kernel::ServiceThread>(*this, 1, name);
|
|
||||||
impl->service_threads.emplace(service_thread);
|
|
||||||
return service_thread;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
|
|
||||||
if (auto strong_ptr = service_thread.lock()) {
|
|
||||||
impl->service_threads.erase(strong_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -42,7 +42,6 @@ class Process;
|
||||||
class ResourceLimit;
|
class ResourceLimit;
|
||||||
class KScheduler;
|
class KScheduler;
|
||||||
class SharedMemory;
|
class SharedMemory;
|
||||||
class ServiceThread;
|
|
||||||
class Synchronization;
|
class Synchronization;
|
||||||
class Thread;
|
class Thread;
|
||||||
class TimeManager;
|
class TimeManager;
|
||||||
|
@ -228,22 +227,6 @@ public:
|
||||||
|
|
||||||
void ExitSVCProfile();
|
void ExitSVCProfile();
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an HLE service thread, which are used to execute service routines asynchronously.
|
|
||||||
* While these are allocated per ServerSession, these need to be owned and managed outside of
|
|
||||||
* ServerSession to avoid a circular dependency.
|
|
||||||
* @param name String name for the ServerSession creating this thread, used for debug purposes.
|
|
||||||
* @returns The a weak pointer newly created service thread.
|
|
||||||
*/
|
|
||||||
std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Releases a HLE service thread, instructing KernelCore to free it. This should be called when
|
|
||||||
* the ServerSession associated with the thread is destroyed.
|
|
||||||
* @param service_thread Service thread to release.
|
|
||||||
*/
|
|
||||||
void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Object;
|
friend class Object;
|
||||||
friend class Process;
|
friend class Process;
|
||||||
|
|
|
@ -25,10 +25,7 @@
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
||||||
|
ServerSession::~ServerSession() = default;
|
||||||
ServerSession::~ServerSession() {
|
|
||||||
kernel.ReleaseServiceThread(service_thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
|
ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
|
||||||
std::shared_ptr<Session> parent,
|
std::shared_ptr<Session> parent,
|
||||||
|
@ -37,7 +34,7 @@ ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kern
|
||||||
|
|
||||||
session->name = std::move(name);
|
session->name = std::move(name);
|
||||||
session->parent = std::move(parent);
|
session->parent = std::move(parent);
|
||||||
session->service_thread = kernel.CreateServiceThread(session->name);
|
session->service_thread = std::make_unique<ServiceThread>(kernel, 1);
|
||||||
|
|
||||||
return MakeResult(std::move(session));
|
return MakeResult(std::move(session));
|
||||||
}
|
}
|
||||||
|
@ -142,11 +139,7 @@ ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread,
|
||||||
std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread));
|
std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread));
|
||||||
|
|
||||||
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
|
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
|
||||||
|
service_thread->QueueSyncRequest(*this, std::move(context));
|
||||||
if (auto strong_ptr = service_thread.lock()) {
|
|
||||||
strong_ptr->QueueSyncRequest(*this, std::move(context));
|
|
||||||
return RESULT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -167,7 +167,7 @@ private:
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
/// Thread to dispatch service requests
|
/// Thread to dispatch service requests
|
||||||
std::weak_ptr<ServiceThread> service_thread;
|
std::unique_ptr<ServiceThread> service_thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/scope_exit.h"
|
#include "common/scope_exit.h"
|
||||||
#include "common/thread.h"
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
#include "core/hle/kernel/server_session.h"
|
#include "core/hle/kernel/server_session.h"
|
||||||
|
@ -23,7 +22,7 @@ namespace Kernel {
|
||||||
|
|
||||||
class ServiceThread::Impl final {
|
class ServiceThread::Impl final {
|
||||||
public:
|
public:
|
||||||
explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name);
|
explicit Impl(KernelCore& kernel, std::size_t num_threads);
|
||||||
~Impl();
|
~Impl();
|
||||||
|
|
||||||
void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context);
|
void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context);
|
||||||
|
@ -33,17 +32,12 @@ private:
|
||||||
std::queue<std::function<void()>> requests;
|
std::queue<std::function<void()>> requests;
|
||||||
std::mutex queue_mutex;
|
std::mutex queue_mutex;
|
||||||
std::condition_variable condition;
|
std::condition_variable condition;
|
||||||
const std::string service_name;
|
|
||||||
bool stop{};
|
bool stop{};
|
||||||
};
|
};
|
||||||
|
|
||||||
ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name)
|
ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads) {
|
||||||
: service_name{name} {
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < num_threads; ++i)
|
for (std::size_t i = 0; i < num_threads; ++i)
|
||||||
threads.emplace_back([this, &kernel] {
|
threads.emplace_back([&] {
|
||||||
Common::SetCurrentThreadName(std::string{"Hle_" + service_name}.c_str());
|
|
||||||
|
|
||||||
// Wait for first request before trying to acquire a render context
|
// Wait for first request before trying to acquire a render context
|
||||||
{
|
{
|
||||||
std::unique_lock lock{queue_mutex};
|
std::unique_lock lock{queue_mutex};
|
||||||
|
@ -58,7 +52,7 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std
|
||||||
{
|
{
|
||||||
std::unique_lock lock{queue_mutex};
|
std::unique_lock lock{queue_mutex};
|
||||||
condition.wait(lock, [this] { return stop || !requests.empty(); });
|
condition.wait(lock, [this] { return stop || !requests.empty(); });
|
||||||
if (stop || requests.empty()) {
|
if (stop && requests.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
task = std::move(requests.front());
|
task = std::move(requests.front());
|
||||||
|
@ -93,8 +87,8 @@ ServiceThread::Impl::~Impl() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_thread, const std::string& name)
|
ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads)
|
||||||
: impl{std::make_unique<Impl>(kernel, num_thread, name)} {}
|
: impl{std::make_unique<Impl>(kernel, num_threads)} {}
|
||||||
|
|
||||||
ServiceThread::~ServiceThread() = default;
|
ServiceThread::~ServiceThread() = default;
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
@ -15,7 +14,7 @@ class ServerSession;
|
||||||
|
|
||||||
class ServiceThread final {
|
class ServiceThread final {
|
||||||
public:
|
public:
|
||||||
explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name);
|
explicit ServiceThread(KernelCore& kernel, std::size_t num_threads);
|
||||||
~ServiceThread();
|
~ServiceThread();
|
||||||
|
|
||||||
void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context);
|
void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context);
|
||||||
|
|
|
@ -70,8 +70,10 @@ public:
|
||||||
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioOutBufferReleased");
|
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioOutBufferReleased");
|
||||||
|
|
||||||
stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
|
stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
|
||||||
audio_params.channel_count, std::move(unique_name),
|
audio_params.channel_count, std::move(unique_name), [this] {
|
||||||
[this] { buffer_event.writable->Signal(); });
|
const auto guard = LockService();
|
||||||
|
buffer_event.writable->Signal();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -49,16 +49,16 @@ public:
|
||||||
|
|
||||||
system_event =
|
system_event =
|
||||||
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent");
|
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent");
|
||||||
renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), system.Memory(),
|
renderer = std::make_unique<AudioCore::AudioRenderer>(
|
||||||
audren_params, system_event.writable,
|
system.CoreTiming(), system.Memory(), audren_params,
|
||||||
instance_number);
|
[this]() {
|
||||||
|
const auto guard = LockService();
|
||||||
|
system_event.writable->Signal();
|
||||||
|
},
|
||||||
|
instance_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateAudioCallback() {
|
|
||||||
system_event.writable->Signal();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetSampleRate(Kernel::HLERequestContext& ctx) {
|
void GetSampleRate(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_Audio, "called");
|
LOG_DEBUG(Service_Audio, "called");
|
||||||
|
|
||||||
|
|
|
@ -78,11 +78,13 @@ IAppletResource::IAppletResource(Core::System& system_)
|
||||||
pad_update_event = Core::Timing::CreateEvent(
|
pad_update_event = Core::Timing::CreateEvent(
|
||||||
"HID::UpdatePadCallback",
|
"HID::UpdatePadCallback",
|
||||||
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||||
|
const auto guard = LockService();
|
||||||
UpdateControllers(user_data, ns_late);
|
UpdateControllers(user_data, ns_late);
|
||||||
});
|
});
|
||||||
motion_update_event = Core::Timing::CreateEvent(
|
motion_update_event = Core::Timing::CreateEvent(
|
||||||
"HID::MotionPadCallback",
|
"HID::MotionPadCallback",
|
||||||
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||||
|
const auto guard = LockService();
|
||||||
UpdateMotion(user_data, ns_late);
|
UpdateMotion(user_data, ns_late);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -95,9 +95,14 @@ ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* se
|
||||||
: system{system_}, service_name{service_name_}, max_sessions{max_sessions_},
|
: system{system_}, service_name{service_name_}, max_sessions{max_sessions_},
|
||||||
handler_invoker{handler_invoker_} {}
|
handler_invoker{handler_invoker_} {}
|
||||||
|
|
||||||
ServiceFrameworkBase::~ServiceFrameworkBase() = default;
|
ServiceFrameworkBase::~ServiceFrameworkBase() {
|
||||||
|
// Wait for other threads to release access before destroying
|
||||||
|
const auto guard = LockService();
|
||||||
|
}
|
||||||
|
|
||||||
void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
|
void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
|
||||||
|
const auto guard = LockService();
|
||||||
|
|
||||||
ASSERT(!port_installed);
|
ASSERT(!port_installed);
|
||||||
|
|
||||||
auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap();
|
auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap();
|
||||||
|
@ -106,6 +111,8 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager)
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {
|
void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {
|
||||||
|
const auto guard = LockService();
|
||||||
|
|
||||||
ASSERT(!port_installed);
|
ASSERT(!port_installed);
|
||||||
|
|
||||||
auto [server_port, client_port] =
|
auto [server_port, client_port] =
|
||||||
|
@ -115,17 +122,6 @@ void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {
|
||||||
port_installed = true;
|
port_installed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) {
|
|
||||||
ASSERT(!port_installed);
|
|
||||||
|
|
||||||
auto [server_port, client_port] =
|
|
||||||
Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name);
|
|
||||||
auto port = MakeResult(std::move(server_port)).Unwrap();
|
|
||||||
port->SetHleHandler(shared_from_this());
|
|
||||||
port_installed = true;
|
|
||||||
return client_port;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
|
void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
|
||||||
handlers.reserve(handlers.size() + n);
|
handlers.reserve(handlers.size() + n);
|
||||||
for (std::size_t i = 0; i < n; ++i) {
|
for (std::size_t i = 0; i < n; ++i) {
|
||||||
|
@ -164,6 +160,8 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) {
|
ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) {
|
||||||
|
const auto guard = LockService();
|
||||||
|
|
||||||
switch (context.GetCommandType()) {
|
switch (context.GetCommandType()) {
|
||||||
case IPC::CommandType::Close: {
|
case IPC::CommandType::Close: {
|
||||||
IPC::ResponseBuilder rb{context, 2};
|
IPC::ResponseBuilder rb{context, 2};
|
||||||
|
|
|
@ -5,9 +5,11 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <boost/container/flat_map.hpp>
|
#include <boost/container/flat_map.hpp>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/spin_lock.h"
|
||||||
#include "core/hle/kernel/hle_ipc.h"
|
#include "core/hle/kernel/hle_ipc.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
|
|
||||||
|
@ -68,11 +70,9 @@ public:
|
||||||
void InstallAsService(SM::ServiceManager& service_manager);
|
void InstallAsService(SM::ServiceManager& service_manager);
|
||||||
/// Creates a port pair and registers it on the kernel's global port registry.
|
/// Creates a port pair and registers it on the kernel's global port registry.
|
||||||
void InstallAsNamedPort(Kernel::KernelCore& kernel);
|
void InstallAsNamedPort(Kernel::KernelCore& kernel);
|
||||||
/// Creates and returns an unregistered port for the service.
|
/// Invokes a service request routine.
|
||||||
std::shared_ptr<Kernel::ClientPort> CreatePort(Kernel::KernelCore& kernel);
|
|
||||||
|
|
||||||
void InvokeRequest(Kernel::HLERequestContext& ctx);
|
void InvokeRequest(Kernel::HLERequestContext& ctx);
|
||||||
|
/// Handles a synchronization request for the service.
|
||||||
ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override;
|
ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -80,6 +80,11 @@ protected:
|
||||||
template <typename Self>
|
template <typename Self>
|
||||||
using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&);
|
using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&);
|
||||||
|
|
||||||
|
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
|
||||||
|
[[nodiscard]] std::scoped_lock<Common::SpinLock> LockService() {
|
||||||
|
return std::scoped_lock{lock_service};
|
||||||
|
}
|
||||||
|
|
||||||
/// System context that the service operates under.
|
/// System context that the service operates under.
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
|
||||||
|
@ -115,6 +120,9 @@ private:
|
||||||
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
|
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
|
||||||
InvokerFn* handler_invoker;
|
InvokerFn* handler_invoker;
|
||||||
boost::container::flat_map<u32, FunctionInfoBase> handlers;
|
boost::container::flat_map<u32, FunctionInfoBase> handlers;
|
||||||
|
|
||||||
|
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
|
||||||
|
Common::SpinLock lock_service;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -186,18 +186,18 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
|
||||||
// Reset the screen info's display texture to its own permanent texture
|
// Reset the screen info's display texture to its own permanent texture
|
||||||
screen_info.display_texture = screen_info.texture.resource.handle;
|
screen_info.display_texture = screen_info.texture.resource.handle;
|
||||||
|
|
||||||
|
// TODO(Rodrigo): Read this from HLE
|
||||||
|
constexpr u32 block_height_log2 = 4;
|
||||||
const auto pixel_format{
|
const auto pixel_format{
|
||||||
VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)};
|
VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)};
|
||||||
const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)};
|
const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)};
|
||||||
const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel};
|
const u64 size_in_bytes{Tegra::Texture::CalculateSize(
|
||||||
u8* const host_ptr{cpu_memory.GetPointer(framebuffer_addr)};
|
true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)};
|
||||||
rasterizer->FlushRegion(ToCacheAddr(host_ptr), size_in_bytes);
|
const u8* const host_ptr{cpu_memory.GetPointer(framebuffer_addr)};
|
||||||
|
const std::span<const u8> input_data(host_ptr, size_in_bytes);
|
||||||
// TODO(Rodrigo): Read this from HLE
|
Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel,
|
||||||
constexpr u32 block_height_log2 = 4;
|
framebuffer.width, framebuffer.height, 1, block_height_log2,
|
||||||
Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, std::span<u8>(host_ptr, size_in_bytes),
|
0);
|
||||||
bytes_per_pixel, framebuffer.width, framebuffer.height, 1,
|
|
||||||
block_height_log2, 0);
|
|
||||||
|
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));
|
||||||
|
|
|
@ -116,19 +116,6 @@ constexpr std::array DYNAMIC_STATES{
|
||||||
VK_DYNAMIC_STATE_VIEWPORT,
|
VK_DYNAMIC_STATE_VIEWPORT,
|
||||||
VK_DYNAMIC_STATE_SCISSOR,
|
VK_DYNAMIC_STATE_SCISSOR,
|
||||||
};
|
};
|
||||||
constexpr std::array EXTENDED_DYNAMIC_STATES{
|
|
||||||
VK_DYNAMIC_STATE_VIEWPORT,
|
|
||||||
VK_DYNAMIC_STATE_SCISSOR,
|
|
||||||
VK_DYNAMIC_STATE_CULL_MODE_EXT,
|
|
||||||
VK_DYNAMIC_STATE_FRONT_FACE_EXT,
|
|
||||||
VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT,
|
|
||||||
VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT,
|
|
||||||
VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT,
|
|
||||||
VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT,
|
|
||||||
VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT,
|
|
||||||
VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT,
|
|
||||||
VK_DYNAMIC_STATE_STENCIL_OP_EXT,
|
|
||||||
};
|
|
||||||
constexpr VkPipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{
|
constexpr VkPipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
|
@ -136,13 +123,6 @@ constexpr VkPipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{
|
||||||
.dynamicStateCount = static_cast<u32>(DYNAMIC_STATES.size()),
|
.dynamicStateCount = static_cast<u32>(DYNAMIC_STATES.size()),
|
||||||
.pDynamicStates = DYNAMIC_STATES.data(),
|
.pDynamicStates = DYNAMIC_STATES.data(),
|
||||||
};
|
};
|
||||||
constexpr VkPipelineDynamicStateCreateInfo PIPELINE_EXTENDED_DYNAMIC_STATE_CREATE_INFO{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
|
||||||
.pNext = nullptr,
|
|
||||||
.flags = 0,
|
|
||||||
.dynamicStateCount = static_cast<u32>(EXTENDED_DYNAMIC_STATES.size()),
|
|
||||||
.pDynamicStates = EXTENDED_DYNAMIC_STATES.data(),
|
|
||||||
};
|
|
||||||
constexpr VkPipelineColorBlendStateCreateInfo PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO{
|
constexpr VkPipelineColorBlendStateCreateInfo PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO{
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
|
@ -309,7 +289,7 @@ void UpdateTwoTexturesDescriptorSet(const VKDevice& device, VkDescriptorSet desc
|
||||||
device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr);
|
device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BindBlitState(const VKDevice& device, vk::CommandBuffer cmdbuf, VkPipelineLayout layout,
|
void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout,
|
||||||
const std::array<Offset2D, 2>& dst_region,
|
const std::array<Offset2D, 2>& dst_region,
|
||||||
const std::array<Offset2D, 2>& src_region) {
|
const std::array<Offset2D, 2>& src_region) {
|
||||||
const VkOffset2D offset{
|
const VkOffset2D offset{
|
||||||
|
@ -341,22 +321,6 @@ void BindBlitState(const VKDevice& device, vk::CommandBuffer cmdbuf, VkPipelineL
|
||||||
};
|
};
|
||||||
cmdbuf.SetViewport(0, viewport);
|
cmdbuf.SetViewport(0, viewport);
|
||||||
cmdbuf.SetScissor(0, scissor);
|
cmdbuf.SetScissor(0, scissor);
|
||||||
if (device.IsExtExtendedDynamicStateSupported()) {
|
|
||||||
// Workaround bug on Nvidia's drivers where the state is not properly handled when switching
|
|
||||||
// from one pipeline without dynamic state to one with.
|
|
||||||
// To workaround the bug, we manually set the pipeline state as dynamic state and keep the
|
|
||||||
// relevant bits enabled.
|
|
||||||
cmdbuf.SetCullModeEXT(PIPELINE_RASTERIZATION_STATE_CREATE_INFO.cullMode);
|
|
||||||
cmdbuf.SetFrontFaceEXT(PIPELINE_RASTERIZATION_STATE_CREATE_INFO.frontFace);
|
|
||||||
cmdbuf.SetDepthTestEnableEXT(PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO.depthTestEnable);
|
|
||||||
cmdbuf.SetDepthWriteEnableEXT(PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO.depthWriteEnable);
|
|
||||||
cmdbuf.SetDepthCompareOpEXT(PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO.depthCompareOp);
|
|
||||||
cmdbuf.SetDepthBoundsTestEnableEXT(
|
|
||||||
PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO.depthBoundsTestEnable);
|
|
||||||
cmdbuf.SetStencilTestEnableEXT(PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO.stencilTestEnable);
|
|
||||||
cmdbuf.SetStencilOpEXT(VK_STENCIL_FACE_FRONT_AND_BACK, VK_STENCIL_OP_KEEP,
|
|
||||||
VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_NEVER);
|
|
||||||
}
|
|
||||||
cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
|
cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,7 +375,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV
|
||||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
||||||
nullptr);
|
nullptr);
|
||||||
BindBlitState(device, cmdbuf, layout, dst_region, src_region);
|
BindBlitState(cmdbuf, layout, dst_region, src_region);
|
||||||
cmdbuf.Draw(3, 1, 0, 0);
|
cmdbuf.Draw(3, 1, 0, 0);
|
||||||
});
|
});
|
||||||
scheduler.InvalidateState();
|
scheduler.InvalidateState();
|
||||||
|
@ -440,7 +404,7 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
|
||||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
||||||
nullptr);
|
nullptr);
|
||||||
BindBlitState(device, cmdbuf, layout, dst_region, src_region);
|
BindBlitState(cmdbuf, layout, dst_region, src_region);
|
||||||
cmdbuf.Draw(3, 1, 0, 0);
|
cmdbuf.Draw(3, 1, 0, 0);
|
||||||
});
|
});
|
||||||
scheduler.InvalidateState();
|
scheduler.InvalidateState();
|
||||||
|
@ -562,9 +526,7 @@ VkPipeline BlitImageHelper::FindOrEmplacePipeline(const BlitImagePipelineKey& ke
|
||||||
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||||
.pDepthStencilState = nullptr,
|
.pDepthStencilState = nullptr,
|
||||||
.pColorBlendState = &color_blend_create_info,
|
.pColorBlendState = &color_blend_create_info,
|
||||||
.pDynamicState = device.IsExtExtendedDynamicStateSupported()
|
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||||
? &PIPELINE_EXTENDED_DYNAMIC_STATE_CREATE_INFO
|
|
||||||
: &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
|
||||||
.layout = *one_texture_pipeline_layout,
|
.layout = *one_texture_pipeline_layout,
|
||||||
.renderPass = key.renderpass,
|
.renderPass = key.renderpass,
|
||||||
.subpass = 0,
|
.subpass = 0,
|
||||||
|
@ -593,9 +555,7 @@ VkPipeline BlitImageHelper::BlitDepthStencilPipeline(VkRenderPass renderpass) {
|
||||||
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||||
.pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
.pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||||
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO,
|
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO,
|
||||||
.pDynamicState = device.IsExtExtendedDynamicStateSupported()
|
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||||
? &PIPELINE_EXTENDED_DYNAMIC_STATE_CREATE_INFO
|
|
||||||
: &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
|
||||||
.layout = *two_textures_pipeline_layout,
|
.layout = *two_textures_pipeline_layout,
|
||||||
.renderPass = renderpass,
|
.renderPass = renderpass,
|
||||||
.subpass = 0,
|
.subpass = 0,
|
||||||
|
|
|
@ -477,14 +477,13 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateDynamicStates();
|
|
||||||
|
|
||||||
buffer_bindings.Bind(device, scheduler);
|
buffer_bindings.Bind(device, scheduler);
|
||||||
|
|
||||||
BeginTransformFeedback();
|
BeginTransformFeedback();
|
||||||
|
|
||||||
scheduler.RequestRenderpass(framebuffer);
|
scheduler.RequestRenderpass(framebuffer);
|
||||||
scheduler.BindGraphicsPipeline(pipeline->GetHandle());
|
scheduler.BindGraphicsPipeline(pipeline->GetHandle());
|
||||||
|
UpdateDynamicStates();
|
||||||
|
|
||||||
const auto pipeline_layout = pipeline->GetLayout();
|
const auto pipeline_layout = pipeline->GetLayout();
|
||||||
const auto descriptor_set = pipeline->CommitDescriptorSet();
|
const auto descriptor_set = pipeline->CommitDescriptorSet();
|
||||||
|
|
Loading…
Reference in a new issue