Browse Source
video_core: gpu: Refactor out synchronous/asynchronous GPU implementations.
video_core: gpu: Refactor out synchronous/asynchronous GPU implementations.
- We must always use a GPU thread now, even with synchronous GPU.nce_cpp
10 changed files with 130 additions and 289 deletions
-
5src/video_core/CMakeLists.txt
-
31src/video_core/framebuffer_config.h
-
76src/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
-
7src/video_core/gpu_thread.h
-
10src/video_core/video_core.cpp
@ -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