Show a popup error if love.window loads but love.graphics does not.

Also include backend-specific errors in graphics initalization error messages.
Improves visibility of errors related to vulkan/metal/opengl initialization.
Related to #2335.
This commit is contained in:
Sasha Szpakowski
2026-07-12 11:01:02 -03:00
parent 540e681454
commit e47acd766d
6 changed files with 48 additions and 27 deletions
+23 -7
View File
@@ -36,6 +36,7 @@
// C++
#include <algorithm>
#include <tuple>
#include <stdlib.h>
namespace love
@@ -106,12 +107,12 @@ bool isDebugEnabled()
love::Type Graphics::type("graphics", &Module::type);
namespace opengl { extern love::graphics::Graphics *createInstance(); }
namespace opengl { extern std::tuple<love::graphics::Graphics *, std::string> createInstance(); }
#ifdef LOVE_GRAPHICS_METAL
namespace metal { extern love::graphics::Graphics *createInstance(); }
namespace metal { extern std::tuple<love::graphics::Graphics *, std::string> createInstance(); }
#endif
#ifdef LOVE_GRAPHICS_VULKAN
namespace vulkan { extern love::graphics::Graphics *createInstance(); }
namespace vulkan { extern std::tuple<love::graphics::Graphics *, std::string> createInstance(); }
#endif
static const Renderer rendererOrder[] = {
@@ -164,6 +165,7 @@ bool isLowPowerPreferred()
Graphics *Graphics::createInstance()
{
Graphics *instance = Module::getInstance<Graphics>(M_GRAPHICS);
std::string errors;
if (instance != nullptr)
instance->retain();
@@ -171,25 +173,39 @@ Graphics *Graphics::createInstance()
{
for (auto r : rendererOrder)
{
if (std::find(_renderers.begin(), _renderers.end(), r) == _renderers.end())
continue;
std::string err;
#ifdef LOVE_GRAPHICS_VULKAN
if (r == RENDERER_VULKAN)
instance = vulkan::createInstance();
std::tie(instance, err) = vulkan::createInstance();
#endif
if (r == RENDERER_OPENGL)
instance = opengl::createInstance();
std::tie(instance, err) = opengl::createInstance();
#ifdef LOVE_GRAPHICS_METAL
if (r == RENDERER_METAL)
instance = metal::createInstance();
std::tie(instance, err) = metal::createInstance();
#endif
if (!err.empty())
{
errors += err;
if (isDebugEnabled())
::printf("%s", err.c_str());
}
if (instance != nullptr)
break;
}
}
if (instance == nullptr)
{
throw love::Exception("Cannot create graphics: no supported renderer on this system.\n%s", errors.c_str());
}
return instance;
}
+6 -3
View File
@@ -29,6 +29,8 @@
#include "image/Image.h"
#include "common/memory.h"
#include <tuple>
#import <QuartzCore/CAMetalLayer.h>
#ifdef LOVE_MACOS
@@ -239,9 +241,10 @@ static inline void setSampler(id<MTLComputeCommandEncoder> encoder, Graphics::Re
}
}
love::graphics::Graphics *createInstance()
std::tuple<love::graphics::Graphics *, std::string> createInstance()
{
love::graphics::Graphics *instance = nullptr;
std::string err;
try
{
@@ -249,10 +252,10 @@ love::graphics::Graphics *createInstance()
}
catch (love::Exception &e)
{
printf("Cannot create Metal renderer: %s\n", e.what());
err = "Cannot create Metal renderer: " + std::string(e.what()) + "\n";
}
return instance;
return { instance, err };
}
struct DefaultVertexAttributes
+5 -3
View File
@@ -39,6 +39,7 @@
#include <sstream>
#include <algorithm>
#include <iterator>
#include <tuple>
// C
#include <cmath>
@@ -89,9 +90,10 @@ static GLenum getGLBlendFactor(BlendFactor factor)
return 0;
}
love::graphics::Graphics *createInstance()
std::tuple<love::graphics::Graphics *, std::string> createInstance()
{
love::graphics::Graphics *instance = nullptr;
std::string err;
try
{
@@ -99,10 +101,10 @@ love::graphics::Graphics *createInstance()
}
catch (love::Exception &e)
{
printf("Cannot create OpenGL renderer: %s\n", e.what());
err = "Cannot create OpenGL renderer: " + std::string(e.what()) + "\n";
}
return instance;
return { instance, err };
}
Graphics::Graphics()
+5 -4
View File
@@ -39,6 +39,7 @@
#include <set>
#include <sstream>
#include <array>
#include <tuple>
#define VOLK_IMPLEMENTATION
#include "libraries/volk/volk.h"
@@ -3603,9 +3604,10 @@ void Graphics::recreateSwapChain()
transitionColorDepthLayouts = true;
}
love::graphics::Graphics *createInstance()
std::tuple<love::graphics::Graphics *, std::string> createInstance()
{
love::graphics::Graphics *instance = nullptr;
std::string err;
try
{
@@ -3613,11 +3615,10 @@ love::graphics::Graphics *createInstance()
}
catch (love::Exception &e)
{
if (isDebugEnabled())
printf("Cannot create Vulkan renderer: %s\n", e.what());
err = "Cannot create Vulkan renderer: " + std::string(e.what()) + "\n";
}
return instance;
return { instance, err };
}
} // vulkan
+2 -7
View File
@@ -4208,13 +4208,8 @@ static const lua_CFunction types[] =
extern "C" int luaopen_love_graphics(lua_State *L)
{
Graphics *instance = Graphics::createInstance();
if (instance == nullptr)
{
printf("Cannot create graphics: no supported renderer on this system.\n");
return luaL_error(L, "Cannot create graphics: no supported renderer on this system.");
}
Graphics *instance = nullptr;
luax_catchexcept(L, [&]() { instance = Graphics::createInstance(); });
WrappedModule w;
w.module = instance;
+7 -3
View File
@@ -223,13 +223,17 @@ function love.errorhandler(msg)
error_printer(msg, 2)
if not love.window or not love.graphics or not love.event then
if not love.window then
return
end
if not love.graphics.isCreated() or not love.window.isOpen() then
local success, status = pcall(love.window.setMode, 800, 600)
if not love.graphics or not love.event or not love.graphics.isCreated() or not love.window.isOpen() then
local success, status
if love.graphics and love.event then
success, status = pcall(love.window.setMode, 800, 600)
end
if not success or not status then
love.window.showMessageBox("Error during startup", msg, "error", false)
return
end
end