mirror of
https://github.com/love2d/love.git
synced 2026-08-19 12:14:20 +02:00
Merge pull request #1979 from nikeinikei/12.0-development
vk: fix crash caused by love.window.close()
This commit is contained in:
@@ -65,29 +65,100 @@ const char *Graphics::getName() const
|
|||||||
return "love.graphics.vulkan";
|
return "love.graphics.vulkan";
|
||||||
}
|
}
|
||||||
|
|
||||||
const VkDevice Graphics::getDevice() const
|
VkDevice Graphics::getDevice() const
|
||||||
{
|
{
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VmaAllocator Graphics::getVmaAllocator() const
|
VmaAllocator Graphics::getVmaAllocator() const
|
||||||
{
|
{
|
||||||
return vmaAllocator;
|
return vmaAllocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void checkOptionalInstanceExtensions(OptionalInstanceExtensions& ext)
|
||||||
|
{
|
||||||
|
uint32_t count;
|
||||||
|
|
||||||
|
vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
|
||||||
|
|
||||||
|
std::vector<VkExtensionProperties> extensions(count);
|
||||||
|
|
||||||
|
vkEnumerateInstanceExtensionProperties(nullptr, &count, extensions.data());
|
||||||
|
|
||||||
|
for (const auto& extension : extensions)
|
||||||
|
{
|
||||||
|
if (strcmp(extension.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0)
|
||||||
|
ext.physicalDeviceProperties2 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Graphics::Graphics()
|
Graphics::Graphics()
|
||||||
{
|
{
|
||||||
if (SDL_Vulkan_LoadLibrary(nullptr))
|
if (SDL_Vulkan_LoadLibrary(nullptr))
|
||||||
throw love::Exception("could not find vulkan");
|
throw love::Exception("could not find vulkan");
|
||||||
|
|
||||||
volkInitializeCustom((PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr());
|
volkInitializeCustom((PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr());
|
||||||
|
|
||||||
|
if (isDebugEnabled() && !checkValidationSupport())
|
||||||
|
throw love::Exception("validation layers requested, but not available");
|
||||||
|
|
||||||
|
VkApplicationInfo appInfo{};
|
||||||
|
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||||
|
appInfo.pApplicationName = "LOVE";
|
||||||
|
appInfo.applicationVersion = VK_MAKE_API_VERSION(0, 1, 0, 0); // get this version from somewhere else?
|
||||||
|
appInfo.pEngineName = "LOVE Game Framework";
|
||||||
|
appInfo.engineVersion = VK_MAKE_API_VERSION(0, VERSION_MAJOR, VERSION_MINOR, VERSION_REV);
|
||||||
|
appInfo.apiVersion = VK_API_VERSION_1_3;
|
||||||
|
|
||||||
|
VkInstanceCreateInfo createInfo{};
|
||||||
|
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
|
createInfo.pApplicationInfo = &appInfo;
|
||||||
|
createInfo.pNext = nullptr;
|
||||||
|
|
||||||
|
// GetInstanceExtensions works with a null window parameter as long as
|
||||||
|
// SDL_Vulkan_LoadLibrary has been called (which we do earlier).
|
||||||
|
unsigned int count;
|
||||||
|
if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, nullptr) != SDL_TRUE)
|
||||||
|
throw love::Exception("couldn't retrieve sdl vulkan extensions");
|
||||||
|
|
||||||
|
std::vector<const char*> extensions = {};
|
||||||
|
|
||||||
|
checkOptionalInstanceExtensions(optionalInstanceExtensions);
|
||||||
|
|
||||||
|
if (optionalInstanceExtensions.physicalDeviceProperties2)
|
||||||
|
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
||||||
|
|
||||||
|
size_t additional_extension_count = extensions.size();
|
||||||
|
extensions.resize(additional_extension_count + count);
|
||||||
|
|
||||||
|
if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, extensions.data() + additional_extension_count) != SDL_TRUE)
|
||||||
|
throw love::Exception("couldn't retrieve sdl vulkan extensions");
|
||||||
|
|
||||||
|
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||||
|
createInfo.ppEnabledExtensionNames = extensions.data();
|
||||||
|
|
||||||
|
if (isDebugEnabled())
|
||||||
|
{
|
||||||
|
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
|
||||||
|
createInfo.ppEnabledLayerNames = validationLayers.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS)
|
||||||
|
throw love::Exception("couldn't create vulkan instance");
|
||||||
|
|
||||||
|
volkLoadInstance(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
Graphics::~Graphics()
|
Graphics::~Graphics()
|
||||||
{
|
{
|
||||||
|
defaultConstantTexCoord.set(nullptr);
|
||||||
defaultConstantColor.set(nullptr);
|
defaultConstantColor.set(nullptr);
|
||||||
defaultTexture.set(nullptr);
|
defaultTexture.set(nullptr);
|
||||||
|
|
||||||
|
Volatile::unloadAll();
|
||||||
|
cleanup();
|
||||||
|
vkDestroyInstance(instance, nullptr);
|
||||||
|
|
||||||
SDL_Vulkan_UnloadLibrary();
|
SDL_Vulkan_UnloadLibrary();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,14 +373,14 @@ void Graphics::discard(const std::vector<bool> &colorbuffers, bool depthstencil)
|
|||||||
startRenderPass();
|
startRenderPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::submitGpuCommands(bool present, void *screenshotCallbackData)
|
void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallbackData)
|
||||||
{
|
{
|
||||||
flushBatchedDraws();
|
flushBatchedDraws();
|
||||||
|
|
||||||
if (renderPassState.active)
|
if (renderPassState.active)
|
||||||
endRenderPass();
|
endRenderPass();
|
||||||
|
|
||||||
if (present)
|
if (submitMode == SUBMIT_PRESENT)
|
||||||
{
|
{
|
||||||
if (pendingScreenshotCallbacks.empty())
|
if (pendingScreenshotCallbacks.empty())
|
||||||
Vulkan::cmdTransitionImageLayout(
|
Vulkan::cmdTransitionImageLayout(
|
||||||
@@ -435,7 +506,7 @@ void Graphics::submitGpuCommands(bool present, void *screenshotCallbackData)
|
|||||||
|
|
||||||
VkFence fence = VK_NULL_HANDLE;
|
VkFence fence = VK_NULL_HANDLE;
|
||||||
|
|
||||||
if (present)
|
if (submitMode == SUBMIT_PRESENT)
|
||||||
{
|
{
|
||||||
submitInfo.signalSemaphoreCount = 1;
|
submitInfo.signalSemaphoreCount = 1;
|
||||||
submitInfo.pSignalSemaphores = signalSemaphores;
|
submitInfo.pSignalSemaphores = signalSemaphores;
|
||||||
@@ -447,7 +518,7 @@ void Graphics::submitGpuCommands(bool present, void *screenshotCallbackData)
|
|||||||
if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, fence) != VK_SUCCESS)
|
if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, fence) != VK_SUCCESS)
|
||||||
throw love::Exception("failed to submit draw command buffer");
|
throw love::Exception("failed to submit draw command buffer");
|
||||||
|
|
||||||
if (!present)
|
if (submitMode == SUBMIT_NOPRESENT || submitMode == SUBMIT_RESTART)
|
||||||
{
|
{
|
||||||
vkQueueWaitIdle(graphicsQueue);
|
vkQueueWaitIdle(graphicsQueue);
|
||||||
|
|
||||||
@@ -458,7 +529,8 @@ void Graphics::submitGpuCommands(bool present, void *screenshotCallbackData)
|
|||||||
callbacks.clear();
|
callbacks.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
startRecordingGraphicsCommands();
|
if (submitMode == SUBMIT_RESTART)
|
||||||
|
startRecordingGraphicsCommands();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,7 +547,7 @@ void Graphics::present(void *screenshotCallbackdata)
|
|||||||
|
|
||||||
deprecations.draw(this);
|
deprecations.draw(this);
|
||||||
|
|
||||||
submitGpuCommands(true, screenshotCallbackdata);
|
submitGpuCommands(SUBMIT_PRESENT, screenshotCallbackdata);
|
||||||
|
|
||||||
VkPresentInfoKHR presentInfo{};
|
VkPresentInfoKHR presentInfo{};
|
||||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||||
@@ -540,64 +612,80 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
|
|||||||
readbackCallbacks.clear();
|
readbackCallbacks.clear();
|
||||||
readbackCallbacks.resize(MAX_FRAMES_IN_FLIGHT);
|
readbackCallbacks.resize(MAX_FRAMES_IN_FLIGHT);
|
||||||
|
|
||||||
createVulkanInstance();
|
bool createBaseObjects = physicalDevice == VK_NULL_HANDLE;
|
||||||
|
|
||||||
createSurface();
|
createSurface();
|
||||||
pickPhysicalDevice();
|
|
||||||
createLogicalDevice();
|
if (createBaseObjects)
|
||||||
createPipelineCache();
|
{
|
||||||
initVMA();
|
pickPhysicalDevice();
|
||||||
initCapabilities();
|
createLogicalDevice();
|
||||||
|
createPipelineCache();
|
||||||
|
initVMA();
|
||||||
|
initCapabilities();
|
||||||
|
}
|
||||||
|
|
||||||
|
msaaSamples = getMsaaCount(requestedMsaa);
|
||||||
|
|
||||||
createSwapChain();
|
createSwapChain();
|
||||||
createImageViews();
|
createImageViews();
|
||||||
createScreenshotCallbackBuffers();
|
createScreenshotCallbackBuffers();
|
||||||
createSyncObjects();
|
|
||||||
createColorResources();
|
createColorResources();
|
||||||
createDepthResources();
|
createDepthResources();
|
||||||
transitionColorDepthLayouts = true;
|
transitionColorDepthLayouts = true;
|
||||||
createCommandPool();
|
|
||||||
createCommandBuffers();
|
if (createBaseObjects)
|
||||||
|
{
|
||||||
|
createCommandPool();
|
||||||
|
createCommandBuffers();
|
||||||
|
createSyncObjects();
|
||||||
|
}
|
||||||
|
|
||||||
beginFrame();
|
beginFrame();
|
||||||
|
|
||||||
if (batchedDrawState.vb[0] == nullptr)
|
if (createBaseObjects)
|
||||||
{
|
{
|
||||||
// Initial sizes that should be good enough for most cases. It will
|
if (batchedDrawState.vb[0] == nullptr)
|
||||||
// resize to fit if needed, later.
|
{
|
||||||
batchedDrawState.vb[0] = new StreamBuffer(this, BUFFERUSAGE_VERTEX, 1024 * 1024 * 1);
|
// Initial sizes that should be good enough for most cases. It will
|
||||||
batchedDrawState.vb[1] = new StreamBuffer(this, BUFFERUSAGE_VERTEX, 256 * 1024 * 1);
|
// resize to fit if needed, later.
|
||||||
batchedDrawState.indexBuffer = new StreamBuffer(this, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
|
batchedDrawState.vb[0] = new StreamBuffer(this, BUFFERUSAGE_VERTEX, 1024 * 1024 * 1);
|
||||||
}
|
batchedDrawState.vb[1] = new StreamBuffer(this, BUFFERUSAGE_VERTEX, 256 * 1024 * 1);
|
||||||
|
batchedDrawState.indexBuffer = new StreamBuffer(this, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
// sometimes the VertexTexCoord is not set, so we manually adjust it to (0, 0)
|
// sometimes the VertexTexCoord is not set, so we manually adjust it to (0, 0)
|
||||||
if (defaultConstantTexCoord == nullptr)
|
if (defaultConstantTexCoord == nullptr)
|
||||||
{
|
{
|
||||||
float zeroTexCoord[2] = { 0.0f, 0.0f };
|
float zeroTexCoord[2] = { 0.0f, 0.0f };
|
||||||
Buffer::DataDeclaration format("ConstantTexCoord", DATAFORMAT_FLOAT_VEC2);
|
Buffer::DataDeclaration format("ConstantTexCoord", DATAFORMAT_FLOAT_VEC2);
|
||||||
Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC);
|
Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC);
|
||||||
defaultConstantTexCoord = newBuffer(settings, { format }, zeroTexCoord, sizeof(zeroTexCoord), 1);
|
defaultConstantTexCoord = newBuffer(settings, { format }, zeroTexCoord, sizeof(zeroTexCoord), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sometimes the VertexColor is not set, so we manually adjust it to white color
|
// sometimes the VertexColor is not set, so we manually adjust it to white color
|
||||||
if (defaultConstantColor == nullptr)
|
if (defaultConstantColor == nullptr)
|
||||||
{
|
{
|
||||||
uint8 whiteColor[] = { 255, 255, 255, 255 };
|
uint8 whiteColor[] = { 255, 255, 255, 255 };
|
||||||
Buffer::DataDeclaration format("ConstantColor", DATAFORMAT_UNORM8_VEC4);
|
Buffer::DataDeclaration format("ConstantColor", DATAFORMAT_UNORM8_VEC4);
|
||||||
Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC);
|
Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC);
|
||||||
defaultConstantColor = newBuffer(settings, { format }, whiteColor, sizeof(whiteColor), 1);
|
defaultConstantColor = newBuffer(settings, { format }, whiteColor, sizeof(whiteColor), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
createDefaultTexture();
|
createDefaultTexture();
|
||||||
createDefaultShaders();
|
createDefaultShaders();
|
||||||
Shader::current = Shader::standardShaders[Shader::StandardShader::STANDARD_DEFAULT];
|
Shader::current = Shader::standardShaders[Shader::StandardShader::STANDARD_DEFAULT];
|
||||||
createQuadIndexBuffer();
|
createQuadIndexBuffer();
|
||||||
createFanIndexBuffer();
|
createFanIndexBuffer();
|
||||||
|
|
||||||
|
frameCounter = 0;
|
||||||
|
currentFrame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
restoreState(states.back());
|
restoreState(states.back());
|
||||||
|
|
||||||
Vulkan::resetShaderSwitches();
|
Vulkan::resetShaderSwitches();
|
||||||
|
|
||||||
frameCounter = 0;
|
|
||||||
currentFrame = 0;
|
|
||||||
created = true;
|
created = true;
|
||||||
drawCalls = 0;
|
drawCalls = 0;
|
||||||
drawCallsBatched = 0;
|
drawCallsBatched = 0;
|
||||||
@@ -659,14 +747,12 @@ void Graphics::getAPIStats(int &shaderswitches) const
|
|||||||
|
|
||||||
void Graphics::unSetMode()
|
void Graphics::unSetMode()
|
||||||
{
|
{
|
||||||
renderPassUsages.clear();
|
submitGpuCommands(SUBMIT_NOPRESENT);
|
||||||
framebufferUsages.clear();
|
|
||||||
pipelineUsages.clear();
|
|
||||||
|
|
||||||
created = false;
|
created = false;
|
||||||
vkDeviceWaitIdle(device);
|
|
||||||
Volatile::unloadAll();
|
cleanupSwapChain();
|
||||||
cleanup();
|
vkDestroySurfaceKHR(instance, surface, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::setActive(bool enable)
|
void Graphics::setActive(bool enable)
|
||||||
@@ -1332,75 +1418,6 @@ const OptionalDeviceExtensions &Graphics::getEnabledOptionalDeviceExtensions() c
|
|||||||
return optionalDeviceExtensions;
|
return optionalDeviceExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkOptionalInstanceExtensions(OptionalInstanceExtensions &ext)
|
|
||||||
{
|
|
||||||
uint32_t count;
|
|
||||||
|
|
||||||
vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
|
|
||||||
|
|
||||||
std::vector<VkExtensionProperties> extensions(count);
|
|
||||||
|
|
||||||
vkEnumerateInstanceExtensionProperties(nullptr, &count, extensions.data());
|
|
||||||
|
|
||||||
for (const auto &extension : extensions)
|
|
||||||
{
|
|
||||||
if (strcmp(extension.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0)
|
|
||||||
ext.physicalDeviceProperties2 = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Graphics::createVulkanInstance()
|
|
||||||
{
|
|
||||||
if (isDebugEnabled() && !checkValidationSupport())
|
|
||||||
throw love::Exception("validation layers requested, but not available");
|
|
||||||
|
|
||||||
VkApplicationInfo appInfo{};
|
|
||||||
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
|
||||||
appInfo.pApplicationName = "LOVE";
|
|
||||||
appInfo.applicationVersion = VK_MAKE_API_VERSION(0, 1, 0, 0); // get this version from somewhere else?
|
|
||||||
appInfo.pEngineName = "LOVE Game Framework";
|
|
||||||
appInfo.engineVersion = VK_MAKE_API_VERSION(0, VERSION_MAJOR, VERSION_MINOR, VERSION_REV);
|
|
||||||
appInfo.apiVersion = VK_API_VERSION_1_3;
|
|
||||||
|
|
||||||
VkInstanceCreateInfo createInfo{};
|
|
||||||
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
||||||
createInfo.pApplicationInfo = &appInfo;
|
|
||||||
createInfo.pNext = nullptr;
|
|
||||||
|
|
||||||
// GetInstanceExtensions works with a null window parameter as long as
|
|
||||||
// SDL_Vulkan_LoadLibrary has been called (which we do earlier).
|
|
||||||
unsigned int count;
|
|
||||||
if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, nullptr) != SDL_TRUE)
|
|
||||||
throw love::Exception("couldn't retrieve sdl vulkan extensions");
|
|
||||||
|
|
||||||
std::vector<const char*> extensions = {};
|
|
||||||
|
|
||||||
checkOptionalInstanceExtensions(optionalInstanceExtensions);
|
|
||||||
|
|
||||||
if (optionalInstanceExtensions.physicalDeviceProperties2)
|
|
||||||
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
|
||||||
|
|
||||||
size_t additional_extension_count = extensions.size();
|
|
||||||
extensions.resize(additional_extension_count + count);
|
|
||||||
|
|
||||||
if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, extensions.data() + additional_extension_count) != SDL_TRUE)
|
|
||||||
throw love::Exception("couldn't retrieve sdl vulkan extensions");
|
|
||||||
|
|
||||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
|
||||||
createInfo.ppEnabledExtensionNames = extensions.data();
|
|
||||||
|
|
||||||
if (isDebugEnabled())
|
|
||||||
{
|
|
||||||
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
|
|
||||||
createInfo.ppEnabledLayerNames = validationLayers.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS)
|
|
||||||
throw love::Exception("couldn't create vulkan instance");
|
|
||||||
|
|
||||||
volkLoadInstance(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Graphics::checkValidationSupport()
|
bool Graphics::checkValidationSupport()
|
||||||
{
|
{
|
||||||
uint32_t layerCount;
|
uint32_t layerCount;
|
||||||
@@ -1458,7 +1475,6 @@ void Graphics::pickPhysicalDevice()
|
|||||||
minUniformBufferOffsetAlignment = properties.limits.minUniformBufferOffsetAlignment;
|
minUniformBufferOffsetAlignment = properties.limits.minUniformBufferOffsetAlignment;
|
||||||
deviceApiVersion = properties.apiVersion;
|
deviceApiVersion = properties.apiVersion;
|
||||||
|
|
||||||
msaaSamples = getMsaaCount(requestedMsaa);
|
|
||||||
depthStencilFormat = findDepthFormat();
|
depthStencilFormat = findDepthFormat();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1573,7 +1589,7 @@ static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, Option
|
|||||||
optionalDeviceExtensions.memoryRequirements2 = true;
|
optionalDeviceExtensions.memoryRequirements2 = true;
|
||||||
if (strcmp(extension.extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
|
if (strcmp(extension.extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
|
||||||
optionalDeviceExtensions.dedicatedAllocation = true;
|
optionalDeviceExtensions.dedicatedAllocation = true;
|
||||||
if (strcmp(extension.extensionName, VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) == 0)
|
if (strcmp(extension.extensionName, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0)
|
||||||
optionalDeviceExtensions.memoryBudget = true;
|
optionalDeviceExtensions.memoryBudget = true;
|
||||||
if (strcmp(extension.extensionName, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME) == 0)
|
if (strcmp(extension.extensionName, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME) == 0)
|
||||||
optionalDeviceExtensions.shaderFloatControls = true;
|
optionalDeviceExtensions.shaderFloatControls = true;
|
||||||
@@ -3040,8 +3056,6 @@ void Graphics::createDefaultTexture()
|
|||||||
|
|
||||||
void Graphics::cleanup()
|
void Graphics::cleanup()
|
||||||
{
|
{
|
||||||
cleanupSwapChain();
|
|
||||||
|
|
||||||
for (auto &cleanUpFns : cleanUpFunctions)
|
for (auto &cleanUpFns : cleanUpFunctions)
|
||||||
for (auto &cleanUpFn : cleanUpFns)
|
for (auto &cleanUpFn : cleanUpFns)
|
||||||
cleanUpFn();
|
cleanUpFn();
|
||||||
@@ -3076,8 +3090,6 @@ void Graphics::cleanup()
|
|||||||
vkDestroyCommandPool(device, commandPool, nullptr);
|
vkDestroyCommandPool(device, commandPool, nullptr);
|
||||||
vkDestroyPipelineCache(device, pipelineCache, nullptr);
|
vkDestroyPipelineCache(device, pipelineCache, nullptr);
|
||||||
vkDestroyDevice(device, nullptr);
|
vkDestroyDevice(device, nullptr);
|
||||||
vkDestroySurfaceKHR(instance, surface, nullptr);
|
|
||||||
vkDestroyInstance(instance, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::cleanupSwapChain()
|
void Graphics::cleanupSwapChain()
|
||||||
@@ -3087,8 +3099,11 @@ void Graphics::cleanupSwapChain()
|
|||||||
vmaDestroyBuffer(vmaAllocator, readbackBuffer.buffer, readbackBuffer.allocation);
|
vmaDestroyBuffer(vmaAllocator, readbackBuffer.buffer, readbackBuffer.allocation);
|
||||||
vmaDestroyImage(vmaAllocator, readbackBuffer.image, readbackBuffer.imageAllocation);
|
vmaDestroyImage(vmaAllocator, readbackBuffer.image, readbackBuffer.imageAllocation);
|
||||||
}
|
}
|
||||||
vkDestroyImageView(device, colorImageView, nullptr);
|
if (colorImage)
|
||||||
vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation);
|
{
|
||||||
|
vkDestroyImageView(device, colorImageView, nullptr);
|
||||||
|
vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation);
|
||||||
|
}
|
||||||
vkDestroyImageView(device, depthImageView, nullptr);
|
vkDestroyImageView(device, depthImageView, nullptr);
|
||||||
vmaDestroyImage(vmaAllocator, depthImage, depthImageAllocation);
|
vmaDestroyImage(vmaAllocator, depthImage, depthImageAllocation);
|
||||||
for (const auto &swapChainImageView : swapChainImageViews)
|
for (const auto &swapChainImageView : swapChainImageViews)
|
||||||
|
|||||||
@@ -256,6 +256,14 @@ struct ScreenshotReadbackBuffer
|
|||||||
VmaAllocation imageAllocation;
|
VmaAllocation imageAllocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SubmitMode
|
||||||
|
{
|
||||||
|
SUBMIT_PRESENT,
|
||||||
|
SUBMIT_NOPRESENT,
|
||||||
|
SUBMIT_RESTART,
|
||||||
|
SUBMIT_MAXENUM,
|
||||||
|
};
|
||||||
|
|
||||||
class Graphics final : public love::graphics::Graphics
|
class Graphics final : public love::graphics::Graphics
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -300,12 +308,12 @@ public:
|
|||||||
|
|
||||||
// internal functions.
|
// internal functions.
|
||||||
|
|
||||||
const VkDevice getDevice() const;
|
VkDevice getDevice() const;
|
||||||
const VmaAllocator getVmaAllocator() const;
|
VmaAllocator getVmaAllocator() const;
|
||||||
VkCommandBuffer getCommandBufferForDataTransfer();
|
VkCommandBuffer getCommandBufferForDataTransfer();
|
||||||
void queueCleanUp(std::function<void()> cleanUp);
|
void queueCleanUp(std::function<void()> cleanUp);
|
||||||
void addReadbackCallback(std::function<void()> callback);
|
void addReadbackCallback(std::function<void()> callback);
|
||||||
void submitGpuCommands(bool present, void *screenshotCallbackData = nullptr);
|
void submitGpuCommands(SubmitMode, void *screenshotCallbackData = nullptr);
|
||||||
const VkDeviceSize getMinUniformBufferOffsetAlignment() const;
|
const VkDeviceSize getMinUniformBufferOffsetAlignment() const;
|
||||||
VkSampler getCachedSampler(const SamplerState &sampler);
|
VkSampler getCachedSampler(const SamplerState &sampler);
|
||||||
void setComputeShader(Shader *computeShader);
|
void setComputeShader(Shader *computeShader);
|
||||||
@@ -326,7 +334,6 @@ protected:
|
|||||||
void setRenderTargetsInternal(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture) override;
|
void setRenderTargetsInternal(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createVulkanInstance();
|
|
||||||
bool checkValidationSupport();
|
bool checkValidationSupport();
|
||||||
void pickPhysicalDevice();
|
void pickPhysicalDevice();
|
||||||
int rateDeviceSuitability(VkPhysicalDevice device);
|
int rateDeviceSuitability(VkPhysicalDevice device);
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ GraphicsReadback::GraphicsReadback(love::graphics::Graphics *gfx, ReadbackMethod
|
|||||||
|
|
||||||
if (method == READBACK_IMMEDIATE)
|
if (method == READBACK_IMMEDIATE)
|
||||||
{
|
{
|
||||||
vgfx->submitGpuCommands(false);
|
vgfx->submitGpuCommands(SUBMIT_RESTART);
|
||||||
if (stagingBuffer.get()) {
|
if (stagingBuffer.get()) {
|
||||||
status = readbackBuffer(stagingBuffer, 0, size);
|
status = readbackBuffer(stagingBuffer, 0, size);
|
||||||
gfx->releaseTemporaryBuffer(stagingBuffer);
|
gfx->releaseTemporaryBuffer(stagingBuffer);
|
||||||
@@ -79,7 +79,7 @@ GraphicsReadback::GraphicsReadback(love::graphics::Graphics *gfx, ReadbackMethod
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (method == READBACK_IMMEDIATE)
|
if (method == READBACK_IMMEDIATE)
|
||||||
vgfx->submitGpuCommands(false);
|
vgfx->submitGpuCommands(SUBMIT_RESTART);
|
||||||
}
|
}
|
||||||
|
|
||||||
GraphicsReadback::~GraphicsReadback()
|
GraphicsReadback::~GraphicsReadback()
|
||||||
@@ -89,7 +89,7 @@ GraphicsReadback::~GraphicsReadback()
|
|||||||
void GraphicsReadback::wait()
|
void GraphicsReadback::wait()
|
||||||
{
|
{
|
||||||
if (status == STATUS_WAITING)
|
if (status == STATUS_WAITING)
|
||||||
vgfx->submitGpuCommands(false);
|
vgfx->submitGpuCommands(SUBMIT_RESTART);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsReadback::update()
|
void GraphicsReadback::update()
|
||||||
|
|||||||
Reference in New Issue
Block a user