diff --git a/include/application.hpp b/include/application.hpp index 11315e2..e84b63b 100644 --- a/include/application.hpp +++ b/include/application.hpp @@ -3,6 +3,7 @@ #include "resource_manager.hpp" #include "gfx.hpp" +#include "gfx_device.hpp" #include diff --git a/src/gfx_device_vulkan.cpp b/src/gfx_device_vulkan.cpp index 94b806f..3628316 100644 --- a/src/gfx_device_vulkan.cpp +++ b/src/gfx_device_vulkan.cpp @@ -559,10 +559,10 @@ namespace engine { }; DeviceRequirements deviceRequirements{}; - deviceRequirements.requiredExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME }; + deviceRequirements.requiredExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; + deviceRequirements.optionalExtensions = { VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME }; deviceRequirements.requiredFeatures.samplerAnisotropy = VK_TRUE; deviceRequirements.requiredFeatures.fillModeNonSolid = VK_TRUE; - deviceRequirements.memoryPriorityFeature = VK_TRUE; deviceRequirements.formats.push_back( FormatRequirements{ .format = VK_FORMAT_R8G8B8A8_SRGB, @@ -678,7 +678,7 @@ namespace engine { /* create a global descriptor pool */ std::vector poolSizes{}; - poolSizes.emplace_back(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 100); // purposely low limit + poolSizes.emplace_back(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 100u); // purposely low limit VkDescriptorPoolCreateInfo descriptorPoolInfo{}; descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; @@ -740,12 +740,15 @@ namespace engine { res = vkResetFences(pimpl->device.device, 1, &frameData.renderFence); VKCHECK(res); - if (pimpl->device.queues.transferQueues.size() < 2) throw std::runtime_error("Need at least 2 transfer queues!"); + uint32_t transferQueueIndex = 0; + if (pimpl->device.queues.transferQueues.size() >= 2) { + transferQueueIndex = 1; + } /* first empty the descriptor buffer write queue */ auto& writeQueue = pimpl->descriptorBufferWriteQueues[currentFrameIndex]; if (writeQueue.empty() == false) { - LOG_TRACE("write queue size: {}", writeQueue.size()); +// LOG_TRACE("write queue size: {}", writeQueue.size()); // vkQueueWaitIdle(pimpl->device.queues.drawQueues[0]); } for (gfx::DescriptorBuffer* buffer : writeQueue) { @@ -761,7 +764,7 @@ namespace engine { res = vkAllocateCommandBuffers(pimpl->device.device, &allocInfo, &commandBuffer); assert(res == VK_SUCCESS); - LOG_TRACE(" write command buffer: {}", (void*)commandBuffer); +// LOG_TRACE(" write command buffer: {}", (void*)commandBuffer); VkCommandBufferBeginInfo beginInfo{}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -813,7 +816,7 @@ namespace engine { submitInfo.waitSemaphoreCount = 0; submitInfo.pWaitSemaphores = nullptr; - res = vkQueueSubmit(pimpl->device.queues.transferQueues[1], 1, &submitInfo, VK_NULL_HANDLE); + res = vkQueueSubmit(pimpl->device.queues.transferQueues[transferQueueIndex], 1, &submitInfo, VK_NULL_HANDLE); assert(res == VK_SUCCESS); } diff --git a/src/vulkan/device.cpp b/src/vulkan/device.cpp index 0c2916c..3becb77 100644 --- a/src/vulkan/device.cpp +++ b/src/vulkan/device.cpp @@ -37,16 +37,24 @@ namespace engine { res = vkEnumeratePhysicalDevices(instance, &physDeviceCount, physicalDevices.data()); assert(res == VK_SUCCESS); + std::vector availableExtensions{}; + for (VkPhysicalDevice physDev : physicalDevices) { // first, check extension support + availableExtensions.clear(); uint32_t extensionCount; res = vkEnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, nullptr); assert(res == VK_SUCCESS); + availableExtensions.resize(extensionCount); std::vector availableExtensions(extensionCount); res = vkEnumerateDeviceExtensionProperties(physDev, nullptr, &extensionCount, availableExtensions.data()); assert(res == VK_SUCCESS); + for (const VkExtensionProperties& ext : availableExtensions) { + LOG_TRACE("extension: {}", ext.extensionName); + } + bool foundRequiredExtensions = true; for (const char* extToFind : requirements.requiredExtensions) { bool extFound = false; @@ -190,8 +198,40 @@ namespace engine { if (requirements.requiredFeatures.inheritedQueries == VK_TRUE) if (devFeatures.features.inheritedQueries == VK_FALSE) continue; - if (requirements.memoryPriorityFeature == VK_TRUE) - if (memoryPriorityFeatures.memoryPriority == VK_FALSE) continue; + /* check the memory priority extension was even requested */ + bool memoryPriorityRequired = false; + for (const char* ext : requirements.requiredExtensions) { + if (strcmp(ext, VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME) == 0) { + memoryPriorityRequired = true; + break; + } + } + if (memoryPriorityRequired) { + if (memoryPriorityFeatures.memoryPriority == VK_FALSE) { + throw std::runtime_error("Required device feature 'memoryPriority' not found, but extension was"); + } else { + d.memoryPriorityFeature = true; + } + } else { + // see if memoryPriority was optionally requested */ + for (const char* optExt : requirements.optionalExtensions) { + if (strcmp(optExt, VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME) == 0) { + for (const VkExtensionProperties& extAvail : availableExtensions) { + if (strcmp(extAvail.extensionName, VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME) == 0) { + if (memoryPriorityFeatures.memoryPriority == VK_TRUE) { + d.memoryPriorityFeature = true; + } else { + throw std::runtime_error("Optional device extension 'VK_EXT_memory_priority' found, but feature wasn't"); + } + break; // | + } // | + } // V + // <-------------------- + break; // | + } // | + } // V + // <-------------------- + } } bool formatsSupported = true; @@ -305,12 +345,22 @@ namespace engine { /* set enabled features */ VkPhysicalDeviceMemoryPriorityFeaturesEXT memoryPriorityFeaturesToEnable{}; memoryPriorityFeaturesToEnable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT; - memoryPriorityFeaturesToEnable.memoryPriority = requirements.memoryPriorityFeature; + memoryPriorityFeaturesToEnable.memoryPriority = d.memoryPriorityFeature ? VK_TRUE : VK_FALSE; VkPhysicalDeviceFeatures2 featuresToEnable{}; featuresToEnable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; featuresToEnable.pNext = &memoryPriorityFeaturesToEnable; featuresToEnable.features = requirements.requiredFeatures; + /* get list of extensions to enable */ + std::vector extensionsToEnable{}; + for (const VkExtensionProperties& availableExt : availableExtensions) { + if ( std::find(requirements.optionalExtensions.begin(), requirements.optionalExtensions.end(), + std::string(availableExt.extensionName)) != requirements.optionalExtensions.end()) { + extensionsToEnable.push_back(availableExt.extensionName); + } + } + extensionsToEnable.insert(extensionsToEnable.end(), requirements.requiredExtensions.begin(), requirements.requiredExtensions.end()); + /* create device now */ VkDeviceCreateInfo deviceCreateInfo{ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, @@ -320,8 +370,8 @@ namespace engine { .pQueueCreateInfos = queueCreateInfos.data(), .enabledLayerCount = 0, // deprecated and ignored .ppEnabledLayerNames = nullptr, // deprecated and ignored - .enabledExtensionCount = static_cast(requirements.requiredExtensions.size()), - .ppEnabledExtensionNames = requirements.requiredExtensions.data(), + .enabledExtensionCount = static_cast(extensionsToEnable.size()), + .ppEnabledExtensionNames = extensionsToEnable.data(), .pEnabledFeatures = nullptr, }; @@ -332,6 +382,12 @@ namespace engine { volkLoadDevice(d.device); + /* get list of extensions enabled */ + d.enabledExtensions.clear(); + for (const char* ext : extensionsToEnable) { + // must be copied into std::strings + d.enabledExtensions.emplace_back(ext); + } if (transferFamily != graphicsFamily) { vkGetDeviceQueue(d.device, graphicsFamily, 0, &d.queues.presentQueue); diff --git a/src/vulkan/device.h b/src/vulkan/device.h index 7e20b11..b80ef1f 100644 --- a/src/vulkan/device.h +++ b/src/vulkan/device.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include @@ -13,17 +14,18 @@ namespace engine { struct DeviceRequirements { std::vector requiredExtensions; + std::vector optionalExtensions; VkPhysicalDeviceFeatures requiredFeatures; - VkBool32 memoryPriorityFeature; std::vector formats{}; }; struct Device { VkDevice device = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; + std::vector enabledExtensions{}; VkPhysicalDeviceProperties properties{}; VkPhysicalDeviceFeatures features{}; - + bool memoryPriorityFeature = false; struct DeviceQueues { VkQueue presentQueue = VK_NULL_HANDLE; std::vector drawQueues{};