mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Merge pull request #22171 from hrydgard/vulkan-surface-init-errors
Vulkan: Report surface init failures instead of asserting later
This commit is contained in:
6 files changed
+39
-11
No files matched your search
@@ -1316,10 +1316,14 @@ VkResult VulkanContext::ReinitSurface() {
|
||||
}
|
||||
|
||||
if (retval != VK_SUCCESS) {
|
||||
init_error_ = StringFromFormat("Failed to create a Vulkan surface for window system %s: %s", WindowSystemToString(winsys_), VulkanResultToString(retval));
|
||||
ERROR_LOG(Log::G3D, "%s", init_error_.c_str());
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (!ChooseQueue()) {
|
||||
init_error_ = "Failed to find a Vulkan queue and surface format that can present to the window";
|
||||
ERROR_LOG(Log::G3D, "%s", init_error_.c_str());
|
||||
return VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
|
||||
@@ -1337,6 +1341,13 @@ VkResult VulkanContext::ReinitSurface() {
|
||||
res = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_devices_[physical_device_], surface_, &presentModeCount, availablePresentModes_.data());
|
||||
_dbg_assert_(res == VK_SUCCESS);
|
||||
}
|
||||
if (res != VK_SUCCESS || availablePresentModes_.empty()) {
|
||||
// Should be impossible - the spec guarantees at least FIFO for any surface we could create.
|
||||
availablePresentModes_.clear();
|
||||
init_error_ = StringFromFormat("Failed to enumerate Vulkan present modes: %s (count %d)", VulkanResultToString(res), (int)presentModeCount);
|
||||
ERROR_LOG(Log::G3D, "%s", init_error_.c_str());
|
||||
return res != VK_SUCCESS ? res : VK_ERROR_INITIALIZATION_FAILED;
|
||||
}
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@
|
||||
#include "Common/GPU/Vulkan/VulkanRenderManager.h"
|
||||
#include "Common/GPU/Vulkan/VulkanGraphicsContext.h"
|
||||
#include "Common/Data/Text/Parsers.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "GPU/Vulkan/VulkanUtil.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
@@ -119,7 +120,17 @@ bool VulkanGraphicsContext::InitAPI(void *wnd, std::string *deviceName, std::str
|
||||
}
|
||||
|
||||
bool VulkanGraphicsContext::InitSurface(WindowSystem winsys, void *data1, void *data2, std::string *errorMessage) {
|
||||
vulkan_->InitSurface(winsys, data1, data2);
|
||||
// Don't proceed on failure - without a surface there's no present mode, no swapchain and no queue,
|
||||
// so everything below would just fail in more confusing ways further down (it used to assert deep
|
||||
// inside the thin3d context constructor). Let the caller fall back to another backend instead.
|
||||
VkResult res = vulkan_->InitSurface(winsys, data1, data2);
|
||||
if (res != VK_SUCCESS) {
|
||||
*errorMessage = vulkan_->InitError();
|
||||
if (errorMessage->empty()) {
|
||||
*errorMessage = StringFromFormat("Failed to initialize Vulkan surface: %s", VulkanResultToString(res));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool useMultiThreading = g_Config.bRenderMultiThreading;
|
||||
if (g_Config.iInflightFrames == 1) {
|
||||
|
||||
+4
-5
@@ -126,14 +126,13 @@ bool RunMainLoop(GraphicsContext *graphicsContext, Application *application, std
|
||||
}
|
||||
|
||||
// Call InitAPI and ShutdownAPI outside this!
|
||||
bool MainThreadFunc(GraphicsContext *graphicsContext, Application *application, const WindowDesc &windowDesc, std::function<bool(GraphicsContext *)> frame) {
|
||||
bool MainThreadFunc(GraphicsContext *graphicsContext, Application *application, const WindowDesc &windowDesc, std::function<bool(GraphicsContext *)> frame, std::string *errorMessage) {
|
||||
// This is now the render thread, and will spawn the emu thread below.
|
||||
std::string error_string;
|
||||
bool success = graphicsContext->InitSurface(windowDesc.winsys, windowDesc.data1, windowDesc.data2, &error_string);
|
||||
if (!success) {
|
||||
if (!graphicsContext->InitSurface(windowDesc.winsys, windowDesc.data1, windowDesc.data2, errorMessage)) {
|
||||
ERROR_LOG(Log::G3D, "MainThreadFunc: InitSurface failed: %s", errorMessage->c_str());
|
||||
delete application;
|
||||
return false;
|
||||
}
|
||||
std::string errorMessage;
|
||||
if (graphicsContext->NeedsSeparateEmuThread()) {
|
||||
SetCurrentThreadName("RenderThread");
|
||||
|
||||
|
||||
+4
-1
@@ -18,6 +18,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "Common/System/Application.h"
|
||||
@@ -34,7 +35,9 @@ struct WindowDesc;
|
||||
// This should be used by platforms that launch a separate thread and doesn't
|
||||
// need to run a polling loop in it.
|
||||
// NOTE: Does take ownership over Application (which is just a wrapper for NativeInitGraphics/NativeShutdownGraphics/NativeFrame).
|
||||
bool MainThreadFunc(GraphicsContext * graphicsContext, Application *application, const WindowDesc &windowDesc, std::function<bool(GraphicsContext *)> frame);
|
||||
// On failure (which currently only means the graphics surface couldn't be initialized), errorMessage
|
||||
// gets the reason - pass it on to the user, it's the only place it's available.
|
||||
bool MainThreadFunc(GraphicsContext * graphicsContext, Application *application, const WindowDesc &windowDesc, std::function<bool(GraphicsContext *)> frame, std::string *errorMessage);
|
||||
|
||||
// If you're not using MainThreadFunc, you can at least use these to manage a spinning EmuThread (that calls NativeFrame),
|
||||
// whether your graphics context requires multithreading or not. Then use RunMainLoop to implement your main loop for
|
||||
|
||||
+2
-2
@@ -1251,8 +1251,8 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
|
||||
[](GraphicsContext *graphicsContext) {
|
||||
NativeFrame(graphicsContext);
|
||||
return GetUIState() != UISTATE_EXIT;
|
||||
})) {
|
||||
HandleGraphicsFailure("Failed to initialize main thread function.");
|
||||
}, &errorMessage)) {
|
||||
HandleGraphicsFailure(errorMessage);
|
||||
return;
|
||||
}
|
||||
graphicsContext->ShutdownAPI();
|
||||
|
||||
@@ -884,10 +884,14 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
|
||||
int retval = 0;
|
||||
MainThreadFunc(graphicsContext, new HeadlessApplication(), windowDesc, [&retval, &coreParameter, &testOptions, &testFilenames](GraphicsContext *graphicsContext) {
|
||||
if (!MainThreadFunc(graphicsContext, new HeadlessApplication(), windowDesc, [&retval, &coreParameter, &testOptions, &testFilenames](GraphicsContext *graphicsContext) {
|
||||
retval = RunTests(graphicsContext, coreParameter, testOptions, testFilenames);
|
||||
return false;
|
||||
});
|
||||
}, &errorMessage)) {
|
||||
// No fallbacks in headless - if we can't run it, we can't. Let's not get confusing.
|
||||
fprintf(stderr, "Failed to initialize graphics surface: %s\n", errorMessage.c_str());
|
||||
retval = 1;
|
||||
}
|
||||
|
||||
graphicsContext->ShutdownAPI();
|
||||
|
||||
|
||||
Reference in new issue
Block a user