Skip to content

Commit

Permalink
vulkan: improve module initialization code to exit to other backends …
Browse files Browse the repository at this point in the history
…if there's a device but it's not suitable for love.

Disallow software rendering (CPU devices) with vulkan by default. The environment variable LOVE_GRAPHICS_VULKAN_ALLOW_SOFTWARE can be set to 1 to override that behaviour.
  • Loading branch information
slime73 committed Jan 11, 2025
1 parent 21c9c06 commit 652b012
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 9 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ jobs:
- name: Run Test Suite (vulkan)
env:
LOVE_GRAPHICS_DEBUG: 1
LOVE_GRAPHICS_VULKAN_ALLOW_SOFTWARE: 1
run: |
./love-${{ github.sha }}.AppImage love2d-${{ github.sha }}/testing/main.lua --all --isRunner --renderers vulkan
- name: Love Test Report (vulkan)
Expand Down Expand Up @@ -390,6 +391,7 @@ jobs:
# if: steps.vars.outputs.arch != 'ARM64'
# env:
# LOVE_GRAPHICS_DEBUG: 1
# LOVE_GRAPHICS_VULKAN_ALLOW_SOFTWARE: 1
# run: |
# powershell.exe ./install/lovec.exe ./megasource/libs/love/testing/main.lua --all --isRunner --renderers vulkan
# - name: Love Test Report (vulkan)
Expand Down
61 changes: 53 additions & 8 deletions src/modules/graphics/vulkan/Graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "Vulkan.h"

#include <SDL3/SDL_vulkan.h>
#include <SDL3/SDL_hints.h>

#include <algorithm>
#include <vector>
Expand Down Expand Up @@ -100,7 +101,10 @@ Graphics::Graphics()
volkInitializeCustom((PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr());

if (isDebugEnabled() && !checkValidationSupport())
{
SDL_Vulkan_UnloadLibrary();
throw love::Exception("validation layers requested, but not available");
}

VkApplicationInfo appInfo{};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
Expand All @@ -120,7 +124,10 @@ Graphics::Graphics()
unsigned int count = 0;
char const* const* extensions_string = SDL_Vulkan_GetInstanceExtensions(&count);
if (extensions_string == nullptr)
{
SDL_Vulkan_UnloadLibrary();
throw love::Exception("couldn't retrieve sdl vulkan extensions");
}

std::vector<const char*> extensions(extensions_string, extensions_string + count);

Expand All @@ -141,9 +148,38 @@ Graphics::Graphics()
}

if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS)
{
SDL_Vulkan_UnloadLibrary();
throw love::Exception("couldn't create vulkan instance");
}

volkLoadInstance(instance);

uint32_t deviceCount = 0;
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);

int maxScore = 0;

if (deviceCount > 0)
{
std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());

// This is imperfect because we can't query a swap chain at this point.
// In theory it could cause a device to have a non-zero score here and
// no devices to have a non-zero score later in setMode, but hopefully
// that won't happen in practice...
for (const auto &device : devices)
maxScore = std::max(maxScore, rateDeviceSuitability(device, false));
}

// Exit here if there are no suitable devices, to let other backends take over.
if (maxScore == 0)
{
vkDestroyInstance(instance, nullptr);
SDL_Vulkan_UnloadLibrary();
throw love::Exception("no suitable vulkan physical devices found");
}
}

Graphics::~Graphics()
Expand Down Expand Up @@ -1535,7 +1571,7 @@ void Graphics::pickPhysicalDevice()

for (const auto &device : devices)
{
int score = rateDeviceSuitability(device);
int score = rateDeviceSuitability(device, true);
candidates.insert(std::make_pair(score, device));
}

Expand Down Expand Up @@ -1583,7 +1619,7 @@ bool Graphics::checkDeviceExtensionSupport(VkPhysicalDevice device)
// if the score is nonzero then the device is suitable.
// A higher rating means generally better performance
// if the score is 0 the device is unsuitable
int Graphics::rateDeviceSuitability(VkPhysicalDevice device)
int Graphics::rateDeviceSuitability(VkPhysicalDevice device, bool querySwapChain)
{
VkPhysicalDeviceProperties deviceProperties;
VkPhysicalDeviceFeatures deviceFeatures;
Expand All @@ -1603,15 +1639,21 @@ int Graphics::rateDeviceSuitability(VkPhysicalDevice device)

// definitely needed

if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU)
{
if (!SDL_GetHintBoolean("LOVE_GRAPHICS_VULKAN_ALLOW_SOFTWARE", false))
score = 0;
}

QueueFamilyIndices indices = findQueueFamilies(device);
if (!indices.isComplete())
if (!indices.isComplete() && (querySwapChain || !indices.graphicsFamily.hasValue))
score = 0;

bool extensionsSupported = checkDeviceExtensionSupport(device);
if (!extensionsSupported)
score = 0;

if (extensionsSupported)
if (extensionsSupported && querySwapChain)
{
auto swapChainSupport = querySwapChainSupport(device);
bool swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
Expand Down Expand Up @@ -1644,11 +1686,14 @@ QueueFamilyIndices Graphics::findQueueFamilies(VkPhysicalDevice device)
if ((queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) && (queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT))
indices.graphicsFamily = i;

VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
if (surface != VK_NULL_HANDLE)
{
VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);

if (presentSupport)
indices.presentFamily = i;
if (presentSupport)
indices.presentFamily = i;
}

if (indices.isComplete())
break;
Expand Down
2 changes: 1 addition & 1 deletion src/modules/graphics/vulkan/Graphics.h
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ class Graphics final : public love::graphics::Graphics
private:
bool checkValidationSupport();
void pickPhysicalDevice();
int rateDeviceSuitability(VkPhysicalDevice device);
int rateDeviceSuitability(VkPhysicalDevice device, bool querySwapChain);
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device);
void createLogicalDevice();
void createPipelineCache();
Expand Down

0 comments on commit 652b012

Please sign in to comment.