Are there tool functions to analyze errors in Vulkan?

If the variable ‘texture’ is nullptr then there is no error but if it’s not nullptr like in the image below then there is an error (Exception thrown at …) on vkUpdateDescriptorSets. Note that it’s not nullptr because the texture is successfully created, and I took an example from official website (“Vulkan C++ examples and demos”, the link is in the comment of the code below).

One of the biggest difficult on programming is when there is no idea where is the error of an API function, but most of the time, if the source code of the API is shared then it’s much more easier to locate the error. So, are there tool functions to analyze errors in Vulkan?

That function vkUpdateDescriptorSets doesn’t have a result return value.
And I profit of this thread, how to fix that error?

// Descriptor set
{
    // Referenced from "texture.cpp" in "Vulkan C++ examples and demos" https://github.com/SaschaWillems/Vulkan

    VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(_descriptorPool, &_descriptorSetLayout, 1);
    VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &_descriptorSet));

    std::vector<VkWriteDescriptorSet> writeDescriptorSets;
        
    // Binding 0 : Vertex shader uniform buffer
    writeDescriptorSets.push_back(
        vks::initializers::writeDescriptorSet(
            _descriptorSet,
            VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
            0,
            &_uniformBufferVS->descriptor));

    // Binding 1 : Fragment shader texture sampler
    //   Fragment shader: layout (binding = 1) uniform sampler2D samplerColor;
    if (texture) {
        // Setup a descriptor image info for the current texture to be used as a combined image sampler
        VkDescriptorImageInfo textureDescriptor = {};
        textureDescriptor.imageView = texture->_view;           // The image's view (images are never directly accessed by the shader, but rather through views defining subresources)
        textureDescriptor.sampler = texture->_sampler;          // The sampler (Telling the pipeline how to sample the texture, including repeat, border, etc.)
        textureDescriptor.imageLayout = texture->_imageLayout;  // The current layout of the image (Note: Should always fit the actual use, e.g. shader read)

        writeDescriptorSets.push_back(
            vks::initializers::writeDescriptorSet(
                _descriptorSet,
                VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,  // The descriptor set will use a combined image sampler (sampler and image could be split)
                1,                                          // Shader binding point 1
                &textureDescriptor));                       // Pointer to the descriptor image for our texture
    }

    vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr);
}

I don’t know what vks:initializers::writeDescriptorSet does, but unless it makes a copy of textureDescriptor the lifetime of that VkDescriptorImageInfo ends at the closing brace of the quoted code and when you call vkUpdateDescriptorSets you are passing data that contains a dangling pointer - this looks like a plain C++ object lifetime error to me.

More generally you should develop with the validation layers enabled, see Vulkan SDK validation layers. The Vulkan API does very little error checking, the validation layers are there to do this during development (only).

1 Like

The origin of the code below is in the same link I gave.

namespace vks
{
    namespace initializers
    {
        ...
        inline VkWriteDescriptorSet writeDescriptorSet(
            VkDescriptorSet dstSet,
            VkDescriptorType type,
            uint32_t binding,
            VkDescriptorImageInfo *imageInfo,
            uint32_t descriptorCount = 1)
        {
            VkWriteDescriptorSet writeDescriptorSet {};
            writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
            writeDescriptorSet.dstSet = dstSet;
            writeDescriptorSet.descriptorType = type;
            writeDescriptorSet.dstBinding = binding;
            writeDescriptorSet.pImageInfo = imageInfo;
            writeDescriptorSet.descriptorCount = descriptorCount;
            return writeDescriptorSet;
        }
        ...
    }
}

Thanks, I will come back later. Because the more I work on the problems, the more problem solved.

A code from the Official Vulkan Base used for my real project.

/** @brief Activates validation layers (and message output) when set to true */
bool validation = true; // EDIT: it was false before

A screenshot of an error without validation message.

I already set the ‘validation’ variable to true. But how to use it? … I’ve already worked on the problem, I even copied codes line by line twice (Vulkan C++ style to Vulkan C style * 2 times) then compare both files to find mistakes, but the problem is I deleted them all and I end up to this: I discover that ‘validation’ variable, but I don’t see any message, but how to show the validation message?

You have not addressed the problem I pointed out earlier:

Your code has a C++ object lifetime error and I would not be surprised if it crashes before the validation layers get to do anything useful.

Have you followed the documentation in the SDK about setting up the validation layers? You don’t necessarily have to modify source code to enable them, it can be done (among other things) by setting environment variables. The output normally goes to the terminal, when running from inside Visual Studio I think it goes to the “Output” window - sorry don’t I don’t use Visual Studio a lot.

Thank you so much, the hint ‘validation’ you gave to me is enough, with great solution. Vulkan is giant.

Two reasons I always post the solution on forum when solved:

  • It will always help me in a very far future about a precise problem, and I won’t regret.
  • My reputation increases.
// Referenced from "official imgui (v1.84)" > "examples/example_sdl_vulkan/main.cpp" > SetupVulkan

static VkDebugReportCallbackEXT g_vk_debugReport = VK_NULL_HANDLE;

#ifdef MYENGINE_VULKAN_DEBUG_REPORT
static VKAPI_ATTR VkBool32 VKAPI_CALL vk_debugReport(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage, void* pUserData)
{
    (void)flags; (void)object; (void)location; (void)messageCode; (void)pUserData; (void)pLayerPrefix; // Unused arguments
    std::string error = std::string("[vulkan] Debug report from ObjectType: ") + std::to_string(uint32_t(objectType)) + "\n\nMessage: " + pMessage + "\n\n";
    MessageBox(nullptr, error.c_str(), "Error", MB_OK | MB_ICONERROR);

    return VK_FALSE;
}
#endif

Note: The reason I currently don’t use a console output but a MessageBox is my engine currently doesn’t support a console. The best solution is to print the multiple validation messages to a text file.