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.
This commit is contained in:
parent
19156292a3
commit
75ccd9959c
27 changed files with 176 additions and 232 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue