大家好,有错误
此错误消息表明创建 Vulkan 设备时必须启用 VK_KHR_portability_subset 扩展。 macOS 上的 Vulkan 实现(使用 MoltenVK)似乎需要此扩展才能实现正确的功能。
在我的 Vulkan 应用程序中,我尝试在不启用此扩展的情况下创建逻辑设备,这可能会导致错误。我怀疑在设置 VkDeviceCreateInfo 结构时需要将 VK_KHR_portability_subset 包含在所需设备扩展列表中。
请求帮助:
有人可以帮助我理解为什么会发生此错误以及如何在 macOS 上的 Vulkan 应用程序中正确启用 VK_KHR_portability_subset 扩展吗?任何有关解决此验证错误的指导将不胜感激。
validation layer: Validation Error: \[ VUID-VkDeviceCreateInfo-pProperties-04451 \] Object 0: handle = 0x600002e50360, type = VK_OBJECT_TYPE_PHYSICAL_DEVICE; | MessageID = 0x3a3b6ca0 | vkCreateDevice(): VK_KHR_portability_subset must be enabled because physical device VkPhysicalDevice 0x600002e50360\[
我可以寻求帮助吗 谢谢
#ifndef WINDOW_H
#define WINDOW_H
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <iostream>
#include<vector>
#include<optional>
#ifdef NDEBUG
const bool enableValidationLayers = false;
#else
const bool enableValidationLayers = true;
#endif
namespace Application {
struct QueueFamilyIndices {
std::optional<uint32_t> graphicsFamily;
std::optional<uint32_t> presentFamily;
bool isComplete() {
return graphicsFamily.has_value();
}
};
struct SwapChainSupportDetails {
VkSurfaceCapabilitiesKHR capabilities;
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> presentModes;
};
class Window {
public:
void run();
private:
GLFWwindow *window;
uint32_t WIDTH = 800;
uint32_t HEIGHT = 600;
VkInstance instance;
VkDebugUtilsMessengerEXT debugMessenger;
const std::vector<const char *> validationLayers = {
"VK_LAYER_KHRONOS_validation"
};
void initWindow();
void initVulkan();
void mainLoop() const;
void cleanup() const;
void setupDebugMessenger();
std::vector<const char *> getRequiredExtensions(bool includePortabilityExtension = true);
void extensionProperties() const;
bool checkValidationLayerSupport();
static void mouse_button_callback(GLFWwindow *window, int button, int action, int mods);
void createInstance();
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device);
void pickPhysicalDevice();
bool isDeviceSuitable(const VkPhysicalDevice &device, int &score);
int rateDeviceSuitability(VkPhysicalDevice devices);
VkDevice device;
VkQueue graphicsQueue;
void createLogicalDevice();
VkSurfaceKHR surface;
void createSurface();
VkQueue presentQueue;
const std::vector<const char *> deviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
bool checkDeviceExtensionSupport(VkPhysicalDevice device);
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device);
};
}
#endif // WINDOW_HPP
//
// Created by Abdulkafi on 03/10/2024 A.
//
#include "Window.hpp"
#include <iostream>
#include <stdexcept>
#include <set>
namespace Application {
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT meesageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackDate,
void *pUserData) {
std::cerr << "validation layer: " << pCallbackDate->pMessage << std::endl;
return VK_FALSE;
}
VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkDebugUtilsMessengerEXT *pDebugMessenger) {
auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance,
"vkCreateDebugUtilsMessengerEXT");
if (func != nullptr) {
return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
} else {
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
}
void DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger,
const VkAllocationCallbacks *pAllocator) {
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance,
"vkDestroyDebugUtilsMessengerEXT");
if (func != nullptr) {
func(instance, debugMessenger, pAllocator);
}
}
void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT &createInfo) {
createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
createInfo.pfnUserCallback = debugCallback;
}
void Window::setupDebugMessenger() {
if (!enableValidationLayers) return;
VkDebugUtilsMessengerCreateInfoEXT createInfoExt{};
populateDebugMessengerCreateInfo(createInfoExt);
if (CreateDebugUtilsMessengerEXT(instance, &createInfoExt, nullptr, &debugMessenger) != VK_SUCCESS) {
throw std::runtime_error("Failed to set up debug messenger!");
}
}
void Window::run() {
initWindow();
initVulkan();
mainLoop();
cleanup();
}
void Window::initWindow() {
if (!glfwInit()) {
throw std::runtime_error("Failed to initialize GLFW");
}
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
GLFWmonitor *primaryMonitor = glfwGetPrimaryMonitor();
if (!primaryMonitor) {
glfwTerminate();
throw std::runtime_error("Failed to get primary monitor");
}
const GLFWvidmode *videoMode = glfwGetVideoMode(primaryMonitor);
if (videoMode) {
std::cout << "Screen Width: " << videoMode->width << std::endl;
std::cout << "Screen Height: " << videoMode->height << std::endl;
std::cout << "Refresh Rate: " << videoMode->refreshRate << " Hz" << std::endl;
}
WIDTH = videoMode->width;
HEIGHT = videoMode->height;
window = glfwCreateWindow(WIDTH / 2, HEIGHT / 2, "Abdulkafi", nullptr, nullptr);
if (!window) {
glfwTerminate();
throw std::runtime_error("Failed to create GLFW window");
}
glfwMakeContextCurrent(window);
glfwSetMouseButtonCallback(window, mouse_button_callback);
}
void Window::initVulkan() {
createInstance();
setupDebugMessenger();
createSurface();
pickPhysicalDevice();
createLogicalDevice();
}
void Window::mouse_button_callback(GLFWwindow *window, int button, int action, int mods) {
if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
std::cout << "mouse left!" << std::endl;
} else if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS) {
std::cout << "mouse right!" << std::endl;
}
}
void Window::mainLoop() const {
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
}
}
void Window::cleanup() const {
vkDestroyDevice(device, nullptr);
if (enableValidationLayers) {
DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
}
vkDestroySurfaceKHR(instance, surface, nullptr);
vkDestroyInstance(instance, nullptr);
glfwDestroyWindow(window);
glfwTerminate();
}
void Window::createInstance() {
if (enableValidationLayers && !checkValidationLayerSupport()) {
throw std::runtime_error("validation layers requested, but not available!");
}
VkApplicationInfo appInfo{};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "Abdulkafi BK Game";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "no Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0);
VkInstanceCreateInfo instanceCreateInfo{};
instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instanceCreateInfo.flags = 0;
instanceCreateInfo.pApplicationInfo = &appInfo;
instanceCreateInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
std::vector<const char *> requiredextensions = getRequiredExtensions();
instanceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(requiredextensions.size());
instanceCreateInfo.ppEnabledExtensionNames = requiredextensions.data();
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
if (enableValidationLayers) {
instanceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
instanceCreateInfo.ppEnabledLayerNames = validationLayers.data();
populateDebugMessengerCreateInfo(debugCreateInfo);
instanceCreateInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT *) &debugCreateInfo;
} else {
instanceCreateInfo.enabledLayerCount = 0;
instanceCreateInfo.pNext = nullptr;
}
if (vkCreateInstance(&instanceCreateInfo, nullptr, &instance) != VK_SUCCESS) {
throw std::runtime_error("Failed to create instance");
}
#ifdef DEBUG_MODE
std::cout << "VkInstance created successfully. Handle value: " << reinterpret_cast<uintptr_t>(instance)
<< std::endl;
extensionProperties();
#endif
}
void Window::extensionProperties() const {
uint32_t extensionCount = 0;
VkResult result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
if (result != VK_SUCCESS) {
throw std::runtime_error("Failed to enumerate instance extension properties.");
}
std::vector<VkExtensionProperties> extensions(extensionCount);
result = vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
if (result != VK_SUCCESS) {
throw std::runtime_error("Failed to enumerate instance extension properties.");
}
std::cout << "Available extensions: " << extensionCount << std::endl;
for (const auto &extension: extensions) {
std::cout << " Name: " << extension.extensionName
<< " | Version: " << extension.specVersion << std::endl;
}
}
std::vector<const char *> Window::getRequiredExtensions(bool includePortabilityExtension) {
uint32_t glfwExtensionCount = 0;
const char **glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
if (!glfwExtensions) {
throw std::runtime_error("Failed to get required GLFW extensions");
}
std::set<const char *> requiredExtensionsSet(glfwExtensions, glfwExtensions + glfwExtensionCount);
if (includePortabilityExtension) {
requiredExtensionsSet.insert(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
}
std::vector<const char *> requiredExtensions(requiredExtensionsSet.begin(), requiredExtensionsSet.end());
if (enableValidationLayers) {
requiredExtensions.emplace_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
#ifdef DEBUG_MODE
std::cout << "Required extensions count: " << requiredExtensions.size() << std::endl;
for (const auto &extension: requiredExtensions) {
std::cout << extension << std::endl;
}
#endif
return requiredExtensions;
}
bool Window::checkValidationLayerSupport() {
uint32_t layerCount;
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
std::vector<VkLayerProperties> availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
for (const char *layerName: validationLayers) {
bool layerFound = false;
for (const auto &layerProperties: availableLayers) {
if (strcmp(layerName, layerProperties.layerName) == 0) {
layerFound = true;
break;
}
}
if (!layerFound) {
return false;
}
}
return true;
}
bool Window::isDeviceSuitable(const VkPhysicalDevice &device, int &score) {
VkPhysicalDeviceProperties deviceProperties;
VkPhysicalDeviceFeatures deviceFeatures;
vkGetPhysicalDeviceProperties(device, &deviceProperties);
vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
score = 0;
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
score += 1000;
} else if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) {
score += 500;
}
score += deviceProperties.limits.maxImageDimension2D / 1000;
if (deviceFeatures.geometryShader) {
score += 100;
}
return score > 0;
}
QueueFamilyIndices Window::findQueueFamilies(VkPhysicalDevice device) {
QueueFamilyIndices indices;
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
if (queueFamilyCount == 0) {
return indices;
}
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
int i = 0;
for (const auto &queueFamily: queueFamilies) {
if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
indices.graphicsFamily = i;
}
VkBool32 presentSupport = false;
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
if (presentSupport) {
indices.presentFamily = i;
}
if (indices.isComplete()) {
break;
}
i++;
}
return indices;
}
void Window::pickPhysicalDevice() {
uint32_t deviceCount = 0;
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
if (deviceCount == 0) {
throw std::runtime_error("coldn't get physical device");
}
std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
std::cout << "found device " << deviceCount << " physical" << std::endl;
int highestScore = -1;
VkPhysicalDevice bestDevice = VK_NULL_HANDLE;
for (const auto &device: devices) {
int currentScore = 0;
if (isDeviceSuitable(device, currentScore)) {
QueueFamilyIndices indices = findQueueFamilies(device);
if (indices.isComplete() && currentScore > highestScore) {
highestScore = currentScore;
bestDevice = device;
}
}
}
if (bestDevice != VK_NULL_HANDLE) {
physicalDevice = bestDevice;
VkPhysicalDeviceProperties bestProperties{};
vkGetPhysicalDeviceProperties(bestDevice, &bestProperties);
std::cout << "chose device : " << bestProperties.deviceName << std::endl;
} else {
throw std::runtime_error("faild got device physical");
}
}
void Window::createLogicalDevice() {
QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
std::set<uint32_t> uniqueQueueFamilies = {
indices.graphicsFamily.value(),
indices.presentFamily.value()
};
float queuePriority = 1.0f;
for (uint32_t queueFamily: uniqueQueueFamilies) {
VkDeviceQueueCreateInfo queueCreateInfo{};
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queueCreateInfo.queueFamilyIndex = queueFamily;
queueCreateInfo.queueCount = 1;
queueCreateInfo.pQueuePriorities = &queuePriority;
queueCreateInfos.push_back(queueCreateInfo);
}
VkPhysicalDeviceFeatures deviceFeatures{};
VkDeviceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
createInfo.pQueueCreateInfos = queueCreateInfos.data();
createInfo.pEnabledFeatures = &deviceFeatures;
createInfo.enabledExtensionCount = 0;
if (enableValidationLayers) {
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
createInfo.ppEnabledLayerNames = validationLayers.data();
} else {
createInfo.enabledLayerCount = 0;
}
if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
throw std::runtime_error("failed to create logical device");
}
int deviceValue = (device != VK_NULL_HANDLE) ? reinterpret_cast<uintptr_t>(device) : 0;
std::cout << "number device : " << deviceValue << std::endl;
vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
}
void Window::createSurface() {
if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
throw std::runtime_error("failed to create window surface!");
}
}
bool Window::checkDeviceExtensionSupport(VkPhysicalDevice device) {
uint32_t extensionCount;
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());
std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
for (const auto &extension: availableExtensions) {
requiredExtensions.erase(extension.extensionName);
}
return requiredExtensions.empty();
}
SwapChainSupportDetails Window::querySwapChainSupport(VkPhysicalDevice device) {
SwapChainSupportDetails details;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
uint32_t formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
if (formatCount != 0) {
details.formats.reserve(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
}
return details;
}
};
vulkan 1 Macos 有错误
你确实回答了你自己的问题。
是的,macOS 上的 Vulkan 与 MoltenVk 需要可移植性子集。这是因为完整 Vulkan 所做的一些事情无法(有效)转换为 Metal API 调用。
是的,您需要在创建设备时启用扩展。
Khronos 示例存储库中有一个代码示例展示了如何启用它:
https://docs.vulkan.org/samples/latest/samples/extensions/portability/README.html