[英]Linux GLFW - Vulkan Surface not creating: glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API) is being ignored?
我在為 Linux 中的 GLFW 窗口創建 Vulkan 表面時遇到問題。 顯然,您需要創建一個沒有客戶端 API 的窗口。 但不知何故,GLFW 忽略了那個窗口提示?
GLFW 吐出以下錯誤消息:
GLFW Error 65540: Vulkan: Window surface creation requires the window to have the client API set to GLFW_NO_API
我不知道為什么這不起作用,似乎 GLFW 本身已經壞了。 注意函數 glfwWindowShouldClose() 似乎也忽略了關閉事件? 不得不做一個小的解決方法。
這是完整的程序:
#include <vulkan/vulkan.h>
#include <iostream>
#include <stdexcept>
#include <cstdlib>
#include <vector>
#include <cstring>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
const uint32_t WINDOW_WIDTH = 1024;
const uint32_t WINDOW_HEIGHT = 768;
// NOTE: somehow GLFW's glfwWindowShouldClose() never returns true?!
// So, we create this global for intended behaviour.
bool RUNNING = false;
std::vector<const char*> validation_layers = {
"VK_LAYER_KHRONOS_validation"
};
#if NDEBUG
const bool enable_validation_layers = false;
#else
const bool enable_validation_layers = true;
#endif
struct Application {
GLFWwindow *window;
VkInstance vk_instance;
VkPhysicalDevice vk_physical_device = VK_NULL_HANDLE;
VkDevice vk_device;
VkQueue vk_graphics_queue;
VkSurfaceKHR vk_surface;
};
void glfwErrorCallback(int code, const char* description) {
std::cerr << "GLFW Error " << code << ": " << description << std::endl;
}
bool checkValidationLayerSupport() {
uint32_t count;
vkEnumerateInstanceLayerProperties(&count, nullptr);
std::vector<VkLayerProperties> available_layers(count);
vkEnumerateInstanceLayerProperties(&count, available_layers.data());
for (const auto &layer_name : validation_layers) {
bool found = false;
for (const auto &layer_properties : available_layers) {
if (strcmp(layer_name, layer_properties.layerName)) {
found = true;
break;
}
}
if (!found) return false;
}
return true;
}
void windowCloseCallback(GLFWwindow *window) {
RUNNING = false;
}
void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) {
// nothing
}
static void createVKInstance(VkInstance *instance) {
if ( enable_validation_layers && !checkValidationLayerSupport() ) {
throw std::runtime_error("Validation layer requested, but not available!");
}
VkApplicationInfo app_info = {};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.pApplicationName = "Hello Sailor!";
app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
app_info.pEngineName = " No engine";
app_info.engineVersion = VK_MAKE_VERSION(1, 0 ,0);
app_info.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
create_info.pApplicationInfo = &app_info;
uint32_t glfw_extension_count = 0;
const char **glfw_extensions;
glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count);
create_info.enabledExtensionCount = glfw_extension_count;
create_info.ppEnabledExtensionNames = glfw_extensions;
if (enable_validation_layers) {
create_info.enabledLayerCount = (uint32_t) validation_layers.size();
create_info.ppEnabledLayerNames = validation_layers.data();
}
else {
create_info.enabledLayerCount = 0;
}
auto result = vkCreateInstance(&create_info, nullptr, instance);
if (result != VK_SUCCESS) {
throw std::runtime_error(" Failed to create Vulkan instance!\n");
}
#if 0
uint32_t p_count = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &p_count, nullptr);
std::vector<VkExtensionProperties> props(p_count);
vkEnumerateInstanceExtensionProperties(nullptr, &p_count, props.data());
for (auto &prop : props) {
std::cout << prop.extensionName << std::endl;
}
#endif
}
#include <optional>
struct QueueFamilyIndices {
std::optional<uint32_t> graphics_family;
};
static bool isComplete(QueueFamilyIndices *indices) {
return indices->graphics_family.has_value();
}
static QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
QueueFamilyIndices indices;
uint32_t count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &count, nullptr);
std::vector<VkQueueFamilyProperties> queue_families(count);
vkGetPhysicalDeviceQueueFamilyProperties(device, &count, queue_families.data());
int i = 0;
for (const auto &queue_family : queue_families) {
if (queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
indices.graphics_family = i;
}
if (isComplete(&indices)) break;
i++;
}
return indices;
}
static bool isDeviceSuitable(VkPhysicalDevice device) {
QueueFamilyIndices indices = findQueueFamilies(device);
return isComplete(&indices);
}
static void pickPhysicalDevice(VkInstance instance, VkPhysicalDevice *physical_device) {
uint32_t count = 0;
vkEnumeratePhysicalDevices(instance, &count, nullptr);
if (count == 0) {
throw std::runtime_error("Failed to find GPUs with Vulkan support!");
}
std::vector<VkPhysicalDevice> devices(count);
vkEnumeratePhysicalDevices(instance, &count, devices.data());
for (const auto &device : devices) {
if (isDeviceSuitable(device)) {
*physical_device = device;
break;
}
}
if (*physical_device == VK_NULL_HANDLE) {
throw std::runtime_error("Failed to find suitable GPU!");
}
}
static void createLogicalDevice(VkPhysicalDevice physical_device, VkDevice *device, VkQueue *graphics_queue) {
QueueFamilyIndices indices = findQueueFamilies(physical_device);
if (!isComplete(&indices)) {
throw std::runtime_error("No queue family indices!");
}
VkDeviceQueueCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
create_info.queueFamilyIndex = indices.graphics_family.value();
create_info.queueCount = 1;
float queue_priority = 1.0f;
create_info.pQueuePriorities = &queue_priority;
VkPhysicalDeviceFeatures features = {};
VkDeviceCreateInfo device_create_info = {};
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device_create_info.pQueueCreateInfos = &create_info;
device_create_info.queueCreateInfoCount = 1;
device_create_info.pEnabledFeatures = &features;
device_create_info.enabledExtensionCount = 0;
if (enable_validation_layers) {
device_create_info.enabledLayerCount = (uint32_t) validation_layers.size();
device_create_info.ppEnabledLayerNames = validation_layers.data();
}
else {
device_create_info.enabledLayerCount = 0;
}
if (vkCreateDevice(physical_device, &device_create_info, nullptr, device) != VK_SUCCESS) {
throw std::runtime_error("Failed to create logical device!");
}
vkGetDeviceQueue(*device, indices.graphics_family.value(), 0, graphics_queue);
}
static void createSurface(GLFWwindow *window, VkInstance instance, VkSurfaceKHR *surface) {
auto result = glfwCreateWindowSurface(instance, window, nullptr, surface);
if (result != VK_SUCCESS) {
throw std::runtime_error("Failed to create window surface!");
}
}
static void initVulkan(/*GLFWwindow *window, VkInstance *instance, VkPhysicalDevice *physical_device, VkDevice *device, VkQueue *graphics_queue, VkSurfaceKHR *surface */
Application *app
) {
createVKInstance(&app->vk_instance);
createSurface(app->window, app->vk_instance, &app->vk_surface);
pickPhysicalDevice(app->vk_instance, &app->vk_physical_device);
createLogicalDevice(app->vk_physical_device, &app->vk_device, &app->vk_graphics_queue);
}
static void initWindow(GLFWwindow *window) {
glfwInit();
glfwSetErrorCallback(glfwErrorCallback);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Vulkan", nullptr, nullptr);
if (window == NULL) {
throw std::runtime_error("Failed to create window!\n");
}
else {
printf("Created window.\n");
}
glfwSetWindowCloseCallback(window, windowCloseCallback);
glfwSetKeyCallback(window, keyCallback);
RUNNING = true;
}
static void mainLoop(GLFWwindow *window) {
while (RUNNING) {
glfwPollEvents();
}
}
static void cleanUp(GLFWwindow *window, VkInstance instance, VkDevice device, VkSurfaceKHR surface) {
printf("Cleaning up!\n");
glfwDestroyWindow(window);
glfwTerminate();
vkDestroySurfaceKHR(instance, surface, nullptr);
vkDestroyInstance(instance, nullptr);
vkDestroyDevice(device, nullptr);
}
static void runApplication(Application *app) {
initWindow(app->window);
initVulkan(app);
mainLoop(app->window);
cleanUp(app->window, app->vk_instance, app->vk_device, app->vk_surface);
}
int main() {
Application app;
try {
runApplication(&app);
}
catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Application
結構中,因為您通過值傳遞它,而不是通過引用 [1]glfwInit
返回錯誤代碼,必須檢查該代碼,並且\或應在調用之前設置回調。glfwVulkanSupported
。RUNNING
變量的排序錯誤。 即使窗口關閉,它也可以設置為true
。1:
struct Application {
GLFWwindow *window;
};
// passing GLFWwindow* by value (local copy):
static void initWindow(GLFWwindow *window) {
// writing to a local GLFWwindow*,
// which will be destroyed at end of scope
window = glfwCreateWindow(/*snip*/);
}
// passing GLFWwindow* by value, not reference:
initWindow(app->window);
// reading\dereferencing uninitialized variable app->window:
createSurface(app->window, app->vk_instance, &app->vk_surface);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.