committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 772 additions and 1003 deletions
-
13src/audio_core/audio_renderer.cpp
-
8src/audio_core/audio_renderer.h
-
12src/audio_core/stream.cpp
-
2src/common/CMakeLists.txt
-
58src/common/thread_worker.cpp
-
30src/common/thread_worker.h
-
3src/core/CMakeLists.txt
-
3src/core/core.cpp
-
37src/core/hle/kernel/hle_ipc.cpp
-
17src/core/hle/kernel/hle_ipc.h
-
113src/core/hle/kernel/kernel.cpp
-
17src/core/hle/kernel/kernel.h
-
29src/core/hle/kernel/server_session.cpp
-
12src/core/hle/kernel/server_session.h
-
110src/core/hle/kernel/service_thread.cpp
-
28src/core/hle/kernel/service_thread.h
-
6src/core/hle/service/audio/audout_u.cpp
-
14src/core/hle/service/audio/audren_u.cpp
-
2src/core/hle/service/hid/hid.cpp
-
9src/core/hle/service/nvdrv/devices/nvdevice.h
-
9src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
-
8src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
-
9src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
-
8src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
-
20src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
-
11src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
-
8src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
-
8src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
-
8src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
-
8src/core/hle/service/nvdrv/devices/nvhost_gpu.h
-
9src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
-
8src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
-
9src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
-
8src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
-
8src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
-
8src/core/hle/service/nvdrv/devices/nvhost_vic.h
-
8src/core/hle/service/nvdrv/devices/nvmap.cpp
-
8src/core/hle/service/nvdrv/devices/nvmap.h
-
92src/core/hle/service/nvdrv/interface.cpp
-
11src/core/hle/service/nvdrv/nvdata.h
-
13src/core/hle/service/nvdrv/nvdrv.cpp
-
6src/core/hle/service/nvdrv/nvdrv.h
-
40src/core/hle/service/nvflinger/buffer_queue.cpp
-
17src/core/hle/service/nvflinger/buffer_queue.h
-
34src/core/hle/service/nvflinger/nvflinger.cpp
-
9src/core/hle/service/nvflinger/nvflinger.h
-
28src/core/hle/service/service.cpp
-
16src/core/hle/service/service.h
-
161src/core/hle/service/sockets/blocking_worker.h
-
124src/core/hle/service/sockets/bsd.cpp
-
9src/core/hle/service/sockets/bsd.h
-
45src/core/hle/service/vi/vi.cpp
-
5src/core/settings.cpp
-
3src/core/settings.h
-
5src/video_core/CMakeLists.txt
-
31src/video_core/framebuffer_config.h
-
79src/video_core/gpu.cpp
-
55src/video_core/gpu.h
-
86src/video_core/gpu_asynch.cpp
-
47src/video_core/gpu_asynch.h
-
61src/video_core/gpu_synch.cpp
-
41src/video_core/gpu_synch.h
-
36src/video_core/gpu_thread.cpp
-
10src/video_core/gpu_thread.h
-
10src/video_core/video_core.cpp
-
2src/yuzu/configuration/config.cpp
-
13src/yuzu/main.cpp
@ -0,0 +1,58 @@ |
|||
// Copyright 2020 yuzu emulator team
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include "common/thread.h"
|
|||
#include "common/thread_worker.h"
|
|||
|
|||
namespace Common { |
|||
|
|||
ThreadWorker::ThreadWorker(std::size_t num_workers, const std::string& name) { |
|||
for (std::size_t i = 0; i < num_workers; ++i) |
|||
threads.emplace_back([this, thread_name{std::string{name}}] { |
|||
Common::SetCurrentThreadName(thread_name.c_str()); |
|||
|
|||
// Wait for first request
|
|||
{ |
|||
std::unique_lock lock{queue_mutex}; |
|||
condition.wait(lock, [this] { return stop || !requests.empty(); }); |
|||
} |
|||
|
|||
while (true) { |
|||
std::function<void()> task; |
|||
|
|||
{ |
|||
std::unique_lock lock{queue_mutex}; |
|||
condition.wait(lock, [this] { return stop || !requests.empty(); }); |
|||
if (stop || requests.empty()) { |
|||
return; |
|||
} |
|||
task = std::move(requests.front()); |
|||
requests.pop(); |
|||
} |
|||
|
|||
task(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
ThreadWorker::~ThreadWorker() { |
|||
{ |
|||
std::unique_lock lock{queue_mutex}; |
|||
stop = true; |
|||
} |
|||
condition.notify_all(); |
|||
for (std::thread& thread : threads) { |
|||
thread.join(); |
|||
} |
|||
} |
|||
|
|||
void ThreadWorker::QueueWork(std::function<void()>&& work) { |
|||
{ |
|||
std::unique_lock lock{queue_mutex}; |
|||
requests.emplace(work); |
|||
} |
|||
condition.notify_one(); |
|||
} |
|||
|
|||
} // namespace Common
|
|||
@ -0,0 +1,30 @@ |
|||
// Copyright 2020 yuzu emulator team |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <atomic> |
|||
#include <functional> |
|||
#include <mutex> |
|||
#include <string> |
|||
#include <vector> |
|||
#include <queue> |
|||
|
|||
namespace Common { |
|||
|
|||
class ThreadWorker final { |
|||
public: |
|||
explicit ThreadWorker(std::size_t num_workers, const std::string& name); |
|||
~ThreadWorker(); |
|||
void QueueWork(std::function<void()>&& work); |
|||
|
|||
private: |
|||
std::vector<std::thread> threads; |
|||
std::queue<std::function<void()>> requests; |
|||
std::mutex queue_mutex; |
|||
std::condition_variable condition; |
|||
std::atomic_bool stop{}; |
|||
}; |
|||
|
|||
} // namespace Common |
|||
@ -0,0 +1,110 @@ |
|||
// Copyright 2020 yuzu emulator team
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <condition_variable>
|
|||
#include <functional>
|
|||
#include <mutex>
|
|||
#include <thread>
|
|||
#include <vector>
|
|||
#include <queue>
|
|||
|
|||
#include "common/assert.h"
|
|||
#include "common/scope_exit.h"
|
|||
#include "common/thread.h"
|
|||
#include "core/core.h"
|
|||
#include "core/hle/kernel/kernel.h"
|
|||
#include "core/hle/kernel/server_session.h"
|
|||
#include "core/hle/kernel/service_thread.h"
|
|||
#include "core/hle/lock.h"
|
|||
#include "video_core/renderer_base.h"
|
|||
|
|||
namespace Kernel { |
|||
|
|||
class ServiceThread::Impl final { |
|||
public: |
|||
explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name); |
|||
~Impl(); |
|||
|
|||
void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context); |
|||
|
|||
private: |
|||
std::vector<std::thread> threads; |
|||
std::queue<std::function<void()>> requests; |
|||
std::mutex queue_mutex; |
|||
std::condition_variable condition; |
|||
const std::string service_name; |
|||
bool stop{}; |
|||
}; |
|||
|
|||
ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name) |
|||
: service_name{name} { |
|||
for (std::size_t i = 0; i < num_threads; ++i) |
|||
threads.emplace_back([this, &kernel] { |
|||
Common::SetCurrentThreadName(std::string{"yuzu:HleService:" + service_name}.c_str()); |
|||
|
|||
// Wait for first request before trying to acquire a render context
|
|||
{ |
|||
std::unique_lock lock{queue_mutex}; |
|||
condition.wait(lock, [this] { return stop || !requests.empty(); }); |
|||
} |
|||
|
|||
kernel.RegisterHostThread(); |
|||
|
|||
while (true) { |
|||
std::function<void()> task; |
|||
|
|||
{ |
|||
std::unique_lock lock{queue_mutex}; |
|||
condition.wait(lock, [this] { return stop || !requests.empty(); }); |
|||
if (stop || requests.empty()) { |
|||
return; |
|||
} |
|||
task = std::move(requests.front()); |
|||
requests.pop(); |
|||
} |
|||
|
|||
task(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
void ServiceThread::Impl::QueueSyncRequest(ServerSession& session, |
|||
std::shared_ptr<HLERequestContext>&& context) { |
|||
{ |
|||
std::unique_lock lock{queue_mutex}; |
|||
|
|||
// ServerSession owns the service thread, so we cannot caption a strong pointer here in the
|
|||
// event that the ServerSession is terminated.
|
|||
std::weak_ptr<ServerSession> weak_ptr{SharedFrom(&session)}; |
|||
requests.emplace([weak_ptr, context{std::move(context)}]() { |
|||
if (auto strong_ptr = weak_ptr.lock()) { |
|||
strong_ptr->CompleteSyncRequest(*context); |
|||
} |
|||
}); |
|||
} |
|||
condition.notify_one(); |
|||
} |
|||
|
|||
ServiceThread::Impl::~Impl() { |
|||
{ |
|||
std::unique_lock lock{queue_mutex}; |
|||
stop = true; |
|||
} |
|||
condition.notify_all(); |
|||
for (std::thread& thread : threads) { |
|||
thread.join(); |
|||
} |
|||
} |
|||
|
|||
ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name) |
|||
: impl{std::make_unique<Impl>(kernel, num_threads, name)} {} |
|||
|
|||
ServiceThread::~ServiceThread() = default; |
|||
|
|||
void ServiceThread::QueueSyncRequest(ServerSession& session, |
|||
std::shared_ptr<HLERequestContext>&& context) { |
|||
impl->QueueSyncRequest(session, std::move(context)); |
|||
} |
|||
|
|||
} // namespace Kernel
|
|||
@ -0,0 +1,28 @@ |
|||
// Copyright 2020 yuzu emulator team |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
#include <string> |
|||
|
|||
namespace Kernel { |
|||
|
|||
class HLERequestContext; |
|||
class KernelCore; |
|||
class ServerSession; |
|||
|
|||
class ServiceThread final { |
|||
public: |
|||
explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name); |
|||
~ServiceThread(); |
|||
|
|||
void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context); |
|||
|
|||
private: |
|||
class Impl; |
|||
std::unique_ptr<Impl> impl; |
|||
}; |
|||
|
|||
} // namespace Kernel |
|||
@ -1,161 +0,0 @@ |
|||
// Copyright 2020 yuzu emulator team |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <atomic> |
|||
#include <memory> |
|||
#include <string> |
|||
#include <string_view> |
|||
#include <thread> |
|||
#include <variant> |
|||
#include <vector> |
|||
|
|||
#include <fmt/format.h> |
|||
|
|||
#include "common/assert.h" |
|||
#include "common/microprofile.h" |
|||
#include "common/thread.h" |
|||
#include "core/core.h" |
|||
#include "core/hle/kernel/hle_ipc.h" |
|||
#include "core/hle/kernel/kernel.h" |
|||
#include "core/hle/kernel/thread.h" |
|||
#include "core/hle/kernel/writable_event.h" |
|||
|
|||
namespace Service::Sockets { |
|||
|
|||
/** |
|||
* Worker abstraction to execute blocking calls on host without blocking the guest thread |
|||
* |
|||
* @tparam Service Service where the work is executed |
|||
* @tparam Types Types of work to execute |
|||
*/ |
|||
template <class Service, class... Types> |
|||
class BlockingWorker { |
|||
using This = BlockingWorker<Service, Types...>; |
|||
using WorkVariant = std::variant<std::monostate, Types...>; |
|||
|
|||
public: |
|||
/// Create a new worker |
|||
static std::unique_ptr<This> Create(Core::System& system, Service* service, |
|||
std::string_view name) { |
|||
return std::unique_ptr<This>(new This(system, service, name)); |
|||
} |
|||
|
|||
~BlockingWorker() { |
|||
while (!is_available.load(std::memory_order_relaxed)) { |
|||
// Busy wait until work is finished |
|||
std::this_thread::yield(); |
|||
} |
|||
// Monostate means to exit the thread |
|||
work = std::monostate{}; |
|||
work_event.Set(); |
|||
thread.join(); |
|||
} |
|||
|
|||
/** |
|||
* Try to capture the worker to send work after a success |
|||
* @returns True when the worker has been successfully captured |
|||
*/ |
|||
bool TryCapture() { |
|||
bool expected = true; |
|||
return is_available.compare_exchange_weak(expected, false, std::memory_order_relaxed, |
|||
std::memory_order_relaxed); |
|||
} |
|||
|
|||
/** |
|||
* Send work to this worker abstraction |
|||
* @see TryCapture must be called before attempting to call this function |
|||
*/ |
|||
template <class Work> |
|||
void SendWork(Work new_work) { |
|||
ASSERT_MSG(!is_available, "Trying to send work on a worker that's not captured"); |
|||
work = std::move(new_work); |
|||
work_event.Set(); |
|||
} |
|||
|
|||
/// Generate a callback for @see SleepClientThread |
|||
template <class Work> |
|||
auto Callback() { |
|||
return [this](std::shared_ptr<Kernel::Thread>, Kernel::HLERequestContext& ctx, |
|||
Kernel::ThreadWakeupReason reason) { |
|||
ASSERT(reason == Kernel::ThreadWakeupReason::Signal); |
|||
std::get<Work>(work).Response(ctx); |
|||
is_available.store(true); |
|||
}; |
|||
} |
|||
|
|||
/// Get kernel event that will be signalled by the worker when the host operation finishes |
|||
std::shared_ptr<Kernel::WritableEvent> KernelEvent() const { |
|||
return kernel_event; |
|||
} |
|||
|
|||
private: |
|||
explicit BlockingWorker(Core::System& system, Service* service, std::string_view name) { |
|||
auto pair = Kernel::WritableEvent::CreateEventPair(system.Kernel(), std::string(name)); |
|||
kernel_event = std::move(pair.writable); |
|||
thread = std::thread([this, &system, service, name] { Run(system, service, name); }); |
|||
} |
|||
|
|||
void Run(Core::System& system, Service* service, std::string_view name) { |
|||
system.RegisterHostThread(); |
|||
|
|||
const std::string thread_name = fmt::format("yuzu:{}", name); |
|||
MicroProfileOnThreadCreate(thread_name.c_str()); |
|||
Common::SetCurrentThreadName(thread_name.c_str()); |
|||
|
|||
bool keep_running = true; |
|||
while (keep_running) { |
|||
work_event.Wait(); |
|||
|
|||
const auto visit_fn = [service, &keep_running]<typename T>(T&& w) { |
|||
if constexpr (std::is_same_v<std::decay_t<T>, std::monostate>) { |
|||
keep_running = false; |
|||
} else { |
|||
w.Execute(service); |
|||
} |
|||
}; |
|||
std::visit(visit_fn, work); |
|||
|
|||
kernel_event->Signal(); |
|||
} |
|||
} |
|||
|
|||
std::thread thread; |
|||
WorkVariant work; |
|||
Common::Event work_event; |
|||
std::shared_ptr<Kernel::WritableEvent> kernel_event; |
|||
std::atomic_bool is_available{true}; |
|||
}; |
|||
|
|||
template <class Service, class... Types> |
|||
class BlockingWorkerPool { |
|||
using Worker = BlockingWorker<Service, Types...>; |
|||
|
|||
public: |
|||
explicit BlockingWorkerPool(Core::System& system_, Service* service_) |
|||
: system{system_}, service{service_} {} |
|||
|
|||
/// Returns a captured worker thread, creating new ones if necessary |
|||
Worker* CaptureWorker() { |
|||
for (auto& worker : workers) { |
|||
if (worker->TryCapture()) { |
|||
return worker.get(); |
|||
} |
|||
} |
|||
auto new_worker = Worker::Create(system, service, fmt::format("BSD:{}", workers.size())); |
|||
[[maybe_unused]] const bool success = new_worker->TryCapture(); |
|||
ASSERT(success); |
|||
|
|||
return workers.emplace_back(std::move(new_worker)).get(); |
|||
} |
|||
|
|||
private: |
|||
Core::System& system; |
|||
Service* const service; |
|||
|
|||
std::vector<std::unique_ptr<Worker>> workers; |
|||
}; |
|||
|
|||
} // namespace Service::Sockets |
|||
@ -0,0 +1,31 @@ |
|||
// Copyright 2020 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
namespace Tegra { |
|||
|
|||
/** |
|||
* Struct describing framebuffer configuration |
|||
*/ |
|||
struct FramebufferConfig { |
|||
enum class PixelFormat : u32 { |
|||
A8B8G8R8_UNORM = 1, |
|||
RGB565_UNORM = 4, |
|||
B8G8R8A8_UNORM = 5, |
|||
}; |
|||
|
|||
VAddr address{}; |
|||
u32 offset{}; |
|||
u32 width{}; |
|||
u32 height{}; |
|||
u32 stride{}; |
|||
PixelFormat pixel_format{}; |
|||
|
|||
using TransformFlags = Service::NVFlinger::BufferQueue::BufferTransformFlags; |
|||
TransformFlags transform_flags{}; |
|||
Common::Rectangle<int> crop_rect; |
|||
}; |
|||
|
|||
} // namespace Tegra |
|||
@ -1,86 +0,0 @@ |
|||
// Copyright 2019 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include "core/core.h"
|
|||
#include "core/hardware_interrupt_manager.h"
|
|||
#include "video_core/gpu_asynch.h"
|
|||
#include "video_core/gpu_thread.h"
|
|||
#include "video_core/renderer_base.h"
|
|||
|
|||
namespace VideoCommon { |
|||
|
|||
GPUAsynch::GPUAsynch(Core::System& system_, bool use_nvdec_) |
|||
: GPU{system_, true, use_nvdec_}, gpu_thread{system_} {} |
|||
|
|||
GPUAsynch::~GPUAsynch() = default; |
|||
|
|||
void GPUAsynch::Start() { |
|||
gpu_thread.StartThread(*renderer, renderer->Context(), *dma_pusher, *cdma_pusher); |
|||
cpu_context = renderer->GetRenderWindow().CreateSharedContext(); |
|||
cpu_context->MakeCurrent(); |
|||
} |
|||
|
|||
void GPUAsynch::ObtainContext() { |
|||
cpu_context->MakeCurrent(); |
|||
} |
|||
|
|||
void GPUAsynch::ReleaseContext() { |
|||
cpu_context->DoneCurrent(); |
|||
} |
|||
|
|||
void GPUAsynch::PushGPUEntries(Tegra::CommandList&& entries) { |
|||
gpu_thread.SubmitList(std::move(entries)); |
|||
} |
|||
|
|||
void GPUAsynch::PushCommandBuffer(Tegra::ChCommandHeaderList& entries) { |
|||
if (!use_nvdec) { |
|||
return; |
|||
} |
|||
// This condition fires when a video stream ends, clear all intermediary data
|
|||
if (entries[0].raw == 0xDEADB33F) { |
|||
cdma_pusher.reset(); |
|||
return; |
|||
} |
|||
if (!cdma_pusher) { |
|||
cdma_pusher = std::make_unique<Tegra::CDmaPusher>(*this); |
|||
} |
|||
|
|||
// SubmitCommandBuffer would make the nvdec operations async, this is not currently working
|
|||
// TODO(ameerj): RE proper async nvdec operation
|
|||
// gpu_thread.SubmitCommandBuffer(std::move(entries));
|
|||
|
|||
cdma_pusher->Push(std::move(entries)); |
|||
cdma_pusher->DispatchCalls(); |
|||
} |
|||
|
|||
void GPUAsynch::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { |
|||
gpu_thread.SwapBuffers(framebuffer); |
|||
} |
|||
|
|||
void GPUAsynch::FlushRegion(VAddr addr, u64 size) { |
|||
gpu_thread.FlushRegion(addr, size); |
|||
} |
|||
|
|||
void GPUAsynch::InvalidateRegion(VAddr addr, u64 size) { |
|||
gpu_thread.InvalidateRegion(addr, size); |
|||
} |
|||
|
|||
void GPUAsynch::FlushAndInvalidateRegion(VAddr addr, u64 size) { |
|||
gpu_thread.FlushAndInvalidateRegion(addr, size); |
|||
} |
|||
|
|||
void GPUAsynch::TriggerCpuInterrupt(const u32 syncpoint_id, const u32 value) const { |
|||
auto& interrupt_manager = system.InterruptManager(); |
|||
interrupt_manager.GPUInterruptSyncpt(syncpoint_id, value); |
|||
} |
|||
|
|||
void GPUAsynch::WaitIdle() const { |
|||
gpu_thread.WaitIdle(); |
|||
} |
|||
|
|||
void GPUAsynch::OnCommandListEnd() { |
|||
gpu_thread.OnCommandListEnd(); |
|||
} |
|||
|
|||
} // namespace VideoCommon
|
|||
@ -1,47 +0,0 @@ |
|||
// Copyright 2019 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include "video_core/gpu.h" |
|||
#include "video_core/gpu_thread.h" |
|||
|
|||
namespace Core::Frontend { |
|||
class GraphicsContext; |
|||
} |
|||
|
|||
namespace VideoCore { |
|||
class RendererBase; |
|||
} // namespace VideoCore |
|||
|
|||
namespace VideoCommon { |
|||
|
|||
/// Implementation of GPU interface that runs the GPU asynchronously |
|||
class GPUAsynch final : public Tegra::GPU { |
|||
public: |
|||
explicit GPUAsynch(Core::System& system_, bool use_nvdec_); |
|||
~GPUAsynch() override; |
|||
|
|||
void Start() override; |
|||
void ObtainContext() override; |
|||
void ReleaseContext() override; |
|||
void PushGPUEntries(Tegra::CommandList&& entries) override; |
|||
void PushCommandBuffer(Tegra::ChCommandHeaderList& entries) override; |
|||
void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; |
|||
void FlushRegion(VAddr addr, u64 size) override; |
|||
void InvalidateRegion(VAddr addr, u64 size) override; |
|||
void FlushAndInvalidateRegion(VAddr addr, u64 size) override; |
|||
void WaitIdle() const override; |
|||
|
|||
void OnCommandListEnd() override; |
|||
|
|||
protected: |
|||
void TriggerCpuInterrupt(u32 syncpoint_id, u32 value) const override; |
|||
|
|||
private: |
|||
GPUThread::ThreadManager gpu_thread; |
|||
std::unique_ptr<Core::Frontend::GraphicsContext> cpu_context; |
|||
}; |
|||
|
|||
} // namespace VideoCommon |
|||
@ -1,61 +0,0 @@ |
|||
// Copyright 2019 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include "video_core/gpu_synch.h"
|
|||
#include "video_core/renderer_base.h"
|
|||
|
|||
namespace VideoCommon { |
|||
|
|||
GPUSynch::GPUSynch(Core::System& system_, bool use_nvdec_) : GPU{system_, false, use_nvdec_} {} |
|||
|
|||
GPUSynch::~GPUSynch() = default; |
|||
|
|||
void GPUSynch::Start() {} |
|||
|
|||
void GPUSynch::ObtainContext() { |
|||
renderer->Context().MakeCurrent(); |
|||
} |
|||
|
|||
void GPUSynch::ReleaseContext() { |
|||
renderer->Context().DoneCurrent(); |
|||
} |
|||
|
|||
void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) { |
|||
dma_pusher->Push(std::move(entries)); |
|||
dma_pusher->DispatchCalls(); |
|||
} |
|||
|
|||
void GPUSynch::PushCommandBuffer(Tegra::ChCommandHeaderList& entries) { |
|||
if (!use_nvdec) { |
|||
return; |
|||
} |
|||
// This condition fires when a video stream ends, clears all intermediary data
|
|||
if (entries[0].raw == 0xDEADB33F) { |
|||
cdma_pusher.reset(); |
|||
return; |
|||
} |
|||
if (!cdma_pusher) { |
|||
cdma_pusher = std::make_unique<Tegra::CDmaPusher>(*this); |
|||
} |
|||
cdma_pusher->Push(std::move(entries)); |
|||
cdma_pusher->DispatchCalls(); |
|||
} |
|||
|
|||
void GPUSynch::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { |
|||
renderer->SwapBuffers(framebuffer); |
|||
} |
|||
|
|||
void GPUSynch::FlushRegion(VAddr addr, u64 size) { |
|||
renderer->Rasterizer().FlushRegion(addr, size); |
|||
} |
|||
|
|||
void GPUSynch::InvalidateRegion(VAddr addr, u64 size) { |
|||
renderer->Rasterizer().InvalidateRegion(addr, size); |
|||
} |
|||
|
|||
void GPUSynch::FlushAndInvalidateRegion(VAddr addr, u64 size) { |
|||
renderer->Rasterizer().FlushAndInvalidateRegion(addr, size); |
|||
} |
|||
|
|||
} // namespace VideoCommon
|
|||
@ -1,41 +0,0 @@ |
|||
// Copyright 2019 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include "video_core/gpu.h" |
|||
|
|||
namespace Core::Frontend { |
|||
class GraphicsContext; |
|||
} |
|||
|
|||
namespace VideoCore { |
|||
class RendererBase; |
|||
} // namespace VideoCore |
|||
|
|||
namespace VideoCommon { |
|||
|
|||
/// Implementation of GPU interface that runs the GPU synchronously |
|||
class GPUSynch final : public Tegra::GPU { |
|||
public: |
|||
explicit GPUSynch(Core::System& system_, bool use_nvdec_); |
|||
~GPUSynch() override; |
|||
|
|||
void Start() override; |
|||
void ObtainContext() override; |
|||
void ReleaseContext() override; |
|||
void PushGPUEntries(Tegra::CommandList&& entries) override; |
|||
void PushCommandBuffer(Tegra::ChCommandHeaderList& entries) override; |
|||
void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; |
|||
void FlushRegion(VAddr addr, u64 size) override; |
|||
void InvalidateRegion(VAddr addr, u64 size) override; |
|||
void FlushAndInvalidateRegion(VAddr addr, u64 size) override; |
|||
void WaitIdle() const override {} |
|||
|
|||
protected: |
|||
void TriggerCpuInterrupt([[maybe_unused]] u32 syncpoint_id, |
|||
[[maybe_unused]] u32 value) const override {} |
|||
}; |
|||
|
|||
} // namespace VideoCommon |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue