Search code examples
csdlvulkan

Vulkan Instance creation fails with SDL2. I am not sure where I am wrong


I am trying to create an instance and validate that the code can create that instance.

However, For some reason code compiles and fails to create the instance. I do not know what I am doing wrong. Everything before creating instance works. but When I try to validate instance creation it fails. I am using SDL2 to create the window.

This is my cmakelist file:

cmake_minimum_required(VERSION 3.16)
#COMPIER
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_C_COMPILER "gcc")
set(CMAKE_C_STANDARD 17)   
set(CMAKE_C_STANDARD_REQUIRED ON)

#FLAGS
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -ggdb3") 
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra")

#PROJECT
project(Vulkan_test LANGUAGES C)
enable_language(C)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})

#Find packages installed in your system.
include(FindPkgConfig)
pkg_search_module(SDL2 REQUIRED sdl2)
pkg_search_module(Vulkan REQUIRED vulkan)

#Include global directories 
include_directories( 
    ${SDL2_INCLUDE_DIRS}
    ${Vulkan_INCLUDE_DIRS}
)
#Executable Specific
add_executable(VULKAN_TEST 
    ${CMAKE_CURRENT_SOURCE_DIR}/main.c
)

#Compile options
target_compile_options(VULKAN_TEST PUBLIC -O0 -ggdb3 -std=c2x -Wall -Wextra -Wmissing-prototypes -Wwrite-strings -Wpedantic)

#Libraries to link
target_link_libraries(
    VULKAN_TEST
    ${SDL2_LIBRARIES}
    ${Vulkan_LIBRARIES}
)

This is the is the main.h file that I have:

#pragma once
/*  Required Standard Headers  */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>

/* SDL2 */
#include <SDL2/SDL.h>
#include <SDL2/SDL_vulkan.h>

/* Vulkan */
#include <vulkan/vulkan.h>

#define rt_assert(expr, ...) ((void) sizeof ((expr) ? 1 : 0), __extension__ ({                                                     \
    if (!(expr)) {                                                                                                                 \
        fprintf(stderr,"At function [%s] in file [%s:%d], assert failed: [(%s)].\n", __func__, __FILE__, __LINE__, (#expr));       \
        __VA_ARGS__;                                                                                                               \
        exit(EXIT_FAILURE);                                                                                                        \
    }                                                                                                                              \
}))

typedef struct _App {
    SDL_Window *window;
    int window_height;
    int window_width;
    const char* window_name;
    SDL_Event sdl_event;
    bool quit;
    VkInstance inst;
    uint32_t sdlExtCount;
    const char** extNames;
} App;

/* Function Prototype */
void init_window(App *);
void init_vulkan(App *);
void main_loop(App *);
void cleanup(App *);


/* sub vulkan functions */
void init_vk_instance(App *);

This file my main.c

#include "main.h"

#define SDL_MAIN_HANDLED
#define App_init(X) App (X) = { \
    .window = NULL, .window_height = 600, .window_width = 800, \
    .window_name = "Vulkan Test", .quit = false, \
    .inst = VK_NULL_HANDLE \
}

VkApplicationInfo appInfo = {0};
VkInstanceCreateInfo instInfo = {0};

void init_vk_instance(App *App) {
    /* Vulkan VkApplicationInfo */
    appInfo.sType =  VK_STRUCTURE_TYPE_APPLICATION_INFO;
    appInfo.pApplicationName = App->window_name;
    appInfo.applicationVersion = VK_MAKE_API_VERSION(0, 1, 0, 0);
    appInfo.pEngineName = App->window_name;
    appInfo.engineVersion = VK_MAKE_API_VERSION(0, 1, 0, 0);
    /* This is version I have installed from my linux package manager */
    appInfo.apiVersion = VK_MAKE_API_VERSION(0,1,3,231); 
    appInfo.pNext = NULL;
    /* Vulkan Instance info - VkInstanceCreateInfo */
    instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
    instInfo.pApplicationInfo = &appInfo;
    instInfo.enabledLayerCount = 0;
    SDL_Vulkan_GetInstanceExtensions(App->window,&App->sdlExtCount,NULL);
    App->extNames = malloc(App->sdlExtCount * sizeof(const char*));
    SDL_Vulkan_GetInstanceExtensions(App->window,&App->sdlExtCount,App->extNames);
    instInfo.enabledExtensionCount = App->sdlExtCount;
    instInfo.ppEnabledExtensionNames = App->extNames;
    for(uint32_t i = 0; i < App->sdlExtCount; i++) {
        printf("%u : %s\n",i,App->extNames[i]);
    }
    rt_assert( (vkCreateInstance(&instInfo, NULL, &App->inst) == VK_SUCCESS), printf("Instance creation failed\n"), cleanup(App));
}

void init_vulkan(App *App) {
    init_vk_instance(App);
}

void init_window(App *App) {
    App->window =  SDL_CreateWindow( App->window_name,
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 
        App->window_width, App->window_height, SDL_WINDOW_SHOWN | SDL_WINDOW_VULKAN |
        SDL_WINDOW_RESIZABLE);
}
void cleanup(App *App) {
    free(App->extNames);
    SDL_DestroyWindow(App->window);
    SDL_Quit();
}
void main_loop(App *App) {
    while(!App->quit) {
        while (SDL_PollEvent(&App->sdl_event)) {
            if( App->sdl_event.type == SDL_QUIT ) App->quit = true;
        }
    }
}
int main ( void ) {
    printf("Vulkan-Engine\n");
    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
    App_init(test);
    init_window(&test);
    init_vulkan(&test);
    main_loop(&test);
    vkDestroyInstance(test.inst, NULL);
    cleanup(&test);
    return EXIT_SUCCESS;
}

This the output I get after running my program:

Vulkan-Engine
0 : VK_KHR_surface
1 : VK_KHR_xlib_surface
At function [init_vk_instance] in file [/home/Codes/C/Vulkan/main.c:35], assert failed: [((vkCreateInstance(&instInfo, NULL, &App->inst) == VK_SUCCESS))].
Instance creation failed

CMake output during compilation:

-- The C compiler identification is GNU 12.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Found PkgConfig: /usr/bin/pkg-config (found version "0.29.2") 
-- Checking for one of the modules 'sdl2'
-- Checking for one of the modules 'vulkan'
-- Configuring done
-- Generating done
-- Build files have been written to: /home/Codes/C/Vulkan/build
[ 50%] Building C object CMakeFiles/VULKAN_TEST.dir/main.c.o
[100%] Linking C executable /home/Codes/C/Vulkan/VULKAN_TEST
[100%] Built target VULKAN_TEST

These are the vulkan related package I have installed on my system through package manager:

enter image description here

As you see from the image the vulkan api version is 1.3.231.1_1. Am I using the VK_MAKE_API_VERSION(0,1,3,231) properly?


Solution

  • I think you are missing KHR macro
    For example I am using windows 10 and MSYS2 This is what I did

    #define VK_USE_PLATFORM_WIN32_KHR
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdbool.h>
    #define SDL_MAIN_HANDLED
    #include <SDL2/SDL.h>
    #include <SDL2/SDL_vulkan.h>
    #include <vulkan/vulkan.h>
    #include <vulkan/vulkan_core.h>
    
    
    int main(int argc, char** argv)
    {
        if (0 != SDL_Init(SDL_INIT_EVERYTHING))
        {
            printf("failed to initialize SDL2 with everything\n");
        }
    
        SDL_Window* window = SDL_CreateWindow("test", 10, 10, 640, 480, SDL_WINDOW_SHOWN | SDL_WINDOW_VULKAN);
        if (NULL == window)
        {
            printf("failed to create window\n");
        }
    
        VkApplicationInfo app_info = { 0 };
        app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
        app_info.apiVersion = VK_API_VERSION_1_3;
        app_info.pApplicationName = "test-app";
        app_info.applicationVersion = VK_MAKE_API_VERSION(1, 0, 0, 0);
        app_info.pEngineName = "test-engine";
        app_info.engineVersion = VK_MAKE_API_VERSION(1, 0, 0, 0);
    
        VkInstanceCreateInfo instance_info = { 0 };
        instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
        instance_info.pApplicationInfo = &app_info;
        instance_info.enabledLayerCount = 0;
        instance_info.ppEnabledLayerNames = NULL;
    
        unsigned int count = 0;
        SDL_Vulkan_GetInstanceExtensions(window, &count, NULL);
        const char** extensions = malloc(sizeof(char*) * count);
        SDL_Vulkan_GetInstanceExtensions(window, &count, extensions);
    
        for (unsigned int i = 0; i < count; i ++)
        {
            printf("%u: %s\n", i, extensions[i]);
        }
    
        instance_info.enabledExtensionCount = count;
        instance_info.ppEnabledExtensionNames = extensions;
    
        VkInstance instance = VK_NULL_HANDLE;
        if (0 > vkCreateInstance(&instance_info, NULL, &instance))
        {
            printf("failed to create instance\n");
        }
    
        VkSurfaceKHR surface = VK_NULL_HANDLE;
        if (SDL_FALSE == SDL_Vulkan_CreateSurface(window, instance, &surface))
        {
            printf("failed to create surface, SDL Error: %s", SDL_GetError());
        }
    
        return 0;
    }
    

    For me it is working fine, so my observation is you need to find a way for defining similar macro like #define VK_USE_PLATFORM_WIN32_KHR

    Below are the list extensions assumed in vulkan.h

    VK_USE_PLATFORM_ANDROID_KHR
    VK_USE_PLATFORM_FUCHSIA
    VK_USE_PLATFORM_IOS_MVK
    VK_USE_PLATFORM_MACOS_MVK
    VK_USE_PLATFORM_METAL_EXT
    VK_USE_PLATFORM_VI_NN
    VK_USE_PLATFORM_WAYLAND_KHR
    VK_USE_PLATFORM_WIN32_KHR
    VK_USE_PLATFORM_XCB_KHR
    VK_USE_PLATFORM_XLIB_KHR
    VK_USE_PLATFORM_DIRECTFB_EXT
    VK_USE_PLATFORM_XLIB_XRANDR_EXT
    VK_USE_PLATFORM_GGP
    VK_USE_PLATFORM_SCREEN_QNX
    VK_ENABLE_BETA_EXTENSIONS
    

    This is how I compile in MSYS2

    gcc -O0 -g3 -Wall -c -fmessage-length=0 -o "src\\ansi-c.o" "..\\src\\ansi-c.c" 
    gcc -o ansi-c.exe "src\\ansi-c.o" -lmingw32 -lSDL2main -lSDL2 -lvulkan-1.dll