#c #access-violation #vulkan
#c #нарушение доступа #vulkan
Вопрос:
Я пытаюсь изучить Vulkan, следуя отличным руководствам от vulkan-tutorial.com но у меня возникли некоторые проблемы в тот момент, когда я должен создать цепочку обмена. Как указано в названии, vkCreateSwapchainKHR
создает следующую ошибку: Access violation executing location 0x0000000000000000
.
В руководстве предполагается, что это может быть конфликт с наложением steam. Для меня это не тот случай, поскольку копирование всего кода из руководства работает.
Я пытаюсь выяснить, что пошло не так с моим кодом, и узнать, как отлаживать такие проблемы, поскольку в будущем у меня не будет ссылочного кода. Инкриминируемая строка выглядит следующим образом:
if (vkCreateSwapchainKHR(device, amp;swapChainCreateInfo, nullptr, amp;swapChain) != VK_SUCCESS) {
throw std::runtime_error("Could not create swap chain");
}
Я устанавливаю точку останова в этой строке, чтобы сравнить значения аргументов в моем коде со значениями из ссылочного кода. Насколько я могу судить, разницы нет. (Адреса, конечно, разные)
Где мне следует искать проблему в моем коде? Как и ожидалось, переменная swapChain
является NULL
. Неправильно сформированный файл swapChainCreateInfo
не должен приводить vkCreateSwapchainKHR
к сбою. Это просто заставило бы его возвращать то, чего нет VK_SUCCESS
. И устройство было создано без проблем:
if (vkCreateDevice(physicalDevice, amp;createInfo, nullptr, amp;device) != VK_SUCCESS) {
throw std::runtime_error("Failed to create logical device");
}
РЕДАКТИРОВАТЬ — Я использую уровень проверки, VK_LAYER_LUNARG_standard_validation
и моя createInfo
настройка следующая.
// Useful functions and structures
VkPhysicalDevice physicalDevice;
VkSurfaceKHR surface;
VkSwapchainKHR swapChain;
struct QueueFamilyIndices {
std::optional<uint32_t> graphicsFamily;
std::optional<uint32_t> presentationFamily;
bool isComplete() {
return graphicsFamily.has_value() amp;amp; presentationFamily.has_value();
}
};
struct SwapChainSupportDetails {
VkSurfaceCapabilitiesKHR surfaceCapabilities;
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> presentModes;
};
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice physicalDevice) {
SwapChainSupportDetails swapChainSupportDetails;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, amp;swapChainSupportDetails.surfaceCapabilities);
uint32_t formatCount = 0;
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, amp;formatCount, nullptr);
if (formatCount != 0) {
swapChainSupportDetails.formats.resize(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, amp;formatCount, swapChainSupportDetails.formats.data());
}
uint32_t presentModeCount = 0;
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, amp;presentModeCount, nullptr);
if (presentModeCount != 0) {
swapChainSupportDetails.presentModes.resize(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, amp;presentModeCount, swapChainSupportDetails.presentModes.data());
}
return swapChainSupportDetails;
}
VkSurfaceFormatKHR chooseSwapChainSurfaceFormat(const std::vector<VkSurfaceFormatKHR> amp; availableFormats) {
if (availableFormats.size() == 1 amp;amp; availableFormats[0].format == VK_FORMAT_UNDEFINED) {
return { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
}
for (const auto amp; availableFormat : availableFormats) {
if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM amp;amp; availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
return availableFormat;
}
}
return availableFormats[0];
}
VkPresentModeKHR chooseSwapChainPresentMode(const std::vector<VkPresentModeKHR> amp; availablePresentModes) {
VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR;
for (const auto amp; availablePresentMode : availablePresentModes) {
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
return availablePresentMode;
}
else if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
bestMode = availablePresentMode;
}
}
return bestMode;
}
VkExtent2D chooseSwapChainExtent2D(const VkSurfaceCapabilitiesKHR amp; surfaceCapabilities) {
if (surfaceCapabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
return surfaceCapabilities.currentExtent;
}
else {
VkExtent2D actualExtent = { WIDTH, HEIGHT };
actualExtent.width = std::max(std::min(surfaceCapabilities.maxImageExtent.width, actualExtent.width), surfaceCapabilities.minImageExtent.width);
actualExtent.height = std::max(std::min(surfaceCapabilities.maxImageExtent.height, actualExtent.height), surfaceCapabilities.minImageExtent.height);
return actualExtent;
}
}
// Swap Chain creation code
SwapChainSupportDetails swapChainSupportDetails = querySwapChainSupport(physicalDevice);
VkSurfaceFormatKHR surfaceFormat = chooseSwapChainSurfaceFormat(swapChainSupportDetails.formats);
VkPresentModeKHR presentMode = chooseSwapChainPresentMode(swapChainSupportDetails.presentModes);
VkExtent2D extent = chooseSwapChainExtent2D(swapChainSupportDetails.surfaceCapabilities);
uint32_t imageCount = swapChainSupportDetails.surfaceCapabilities.minImageCount 1;
if (swapChainSupportDetails.surfaceCapabilities.maxImageCount > 0 amp;amp; imageCount > swapChainSupportDetails.surfaceCapabilities.maxImageCount) {
imageCount = swapChainSupportDetails.surfaceCapabilities.minImageCount;
}
VkSwapchainCreateInfoKHR swapChainCreateInfo = {};
swapChainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapChainCreateInfo.surface = surface;
swapChainCreateInfo.minImageCount = imageCount;
swapChainCreateInfo.imageFormat = surfaceFormat.format;
swapChainCreateInfo.imageColorSpace = surfaceFormat.colorSpace;
swapChainCreateInfo.imageExtent = extent;
swapChainCreateInfo.imageArrayLayers = 1;
swapChainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
QueueFamilyIndices familyIndices = findQueueFamilies(physicalDevice);
uint32_t queueFamilyIndices[] = { familyIndices.graphicsFamily.value(), familyIndices.presentationFamily.value() };
if (familyIndices.graphicsFamily != familyIndices.presentationFamily) {
swapChainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
swapChainCreateInfo.queueFamilyIndexCount = 2;
swapChainCreateInfo.pQueueFamilyIndices = queueFamilyIndices;
}
else {
swapChainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swapChainCreateInfo.queueFamilyIndexCount = 0;
swapChainCreateInfo.pQueueFamilyIndices = nullptr;
}
swapChainCreateInfo.preTransform = swapChainSupportDetails.surfaceCapabilities.currentTransform;
swapChainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
swapChainCreateInfo.presentMode = presentMode;
swapChainCreateInfo.clipped = VK_TRUE;
swapChainCreateInfo.oldSwapchain = VK_NULL_HANDLE;
if (vkCreateSwapchainKHR(device, amp;swapChainCreateInfo, nullptr, amp;swapChain) != VK_SUCCESS) {
throw std::runtime_error("Could not create swap chain");
}
Комментарии:
1. Вы убедились, что
vkCreateSwapchainKHR
указатель на функцию был успешно загружен вашим загрузчиком, а неnullptr
нет?2. Нет, я не проверяю это в коде. Я только что использовал свою точку останова, хотя адрес не является
nullptr
. Спасибо за ответ!3. «Неправильно сформированный swapChainCreateInfo не должен приводить к сбою vkCreateSwapchainKHR. Это просто заставило бы его возвращать что-то, что не является VK_SUCCESS.» Это неверно. Большую часть времени в Vulkan, если вы вводите неверные входные данные (спецификация определяет, что является допустимым), поведение не определено, и неопределенное поведение может включать сбой. Вы должны использовать уровни проверки, чтобы получить сообщение, объясняющее, что было не так, до сбоя. Если вы разместите здесь содержимое VkSwapchainCreateInfo, возможно, мы сможем выявить проблему для вас.
4. Спасибо за исправление по поводу
swapChainCreateInfo
! Я используюVK_LAYER_LUNARG_standard_validation
уровень проверки, но я не уверен, что пока понимаю, как он работает. Кроме того, я обновил сообщение с моейVkSwapchainCreateInfo
настройкой. Дайте мне знать, если вам нужно больше, и спасибо 🙂
Ответ №1:
Ну, при создании логического устройства нужно установить enabledExtensionCount
фактическое количество требуемых расширений, а не 0, если ожидается, что расширения будут работать. В моем случае это был простой сбой редактирования. Вот жемчужина в моем коде:
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
createInfo.enabledExtensionCount = 0;
Я понял это, заменив каждую функцию из моего кода функциями из ссылочного кода, пока она не заработала. Я немного разочарован тем, что уровни проверки этого не уловили. Я неправильно их установил? Это то, что они должны отслеживать?
РЕДАКТИРОВАТЬ: Как указал ЛЯН ЛЮ, вот инициализация для deviceExtensions:
const std::vector<const char*> deviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
Комментарии:
1. Функция vkCreateSwapchainKHR() вводится расширением. Если расширение не включено во время создания логического устройства, вы не сможете использовать эту функцию. Итак, это то, что определенно должно быть обнаружено уровнями проверки. И я почти уверен, что они действительно обнаруживают подобные проблемы. Самый простой способ проверить, правильно ли работают уровни проверки, — это включить уровень «дамп api» и посмотреть, правильно ли перечислены вызовы функций Vulkan.
2. Я не знал об этом, спасибо! Как указал Cerulean Quasar в своем ответе ниже, уровень проверки требует самого расширения. Итак, установив значение count равным 0, я фактически отключил уровень проверки.
3. Вот почему я включаю уровни проверки не через код, а через переменную среды, которая не требует изменений кода. Вероятно, не все уровни проверки могут быть включены таким образом, и это решение не такое гибкое, но в большинстве случаев этого достаточно, и подобные ошибки легко обнаруживаются.
4. По крайней мере, у 8 человек, похоже, была именно эта проблема (на данный момент), так что, похоже, это то, на что им следует обратить внимание.
5. Спасибо за публикацию этой проблемы и решения. У меня только что была точно такая же проблема, с точно такой же основной причиной. Уровни проверки не дали ничего полезного.
Ответ №2:
Включите VK_KHR_SWAPCHAIN_EXTENSION_NAME при создании VkDevice
void VKRenderer::createVkLogicalDevice()
{
// device extensions
vector<const char*>::type deviceExtensionNames = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
// priorities
float queuePrioritys[2] = { 1.f, 1.f};
// graphics queue
VkDeviceQueueCreateInfo queueCreateInfos;
queueCreateInfos.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfos.pNext = nullptr;
queueCreateInfos.queueFamilyIndex = getGraphicsQueueFamilyIndex();
queueCreateInfos.queueCount = 1;
queueCreateInfos.pQueuePriorities = amp;queuePrioritys[0];
// device features
VkPhysicalDeviceFeatures deviceFeatures = {};
VkDeviceCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.pQueueCreateInfos = amp;queueCreateInfos;
createInfo.queueCreateInfoCount = 1;
createInfo.pEnabledFeatures = amp;deviceFeatures;
createInfo.enabledExtensionCount = deviceExtensionNames.size();
createInfo.ppEnabledExtensionNames = deviceExtensionNames.data();
// create logical device and retrieve graphics queue
if (VK_SUCCESS == vkCreateDevice(m_vkPhysicalDevice, amp;createInfo, nullptr, amp;m_vkDevice))
{
vkGetDeviceQueue(m_vkDevice, getGraphicsQueueFamilyIndex(), 0, amp;m_vkGraphicsQueue);
vkGetDeviceQueue(m_vkDevice, getPresentQueueFamilyIndex(), 0, amp;m_vkPresentQueue);
}
else
{
EchoLogError("Failed to create vulkan logical device!");
}
}
Комментарии:
1. Да, как вы можете видеть в моем ответе выше, я это сделал. К сожалению, я также установил количество расширений равным 0, что отключило это расширение. Кто-то позже сказал мне, что это должно быть обнаружено уровнями проверки, но никто не добавил эту конкретную проверку.
2. Я знаю, я отвечаю на этот вопрос, просто потому, что я не могу найти значение «ppenabledextensionname» из вашего ответа.
3. О да, хороший призыв! Я также отредактировал свой ответ и отдал вам должное.
Ответ №3:
Похоже, что вы вызываете vkCreateDevice в конце вашего сегмента кода для создания цепочки обмена и передачи в нее VkSwapchainCreateInfo. Возможно, вы хотите вызвать vkCreateSwapchainKHR вместо этого, например:
if (vkCreateSwapchainKHR(device, amp;swapChainCreateInfo, nullptr, amp;swapChain) !=
VK_SUCCESS) {
throw std::runtime_error("failed to create swap chain");
}
Если вы на самом деле вызываете vkCreateSwapchainKHR, не могли бы вы отредактировать свой вопрос, чтобы указать на это?
Комментарии:
1. Да, я действительно звоню
vkCreateSwapchainKHR
, извините за это. Я отредактировал код в вопросе 🙂2. Как предложил @JesseHall, для выполнения отладки лучше всего просмотреть выходные данные уровней проверки. Не могли бы вы опубликовать сообщения, которые вы получаете от уровня проверки?
3. Я не получаю никаких сообщений, только сбой. Я знаю, что уровни проверки работают, хотя. Перед попыткой настроить цепочку обмена у меня была работающая программа. В этой программе я попытался «забыть» удалить устройство, а затем я получил сообщение от уровней проверки, в котором говорилось, что произошла утечка памяти. Это имеет смысл или я что-то упускаю?
4. возможно ли, что сообщение об ошибке попадает в выходной буфер и никогда не выводится из-за сбоя программы? Возможно, вам следует прервать обратный вызов отладочных уровней проверки, чтобы убедиться, что это не так?
5. Как вы можете видеть, я решил свою проблему, но я обязательно попробую это!