drshapeless


Fixing Vulkan Validation Error in MoltenVK on macOS

Tags: macos | vulkan

Create: 2023-12-31, Update: 2023-12-31

Recently I attempt to learn Vulkan with vulkan-tutorial. I learn it across a Mac and a Linux machine, therefore I use MoltenVK and encountered this error.

Validation Error: [ VUID-VkDeviceCreateInfo-pProperties-04451 ]

If the VK_KHR_portability_subset extension is included in pProperties
of vkEnumerateDeviceExtensionProperties, ppEnabledExtensionNames must
include "VK_KHR_portability_subset"

When you are following the vulkan-tutorial to this stage, Setup Instance. You will find yourself this error.

There is no good solution on the Internet, but we can find some clues from different sources.

In the comment section of this page Setup Instance, a guy named Bob Goldfield shared a solution for this.

Also, in StackOverflow, vulkan-validation-warning-catch-22, user Dan also shared a solution.

In the error, there is nothing to do with the instance, but the device. But the original function for creating a device does not create any extensions.

Go to the createLogicalDevice function. The macos specific code is enclosed in an ifdef macro. Put this at the top of the file.

#ifdef __APPLE__
const std::vector<const char *> deviceExtensions = {
    VK_KHR_SWAPCHAIN_EXTENSION_NAME, "VK_KHR_portability_subset"
};
#else
const std::vector<const char *> deviceExtensions = {
    VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
#endif

What I have done is forcely insert the extension name into the deviceExtensions. But why there is a VK, it is because of the later swapchain chapter.

Now we can see the next error. Validation Error: [VUID-vkCreateDevice-ppEnabledExtensionNames-01387 ]

Missing extension required by the device extension VK_KHR_portability_subset: VK_KHR_get_physical_device_properties2. The Vulkan spec states: All required device extensions for each extension in the VkDeviceCreateInfo::ppEnabledExtensionNames list must also be present in that list

We need to add VKinto the instance extensions.

    void 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 = "Hello Triangle";
        appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
        appInfo.pEngineName = "No Engine";
        appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
        appInfo.apiVersion = VK_API_VERSION_1_0;

        VkInstanceCreateInfo createInfo{};
        createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
        createInfo.pApplicationInfo = &appInfo;

        auto extensions = getRequiredExtensions();
#ifdef __APPLE__
        extensions.emplace_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
        extensions.emplace_back("VK_KHR_get_physical_device_properties2");

        createInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
#endif
        createInfo.enabledExtensionCount = (uint32_t)extensions.size();
        createInfo.ppEnabledExtensionNames = extensions.data();

        VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
        if (enableValidationLayers) {
            createInfo.enabledLayerCount =
                static_cast<uint32_t>(validationLayers.size());
            createInfo.ppEnabledLayerNames = validationLayers.data();

            populateDebugMessengerCreateInfo(debugCreateInfo);
            createInfo.pNext =
                (VkDebugUtilsMessengerCreateInfoEXT *)&debugCreateInfo;
        } else {
            createInfo.enabledLayerCount = 0;

            createInfo.pNext = nullptr;
        }

        if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
            throw std::runtime_error("failed to create instance!");
        }
    }

Now the error should go away.

Thoughts on Vulkan

It has been a while since last update, I rewrote the blog backend, again. I may talk about this in a future blog post.

I have done some OpenGL in the past, wrote a few little games, like the game of life, snake, and a port of pikachu volleyball using OpenGL and port it into wasm. You may see them in my GitHub.

Vulkan is known to be verbose. But unless you really dive in and learn what it is. You will not understand how suffering it is to a beginner.

I have been coding for about three years, just for fun. I have done a lot in the backend programming or mobile application development. I have a dream that I could write wonderful games without a game engine.

Computer graphics is hard. I have given up 4 times to the vulkan-tutorial in the past. I had never seen a fucking triangle rendered in front of me. This time, it is the fifth time, and I finally reach to the point where I can see the rainbow triangle. I was almost in tears.

Here is a recommendation of how to learn Vulkan using the vulkan-tutorial.

It is a great tutorial. But a lot of the time, you don't know what is going on when typing the code. And the worst part of the tutorial is that, sometimes it explains a concept, followed by some code snippets, but it does not tell you where exactly to put the code into. Often, you will have to think what the code does and put it into a related function.

Every page is so long and hard to understand, because Vulkan is such a complicated API to use. You need about 1000 thousands lines of code to see a triangle.

I recommend you not to expect you can learn anything on the first go. Sometimes you encounter weird errors, sometimes you just have a typo and you think that is an error.

Copy and paste is usually not recommended when it comes to learning how to program. In my opinion, the vulkan-tutorial can be an exception. Too many things have to be set. Too many weird structures that you have never encountered and could not understand what they do. Just read the word, copy and paste the code, compile and run the code. Otherwise, your patience will be in oblivion because you does not receive and positive feedback.

You are not going to see anything rendered on your screen on the first day, or possibly the first few days. That is depressing, but don't give up. When you think you are about to give up, rush the tutorial by copy and paste. Let the code compile. Read the words later.

Setting up Vulkan is the hardest part, but after that, rendering is some pure joy.

I recommend just using C++ to learn Vulkan. Using any other languages may encounter errors that have nothing to do with Vulkan itself. Using C should be fine though, but you have to translate all those C++functions into C, and pass a lot of parameter around madly. Although you may make it a big structure and pass the structure around, if that is the case, why don't just use C++ class function? I knew this is a pain in the ass because I have done it before, and gave up. Maybe it is a skill issue. But if you are skillful enough, C++ is not a big deal.