mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	video_core: Initialize renderer with a GPU
Add an extra step in GPU initialization to be able to initialize render backends with a valid GPU instance.
This commit is contained in:
		
							parent
							
								
									ada9b7fb77
								
							
						
					
					
						commit
						da53bcee60
					
				@ -10,7 +10,13 @@
 | 
			
		||||
 | 
			
		||||
namespace Tegra::Engines {
 | 
			
		||||
 | 
			
		||||
Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer) : rasterizer{rasterizer} {}
 | 
			
		||||
Fermi2D::Fermi2D() = default;
 | 
			
		||||
 | 
			
		||||
Fermi2D::~Fermi2D() = default;
 | 
			
		||||
 | 
			
		||||
void Fermi2D::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) {
 | 
			
		||||
    rasterizer = &rasterizer_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Fermi2D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
 | 
			
		||||
    ASSERT_MSG(method < Regs::NUM_REGS,
 | 
			
		||||
@ -87,7 +93,7 @@ void Fermi2D::HandleSurfaceCopy() {
 | 
			
		||||
    copy_config.src_rect = src_rect;
 | 
			
		||||
    copy_config.dst_rect = dst_rect;
 | 
			
		||||
 | 
			
		||||
    if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst, copy_config)) {
 | 
			
		||||
    if (!rasterizer->AccelerateSurfaceCopy(regs.src, regs.dst, copy_config)) {
 | 
			
		||||
        UNIMPLEMENTED();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -34,8 +34,11 @@ namespace Tegra::Engines {
 | 
			
		||||
 | 
			
		||||
class Fermi2D final : public EngineInterface {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Fermi2D(VideoCore::RasterizerInterface& rasterizer);
 | 
			
		||||
    ~Fermi2D() = default;
 | 
			
		||||
    explicit Fermi2D();
 | 
			
		||||
    ~Fermi2D();
 | 
			
		||||
 | 
			
		||||
    /// Binds a rasterizer to this engine.
 | 
			
		||||
    void BindRasterizer(VideoCore::RasterizerInterface& rasterizer);
 | 
			
		||||
 | 
			
		||||
    /// Write the value to the register identified by method.
 | 
			
		||||
    void CallMethod(u32 method, u32 method_argument, bool is_last_call) override;
 | 
			
		||||
@ -149,7 +152,7 @@ public:
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    VideoCore::RasterizerInterface& rasterizer;
 | 
			
		||||
    VideoCore::RasterizerInterface* rasterizer;
 | 
			
		||||
 | 
			
		||||
    /// Performs the copy from the source surface to the destination surface as configured in the
 | 
			
		||||
    /// registers.
 | 
			
		||||
 | 
			
		||||
@ -16,14 +16,15 @@
 | 
			
		||||
 | 
			
		||||
namespace Tegra::Engines {
 | 
			
		||||
 | 
			
		||||
KeplerCompute::KeplerCompute(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
 | 
			
		||||
                             MemoryManager& memory_manager)
 | 
			
		||||
    : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager}, upload_state{
 | 
			
		||||
                                                                                  memory_manager,
 | 
			
		||||
                                                                                  regs.upload} {}
 | 
			
		||||
KeplerCompute::KeplerCompute(Core::System& system_, MemoryManager& memory_manager_)
 | 
			
		||||
    : system{system_}, memory_manager{memory_manager_}, upload_state{memory_manager, regs.upload} {}
 | 
			
		||||
 | 
			
		||||
KeplerCompute::~KeplerCompute() = default;
 | 
			
		||||
 | 
			
		||||
void KeplerCompute::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) {
 | 
			
		||||
    rasterizer = &rasterizer_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KeplerCompute::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
 | 
			
		||||
    ASSERT_MSG(method < Regs::NUM_REGS,
 | 
			
		||||
               "Invalid KeplerCompute register, increase the size of the Regs structure");
 | 
			
		||||
@ -104,11 +105,11 @@ SamplerDescriptor KeplerCompute::AccessSampler(u32 handle) const {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VideoCore::GuestDriverProfile& KeplerCompute::AccessGuestDriverProfile() {
 | 
			
		||||
    return rasterizer.AccessGuestDriverProfile();
 | 
			
		||||
    return rasterizer->AccessGuestDriverProfile();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const VideoCore::GuestDriverProfile& KeplerCompute::AccessGuestDriverProfile() const {
 | 
			
		||||
    return rasterizer.AccessGuestDriverProfile();
 | 
			
		||||
    return rasterizer->AccessGuestDriverProfile();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KeplerCompute::ProcessLaunch() {
 | 
			
		||||
@ -119,7 +120,7 @@ void KeplerCompute::ProcessLaunch() {
 | 
			
		||||
    const GPUVAddr code_addr = regs.code_loc.Address() + launch_description.program_start;
 | 
			
		||||
    LOG_TRACE(HW_GPU, "Compute invocation launched at address 0x{:016x}", code_addr);
 | 
			
		||||
 | 
			
		||||
    rasterizer.DispatchCompute(code_addr);
 | 
			
		||||
    rasterizer->DispatchCompute(code_addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Texture::TICEntry KeplerCompute::GetTICEntry(u32 tic_index) const {
 | 
			
		||||
 | 
			
		||||
@ -42,10 +42,12 @@ namespace Tegra::Engines {
 | 
			
		||||
 | 
			
		||||
class KeplerCompute final : public ConstBufferEngineInterface, public EngineInterface {
 | 
			
		||||
public:
 | 
			
		||||
    explicit KeplerCompute(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
 | 
			
		||||
                           MemoryManager& memory_manager);
 | 
			
		||||
    explicit KeplerCompute(Core::System& system, MemoryManager& memory_manager);
 | 
			
		||||
    ~KeplerCompute();
 | 
			
		||||
 | 
			
		||||
    /// Binds a rasterizer to this engine.
 | 
			
		||||
    void BindRasterizer(VideoCore::RasterizerInterface& rasterizer);
 | 
			
		||||
 | 
			
		||||
    static constexpr std::size_t NumConstBuffers = 8;
 | 
			
		||||
 | 
			
		||||
    struct Regs {
 | 
			
		||||
@ -230,11 +232,6 @@ public:
 | 
			
		||||
    const VideoCore::GuestDriverProfile& AccessGuestDriverProfile() const override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Core::System& system;
 | 
			
		||||
    VideoCore::RasterizerInterface& rasterizer;
 | 
			
		||||
    MemoryManager& memory_manager;
 | 
			
		||||
    Upload::State upload_state;
 | 
			
		||||
 | 
			
		||||
    void ProcessLaunch();
 | 
			
		||||
 | 
			
		||||
    /// Retrieves information about a specific TIC entry from the TIC buffer.
 | 
			
		||||
@ -242,6 +239,11 @@ private:
 | 
			
		||||
 | 
			
		||||
    /// Retrieves information about a specific TSC entry from the TSC buffer.
 | 
			
		||||
    Texture::TSCEntry GetTSCEntry(u32 tsc_index) const;
 | 
			
		||||
 | 
			
		||||
    Core::System& system;
 | 
			
		||||
    MemoryManager& memory_manager;
 | 
			
		||||
    VideoCore::RasterizerInterface* rasterizer = nullptr;
 | 
			
		||||
    Upload::State upload_state;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define ASSERT_REG_POSITION(field_name, position)                                                  \
 | 
			
		||||
 | 
			
		||||
@ -22,14 +22,19 @@ using VideoCore::QueryType;
 | 
			
		||||
/// First register id that is actually a Macro call.
 | 
			
		||||
constexpr u32 MacroRegistersStart = 0xE00;
 | 
			
		||||
 | 
			
		||||
Maxwell3D::Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
 | 
			
		||||
                     MemoryManager& memory_manager)
 | 
			
		||||
    : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager},
 | 
			
		||||
      macro_engine{GetMacroEngine(*this)}, upload_state{memory_manager, regs.upload} {
 | 
			
		||||
Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_)
 | 
			
		||||
    : system{system_}, memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)},
 | 
			
		||||
      upload_state{memory_manager, regs.upload} {
 | 
			
		||||
    dirty.flags.flip();
 | 
			
		||||
    InitializeRegisterDefaults();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Maxwell3D::~Maxwell3D() = default;
 | 
			
		||||
 | 
			
		||||
void Maxwell3D::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) {
 | 
			
		||||
    rasterizer = &rasterizer_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Maxwell3D::InitializeRegisterDefaults() {
 | 
			
		||||
    // Initializes registers to their default values - what games expect them to be at boot. This is
 | 
			
		||||
    // for certain registers that may not be explicitly set by games.
 | 
			
		||||
@ -192,7 +197,7 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
 | 
			
		||||
 | 
			
		||||
    switch (method) {
 | 
			
		||||
    case MAXWELL3D_REG_INDEX(wait_for_idle): {
 | 
			
		||||
        rasterizer.WaitForIdle();
 | 
			
		||||
        rasterizer->WaitForIdle();
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case MAXWELL3D_REG_INDEX(shadow_ram_control): {
 | 
			
		||||
@ -402,7 +407,7 @@ void Maxwell3D::FlushMMEInlineDraw() {
 | 
			
		||||
 | 
			
		||||
    const bool is_indexed = mme_draw.current_mode == MMEDrawMode::Indexed;
 | 
			
		||||
    if (ShouldExecute()) {
 | 
			
		||||
        rasterizer.Draw(is_indexed, true);
 | 
			
		||||
        rasterizer->Draw(is_indexed, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
 | 
			
		||||
@ -465,7 +470,7 @@ void Maxwell3D::ProcessQueryGet() {
 | 
			
		||||
    switch (regs.query.query_get.operation) {
 | 
			
		||||
    case Regs::QueryOperation::Release:
 | 
			
		||||
        if (regs.query.query_get.fence == 1) {
 | 
			
		||||
            rasterizer.SignalSemaphore(regs.query.QueryAddress(), regs.query.query_sequence);
 | 
			
		||||
            rasterizer->SignalSemaphore(regs.query.QueryAddress(), regs.query.query_sequence);
 | 
			
		||||
        } else {
 | 
			
		||||
            StampQueryResult(regs.query.query_sequence, regs.query.query_get.short_query == 0);
 | 
			
		||||
        }
 | 
			
		||||
@ -533,7 +538,7 @@ void Maxwell3D::ProcessQueryCondition() {
 | 
			
		||||
void Maxwell3D::ProcessCounterReset() {
 | 
			
		||||
    switch (regs.counter_reset) {
 | 
			
		||||
    case Regs::CounterReset::SampleCnt:
 | 
			
		||||
        rasterizer.ResetCounter(QueryType::SamplesPassed);
 | 
			
		||||
        rasterizer->ResetCounter(QueryType::SamplesPassed);
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        LOG_DEBUG(Render_OpenGL, "Unimplemented counter reset={}",
 | 
			
		||||
@ -547,7 +552,7 @@ void Maxwell3D::ProcessSyncPoint() {
 | 
			
		||||
    const u32 increment = regs.sync_info.increment.Value();
 | 
			
		||||
    [[maybe_unused]] const u32 cache_flush = regs.sync_info.unknown.Value();
 | 
			
		||||
    if (increment) {
 | 
			
		||||
        rasterizer.SignalSyncPoint(sync_point);
 | 
			
		||||
        rasterizer->SignalSyncPoint(sync_point);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -570,7 +575,7 @@ void Maxwell3D::DrawArrays() {
 | 
			
		||||
 | 
			
		||||
    const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count};
 | 
			
		||||
    if (ShouldExecute()) {
 | 
			
		||||
        rasterizer.Draw(is_indexed, false);
 | 
			
		||||
        rasterizer->Draw(is_indexed, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if
 | 
			
		||||
@ -590,8 +595,8 @@ std::optional<u64> Maxwell3D::GetQueryResult() {
 | 
			
		||||
        return 0;
 | 
			
		||||
    case Regs::QuerySelect::SamplesPassed:
 | 
			
		||||
        // Deferred.
 | 
			
		||||
        rasterizer.Query(regs.query.QueryAddress(), VideoCore::QueryType::SamplesPassed,
 | 
			
		||||
                         system.GPU().GetTicks());
 | 
			
		||||
        rasterizer->Query(regs.query.QueryAddress(), VideoCore::QueryType::SamplesPassed,
 | 
			
		||||
                          system.GPU().GetTicks());
 | 
			
		||||
        return {};
 | 
			
		||||
    default:
 | 
			
		||||
        LOG_DEBUG(HW_GPU, "Unimplemented query select type {}",
 | 
			
		||||
@ -718,7 +723,7 @@ void Maxwell3D::ProcessClearBuffers() {
 | 
			
		||||
           regs.clear_buffers.R == regs.clear_buffers.B &&
 | 
			
		||||
           regs.clear_buffers.R == regs.clear_buffers.A);
 | 
			
		||||
 | 
			
		||||
    rasterizer.Clear();
 | 
			
		||||
    rasterizer->Clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u32 Maxwell3D::AccessConstBuffer32(ShaderType stage, u64 const_buffer, u64 offset) const {
 | 
			
		||||
@ -752,11 +757,11 @@ SamplerDescriptor Maxwell3D::AccessSampler(u32 handle) const {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VideoCore::GuestDriverProfile& Maxwell3D::AccessGuestDriverProfile() {
 | 
			
		||||
    return rasterizer.AccessGuestDriverProfile();
 | 
			
		||||
    return rasterizer->AccessGuestDriverProfile();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const VideoCore::GuestDriverProfile& Maxwell3D::AccessGuestDriverProfile() const {
 | 
			
		||||
    return rasterizer.AccessGuestDriverProfile();
 | 
			
		||||
    return rasterizer->AccessGuestDriverProfile();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Tegra::Engines
 | 
			
		||||
 | 
			
		||||
@ -51,9 +51,11 @@ namespace Tegra::Engines {
 | 
			
		||||
 | 
			
		||||
class Maxwell3D final : public ConstBufferEngineInterface, public EngineInterface {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer,
 | 
			
		||||
                       MemoryManager& memory_manager);
 | 
			
		||||
    ~Maxwell3D() = default;
 | 
			
		||||
    explicit Maxwell3D(Core::System& system, MemoryManager& memory_manager);
 | 
			
		||||
    ~Maxwell3D();
 | 
			
		||||
 | 
			
		||||
    /// Binds a rasterizer to this engine.
 | 
			
		||||
    void BindRasterizer(VideoCore::RasterizerInterface& rasterizer);
 | 
			
		||||
 | 
			
		||||
    /// Register structure of the Maxwell3D engine.
 | 
			
		||||
    /// TODO(Subv): This structure will need to be made bigger as more registers are discovered.
 | 
			
		||||
@ -1418,12 +1420,12 @@ public:
 | 
			
		||||
        return execute_on;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VideoCore::RasterizerInterface& GetRasterizer() {
 | 
			
		||||
        return rasterizer;
 | 
			
		||||
    VideoCore::RasterizerInterface& Rasterizer() {
 | 
			
		||||
        return *rasterizer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const VideoCore::RasterizerInterface& GetRasterizer() const {
 | 
			
		||||
        return rasterizer;
 | 
			
		||||
    const VideoCore::RasterizerInterface& Rasterizer() const {
 | 
			
		||||
        return *rasterizer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Notify a memory write has happened.
 | 
			
		||||
@ -1460,11 +1462,10 @@ private:
 | 
			
		||||
    void InitializeRegisterDefaults();
 | 
			
		||||
 | 
			
		||||
    Core::System& system;
 | 
			
		||||
 | 
			
		||||
    VideoCore::RasterizerInterface& rasterizer;
 | 
			
		||||
 | 
			
		||||
    MemoryManager& memory_manager;
 | 
			
		||||
 | 
			
		||||
    VideoCore::RasterizerInterface* rasterizer = nullptr;
 | 
			
		||||
 | 
			
		||||
    /// Start offsets of each macro in macro_memory
 | 
			
		||||
    std::array<u32, 0x80> macro_positions = {};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -27,21 +27,28 @@ namespace Tegra {
 | 
			
		||||
 | 
			
		||||
MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
 | 
			
		||||
 | 
			
		||||
GPU::GPU(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer_, bool is_async)
 | 
			
		||||
    : system{system}, renderer{std::move(renderer_)}, is_async{is_async} {
 | 
			
		||||
    auto& rasterizer{renderer->Rasterizer()};
 | 
			
		||||
    memory_manager = std::make_unique<Tegra::MemoryManager>(system, rasterizer);
 | 
			
		||||
    dma_pusher = std::make_unique<Tegra::DmaPusher>(system, *this);
 | 
			
		||||
    maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager);
 | 
			
		||||
    fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer);
 | 
			
		||||
    kepler_compute = std::make_unique<Engines::KeplerCompute>(system, rasterizer, *memory_manager);
 | 
			
		||||
    maxwell_dma = std::make_unique<Engines::MaxwellDMA>(system, *memory_manager);
 | 
			
		||||
    kepler_memory = std::make_unique<Engines::KeplerMemory>(system, *memory_manager);
 | 
			
		||||
    shader_notify = std::make_unique<VideoCore::ShaderNotify>();
 | 
			
		||||
}
 | 
			
		||||
GPU::GPU(Core::System& system_, bool is_async_)
 | 
			
		||||
    : system{system_}, dma_pusher{std::make_unique<Tegra::DmaPusher>(system, *this)},
 | 
			
		||||
      memory_manager{std::make_unique<Tegra::MemoryManager>(system)},
 | 
			
		||||
      maxwell_3d{std::make_unique<Engines::Maxwell3D>(system, *memory_manager)},
 | 
			
		||||
      fermi_2d{std::make_unique<Engines::Fermi2D>()},
 | 
			
		||||
      kepler_compute{std::make_unique<Engines::KeplerCompute>(system, *memory_manager)},
 | 
			
		||||
      maxwell_dma{std::make_unique<Engines::MaxwellDMA>(system, *memory_manager)},
 | 
			
		||||
      kepler_memory{std::make_unique<Engines::KeplerMemory>(system, *memory_manager)},
 | 
			
		||||
      shader_notify{std::make_unique<VideoCore::ShaderNotify>()}, is_async{is_async_} {}
 | 
			
		||||
 | 
			
		||||
GPU::~GPU() = default;
 | 
			
		||||
 | 
			
		||||
void GPU::BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer_) {
 | 
			
		||||
    renderer = std::move(renderer_);
 | 
			
		||||
 | 
			
		||||
    VideoCore::RasterizerInterface& rasterizer = renderer->Rasterizer();
 | 
			
		||||
    memory_manager->BindRasterizer(rasterizer);
 | 
			
		||||
    maxwell_3d->BindRasterizer(rasterizer);
 | 
			
		||||
    fermi_2d->BindRasterizer(rasterizer);
 | 
			
		||||
    kepler_compute->BindRasterizer(rasterizer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Engines::Maxwell3D& GPU::Maxwell3D() {
 | 
			
		||||
    return *maxwell_3d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -142,11 +142,6 @@ class MemoryManager;
 | 
			
		||||
 | 
			
		||||
class GPU {
 | 
			
		||||
public:
 | 
			
		||||
    explicit GPU(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer,
 | 
			
		||||
                 bool is_async);
 | 
			
		||||
 | 
			
		||||
    virtual ~GPU();
 | 
			
		||||
 | 
			
		||||
    struct MethodCall {
 | 
			
		||||
        u32 method{};
 | 
			
		||||
        u32 argument{};
 | 
			
		||||
@ -162,6 +157,12 @@ public:
 | 
			
		||||
              method_count(method_count) {}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    explicit GPU(Core::System& system, bool is_async);
 | 
			
		||||
    virtual ~GPU();
 | 
			
		||||
 | 
			
		||||
    /// Binds a renderer to the GPU.
 | 
			
		||||
    void BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer);
 | 
			
		||||
 | 
			
		||||
    /// Calls a GPU method.
 | 
			
		||||
    void CallMethod(const MethodCall& method_call);
 | 
			
		||||
 | 
			
		||||
@ -345,8 +346,8 @@ private:
 | 
			
		||||
    bool ExecuteMethodOnEngine(u32 method);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    std::unique_ptr<Tegra::DmaPusher> dma_pusher;
 | 
			
		||||
    Core::System& system;
 | 
			
		||||
    std::unique_ptr<Tegra::DmaPusher> dma_pusher;
 | 
			
		||||
    std::unique_ptr<VideoCore::RendererBase> renderer;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
@ -10,16 +10,14 @@
 | 
			
		||||
 | 
			
		||||
namespace VideoCommon {
 | 
			
		||||
 | 
			
		||||
GPUAsynch::GPUAsynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer_,
 | 
			
		||||
                     std::unique_ptr<Core::Frontend::GraphicsContext>&& context)
 | 
			
		||||
    : GPU(system, std::move(renderer_), true), gpu_thread{system},
 | 
			
		||||
      cpu_context(renderer->GetRenderWindow().CreateSharedContext()),
 | 
			
		||||
      gpu_context(std::move(context)) {}
 | 
			
		||||
GPUAsynch::GPUAsynch(Core::System& system) : GPU{system, true}, gpu_thread{system} {}
 | 
			
		||||
 | 
			
		||||
GPUAsynch::~GPUAsynch() = default;
 | 
			
		||||
 | 
			
		||||
void GPUAsynch::Start() {
 | 
			
		||||
    gpu_thread.StartThread(*renderer, *gpu_context, *dma_pusher);
 | 
			
		||||
    gpu_thread.StartThread(*renderer, renderer->Context(), *dma_pusher);
 | 
			
		||||
    cpu_context = renderer->GetRenderWindow().CreateSharedContext();
 | 
			
		||||
    cpu_context->MakeCurrent();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GPUAsynch::ObtainContext() {
 | 
			
		||||
 | 
			
		||||
@ -20,8 +20,7 @@ namespace VideoCommon {
 | 
			
		||||
/// Implementation of GPU interface that runs the GPU asynchronously
 | 
			
		||||
class GPUAsynch final : public Tegra::GPU {
 | 
			
		||||
public:
 | 
			
		||||
    explicit GPUAsynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer,
 | 
			
		||||
                       std::unique_ptr<Core::Frontend::GraphicsContext>&& context);
 | 
			
		||||
    explicit GPUAsynch(Core::System& system);
 | 
			
		||||
    ~GPUAsynch() override;
 | 
			
		||||
 | 
			
		||||
    void Start() override;
 | 
			
		||||
@ -42,7 +41,6 @@ protected:
 | 
			
		||||
private:
 | 
			
		||||
    GPUThread::ThreadManager gpu_thread;
 | 
			
		||||
    std::unique_ptr<Core::Frontend::GraphicsContext> cpu_context;
 | 
			
		||||
    std::unique_ptr<Core::Frontend::GraphicsContext> gpu_context;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace VideoCommon
 | 
			
		||||
 | 
			
		||||
@ -7,20 +7,18 @@
 | 
			
		||||
 | 
			
		||||
namespace VideoCommon {
 | 
			
		||||
 | 
			
		||||
GPUSynch::GPUSynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer,
 | 
			
		||||
                   std::unique_ptr<Core::Frontend::GraphicsContext>&& context)
 | 
			
		||||
    : GPU(system, std::move(renderer), false), context{std::move(context)} {}
 | 
			
		||||
GPUSynch::GPUSynch(Core::System& system) : GPU{system, false} {}
 | 
			
		||||
 | 
			
		||||
GPUSynch::~GPUSynch() = default;
 | 
			
		||||
 | 
			
		||||
void GPUSynch::Start() {}
 | 
			
		||||
 | 
			
		||||
void GPUSynch::ObtainContext() {
 | 
			
		||||
    context->MakeCurrent();
 | 
			
		||||
    renderer->Context().MakeCurrent();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GPUSynch::ReleaseContext() {
 | 
			
		||||
    context->DoneCurrent();
 | 
			
		||||
    renderer->Context().DoneCurrent();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) {
 | 
			
		||||
 | 
			
		||||
@ -19,8 +19,7 @@ namespace VideoCommon {
 | 
			
		||||
/// Implementation of GPU interface that runs the GPU synchronously
 | 
			
		||||
class GPUSynch final : public Tegra::GPU {
 | 
			
		||||
public:
 | 
			
		||||
    explicit GPUSynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer,
 | 
			
		||||
                      std::unique_ptr<Core::Frontend::GraphicsContext>&& context);
 | 
			
		||||
    explicit GPUSynch(Core::System& system);
 | 
			
		||||
    ~GPUSynch() override;
 | 
			
		||||
 | 
			
		||||
    void Start() override;
 | 
			
		||||
@ -36,9 +35,6 @@ public:
 | 
			
		||||
protected:
 | 
			
		||||
    void TriggerCpuInterrupt([[maybe_unused]] u32 syncpoint_id,
 | 
			
		||||
                             [[maybe_unused]] u32 value) const override {}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::unique_ptr<Core::Frontend::GraphicsContext> context;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace VideoCommon
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,7 @@ void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
 | 
			
		||||
    maxwell3d.regs.index_array.first = parameters[4];
 | 
			
		||||
 | 
			
		||||
    if (maxwell3d.ShouldExecute()) {
 | 
			
		||||
        maxwell3d.GetRasterizer().Draw(true, true);
 | 
			
		||||
        maxwell3d.Rasterizer().Draw(true, true);
 | 
			
		||||
    }
 | 
			
		||||
    maxwell3d.regs.index_array.count = 0;
 | 
			
		||||
    maxwell3d.mme_draw.instance_count = 0;
 | 
			
		||||
@ -42,7 +42,7 @@ void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
 | 
			
		||||
    maxwell3d.mme_draw.instance_count = count;
 | 
			
		||||
 | 
			
		||||
    if (maxwell3d.ShouldExecute()) {
 | 
			
		||||
        maxwell3d.GetRasterizer().Draw(false, true);
 | 
			
		||||
        maxwell3d.Rasterizer().Draw(false, true);
 | 
			
		||||
    }
 | 
			
		||||
    maxwell3d.regs.vertex_buffer.count = 0;
 | 
			
		||||
    maxwell3d.mme_draw.instance_count = 0;
 | 
			
		||||
@ -65,7 +65,7 @@ void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&
 | 
			
		||||
    maxwell3d.regs.draw.topology.Assign(
 | 
			
		||||
        static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]));
 | 
			
		||||
    if (maxwell3d.ShouldExecute()) {
 | 
			
		||||
        maxwell3d.GetRasterizer().Draw(true, true);
 | 
			
		||||
        maxwell3d.Rasterizer().Draw(true, true);
 | 
			
		||||
    }
 | 
			
		||||
    maxwell3d.regs.reg_array[0x446] = 0x0; // vertex id base?
 | 
			
		||||
    maxwell3d.regs.index_array.count = 0;
 | 
			
		||||
 | 
			
		||||
@ -14,11 +14,15 @@
 | 
			
		||||
 | 
			
		||||
namespace Tegra {
 | 
			
		||||
 | 
			
		||||
MemoryManager::MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer)
 | 
			
		||||
    : system{system}, rasterizer{rasterizer}, page_table(page_table_size) {}
 | 
			
		||||
MemoryManager::MemoryManager(Core::System& system_)
 | 
			
		||||
    : system{system_}, page_table(page_table_size) {}
 | 
			
		||||
 | 
			
		||||
MemoryManager::~MemoryManager() = default;
 | 
			
		||||
 | 
			
		||||
void MemoryManager::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) {
 | 
			
		||||
    rasterizer = &rasterizer_;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GPUVAddr MemoryManager::UpdateRange(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size) {
 | 
			
		||||
    u64 remaining_size{size};
 | 
			
		||||
    for (u64 offset{}; offset < size; offset += page_size) {
 | 
			
		||||
@ -217,7 +221,7 @@ void MemoryManager::ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::siz
 | 
			
		||||
 | 
			
		||||
            // Flush must happen on the rasterizer interface, such that memory is always synchronous
 | 
			
		||||
            // when it is read (even when in asynchronous GPU mode). Fixes Dead Cells title menu.
 | 
			
		||||
            rasterizer.FlushRegion(src_addr, copy_amount);
 | 
			
		||||
            rasterizer->FlushRegion(src_addr, copy_amount);
 | 
			
		||||
            system.Memory().ReadBlockUnsafe(src_addr, dest_buffer, copy_amount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -266,7 +270,7 @@ void MemoryManager::WriteBlock(GPUVAddr gpu_dest_addr, const void* src_buffer, s
 | 
			
		||||
 | 
			
		||||
            // Invalidate must happen on the rasterizer interface, such that memory is always
 | 
			
		||||
            // synchronous when it is written (even when in asynchronous GPU mode).
 | 
			
		||||
            rasterizer.InvalidateRegion(dest_addr, copy_amount);
 | 
			
		||||
            rasterizer->InvalidateRegion(dest_addr, copy_amount);
 | 
			
		||||
            system.Memory().WriteBlockUnsafe(dest_addr, src_buffer, copy_amount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -68,9 +68,12 @@ static_assert(sizeof(PageEntry) == 4, "PageEntry is too large");
 | 
			
		||||
 | 
			
		||||
class MemoryManager final {
 | 
			
		||||
public:
 | 
			
		||||
    explicit MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer);
 | 
			
		||||
    explicit MemoryManager(Core::System& system);
 | 
			
		||||
    ~MemoryManager();
 | 
			
		||||
 | 
			
		||||
    /// Binds a renderer to the memory manager.
 | 
			
		||||
    void BindRasterizer(VideoCore::RasterizerInterface& rasterizer);
 | 
			
		||||
 | 
			
		||||
    std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const;
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
@ -141,7 +144,7 @@ private:
 | 
			
		||||
 | 
			
		||||
    Core::System& system;
 | 
			
		||||
 | 
			
		||||
    VideoCore::RasterizerInterface& rasterizer;
 | 
			
		||||
    VideoCore::RasterizerInterface* rasterizer = nullptr;
 | 
			
		||||
 | 
			
		||||
    std::vector<PageEntry> page_table;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,9 @@
 | 
			
		||||
 | 
			
		||||
namespace VideoCore {
 | 
			
		||||
 | 
			
		||||
RendererBase::RendererBase(Core::Frontend::EmuWindow& window) : render_window{window} {
 | 
			
		||||
RendererBase::RendererBase(Core::Frontend::EmuWindow& window_,
 | 
			
		||||
                           std::unique_ptr<Core::Frontend::GraphicsContext> context_)
 | 
			
		||||
    : render_window{window_}, context{std::move(context_)} {
 | 
			
		||||
    RefreshBaseSettings();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,8 @@
 | 
			
		||||
 | 
			
		||||
namespace Core::Frontend {
 | 
			
		||||
class EmuWindow;
 | 
			
		||||
}
 | 
			
		||||
class GraphicsContext;
 | 
			
		||||
} // namespace Core::Frontend
 | 
			
		||||
 | 
			
		||||
namespace VideoCore {
 | 
			
		||||
 | 
			
		||||
@ -25,14 +26,15 @@ struct RendererSettings {
 | 
			
		||||
 | 
			
		||||
    // Screenshot
 | 
			
		||||
    std::atomic<bool> screenshot_requested{false};
 | 
			
		||||
    void* screenshot_bits;
 | 
			
		||||
    void* screenshot_bits{};
 | 
			
		||||
    std::function<void()> screenshot_complete_callback;
 | 
			
		||||
    Layout::FramebufferLayout screenshot_framebuffer_layout;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class RendererBase : NonCopyable {
 | 
			
		||||
public:
 | 
			
		||||
    explicit RendererBase(Core::Frontend::EmuWindow& window);
 | 
			
		||||
    explicit RendererBase(Core::Frontend::EmuWindow& window,
 | 
			
		||||
                          std::unique_ptr<Core::Frontend::GraphicsContext> context);
 | 
			
		||||
    virtual ~RendererBase();
 | 
			
		||||
 | 
			
		||||
    /// Initialize the renderer
 | 
			
		||||
@ -68,6 +70,14 @@ public:
 | 
			
		||||
        return *rasterizer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Core::Frontend::GraphicsContext& Context() {
 | 
			
		||||
        return *context;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const Core::Frontend::GraphicsContext& Context() const {
 | 
			
		||||
        return *context;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Core::Frontend::EmuWindow& GetRenderWindow() {
 | 
			
		||||
        return render_window;
 | 
			
		||||
    }
 | 
			
		||||
@ -94,6 +104,7 @@ public:
 | 
			
		||||
protected:
 | 
			
		||||
    Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle.
 | 
			
		||||
    std::unique_ptr<RasterizerInterface> rasterizer;
 | 
			
		||||
    std::unique_ptr<Core::Frontend::GraphicsContext> context;
 | 
			
		||||
    f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer
 | 
			
		||||
    int m_current_frame = 0;  ///< Current frame, should be set by the renderer
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -313,10 +313,11 @@ public:
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system,
 | 
			
		||||
                               Core::Frontend::GraphicsContext& context)
 | 
			
		||||
    : RendererBase{emu_window}, emu_window{emu_window}, system{system}, context{context},
 | 
			
		||||
      program_manager{device}, has_debug_tool{HasDebugTool()} {}
 | 
			
		||||
RendererOpenGL::RendererOpenGL(Core::System& system_, Core::Frontend::EmuWindow& emu_window_,
 | 
			
		||||
                               Tegra::GPU& gpu_,
 | 
			
		||||
                               std::unique_ptr<Core::Frontend::GraphicsContext> context_)
 | 
			
		||||
    : RendererBase{emu_window_, std::move(context_)}, system{system_},
 | 
			
		||||
      emu_window{emu_window_}, gpu{gpu_}, program_manager{device}, has_debug_tool{HasDebugTool()} {}
 | 
			
		||||
 | 
			
		||||
RendererOpenGL::~RendererOpenGL() = default;
 | 
			
		||||
 | 
			
		||||
@ -384,7 +385,7 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
 | 
			
		||||
    if (has_debug_tool) {
 | 
			
		||||
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
 | 
			
		||||
        Present(0);
 | 
			
		||||
        context.SwapBuffers();
 | 
			
		||||
        context->SwapBuffers();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -56,8 +56,9 @@ class FrameMailbox;
 | 
			
		||||
 | 
			
		||||
class RendererOpenGL final : public VideoCore::RendererBase {
 | 
			
		||||
public:
 | 
			
		||||
    explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system,
 | 
			
		||||
                            Core::Frontend::GraphicsContext& context);
 | 
			
		||||
    explicit RendererOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
 | 
			
		||||
                            Tegra::GPU& gpu,
 | 
			
		||||
                            std::unique_ptr<Core::Frontend::GraphicsContext> context);
 | 
			
		||||
    ~RendererOpenGL() override;
 | 
			
		||||
 | 
			
		||||
    bool Init() override;
 | 
			
		||||
@ -93,9 +94,9 @@ private:
 | 
			
		||||
 | 
			
		||||
    bool Present(int timeout_ms);
 | 
			
		||||
 | 
			
		||||
    Core::Frontend::EmuWindow& emu_window;
 | 
			
		||||
    Core::System& system;
 | 
			
		||||
    Core::Frontend::GraphicsContext& context;
 | 
			
		||||
    Core::Frontend::EmuWindow& emu_window;
 | 
			
		||||
    Tegra::GPU& gpu;
 | 
			
		||||
    const Device device;
 | 
			
		||||
 | 
			
		||||
    StateTracker state_tracker{system};
 | 
			
		||||
@ -120,7 +121,7 @@ private:
 | 
			
		||||
    std::vector<u8> gl_framebuffer_data;
 | 
			
		||||
 | 
			
		||||
    /// Used for transforming the framebuffer orientation
 | 
			
		||||
    Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags;
 | 
			
		||||
    Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags{};
 | 
			
		||||
    Common::Rectangle<int> framebuffer_crop_rect;
 | 
			
		||||
 | 
			
		||||
    /// Frame presentation mailbox
 | 
			
		||||
 | 
			
		||||
@ -237,8 +237,10 @@ std::string BuildCommaSeparatedExtensions(std::vector<std::string> available_ext
 | 
			
		||||
 | 
			
		||||
} // Anonymous namespace
 | 
			
		||||
 | 
			
		||||
RendererVulkan::RendererVulkan(Core::Frontend::EmuWindow& window, Core::System& system)
 | 
			
		||||
    : RendererBase(window), system{system} {}
 | 
			
		||||
RendererVulkan::RendererVulkan(Core::System& system_, Core::Frontend::EmuWindow& emu_window,
 | 
			
		||||
                               Tegra::GPU& gpu_,
 | 
			
		||||
                               std::unique_ptr<Core::Frontend::GraphicsContext> context)
 | 
			
		||||
    : RendererBase{emu_window, std::move(context)}, system{system_}, gpu{gpu_} {}
 | 
			
		||||
 | 
			
		||||
RendererVulkan::~RendererVulkan() {
 | 
			
		||||
    ShutDown();
 | 
			
		||||
 | 
			
		||||
@ -38,7 +38,9 @@ struct VKScreenInfo {
 | 
			
		||||
 | 
			
		||||
class RendererVulkan final : public VideoCore::RendererBase {
 | 
			
		||||
public:
 | 
			
		||||
    explicit RendererVulkan(Core::Frontend::EmuWindow& window, Core::System& system);
 | 
			
		||||
    explicit RendererVulkan(Core::System& system, Core::Frontend::EmuWindow& emu_window,
 | 
			
		||||
                            Tegra::GPU& gpu,
 | 
			
		||||
                            std::unique_ptr<Core::Frontend::GraphicsContext> context);
 | 
			
		||||
    ~RendererVulkan() override;
 | 
			
		||||
 | 
			
		||||
    bool Init() override;
 | 
			
		||||
@ -58,6 +60,7 @@ private:
 | 
			
		||||
    void Report() const;
 | 
			
		||||
 | 
			
		||||
    Core::System& system;
 | 
			
		||||
    Tegra::GPU& gpu;
 | 
			
		||||
 | 
			
		||||
    Common::DynamicLibrary library;
 | 
			
		||||
    vk::InstanceDispatch dld;
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/settings.h"
 | 
			
		||||
@ -16,37 +17,46 @@
 | 
			
		||||
#include "video_core/video_core.h"
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
std::unique_ptr<VideoCore::RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window,
 | 
			
		||||
                                                        Core::System& system,
 | 
			
		||||
                                                        Core::Frontend::GraphicsContext& context) {
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<VideoCore::RendererBase> CreateRenderer(
 | 
			
		||||
    Core::System& system, Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu,
 | 
			
		||||
    std::unique_ptr<Core::Frontend::GraphicsContext> context) {
 | 
			
		||||
    switch (Settings::values.renderer_backend.GetValue()) {
 | 
			
		||||
    case Settings::RendererBackend::OpenGL:
 | 
			
		||||
        return std::make_unique<OpenGL::RendererOpenGL>(emu_window, system, context);
 | 
			
		||||
        return std::make_unique<OpenGL::RendererOpenGL>(system, emu_window, gpu,
 | 
			
		||||
                                                        std::move(context));
 | 
			
		||||
#ifdef HAS_VULKAN
 | 
			
		||||
    case Settings::RendererBackend::Vulkan:
 | 
			
		||||
        return std::make_unique<Vulkan::RendererVulkan>(emu_window, system);
 | 
			
		||||
        return std::make_unique<Vulkan::RendererVulkan>(system, emu_window, gpu,
 | 
			
		||||
                                                        std::move(context));
 | 
			
		||||
#endif
 | 
			
		||||
    default:
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // Anonymous namespace
 | 
			
		||||
 | 
			
		||||
namespace VideoCore {
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system) {
 | 
			
		||||
    std::unique_ptr<Tegra::GPU> gpu;
 | 
			
		||||
    if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
 | 
			
		||||
        gpu = std::make_unique<VideoCommon::GPUAsynch>(system);
 | 
			
		||||
    } else {
 | 
			
		||||
        gpu = std::make_unique<VideoCommon::GPUSynch>(system);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto context = emu_window.CreateSharedContext();
 | 
			
		||||
    const auto scope = context->Acquire();
 | 
			
		||||
    auto renderer = CreateRenderer(emu_window, system, *context);
 | 
			
		||||
 | 
			
		||||
    auto renderer = CreateRenderer(system, emu_window, *gpu, std::move(context));
 | 
			
		||||
    if (!renderer->Init()) {
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) {
 | 
			
		||||
        return std::make_unique<VideoCommon::GPUAsynch>(system, std::move(renderer),
 | 
			
		||||
                                                        std::move(context));
 | 
			
		||||
    }
 | 
			
		||||
    return std::make_unique<VideoCommon::GPUSynch>(system, std::move(renderer), std::move(context));
 | 
			
		||||
    gpu->BindRenderer(std::move(renderer));
 | 
			
		||||
    return gpu;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u16 GetResolutionScaleFactor(const RendererBase& renderer) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user