Crash getting a queue

Hi!
I am crashing during a call to vk::GetQueue.

I am using v 1.2.135.0.
GeForce GTX 750 Ti, driver version 445.87 (up to date).
Building in visual studio 19

When I try to get a queue from the the device for the first time it crashes, inside vkGetDeviceQueue or returning from it. The device is valid, the queue family and index both look fine (0 and 0) and I am passing in a newly created queue structure for it to fill in. The device worked on many other calls, at least in initialization.

I have the Lunar G standard validation layer on, which says nothing at all aside from some verbose loading warnings. The enumerator says there were a couple more, but it didn’t seem amused when I tried to turn them on. I do verify that the card supports queue families and use the proper indices

There was an alternate call, getQueue2. I tried it, it didn’t crash, but the queue it returned was not useable.

I am doing the dynamic loading, which works otherwise.

I order my intialization like this:

std::array<std::function<bool()>, 14> initSteps = {
    [&]() {return InitDynamicLoader(); },
    [&]() {return VerifyExtensions(); },
    [&]() {return InitInstance(); },
    [&]() {return InitDebugger(); },
    [&]() {return InitPhysicalDevice(); },
    [&]() {return InitSurface(); },
    [&]() {return IdentifyQueueFamilies(); },
    [&]() {return InitDevice(); },
    [&]() {return InitSwapChain(); },
    [&]() {return InitFrameImages(); },
    [&]() {return InitRenderPass(); },
    [&]() {return InitFrameBuffers(); },
    [&]() {return InitCommandBuffers(); },
    [&]() {return InitSemaphores(); }
}; 

This is my first time messing around with vulkan, and I haven’t seen anything on screen yet. That long chain of calls were refactored from an example online called vulkanHppMinimalExample. I’ve (brainfarts aside) error checked every call and am hanging on everything return to me in some unique pointers.

Hopefully that’s a thorough enough brain dump, thx for any insight anyone might have.

That is very… interesting code. Anyway, where’s the part where you are getting a queue from the device? I see functions for making command buffers, semaphores, and other stuff, but not for the queues you’re using. And how do I know that it happens after this chain of function has executed and before the part where you would destroy such objects?

Basically, that’s not showing us much.

Here’s the part where I am getting the queue:
auto deviceQueue = Device->getQueue(Family.Graphics, 0);

The first variable is set to 0. I moved the call around to many places including right after I initialised the device and I get the same result.

The device looks like a good pointer, as does the function pointer in the dispatch table. I initialise the logical device here:

bool Gpu::InitDevice()
{
    const auto familyIndices = Family.Indices();

    auto listOfQueueCreateInfos = std::vector<vk::DeviceQueueCreateInfo>();

    float queuePriority = 0.0f;
    for (int familyIndex : familyIndices) {
        auto createInfo = vk::DeviceQueueCreateInfo{ vk::DeviceQueueCreateFlags(),
            static_cast<uint32_t>(familyIndex), 
            1, &queuePriority };
        listOfQueueCreateInfos.push_back(createInfo);
    }
    

    const auto deviceCreateInfo = vk::DeviceCreateInfo()
        .setFlags(vk::DeviceCreateFlags())
        .setQueueCreateInfoCount(static_cast<uint32_t>(listOfQueueCreateInfos.size()))
        .setPQueueCreateInfos(listOfQueueCreateInfos.data())
        .setEnabledLayerCount(static_cast<uint32_t>(GpuConfig::Requiredlayers.size()))
        .setPpEnabledLayerNames(GpuConfig::Requiredlayers.data())
        .setEnabledExtensionCount(static_cast<uint32_t>(GpuConfig::DeviceExtensions.size()))
        .setPpEnabledExtensionNames(GpuConfig::DeviceExtensions.data());

    auto result = PhysicalDevice.createDeviceUnique(deviceCreateInfo);
    if (result.result != vk::Result::eSuccess) return false;

    Device = std::move(result.value);
    VULKAN_HPP_DEFAULT_DISPATCHER.init(*Device);


    return true;
}

The queue properties were queried previously here:

bool Gpu::IdentifyQueueFamilies()
{
    const auto queueFamilies = PhysicalDevice.getQueueFamilyProperties();

    auto isGraphicsFamily = [](auto& properties) {
        return properties.queueFlags & vk::QueueFlagBits::eGraphics;
    };
    const auto graphicFamilyQueue = std::find_if(queueFamilies.begin(), queueFamilies.end(), isGraphicsFamily);


    Family.Present = static_cast<uint32_t>(queueFamilies.size());
    Family.Graphics = static_cast<uint32_t>(std::distance(queueFamilies.begin(), graphicFamilyQueue));
    if (Family.Graphics >= queueFamilies.size()) return false;

    for (size_t i = 0; i < queueFamilies.size(); i++) {
        if (PhysicalDevice.getSurfaceSupportKHR(static_cast<uint32_t>(i), Surface.get()).value) {
            Family.Present = static_cast<uint32_t>(i);
        }
    }

    return (Family.Present < queueFamilies.size());
}

Physical device inited here:

bool Gpu::InitPhysicalDevice()
{
    auto result = Instance->enumeratePhysicalDevices();
    if (result.result != vk::Result::eSuccess) return false;

    PhysicalDevice = result.value.front();

    return true;
}

instance initialised here:

bool Gpu::InitInstance()
{
    const std::vector<char const*> enabledExtensions = {
        VK_EXT_DEBUG_UTILS_EXTENSION_NAME
    };

    constexpr auto applicationInfo = vk::ApplicationInfo("name", VK_MAKE_VERSION(0, 0, 0), 
        "name", VK_MAKE_VERSION(0, 0, 0), VK_API_VERSION_1_1);

    const auto instanceCreateInfo = vk::InstanceCreateInfo()
        .setPApplicationInfo(&applicationInfo)
        .setEnabledLayerCount(static_cast<uint32_t>(GpuConfig::Requiredlayers.size()))
        .setPpEnabledLayerNames(GpuConfig::Requiredlayers.data())
        .setEnabledExtensionCount(static_cast<uint32_t>(GpuConfig::RequiredExtensions.size()))
        .setPpEnabledExtensionNames(GpuConfig::RequiredExtensions.data());

    auto result = vk::createInstanceUnique(instanceCreateInfo);
    if (result.result != vk::Result::eSuccess) return false;

    Instance = std::move(result.value);
    VULKAN_HPP_DEFAULT_DISPATCHER.init(*Instance);

    return true;

}

re: interesting code. I started with a giant monolith function from the internet and needed to organise it in a way that it was simple to me. And the array of lambdas are useful at the moment for lazy error checking.

Hm, maybe make a VK_LAYER_LUNARG_api_dump so we can see what is actually going on.

No need, I figured it out. But I had yet to come across the layer dump, so I am going to hook that up anyway cuz it seems very useful.

But its probably good to document the solution for any future versions of me.

When I was creating my array of vk::DeviceQueueCreateInfo, I mistakenly passed the size into the vector’s constructor. In a braindead moment I thought I was reserving rather than creating empty slots. So my array had a mostly empty vk::DeviceQueueCreateInfo as its first element. That was the bug.

A close observer would notice that the bug is not in the code above, and that is because i edited it a few days ago. But it still crashed after I fixed it, so I thought it wasn’t THE fix and edited it here. But the false crash was from an attempt I had made to call get queue another way that crashes no matter what. So it took me a while longer to realise it had actually already been fixed.