2019-01-24 06:17:55 +03:00
|
|
|
// Copyright 2019 yuzu Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <atomic>
|
|
|
|
#include <condition_variable>
|
|
|
|
#include <mutex>
|
|
|
|
#include <optional>
|
|
|
|
#include <thread>
|
|
|
|
#include <variant>
|
2019-02-19 04:58:32 +03:00
|
|
|
#include "common/threadsafe_queue.h"
|
|
|
|
#include "video_core/gpu.h"
|
|
|
|
|
2019-01-24 06:17:55 +03:00
|
|
|
namespace Tegra {
|
|
|
|
struct FramebufferConfig;
|
|
|
|
class DmaPusher;
|
|
|
|
} // namespace Tegra
|
|
|
|
|
2019-03-31 03:08:09 +03:00
|
|
|
namespace Core {
|
2020-03-25 05:58:49 +03:00
|
|
|
namespace Frontend {
|
|
|
|
class GraphicsContext;
|
|
|
|
}
|
2019-03-31 03:08:09 +03:00
|
|
|
class System;
|
|
|
|
} // namespace Core
|
2019-01-24 06:17:55 +03:00
|
|
|
|
|
|
|
namespace VideoCommon::GPUThread {
|
|
|
|
|
2019-02-19 04:58:32 +03:00
|
|
|
/// Command to signal to the GPU thread that processing has ended
|
|
|
|
struct EndProcessingCommand final {};
|
|
|
|
|
2019-01-24 06:17:55 +03:00
|
|
|
/// Command to signal to the GPU thread that a command list is ready for processing
|
|
|
|
struct SubmitListCommand final {
|
|
|
|
explicit SubmitListCommand(Tegra::CommandList&& entries) : entries{std::move(entries)} {}
|
|
|
|
|
|
|
|
Tegra::CommandList entries;
|
|
|
|
};
|
|
|
|
|
2020-10-27 06:07:36 +03:00
|
|
|
/// Command to signal to the GPU thread that a cdma command list is ready for processing
|
|
|
|
struct SubmitChCommandEntries final {
|
|
|
|
explicit SubmitChCommandEntries(Tegra::ChCommandHeaderList&& entries)
|
|
|
|
: entries{std::move(entries)} {}
|
|
|
|
|
|
|
|
Tegra::ChCommandHeaderList entries;
|
|
|
|
};
|
|
|
|
|
2019-01-24 06:17:55 +03:00
|
|
|
/// Command to signal to the GPU thread that a swap buffers is pending
|
|
|
|
struct SwapBuffersCommand final {
|
|
|
|
explicit SwapBuffersCommand(std::optional<const Tegra::FramebufferConfig> framebuffer)
|
|
|
|
: framebuffer{std::move(framebuffer)} {}
|
|
|
|
|
2019-02-19 04:58:32 +03:00
|
|
|
std::optional<Tegra::FramebufferConfig> framebuffer;
|
2019-01-24 06:17:55 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/// Command to signal to the GPU thread to flush a region
|
|
|
|
struct FlushRegionCommand final {
|
2020-04-05 19:58:23 +03:00
|
|
|
explicit constexpr FlushRegionCommand(VAddr addr, u64 size) : addr{addr}, size{size} {}
|
2019-01-24 06:17:55 +03:00
|
|
|
|
2020-04-05 19:58:23 +03:00
|
|
|
VAddr addr;
|
2019-02-19 04:58:32 +03:00
|
|
|
u64 size;
|
2019-01-24 06:17:55 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/// Command to signal to the GPU thread to invalidate a region
|
|
|
|
struct InvalidateRegionCommand final {
|
2020-04-05 19:58:23 +03:00
|
|
|
explicit constexpr InvalidateRegionCommand(VAddr addr, u64 size) : addr{addr}, size{size} {}
|
2019-01-24 06:17:55 +03:00
|
|
|
|
2020-04-05 19:58:23 +03:00
|
|
|
VAddr addr;
|
2019-02-19 04:58:32 +03:00
|
|
|
u64 size;
|
2019-01-24 06:17:55 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/// Command to signal to the GPU thread to flush and invalidate a region
|
|
|
|
struct FlushAndInvalidateRegionCommand final {
|
2020-04-05 19:58:23 +03:00
|
|
|
explicit constexpr FlushAndInvalidateRegionCommand(VAddr addr, u64 size)
|
2019-01-24 06:17:55 +03:00
|
|
|
: addr{addr}, size{size} {}
|
|
|
|
|
2020-04-05 19:58:23 +03:00
|
|
|
VAddr addr;
|
2019-02-19 04:58:32 +03:00
|
|
|
u64 size;
|
2019-01-24 06:17:55 +03:00
|
|
|
};
|
|
|
|
|
2020-02-20 18:55:32 +03:00
|
|
|
/// Command called within the gpu, to schedule actions after a command list end
|
2020-02-18 01:10:23 +03:00
|
|
|
struct OnCommandListEndCommand final {};
|
|
|
|
|
2020-02-20 18:55:32 +03:00
|
|
|
/// Command to make the gpu look into pending requests
|
|
|
|
struct GPUTickCommand final {};
|
|
|
|
|
2019-02-19 04:58:32 +03:00
|
|
|
using CommandData =
|
2020-10-27 06:07:36 +03:00
|
|
|
std::variant<EndProcessingCommand, SubmitListCommand, SubmitChCommandEntries,
|
|
|
|
SwapBuffersCommand, FlushRegionCommand, InvalidateRegionCommand,
|
|
|
|
FlushAndInvalidateRegionCommand, OnCommandListEndCommand, GPUTickCommand>;
|
2019-02-19 04:58:32 +03:00
|
|
|
|
|
|
|
struct CommandDataContainer {
|
|
|
|
CommandDataContainer() = default;
|
|
|
|
|
2019-03-31 03:08:09 +03:00
|
|
|
CommandDataContainer(CommandData&& data, u64 next_fence)
|
|
|
|
: data{std::move(data)}, fence{next_fence} {}
|
2019-02-19 04:58:32 +03:00
|
|
|
|
|
|
|
CommandData data;
|
2019-03-31 03:08:09 +03:00
|
|
|
u64 fence{};
|
2019-02-19 04:58:32 +03:00
|
|
|
};
|
2019-01-24 06:17:55 +03:00
|
|
|
|
|
|
|
/// Struct used to synchronize the GPU thread
|
|
|
|
struct SynchState final {
|
2019-02-19 04:58:32 +03:00
|
|
|
std::atomic_bool is_running{true};
|
|
|
|
|
2020-02-02 05:01:47 +03:00
|
|
|
using CommandQueue = Common::MPSCQueue<CommandDataContainer>;
|
2019-02-19 04:58:32 +03:00
|
|
|
CommandQueue queue;
|
2019-03-31 03:08:09 +03:00
|
|
|
u64 last_fence{};
|
|
|
|
std::atomic<u64> signaled_fence{};
|
2019-01-24 06:17:55 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
/// Class used to manage the GPU thread
|
|
|
|
class ThreadManager final {
|
|
|
|
public:
|
2019-04-09 21:02:00 +03:00
|
|
|
explicit ThreadManager(Core::System& system);
|
2019-01-24 06:17:55 +03:00
|
|
|
~ThreadManager();
|
|
|
|
|
2019-04-09 21:02:00 +03:00
|
|
|
/// Creates and starts the GPU thread.
|
2020-03-25 05:58:49 +03:00
|
|
|
void StartThread(VideoCore::RendererBase& renderer, Core::Frontend::GraphicsContext& context,
|
2020-10-27 06:07:36 +03:00
|
|
|
Tegra::DmaPusher& dma_pusher, Tegra::CDmaPusher& cdma_pusher);
|
2019-04-09 21:02:00 +03:00
|
|
|
|
2019-01-24 06:17:55 +03:00
|
|
|
/// Push GPU command entries to be processed
|
|
|
|
void SubmitList(Tegra::CommandList&& entries);
|
|
|
|
|
2020-10-27 06:07:36 +03:00
|
|
|
/// Push GPU CDMA command buffer entries to be processed
|
|
|
|
void SubmitCommandBuffer(Tegra::ChCommandHeaderList&& entries);
|
|
|
|
|
2019-01-24 06:17:55 +03:00
|
|
|
/// Swap buffers (render frame)
|
2019-08-21 07:55:25 +03:00
|
|
|
void SwapBuffers(const Tegra::FramebufferConfig* framebuffer);
|
2019-01-24 06:17:55 +03:00
|
|
|
|
|
|
|
/// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
|
2020-04-05 19:58:23 +03:00
|
|
|
void FlushRegion(VAddr addr, u64 size);
|
2019-01-24 06:17:55 +03:00
|
|
|
|
|
|
|
/// Notify rasterizer that any caches of the specified region should be invalidated
|
2020-04-05 19:58:23 +03:00
|
|
|
void InvalidateRegion(VAddr addr, u64 size);
|
2019-01-24 06:17:55 +03:00
|
|
|
|
|
|
|
/// Notify rasterizer that any caches of the specified region should be flushed and invalidated
|
2020-04-05 19:58:23 +03:00
|
|
|
void FlushAndInvalidateRegion(VAddr addr, u64 size);
|
2019-01-24 06:17:55 +03:00
|
|
|
|
2019-09-27 02:08:22 +03:00
|
|
|
// Wait until the gpu thread is idle.
|
|
|
|
void WaitIdle() const;
|
|
|
|
|
2020-02-18 01:10:23 +03:00
|
|
|
void OnCommandListEnd();
|
|
|
|
|
2019-01-24 06:17:55 +03:00
|
|
|
private:
|
|
|
|
/// Pushes a command to be executed by the GPU thread
|
2019-03-31 03:08:09 +03:00
|
|
|
u64 PushCommand(CommandData&& command_data);
|
2019-01-24 06:17:55 +03:00
|
|
|
|
|
|
|
private:
|
|
|
|
SynchState state;
|
2019-03-31 03:08:09 +03:00
|
|
|
Core::System& system;
|
2019-03-08 00:05:46 +03:00
|
|
|
std::thread thread;
|
|
|
|
std::thread::id thread_id;
|
2019-01-24 06:17:55 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace VideoCommon::GPUThread
|