vulkan: use dynamic loading

If Vulkan ist not available on a system the program will still run,
and it will fallback to opengl.
This commit is contained in:
niki
2022-09-13 14:11:24 +02:00
parent fb44ddb546
commit 6a2d1a9edd
4 changed files with 25 additions and 132 deletions
+2 -8
View File
@@ -107,7 +107,6 @@ if(MEGA)
${MEGA_SDL2MAIN} ${MEGA_SDL2MAIN}
${MEGA_SDL2} ${MEGA_SDL2}
${MEGA_ZLIB} ${MEGA_ZLIB}
${Vulkan_LIBRARIES}
) )
# These DLLs are moved next to the love binary in a post-build step to # These DLLs are moved next to the love binary in a post-build step to
@@ -202,7 +201,6 @@ Please see https://github.com/love2d/megasource
${LOVE_LUA_LIBRARY} ${LOVE_LUA_LIBRARY}
${OGG_LIBRARY} ${OGG_LIBRARY}
${ZLIB_LIBRARY} ${ZLIB_LIBRARY}
${Vulkan_LIBRARIES}
) )
if(LOVE_JIT) if(LOVE_JIT)
@@ -613,16 +611,12 @@ set(LOVE_SRC_MODULE_GRAPHICS_VULKAN
src/modules/graphics/vulkan/Texture.cpp src/modules/graphics/vulkan/Texture.cpp
src/modules/graphics/vulkan/Vulkan.h src/modules/graphics/vulkan/Vulkan.h
src/modules/graphics/vulkan/Vulkan.cpp src/modules/graphics/vulkan/Vulkan.cpp
src/modules/graphics/vulkan/volk.h
src/modules/graphics/vulkan/volk.cpp
src/modules/graphics/vulkan/vk_mem_alloc.h src/modules/graphics/vulkan/vk_mem_alloc.h
src/modules/graphics/vulkan/UseVMA.cpp src/modules/graphics/vulkan/UseVMA.cpp
src/modules/graphics/vulkan/VulkanWrapper.h) src/modules/graphics/vulkan/VulkanWrapper.h)
if(ANDROID)
set(LOVE_SRC_MODULE_GRAPHICS_VULKAN ${LOVE_SRC_MODULE_GRAPHICS_VULKAN}
src/modules/graphics/vulkan/volk.h
src/modules/graphics/vulkan/volk.cpp)
endif()
set(LOVE_SRC_MODULE_GRAPHICS set(LOVE_SRC_MODULE_GRAPHICS
${LOVE_SRC_MODULE_GRAPHICS_ROOT} ${LOVE_SRC_MODULE_GRAPHICS_ROOT}
${LOVE_SRC_MODULE_GRAPHICS_OPENGL} ${LOVE_SRC_MODULE_GRAPHICS_OPENGL}
+21 -77
View File
@@ -63,6 +63,13 @@ const VmaAllocator Graphics::getVmaAllocator() const
return vmaAllocator; return vmaAllocator;
} }
Graphics::Graphics() {
auto result = volkInitialize();
if (result != VK_SUCCESS) {
throw love::Exception("could not initialize volk");
}
}
Graphics::~Graphics() Graphics::~Graphics()
{ {
// We already cleaned those up by clearing out batchedDrawBuffers. // We already cleaned those up by clearing out batchedDrawBuffers.
@@ -498,7 +505,7 @@ void Graphics::setFrontFaceWinding(Winding winding)
states.back().winding = winding; states.back().winding = winding;
if (optionalDeviceFeatures.extendedDynamicState) if (optionalDeviceFeatures.extendedDynamicState)
ext.vkCmdSetFrontFaceEXT( vkCmdSetFrontFaceEXT(
commandBuffers.at(currentFrame), commandBuffers.at(currentFrame),
Vulkan::getFrontFace(winding)); Vulkan::getFrontFace(winding));
} }
@@ -584,7 +591,7 @@ void Graphics::draw(const DrawIndexedCommand &cmd)
commandBuffers.at(currentFrame), commandBuffers.at(currentFrame),
(VkBuffer)cmd.indexBuffer->getHandle(), (VkBuffer)cmd.indexBuffer->getHandle(),
static_cast<VkDeviceSize>(cmd.indexBufferOffset), static_cast<VkDeviceSize>(cmd.indexBufferOffset),
Vulkan::getVulkanIndexBufferType(cmd.indexType)) Vulkan::getVulkanIndexBufferType(cmd.indexType));
vkCmdDrawIndexed( vkCmdDrawIndexed(
commandBuffers.at(currentFrame), commandBuffers.at(currentFrame),
static_cast<uint32_t>(cmd.indexCount), static_cast<uint32_t>(cmd.indexCount),
@@ -718,7 +725,7 @@ void Graphics::setStencilMode(StencilAction action, CompareMode compare, int val
vkCmdSetStencilReference(commandBuffers.at(currentFrame), VK_STENCIL_FACE_FRONT_AND_BACK, value); vkCmdSetStencilReference(commandBuffers.at(currentFrame), VK_STENCIL_FACE_FRONT_AND_BACK, value);
if (optionalDeviceFeatures.extendedDynamicState) if (optionalDeviceFeatures.extendedDynamicState)
ext.vkCmdSetStencilOpEXT( vkCmdSetStencilOpEXT(
commandBuffers.at(currentFrame), commandBuffers.at(currentFrame),
VK_STENCIL_FACE_FRONT_AND_BACK, VK_STENCIL_FACE_FRONT_AND_BACK,
VK_STENCIL_OP_KEEP, Vulkan::getStencilOp(action), VK_STENCIL_OP_KEEP, Vulkan::getStencilOp(action),
@@ -737,10 +744,10 @@ void Graphics::setDepthMode(CompareMode compare, bool write)
if (optionalDeviceFeatures.extendedDynamicState) if (optionalDeviceFeatures.extendedDynamicState)
{ {
ext.vkCmdSetDepthCompareOpEXT( vkCmdSetDepthCompareOpEXT(
commandBuffers.at(currentFrame), Vulkan::getCompareOp(compare)); commandBuffers.at(currentFrame), Vulkan::getCompareOp(compare));
ext.vkCmdSetDepthWriteEnableEXT( vkCmdSetDepthWriteEnableEXT(
commandBuffers.at(currentFrame), Vulkan::getBool(write)); commandBuffers.at(currentFrame), Vulkan::getBool(write));
} }
@@ -863,19 +870,19 @@ void Graphics::initDynamicState()
if (optionalDeviceFeatures.extendedDynamicState) if (optionalDeviceFeatures.extendedDynamicState)
{ {
ext.vkCmdSetStencilOpEXT( vkCmdSetStencilOpEXT(
commandBuffers.at(currentFrame), commandBuffers.at(currentFrame),
VK_STENCIL_FACE_FRONT_AND_BACK, VK_STENCIL_FACE_FRONT_AND_BACK,
VK_STENCIL_OP_KEEP, Vulkan::getStencilOp(states.back().stencil.action), VK_STENCIL_OP_KEEP, Vulkan::getStencilOp(states.back().stencil.action),
VK_STENCIL_OP_KEEP, Vulkan::getCompareOp(states.back().stencil.compare)); VK_STENCIL_OP_KEEP, Vulkan::getCompareOp(states.back().stencil.compare));
ext.vkCmdSetDepthCompareOpEXT( vkCmdSetDepthCompareOpEXT(
commandBuffers.at(currentFrame), Vulkan::getCompareOp(states.back().depthTest)); commandBuffers.at(currentFrame), Vulkan::getCompareOp(states.back().depthTest));
ext.vkCmdSetDepthWriteEnableEXT( vkCmdSetDepthWriteEnableEXT(
commandBuffers.at(currentFrame), Vulkan::getBool(states.back().depthWrite)); commandBuffers.at(currentFrame), Vulkan::getBool(states.back().depthWrite));
ext.vkCmdSetFrontFaceEXT( vkCmdSetFrontFaceEXT(
commandBuffers.at(currentFrame), Vulkan::getFrontFace(states.back().winding)); commandBuffers.at(currentFrame), Vulkan::getFrontFace(states.back().winding));
} }
} }
@@ -1131,9 +1138,7 @@ void Graphics::createVulkanInstance()
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS)
throw love::Exception("couldn't create vulkan instance"); throw love::Exception("couldn't create vulkan instance");
#ifdef LOVE_ANDROID
volkLoadInstance(instance); volkLoadInstance(instance);
#endif
} }
bool Graphics::checkValidationSupport() bool Graphics::checkValidationSupport()
@@ -1345,7 +1350,7 @@ void Graphics::createLogicalDevice()
optionalDeviceFeatures.memoryBudget = false; optionalDeviceFeatures.memoryBudget = false;
if (optionalDeviceFeatures.spirv14 && !optionalDeviceFeatures.shaderFloatControls) if (optionalDeviceFeatures.spirv14 && !optionalDeviceFeatures.shaderFloatControls)
optionalDeviceFeatures.spirv14 = false; optionalDeviceFeatures.spirv14 = false;
if (optionalDeviceFeatures.spirv14 && VK_API_VERSION_1_1 > vulkanApiVersion) if (optionalDeviceFeatures.spirv14 && vulkanApiVersion < VK_API_VERSION_1_1)
optionalDeviceFeatures.spirv14 = false; optionalDeviceFeatures.spirv14 = false;
VkPhysicalDeviceFeatures deviceFeatures{}; VkPhysicalDeviceFeatures deviceFeatures{};
@@ -1373,6 +1378,8 @@ void Graphics::createLogicalDevice()
enabledExtensions.push_back(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME); enabledExtensions.push_back(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);
if (optionalDeviceFeatures.spirv14) if (optionalDeviceFeatures.spirv14)
enabledExtensions.push_back(VK_KHR_SPIRV_1_4_EXTENSION_NAME); enabledExtensions.push_back(VK_KHR_SPIRV_1_4_EXTENSION_NAME);
if (vulkanApiVersion >= VK_API_VERSION_1_1)
enabledExtensions.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
createInfo.enabledExtensionCount = static_cast<uint32_t>(enabledExtensions.size()); createInfo.enabledExtensionCount = static_cast<uint32_t>(enabledExtensions.size());
createInfo.ppEnabledExtensionNames = enabledExtensions.data(); createInfo.ppEnabledExtensionNames = enabledExtensions.data();
@@ -1395,67 +1402,10 @@ void Graphics::createLogicalDevice()
if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS)
throw love::Exception("failed to create logical device"); throw love::Exception("failed to create logical device");
#ifdef LOVE_ANDROID
volkLoadDevice(device); volkLoadDevice(device);
#endif
vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue); vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue); vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
if (optionalDeviceFeatures.extendedDynamicState)
{
#ifdef LOVE_ANDROID
ext.vkCmdSetCullModeEXT = vkCmdSetCullModeEXT;
ext.vkCmdSetDepthBoundsTestEnableEXT = vkCmdSetDepthBoundsTestEnableEXT;
ext.vkCmdSetDepthBoundsTestEnableEXT = vkCmdSetCullModeEXT;
ext.vkCmdSetDepthTestEnableEXT = vkCmdSetDepthTestEnableEXT;
ext.vkCmdSetDepthWriteEnableEXT = vkCmdSetDepthWriteEnableEXT;
ext.vkCmdSetFrontFaceEXT = vkCmdSetFrontFaceEXT;
ext.vkCmdSetPrimitiveTopologyEXT = vkCmdSetPrimitiveTopologyEXT;
ext.vkCmdSetScissorWithCountEXT = vkCmdSetScissorWithCountEXT;
ext.vkCmdSetStencilOpEXT = vkCmdSetStencilOpEXT;
ext.vkCmdSetStencilTestEnableEXT = vkCmdSetStencilTestEnableEXT;
ext.vkCmdSetViewportWithCountEXT = vkCmdSetViewportWithCountEXT;
#else
ext.vkCmdSetCullModeEXT = (PFN_vkCmdSetCullModeEXT)vkGetDeviceProcAddr(device, "vkCmdSetCullModeEXT");
ext.vkCmdSetDepthBoundsTestEnableEXT = (PFN_vkCmdSetDepthBoundsTestEnableEXT)vkGetDeviceProcAddr(device, "vkCmdSetDepthBoundsTestEnableEXT");
ext.vkCmdSetDepthCompareOpEXT = (PFN_vkCmdSetDepthCompareOpEXT)vkGetDeviceProcAddr(device, "vkCmdSetDepthCompareOpEXT");
ext.vkCmdSetDepthTestEnableEXT = (PFN_vkCmdSetDepthTestEnableEXT)vkGetDeviceProcAddr(device, "vkCmdSetDepthTestEnableEXT");
ext.vkCmdSetDepthWriteEnableEXT = (PFN_vkCmdSetDepthWriteEnableEXT)vkGetDeviceProcAddr(device, "vkCmdSetDepthWriteEnableEXT");
ext.vkCmdSetFrontFaceEXT = (PFN_vkCmdSetFrontFaceEXT)vkGetDeviceProcAddr(device, "vkCmdSetFrontFaceEXT");
ext.vkCmdSetPrimitiveTopologyEXT = (PFN_vkCmdSetPrimitiveTopologyEXT)vkGetDeviceProcAddr(device, "vkCmdSetPrimitiveTopologyEXT");
ext.vkCmdSetScissorWithCountEXT = (PFN_vkCmdSetScissorWithCountEXT)vkGetDeviceProcAddr(device, "vkCmdSetScissorWithCountEXT");
ext.vkCmdSetStencilOpEXT = (PFN_vkCmdSetStencilOpEXT)vkGetDeviceProcAddr(device, "vkCmdSetStencilOpEXT");
ext.vkCmdSetStencilTestEnableEXT = (PFN_vkCmdSetStencilTestEnableEXT)vkGetDeviceProcAddr(device, "vkCmdSetStencilTestEnableEXT");
ext.vkCmdSetViewportWithCountEXT = (PFN_vkCmdSetViewportWithCountEXT)vkGetDeviceProcAddr(device, "vkCmdSetViewportWithCountEXT");
#endif
}
if (optionalDeviceFeatures.memoryRequirements2)
{
#ifdef LOVE_ANDROID
ext.vkGetBufferMemoryRequirements2KHR = vkGetBufferMemoryRequirements2KHR;
ext.vkGetImageMemoryRequirements2KHR = vkGetImageMemoryRequirements2KHR;
ext.vkGetImageSparseMemoryRequirements2KHR = vkGetImageSparseMemoryRequirements2KHR;
#else
ext.vkGetBufferMemoryRequirements2KHR = (PFN_vkGetBufferMemoryRequirements2KHR)vkGetDeviceProcAddr(device, "vkGetBufferMemoryRequirements2KHR");
ext.vkGetImageMemoryRequirements2KHR = (PFN_vkGetImageMemoryRequirements2KHR)vkGetDeviceProcAddr(device, "vkGetImageMemoryRequirements2KHR");
ext.vkGetImageSparseMemoryRequirements2KHR = (PFN_vkGetImageSparseMemoryRequirements2KHR)vkGetDeviceProcAddr(device, "vkGetImageSparseMemoryRequirements2KHR");
#endif
}
if (optionalDeviceFeatures.bufferDeviceAddress)
{
#ifdef LOVE_ANDROID
ext.vkGetBufferDeviceAddressKHR = vkGetBufferDeviceAddressKHR;
ext.vkGetBufferOpaqueCaptureAddressKHR = vkGetBufferOpaqueCaptureAddressKHR;
ext.vkGetDeviceMemoryOpaqueCaptureAddressKHR = vkGetDeviceMemoryOpaqueCaptureAddressKHR;
#else
ext.vkGetBufferDeviceAddressKHR = (PFN_vkGetBufferDeviceAddressKHR)vkGetDeviceProcAddr(device, "vkGetBufferDeviceAddressKHR");
ext.vkGetBufferOpaqueCaptureAddressKHR = (PFN_vkGetBufferOpaqueCaptureAddressKHR)vkGetDeviceProcAddr(device, "vkGetBufferOpaqueCaptureAddressKHR");
ext.vkGetDeviceMemoryOpaqueCaptureAddressKHR = (PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR)vkGetDeviceProcAddr(device, "vkGetDeviceMemoryOpaqueCaptureAddressKHR");
#endif
}
} }
void Graphics::initVMA() void Graphics::initVMA()
@@ -1465,7 +1415,7 @@ void Graphics::initVMA()
allocatorCreateInfo.physicalDevice = physicalDevice; allocatorCreateInfo.physicalDevice = physicalDevice;
allocatorCreateInfo.device = device; allocatorCreateInfo.device = device;
allocatorCreateInfo.instance = instance; allocatorCreateInfo.instance = instance;
#ifdef LOVE_ANDROID
VmaVulkanFunctions vulkanFunctions{}; VmaVulkanFunctions vulkanFunctions{};
vulkanFunctions.vkGetInstanceProcAddr = vkGetInstanceProcAddr; vulkanFunctions.vkGetInstanceProcAddr = vkGetInstanceProcAddr;
@@ -1498,12 +1448,6 @@ void Graphics::initVMA()
vulkanFunctions.vkGetDeviceImageMemoryRequirements = vkGetDeviceImageMemoryRequirements; vulkanFunctions.vkGetDeviceImageMemoryRequirements = vkGetDeviceImageMemoryRequirements;
allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions; allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions;
#else
VmaVulkanFunctions vulkanFunctions{};
vulkanFunctions.vkGetInstanceProcAddr = &vkGetInstanceProcAddr;
vulkanFunctions.vkGetDeviceProcAddr = &vkGetDeviceProcAddr;
allocatorCreateInfo.pVulkanFunctions = &vulkanFunctions;
#endif
if (vmaCreateAllocator(&allocatorCreateInfo, &vmaAllocator) != VK_SUCCESS) if (vmaCreateAllocator(&allocatorCreateInfo, &vmaAllocator) != VK_SUCCESS)
throw love::Exception("failed to create vma allocator"); throw love::Exception("failed to create vma allocator");
@@ -2030,7 +1974,7 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi
configuration.primitiveType = primitiveType; configuration.primitiveType = primitiveType;
if (optionalDeviceFeatures.extendedDynamicState) if (optionalDeviceFeatures.extendedDynamicState)
ext.vkCmdSetCullModeEXT(commandBuffers.at(currentFrame), Vulkan::getCullMode(cullmode)); vkCmdSetCullModeEXT(commandBuffers.at(currentFrame), Vulkan::getCullMode(cullmode));
else else
{ {
configuration.dynamicState.winding = states.back().winding; configuration.dynamicState.winding = states.back().winding;
+2 -39
View File
@@ -132,32 +132,6 @@ struct OptionalDeviceFeatures
bool spirv14 = false; bool spirv14 = false;
}; };
struct OptionalDeviceExtensionFunctions
{
// VK_EXT_extended_dynamic_state
PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT = nullptr;
PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT = nullptr;
PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT = nullptr;
PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT = nullptr;
PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT = nullptr;
PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT = nullptr;
PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT = nullptr;
PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT = nullptr;
PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT = nullptr;
PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT = nullptr;
PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT = nullptr;
// VK_KHR_get_memory_requirements2
PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR = nullptr;
PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR = nullptr;
PFN_vkGetImageSparseMemoryRequirements2KHR vkGetImageSparseMemoryRequirements2KHR = nullptr;
// VK_KHR_buffer_device_address
PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR = nullptr;
PFN_vkGetBufferOpaqueCaptureAddressKHR vkGetBufferOpaqueCaptureAddressKHR = nullptr;
PFN_vkGetDeviceMemoryOpaqueCaptureAddressKHR vkGetDeviceMemoryOpaqueCaptureAddressKHR = nullptr;
};
struct GraphicsPipelineConfiguration struct GraphicsPipelineConfiguration
{ {
VkRenderPass renderPass; VkRenderPass renderPass;
@@ -258,18 +232,8 @@ struct RenderpassState
class Graphics final : public love::graphics::Graphics class Graphics final : public love::graphics::Graphics
{ {
public: public:
#ifdef LOVE_ANDROID Graphics();
Graphics() { ~Graphics();
auto result = volkInitialize();
if (result != VK_SUCCESS) {
throw love::Exception("could not initialize volk");
}
}
#else
Graphics() = default;
#endif
virtual ~Graphics();
const char *getName() const override; const char *getName() const override;
const VkDevice getDevice() const; const VkDevice getDevice() const;
@@ -401,7 +365,6 @@ private:
VkDevice device = VK_NULL_HANDLE; VkDevice device = VK_NULL_HANDLE;
OptionalInstanceExtensions optionalInstanceExtensions; OptionalInstanceExtensions optionalInstanceExtensions;
OptionalDeviceFeatures optionalDeviceFeatures; OptionalDeviceFeatures optionalDeviceFeatures;
OptionalDeviceExtensionFunctions ext;
VkQueue graphicsQueue = VK_NULL_HANDLE; VkQueue graphicsQueue = VK_NULL_HANDLE;
VkQueue presentQueue = VK_NULL_HANDLE; VkQueue presentQueue = VK_NULL_HANDLE;
VkSurfaceKHR surface = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE;
@@ -1,14 +1,6 @@
#pragma once #pragma once
#include "common/config.h"
#ifdef LOVE_ANDROID
#include "volk.h" #include "volk.h"
#define VMA_STATIC_VULKAN_FUNCTIONS 0 #define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0 #define VMA_DYNAMIC_VULKAN_FUNCTIONS 0
#else
#include <vulkan/vulkan.h>
#define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
#endif
#include "vk_mem_alloc.h" #include "vk_mem_alloc.h"