Selaa lähdekoodia

gpu: Report renderer errors with exceptions

Instead of using a two step initialization to report errors, initialize
the GPU renderer and rasterizer on the constructor and report errors
through std::runtime_error.
ReinUsesLisp 5 vuotta sitten
vanhempi
commit
75ccd9959c

+ 2 - 2
src/video_core/engines/fermi_2d.cpp

@@ -18,8 +18,8 @@ Fermi2D::Fermi2D() {
 
 Fermi2D::~Fermi2D() = default;
 
-void Fermi2D::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) {
-    rasterizer = &rasterizer_;
+void Fermi2D::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
+    rasterizer = rasterizer_;
 }
 
 void Fermi2D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {

+ 1 - 1
src/video_core/engines/fermi_2d.h

@@ -38,7 +38,7 @@ public:
     ~Fermi2D();
 
     /// Binds a rasterizer to this engine.
-    void BindRasterizer(VideoCore::RasterizerInterface& rasterizer);
+    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;

+ 2 - 2
src/video_core/engines/kepler_compute.cpp

@@ -21,8 +21,8 @@ KeplerCompute::KeplerCompute(Core::System& system_, MemoryManager& memory_manage
 
 KeplerCompute::~KeplerCompute() = default;
 
-void KeplerCompute::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) {
-    rasterizer = &rasterizer_;
+void KeplerCompute::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
+    rasterizer = rasterizer_;
 }
 
 void KeplerCompute::CallMethod(u32 method, u32 method_argument, bool is_last_call) {

+ 1 - 1
src/video_core/engines/kepler_compute.h

@@ -46,7 +46,7 @@ public:
     ~KeplerCompute();
 
     /// Binds a rasterizer to this engine.
-    void BindRasterizer(VideoCore::RasterizerInterface& rasterizer);
+    void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
 
     static constexpr std::size_t NumConstBuffers = 8;
 

+ 2 - 2
src/video_core/engines/maxwell_3d.cpp

@@ -30,8 +30,8 @@ Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_)
 
 Maxwell3D::~Maxwell3D() = default;
 
-void Maxwell3D::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) {
-    rasterizer = &rasterizer_;
+void Maxwell3D::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
+    rasterizer = rasterizer_;
 }
 
 void Maxwell3D::InitializeRegisterDefaults() {

+ 1 - 1
src/video_core/engines/maxwell_3d.h

@@ -55,7 +55,7 @@ public:
     ~Maxwell3D();
 
     /// Binds a rasterizer to this engine.
-    void BindRasterizer(VideoCore::RasterizerInterface& rasterizer);
+    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.

+ 4 - 4
src/video_core/gpu.cpp

@@ -44,8 +44,8 @@ GPU::~GPU() = default;
 
 void GPU::BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer_) {
     renderer = std::move(renderer_);
+    rasterizer = renderer->ReadRasterizer();
 
-    VideoCore::RasterizerInterface& rasterizer = renderer->Rasterizer();
     memory_manager->BindRasterizer(rasterizer);
     maxwell_3d->BindRasterizer(rasterizer);
     fermi_2d->BindRasterizer(rasterizer);
@@ -171,7 +171,7 @@ void GPU::TickWork() {
         const std::size_t size = request.size;
         flush_requests.pop_front();
         flush_request_mutex.unlock();
-        renderer->Rasterizer().FlushRegion(addr, size);
+        rasterizer->FlushRegion(addr, size);
         current_flush_fence.store(fence);
         flush_request_mutex.lock();
     }
@@ -193,11 +193,11 @@ u64 GPU::GetTicks() const {
 }
 
 void GPU::FlushCommands() {
-    renderer->Rasterizer().FlushCommands();
+    rasterizer->FlushCommands();
 }
 
 void GPU::SyncGuestHost() {
-    renderer->Rasterizer().SyncGuestHost();
+    rasterizer->SyncGuestHost();
 }
 
 enum class GpuSemaphoreOperation {

+ 1 - 0
src/video_core/gpu.h

@@ -366,6 +366,7 @@ protected:
     std::unique_ptr<Tegra::DmaPusher> dma_pusher;
     std::unique_ptr<Tegra::CDmaPusher> cdma_pusher;
     std::unique_ptr<VideoCore::RendererBase> renderer;
+    VideoCore::RasterizerInterface* rasterizer = nullptr;
     const bool use_nvdec;
 
 private:

+ 7 - 5
src/video_core/gpu_thread.cpp

@@ -38,6 +38,7 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
     }
 
     auto current_context = context.Acquire();
+    VideoCore::RasterizerInterface* const rasterizer = renderer.ReadRasterizer();
 
     CommandDataContainer next;
     while (state.is_running) {
@@ -52,13 +53,13 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
         } else if (const auto* data = std::get_if<SwapBuffersCommand>(&next.data)) {
             renderer.SwapBuffers(data->framebuffer ? &*data->framebuffer : nullptr);
         } else if (std::holds_alternative<OnCommandListEndCommand>(next.data)) {
-            renderer.Rasterizer().ReleaseFences();
+            rasterizer->ReleaseFences();
         } else if (std::holds_alternative<GPUTickCommand>(next.data)) {
             system.GPU().TickWork();
         } else if (const auto* flush = std::get_if<FlushRegionCommand>(&next.data)) {
-            renderer.Rasterizer().FlushRegion(flush->addr, flush->size);
+            rasterizer->FlushRegion(flush->addr, flush->size);
         } else if (const auto* invalidate = std::get_if<InvalidateRegionCommand>(&next.data)) {
-            renderer.Rasterizer().OnCPUWrite(invalidate->addr, invalidate->size);
+            rasterizer->OnCPUWrite(invalidate->addr, invalidate->size);
         } else if (std::holds_alternative<EndProcessingCommand>(next.data)) {
             return;
         } else {
@@ -84,6 +85,7 @@ ThreadManager::~ThreadManager() {
 void ThreadManager::StartThread(VideoCore::RendererBase& renderer,
                                 Core::Frontend::GraphicsContext& context,
                                 Tegra::DmaPusher& dma_pusher, Tegra::CDmaPusher& cdma_pusher) {
+    rasterizer = renderer.ReadRasterizer();
     thread = std::thread(RunThread, std::ref(system), std::ref(renderer), std::ref(context),
                          std::ref(dma_pusher), std::ref(state), std::ref(cdma_pusher));
 }
@@ -129,12 +131,12 @@ void ThreadManager::FlushRegion(VAddr addr, u64 size) {
 }
 
 void ThreadManager::InvalidateRegion(VAddr addr, u64 size) {
-    system.Renderer().Rasterizer().OnCPUWrite(addr, size);
+    rasterizer->OnCPUWrite(addr, size);
 }
 
 void ThreadManager::FlushAndInvalidateRegion(VAddr addr, u64 size) {
     // Skip flush on asynch mode, as FlushAndInvalidateRegion is not used for anything too important
-    system.Renderer().Rasterizer().OnCPUWrite(addr, size);
+    rasterizer->OnCPUWrite(addr, size);
 }
 
 void ThreadManager::WaitIdle() const {

+ 5 - 3
src/video_core/gpu_thread.h

@@ -27,6 +27,7 @@ class System;
 } // namespace Core
 
 namespace VideoCore {
+class RasterizerInterface;
 class RendererBase;
 } // namespace VideoCore
 
@@ -151,11 +152,12 @@ private:
     /// Pushes a command to be executed by the GPU thread
     u64 PushCommand(CommandData&& command_data);
 
-    SynchState state;
     Core::System& system;
-    std::thread thread;
-    std::thread::id thread_id;
     const bool is_async;
+    VideoCore::RasterizerInterface* rasterizer = nullptr;
+
+    SynchState state;
+    std::thread thread;
 };
 
 } // namespace VideoCommon::GPUThread

+ 2 - 2
src/video_core/memory_manager.cpp

@@ -21,8 +21,8 @@ MemoryManager::MemoryManager(Core::System& system_)
 
 MemoryManager::~MemoryManager() = default;
 
-void MemoryManager::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) {
-    rasterizer = &rasterizer_;
+void MemoryManager::BindRasterizer(VideoCore::RasterizerInterface* rasterizer_) {
+    rasterizer = rasterizer_;
 }
 
 GPUVAddr MemoryManager::UpdateRange(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size) {

+ 1 - 1
src/video_core/memory_manager.h

@@ -72,7 +72,7 @@ public:
     ~MemoryManager();
 
     /// Binds a renderer to the memory manager.
-    void BindRasterizer(VideoCore::RasterizerInterface& rasterizer);
+    void BindRasterizer(VideoCore::RasterizerInterface* rasterizer);
 
     [[nodiscard]] std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const;
 

+ 2 - 15
src/video_core/renderer_base.h

@@ -37,15 +37,11 @@ public:
                           std::unique_ptr<Core::Frontend::GraphicsContext> context);
     virtual ~RendererBase();
 
-    /// Initialize the renderer
-    [[nodiscard]] virtual bool Init() = 0;
-
-    /// Shutdown the renderer
-    virtual void ShutDown() = 0;
-
     /// Finalize rendering the guest frame and draw into the presentation texture
     virtual void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) = 0;
 
+    [[nodiscard]] virtual RasterizerInterface* ReadRasterizer() = 0;
+
     // Getter/setter functions:
     // ------------------------
 
@@ -57,14 +53,6 @@ public:
         return m_current_frame;
     }
 
-    [[nodiscard]] RasterizerInterface& Rasterizer() {
-        return *rasterizer;
-    }
-
-    [[nodiscard]] const RasterizerInterface& Rasterizer() const {
-        return *rasterizer;
-    }
-
     [[nodiscard]] Core::Frontend::GraphicsContext& Context() {
         return *context;
     }
@@ -98,7 +86,6 @@ 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

+ 16 - 32
src/video_core/renderer_opengl/renderer_opengl.cpp

@@ -132,7 +132,20 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_,
                                Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
                                std::unique_ptr<Core::Frontend::GraphicsContext> context_)
     : RendererBase{emu_window_, std::move(context_)}, telemetry_session{telemetry_session_},
-      emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, program_manager{device} {}
+      emu_window{emu_window_}, cpu_memory{cpu_memory_}, gpu{gpu_}, program_manager{device},
+      rasterizer{emu_window, gpu, cpu_memory, device, screen_info, program_manager, state_tracker} {
+    if (Settings::values.renderer_debug && GLAD_GL_KHR_debug) {
+        glEnable(GL_DEBUG_OUTPUT);
+        glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
+        glDebugMessageCallback(DebugHandler, nullptr);
+    }
+    AddTelemetryFields();
+
+    if (!GLAD_GL_VERSION_4_6) {
+        throw std::runtime_error{"OpenGL 4.3 is not available"};
+    }
+    InitOpenGLObjects();
+}
 
 RendererOpenGL::~RendererOpenGL() = default;
 
@@ -148,7 +161,7 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
 
     ++m_current_frame;
 
-    rasterizer->TickFrame();
+    rasterizer.TickFrame();
 
     context->SwapBuffers();
     render_window.OnFrameDisplayed();
@@ -179,7 +192,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
     framebuffer_crop_rect = framebuffer.crop_rect;
 
     const VAddr framebuffer_addr{framebuffer.address + framebuffer.offset};
-    if (rasterizer->AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride)) {
+    if (rasterizer.AccelerateDisplay(framebuffer, framebuffer_addr, framebuffer.stride)) {
         return;
     }
 
@@ -289,14 +302,6 @@ void RendererOpenGL::AddTelemetryFields() {
     telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version));
 }
 
-void RendererOpenGL::CreateRasterizer() {
-    if (rasterizer) {
-        return;
-    }
-    rasterizer = std::make_unique<RasterizerOpenGL>(emu_window, gpu, cpu_memory, device,
-                                                    screen_info, program_manager, state_tracker);
-}
-
 void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
                                                  const Tegra::FramebufferConfig& framebuffer) {
     texture.width = framebuffer.width;
@@ -497,25 +502,4 @@ void RendererOpenGL::RenderScreenshot() {
     renderer_settings.screenshot_requested = false;
 }
 
-bool RendererOpenGL::Init() {
-    if (Settings::values.renderer_debug && GLAD_GL_KHR_debug) {
-        glEnable(GL_DEBUG_OUTPUT);
-        glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
-        glDebugMessageCallback(DebugHandler, nullptr);
-    }
-
-    AddTelemetryFields();
-
-    if (!GLAD_GL_VERSION_4_6) {
-        return false;
-    }
-
-    InitOpenGLObjects();
-    CreateRasterizer();
-
-    return true;
-}
-
-void RendererOpenGL::ShutDown() {}
-
 } // namespace OpenGL

+ 7 - 4
src/video_core/renderer_opengl/renderer_opengl.h

@@ -10,6 +10,7 @@
 #include "common/math_util.h"
 #include "video_core/renderer_base.h"
 #include "video_core/renderer_opengl/gl_device.h"
+#include "video_core/renderer_opengl/gl_rasterizer.h"
 #include "video_core/renderer_opengl/gl_resource_manager.h"
 #include "video_core/renderer_opengl/gl_shader_manager.h"
 #include "video_core/renderer_opengl/gl_state_tracker.h"
@@ -63,18 +64,18 @@ public:
                             std::unique_ptr<Core::Frontend::GraphicsContext> context_);
     ~RendererOpenGL() override;
 
-    bool Init() override;
-    void ShutDown() override;
     void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override;
 
+    VideoCore::RasterizerInterface* ReadRasterizer() override {
+        return &rasterizer;
+    }
+
 private:
     /// Initializes the OpenGL state and creates persistent objects.
     void InitOpenGLObjects();
 
     void AddTelemetryFields();
 
-    void CreateRasterizer();
-
     void ConfigureFramebufferTexture(TextureInfo& texture,
                                      const Tegra::FramebufferConfig& framebuffer);
 
@@ -118,6 +119,8 @@ private:
     /// Global dummy shader pipeline
     ProgramManager program_manager;
 
+    RasterizerOpenGL rasterizer;
+
     /// OpenGL framebuffer data
     std::vector<u8> gl_framebuffer_data;
 

+ 53 - 100
src/video_core/renderer_vulkan/renderer_vulkan.cpp

@@ -80,17 +80,50 @@ std::string BuildCommaSeparatedExtensions(std::vector<std::string> available_ext
     return separated_extensions;
 }
 
+Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld,
+                    VkSurfaceKHR surface) {
+    const std::vector<VkPhysicalDevice> devices = instance.EnumeratePhysicalDevices();
+    const s32 device_index = Settings::values.vulkan_device.GetValue();
+    if (device_index < 0 || device_index >= static_cast<s32>(devices.size())) {
+        LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index);
+        throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
+    }
+    const vk::PhysicalDevice physical_device(devices[device_index], dld);
+    return Device(*instance, physical_device, surface, dld);
+}
 } // Anonymous namespace
 
 RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
                                Core::Frontend::EmuWindow& emu_window,
                                Core::Memory::Memory& cpu_memory_, Tegra::GPU& gpu_,
-                               std::unique_ptr<Core::Frontend::GraphicsContext> context_)
-    : RendererBase{emu_window, std::move(context_)}, telemetry_session{telemetry_session_},
-      cpu_memory{cpu_memory_}, gpu{gpu_} {}
+                               std::unique_ptr<Core::Frontend::GraphicsContext> context_) try
+    : RendererBase(emu_window, std::move(context_)),
+      telemetry_session(telemetry_session_),
+      cpu_memory(cpu_memory_),
+      gpu(gpu_),
+      library(OpenLibrary()),
+      instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
+                              true, Settings::values.renderer_debug)),
+      debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr),
+      surface(CreateSurface(instance, render_window)),
+      device(CreateDevice(instance, dld, *surface)),
+      memory_allocator(device),
+      state_tracker(gpu),
+      scheduler(device, state_tracker),
+      swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width,
+                render_window.GetFramebufferLayout().height, false),
+      blit_screen(cpu_memory, render_window, device, memory_allocator, swapchain, scheduler,
+                  screen_info),
+      rasterizer(render_window, gpu, gpu.MemoryManager(), cpu_memory, screen_info, device,
+                 memory_allocator, state_tracker, scheduler) {
+    Report();
+} catch (const vk::Exception& exception) {
+    LOG_ERROR(Render_Vulkan, "Vulkan initialization failed with error: {}", exception.what());
+    throw std::runtime_error{fmt::format("Vulkan initialization error {}", exception.what())};
+}
 
 RendererVulkan::~RendererVulkan() {
-    ShutDown();
+    void(device.GetLogical().WaitIdle());
 }
 
 void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
@@ -101,101 +134,38 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
     if (layout.width > 0 && layout.height > 0 && render_window.IsShown()) {
         const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset;
         const bool use_accelerated =
-            rasterizer->AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride);
+            rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride);
         const bool is_srgb = use_accelerated && screen_info.is_srgb;
-        if (swapchain->HasFramebufferChanged(layout) || swapchain->GetSrgbState() != is_srgb) {
-            swapchain->Create(layout.width, layout.height, is_srgb);
-            blit_screen->Recreate();
+        if (swapchain.HasFramebufferChanged(layout) || swapchain.GetSrgbState() != is_srgb) {
+            swapchain.Create(layout.width, layout.height, is_srgb);
+            blit_screen.Recreate();
         }
 
-        scheduler->WaitWorker();
+        scheduler.WaitWorker();
 
-        swapchain->AcquireNextImage();
-        const VkSemaphore render_semaphore = blit_screen->Draw(*framebuffer, use_accelerated);
+        swapchain.AcquireNextImage();
+        const VkSemaphore render_semaphore = blit_screen.Draw(*framebuffer, use_accelerated);
 
-        scheduler->Flush(render_semaphore);
+        scheduler.Flush(render_semaphore);
 
-        if (swapchain->Present(render_semaphore)) {
-            blit_screen->Recreate();
+        if (swapchain.Present(render_semaphore)) {
+            blit_screen.Recreate();
         }
-
-        rasterizer->TickFrame();
+        rasterizer.TickFrame();
     }
 
     render_window.OnFrameDisplayed();
 }
 
-bool RendererVulkan::Init() try {
-    library = OpenLibrary();
-    instance = CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
-                              true, Settings::values.renderer_debug);
-    if (Settings::values.renderer_debug) {
-        debug_callback = CreateDebugCallback(instance);
-    }
-    surface = CreateSurface(instance, render_window);
-
-    InitializeDevice();
-    Report();
-
-    memory_allocator = std::make_unique<MemoryAllocator>(*device);
-
-    state_tracker = std::make_unique<StateTracker>(gpu);
-
-    scheduler = std::make_unique<VKScheduler>(*device, *state_tracker);
-
-    const auto& framebuffer = render_window.GetFramebufferLayout();
-    swapchain = std::make_unique<VKSwapchain>(*surface, *device, *scheduler);
-    swapchain->Create(framebuffer.width, framebuffer.height, false);
-
-    rasterizer = std::make_unique<RasterizerVulkan>(render_window, gpu, gpu.MemoryManager(),
-                                                    cpu_memory, screen_info, *device,
-                                                    *memory_allocator, *state_tracker, *scheduler);
-
-    blit_screen =
-        std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device,
-                                       *memory_allocator, *swapchain, *scheduler, screen_info);
-    return true;
-
-} catch (const vk::Exception& exception) {
-    LOG_ERROR(Render_Vulkan, "Vulkan initialization failed with error: {}", exception.what());
-    return false;
-}
-
-void RendererVulkan::ShutDown() {
-    if (!device) {
-        return;
-    }
-    if (const auto& dev = device->GetLogical()) {
-        dev.WaitIdle();
-    }
-    rasterizer.reset();
-    blit_screen.reset();
-    scheduler.reset();
-    swapchain.reset();
-    memory_allocator.reset();
-    device.reset();
-}
-
-void RendererVulkan::InitializeDevice() {
-    const std::vector<VkPhysicalDevice> devices = instance.EnumeratePhysicalDevices();
-    const s32 device_index = Settings::values.vulkan_device.GetValue();
-    if (device_index < 0 || device_index >= static_cast<s32>(devices.size())) {
-        LOG_ERROR(Render_Vulkan, "Invalid device index {}!", device_index);
-        throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
-    }
-    const vk::PhysicalDevice physical_device(devices[static_cast<size_t>(device_index)], dld);
-    device = std::make_unique<Device>(*instance, physical_device, *surface, dld);
-}
-
 void RendererVulkan::Report() const {
-    const std::string vendor_name{device->GetVendorName()};
-    const std::string model_name{device->GetModelName()};
-    const std::string driver_version = GetDriverVersion(*device);
+    const std::string vendor_name{device.GetVendorName()};
+    const std::string model_name{device.GetModelName()};
+    const std::string driver_version = GetDriverVersion(device);
     const std::string driver_name = fmt::format("{} {}", vendor_name, driver_version);
 
-    const std::string api_version = GetReadableVersion(device->ApiVersion());
+    const std::string api_version = GetReadableVersion(device.ApiVersion());
 
-    const std::string extensions = BuildCommaSeparatedExtensions(device->GetAvailableExtensions());
+    const std::string extensions = BuildCommaSeparatedExtensions(device.GetAvailableExtensions());
 
     LOG_INFO(Render_Vulkan, "Driver: {}", driver_name);
     LOG_INFO(Render_Vulkan, "Device: {}", model_name);
@@ -209,21 +179,4 @@ void RendererVulkan::Report() const {
     telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions);
 }
 
-std::vector<std::string> RendererVulkan::EnumerateDevices() try {
-    vk::InstanceDispatch dld;
-    const Common::DynamicLibrary library = OpenLibrary();
-    const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_0);
-    const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
-    std::vector<std::string> names;
-    names.reserve(physical_devices.size());
-    for (const VkPhysicalDevice device : physical_devices) {
-        names.push_back(vk::PhysicalDevice(device, dld).GetProperties().deviceName);
-    }
-    return names;
-
-} catch (const vk::Exception& exception) {
-    LOG_ERROR(Render_Vulkan, "Failed to enumerate devices with error: {}", exception.what());
-    return {};
-}
-
 } // namespace Vulkan

+ 17 - 26
src/video_core/renderer_vulkan/renderer_vulkan.h

@@ -9,8 +9,14 @@
 #include <vector>
 
 #include "common/dynamic_library.h"
-
 #include "video_core/renderer_base.h"
+#include "video_core/renderer_vulkan/vk_blit_screen.h"
+#include "video_core/renderer_vulkan/vk_rasterizer.h"
+#include "video_core/renderer_vulkan/vk_scheduler.h"
+#include "video_core/renderer_vulkan/vk_state_tracker.h"
+#include "video_core/renderer_vulkan/vk_swapchain.h"
+#include "video_core/vulkan_common/vulkan_device.h"
+#include "video_core/vulkan_common/vulkan_memory_allocator.h"
 #include "video_core/vulkan_common/vulkan_wrapper.h"
 
 namespace Core {
@@ -27,20 +33,6 @@ class GPU;
 
 namespace Vulkan {
 
-class Device;
-class StateTracker;
-class MemoryAllocator;
-class VKBlitScreen;
-class VKSwapchain;
-class VKScheduler;
-
-struct VKScreenInfo {
-    VkImageView image_view{};
-    u32 width{};
-    u32 height{};
-    bool is_srgb{};
-};
-
 class RendererVulkan final : public VideoCore::RendererBase {
 public:
     explicit RendererVulkan(Core::TelemetrySession& telemtry_session,
@@ -49,15 +41,13 @@ public:
                             std::unique_ptr<Core::Frontend::GraphicsContext> context_);
     ~RendererVulkan() override;
 
-    bool Init() override;
-    void ShutDown() override;
     void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override;
 
-    static std::vector<std::string> EnumerateDevices();
+    VideoCore::RasterizerInterface* ReadRasterizer() override {
+        return &rasterizer;
+    }
 
 private:
-    void InitializeDevice();
-
     void Report() const;
 
     Core::TelemetrySession& telemetry_session;
@@ -74,12 +64,13 @@ private:
     VKScreenInfo screen_info;
 
     vk::DebugUtilsMessenger debug_callback;
-    std::unique_ptr<Device> device;
-    std::unique_ptr<MemoryAllocator> memory_allocator;
-    std::unique_ptr<StateTracker> state_tracker;
-    std::unique_ptr<VKScheduler> scheduler;
-    std::unique_ptr<VKSwapchain> swapchain;
-    std::unique_ptr<VKBlitScreen> blit_screen;
+    Device device;
+    MemoryAllocator memory_allocator;
+    StateTracker state_tracker;
+    VKScheduler scheduler;
+    VKSwapchain swapchain;
+    VKBlitScreen blit_screen;
+    RasterizerVulkan rasterizer;
 };
 
 } // namespace Vulkan

+ 4 - 7
src/video_core/renderer_vulkan/vk_blit_screen.cpp

@@ -18,7 +18,6 @@
 #include "video_core/gpu.h"
 #include "video_core/host_shaders/vulkan_present_frag_spv.h"
 #include "video_core/host_shaders/vulkan_present_vert_spv.h"
-#include "video_core/rasterizer_interface.h"
 #include "video_core/renderer_vulkan/renderer_vulkan.h"
 #include "video_core/renderer_vulkan/vk_blit_screen.h"
 #include "video_core/renderer_vulkan/vk_master_semaphore.h"
@@ -113,13 +112,12 @@ struct VKBlitScreen::BufferData {
 };
 
 VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_,
-                           Core::Frontend::EmuWindow& render_window_,
-                           VideoCore::RasterizerInterface& rasterizer_, const Device& device_,
+                           Core::Frontend::EmuWindow& render_window_, const Device& device_,
                            MemoryAllocator& memory_allocator_, VKSwapchain& swapchain_,
                            VKScheduler& scheduler_, const VKScreenInfo& screen_info_)
-    : cpu_memory{cpu_memory_}, render_window{render_window_}, rasterizer{rasterizer_},
-      device{device_}, memory_allocator{memory_allocator_}, swapchain{swapchain_},
-      scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} {
+    : cpu_memory{cpu_memory_}, render_window{render_window_}, device{device_},
+      memory_allocator{memory_allocator_}, swapchain{swapchain_}, scheduler{scheduler_},
+      image_count{swapchain.GetImageCount()}, screen_info{screen_info_} {
     resource_ticks.resize(image_count);
 
     CreateStaticResources();
@@ -159,7 +157,6 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool
         const VAddr framebuffer_addr = framebuffer.address + framebuffer.offset;
         const u8* const host_ptr = cpu_memory.GetPointer(framebuffer_addr);
         const size_t size_bytes = GetSizeInBytes(framebuffer);
-        rasterizer.FlushRegion(ToCacheAddr(host_ptr), size_bytes);
 
         // TODO(Rodrigo): Read this from HLE
         constexpr u32 block_height_log2 = 4;

+ 10 - 5
src/video_core/renderer_vulkan/vk_blit_screen.h

@@ -38,12 +38,18 @@ class RasterizerVulkan;
 class VKScheduler;
 class VKSwapchain;
 
-class VKBlitScreen final {
+struct VKScreenInfo {
+    VkImageView image_view{};
+    u32 width{};
+    u32 height{};
+    bool is_srgb{};
+};
+
+class VKBlitScreen {
 public:
     explicit VKBlitScreen(Core::Memory::Memory& cpu_memory,
-                          Core::Frontend::EmuWindow& render_window,
-                          VideoCore::RasterizerInterface& rasterizer, const Device& device,
-                          MemoryAllocator& memory_allocator, VKSwapchain& swapchain,
+                          Core::Frontend::EmuWindow& render_window, const Device& device,
+                          MemoryAllocator& memory_manager, VKSwapchain& swapchain,
                           VKScheduler& scheduler, const VKScreenInfo& screen_info);
     ~VKBlitScreen();
 
@@ -84,7 +90,6 @@ private:
 
     Core::Memory::Memory& cpu_memory;
     Core::Frontend::EmuWindow& render_window;
-    VideoCore::RasterizerInterface& rasterizer;
     const Device& device;
     MemoryAllocator& memory_allocator;
     VKSwapchain& swapchain;

+ 5 - 2
src/video_core/renderer_vulkan/vk_swapchain.cpp

@@ -56,8 +56,11 @@ VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 wi
 
 } // Anonymous namespace
 
-VKSwapchain::VKSwapchain(VkSurfaceKHR surface_, const Device& device_, VKScheduler& scheduler_)
-    : surface{surface_}, device{device_}, scheduler{scheduler_} {}
+VKSwapchain::VKSwapchain(VkSurfaceKHR surface_, const Device& device_, VKScheduler& scheduler_,
+                         u32 width, u32 height, bool srgb)
+    : surface{surface_}, device{device_}, scheduler{scheduler_} {
+    Create(width, height, srgb);
+}
 
 VKSwapchain::~VKSwapchain() = default;
 

+ 2 - 1
src/video_core/renderer_vulkan/vk_swapchain.h

@@ -20,7 +20,8 @@ class VKScheduler;
 
 class VKSwapchain {
 public:
-    explicit VKSwapchain(VkSurfaceKHR surface, const Device& device, VKScheduler& scheduler);
+    explicit VKSwapchain(VkSurfaceKHR surface, const Device& device, VKScheduler& scheduler,
+                         u32 width, u32 height, bool srgb);
     ~VKSwapchain();
 
     /// Creates (or recreates) the swapchain with a given size.

+ 9 - 10
src/video_core/video_core.cpp

@@ -38,19 +38,18 @@ namespace VideoCore {
 
 std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system) {
     const bool use_nvdec = Settings::values.use_nvdec_emulation.GetValue();
-    std::unique_ptr<Tegra::GPU> gpu = std::make_unique<Tegra::GPU>(
-        system, Settings::values.use_asynchronous_gpu_emulation.GetValue(), use_nvdec);
-
+    const bool use_async = Settings::values.use_asynchronous_gpu_emulation.GetValue();
+    auto gpu = std::make_unique<Tegra::GPU>(system, use_async, use_nvdec);
     auto context = emu_window.CreateSharedContext();
-    const auto scope = context->Acquire();
-
-    auto renderer = CreateRenderer(system, emu_window, *gpu, std::move(context));
-    if (!renderer->Init()) {
+    auto scope = context->Acquire();
+    try {
+        auto renderer = CreateRenderer(system, emu_window, *gpu, std::move(context));
+        gpu->BindRenderer(std::move(renderer));
+        return gpu;
+    } catch (const std::runtime_error& exception) {
+        LOG_ERROR(HW_GPU, "Failed to initialize GPU: {}", exception.what());
         return nullptr;
     }
-
-    gpu->BindRenderer(std::move(renderer));
-    return gpu;
 }
 
 u16 GetResolutionScaleFactor(const RendererBase& renderer) {

+ 1 - 1
src/video_core/vulkan_common/vulkan_device.h

@@ -23,7 +23,7 @@ enum class FormatType { Linear, Optimal, Buffer };
 const u32 GuestWarpSize = 32;
 
 /// Handles data specific to a physical device.
-class Device final {
+class Device {
 public:
     explicit Device(VkInstance instance, vk::PhysicalDevice physical, VkSurfaceKHR surface,
                     const vk::InstanceDispatch& dld);

+ 3 - 0
src/video_core/vulkan_common/vulkan_wrapper.h

@@ -344,6 +344,9 @@ public:
     /// Construct an empty handle.
     Handle() = default;
 
+    /// Construct an empty handle.
+    Handle(std::nullptr_t) {}
+
     /// Copying Vulkan objects is not supported and will never be.
     Handle(const Handle&) = delete;
     Handle& operator=(const Handle&) = delete;

+ 1 - 1
src/yuzu/bootmanager.cpp

@@ -64,7 +64,7 @@ void EmuThread::run() {
 
     emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0);
 
-    system.Renderer().Rasterizer().LoadDiskResources(
+    system.Renderer().ReadRasterizer()->LoadDiskResources(
         system.CurrentProcess()->GetTitleID(), stop_run,
         [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) {
             emit LoadProgress(stage, value, total);

+ 16 - 3
src/yuzu/configuration/configure_graphics.cpp

@@ -11,7 +11,8 @@
 #include "core/core.h"
 #include "core/settings.h"
 #include "ui_configure_graphics.h"
-#include "video_core/renderer_vulkan/renderer_vulkan.h"
+#include "video_core/vulkan_common/vulkan_instance.h"
+#include "video_core/vulkan_common/vulkan_library.h"
 #include "yuzu/configuration/configuration_shared.h"
 #include "yuzu/configuration/configure_graphics.h"
 
@@ -212,11 +213,23 @@ void ConfigureGraphics::UpdateDeviceComboBox() {
     ui->device->setEnabled(enabled && !Core::System::GetInstance().IsPoweredOn());
 }
 
-void ConfigureGraphics::RetrieveVulkanDevices() {
+void ConfigureGraphics::RetrieveVulkanDevices() try {
+    using namespace Vulkan;
+
+    vk::InstanceDispatch dld;
+    const Common::DynamicLibrary library = OpenLibrary();
+    const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_0);
+    const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices();
+
     vulkan_devices.clear();
-    for (const auto& name : Vulkan::RendererVulkan::EnumerateDevices()) {
+    vulkan_devices.reserve(physical_devices.size());
+    for (const VkPhysicalDevice device : physical_devices) {
+        const char* const name = vk::PhysicalDevice(device, dld).GetProperties().deviceName;
         vulkan_devices.push_back(QString::fromStdString(name));
     }
+
+} catch (const Vulkan::vk::Exception& exception) {
+    LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what());
 }
 
 Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const {

+ 1 - 1
src/yuzu_cmd/yuzu.cpp

@@ -215,7 +215,7 @@ int main(int argc, char** argv) {
     // Core is loaded, start the GPU (makes the GPU contexts current to this thread)
     system.GPU().Start();
 
-    system.Renderer().Rasterizer().LoadDiskResources(
+    system.Renderer().ReadRasterizer()->LoadDiskResources(
         system.CurrentProcess()->GetTitleID(), false,
         [](VideoCore::LoadCallbackStage, size_t value, size_t total) {});