首页 > 解决方案 > 什么是打破 vulkan 以测试调试回调是否设置正确的好方法?

问题描述

我是第一次学习 vulkan,我正在学习 vulkan教程的第 2 步。绘制三角形->设置->验证层。

我为错误回调进行了设置,现在我想测试它是否真的有效(我无法收到任何错误消息)。

我检查了我的所有函数都被调用(唯一不打印任何东西的是 debugCallBack 本身)。

似乎什么都没有损坏。我怎样才能打破东西来测试错误回调是否设置正确?

例如,如果这是 OpenGL,我会尝试在标准程序 (0) 中设置一个随机统一名称。

提前致谢。

标签: c++debuggingvulkan

解决方案


我一直在关注不同的教程;但是,我有一组文件Validation.hValidation.cpp它们用于Vulkan's ValidationLayers它们非常简单,因为它们只包含一个独立的函数。使用的文件ValidationLayers如下所示:

-验证.h-

#pragma once

#include <vulkan\vulkan.h>

void ErrorCheck( VkResult res );

-Validation.cpp-

#include "Validation.h"

#include <assert.h>
#include <iostream>

void ErrorCheck( VkResult res ) {
    if ( res != VK_SUCCESS ) {
        std::cout << "Error" << std::endl;
        assert( 0 && "There Was An Error" );
    }
}

这只是一个简单的函数,用于将消息打印到控制台并断言存在错误。实际ValidationLayers位于不同的位置,如下所示。


现在要设置Validation Layers我有一个名为VulkanInstance. 该类如下所示:

-VulkanInstance.h-

#pragma once

#include "VulkanConfiguration.h"

#include <vector>
#include <vulkan\vulkan.h>

class VulkanInstance {
private:
    VkInstance m_instance;
    std::vector<const char*> m_layers;
    std::vector<const char*> m_extensions;

public:
    VulkanInstance( VulkanConfiguration& vulkan_config );
    ~VulkanInstance();

    VkInstance& getInstance();
};

-VulkanInstance.cpp-

#include "VulkanInstance.h"

#include "Validation.h"
#include "Initializers.h"

#include <iostream>

VulkanInstance::VulkanInstance( VulkanConfiguration& vulkan_config ) {
    m_layers.push_back("VK_LAYER_LUNARG_standard_validation");
    m_extensions.push_back("VK_EXT_debug_report");

    VkApplicationInfo application_info = Initializers::applicationInfo( vulkan_config );
    VkInstanceCreateInfo instance_info = Initializers::instanceCreateInfo( application_info, m_layers, m_extensions );
    ErrorCheck( vkCreateInstance( &instance_info, NULL, &m_instance ) );
}

VulkanInstance::~VulkanInstance() {
    vkDestroyInstance( m_instance, NULL );
}

VkInstance& VulkanInstance::getInstance() {
    return m_instance;
}

由于上面的这个类确实有几个依赖项,我将向您展示VulkanConfigurationInitializers. VulkanConfiguration只是一个标题,Initializers是一堆独立的函数,用于创建Vulkan包装在namespace. 我将显示完整的Initializers标题,但我只会显示 和 所需的相关函数ValidationLayers声明VulkanInstance


-VulkanConfiguration.h-

#pragma once

#include <vulkan\vulkan.h>

struct VulkanConfiguration {
    const char* application_name = "";
    uint32_t application_version = VK_MAKE_VERSION( 0, 0, 0 );
    const char* engine_name = "My Vulkan Engine";
    const uint32_t engine_version = VK_MAKE_VERSION( 0, 0, 0 );
    const uint32_t api_version = VK_MAKE_VERSION( 1, 1, 82 );
};

-Initializers.h-

#pragma once

#include <vulkan\vulkan.h>
#include <vector>

struct VulkanConfiguration;

namespace Initializers {    
    VkApplicationInfo applicationInfo( VulkanConfiguration& config );
    VkInstanceCreateInfo instanceCreateInfo( VkApplicationInfo& app_info, std::vector<const char*>& layers, std::vector<const char*>& extensions );
    VkDeviceQueueCreateInfo deviceQueueCreateInfo( uint32_t queue_family_index, float& priority );
    VkDeviceCreateInfo deviceCreateInfo( std::vector<VkDeviceQueueCreateInfo>& queue_create_infos, VkPhysicalDeviceFeatures& device_features );
    VkCommandPoolCreateInfo commandPoolCreateInfo( uint32_t queue_family_index, VkCommandPoolCreateFlags flags = 0 );
    VkCommandBufferAllocateInfo commandBufferAllocateInfo( VkCommandPool pool, uint32_t count );
    VkBufferCreateInfo bufferCreate( VkDeviceSize size, VkBufferUsageFlags usage );
    VkMemoryAllocateInfo memoryAllocateInfo( VkDeviceSize size, uint32_t memory_type_index );
}

-初始化器.cpp-

#include "Initializers.h"
#include "VulkanConfiguration.h"

VkApplicationInfo Initializers::applicationInfo( VulkanConfiguration& config ) {
    VkApplicationInfo info = {};
    info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
    info.pApplicationName = config.application_name;
    info.pEngineName = config.engine_name;
    info.applicationVersion = config.application_version;
    info.engineVersion = config.engine_version;
    info.apiVersion = config.api_version;
    return info;
}

VkInstanceCreateInfo Initializers::instanceCreateInfo( VkApplicationInfo& app_info, std::vector<const char*>& layers, std::vector<const char*>& extensions ) {
    VkInstanceCreateInfo info = {};
    info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
    info.pApplicationInfo = &app_info;
    info.enabledExtensionCount = extensions.size();
    info.enabledLayerCount = layers.size();
    info.ppEnabledExtensionNames = extensions.data();
    info.ppEnabledLayerNames = layers.data();
    return info;
} 

这应该为我们ValidationLayers提供设置所需的一切。


现在要让 Vulkan 完全运行,您确实需要VulkanDevice,VulkanPhysicalDeviceQueueFamilyIndices,但是我敢肯定,由于您可能已经在渲染三角形,因此您应该将它们放在适当的位置。为了演示如何使其ValidationLayers工作,我将向您展示类的构造函数和析构函数VulkanDevice......

-VulkanDevice.cpp- -- 部分源代码

#include "VulkanDevice.h"

#include "Initializers.h"
#include "Validation.h"
#include "VulkanPhysicalDevice.h"

#include <vector>

VulkanDevice::VulkanDevice( VulkanInstance* instance, VulkanPhysicalDevice* physical_device ) {
    m_instance = instance;
    m_vulkan_physical_device = physical_device;

    std::vector<VkDeviceQueueCreateInfo> queue_create_infos;
    float priority = 1.0f;
    queue_create_infos.push_back( Initializers::deviceQueueCreateInfo( m_vulkan_physical_device->getQueueFamilyIndices().compute_indices, priority ) );

    VkDeviceCreateInfo create_info = Initializers::deviceCreateInfo( queue_create_infos, m_vulkan_physical_device->getPhysicalDeviceFeatures() );

    ErrorCheck( vkCreateDevice(
        m_vulkan_physical_device->getPhysicalDevice(),
        &create_info,
        nullptr,
        &m_device
    ) );

    vkGetDeviceQueue(
        m_device,
        m_vulkan_physical_device->getQueueFamilyIndices().compute_indices,
        0,
        &m_compute_queue
    );

    VkCommandPoolCreateInfo compute_pool_info = Initializers::commandPoolCreateInfo( m_vulkan_physical_device->getQueueFamilyIndices().compute_indices );

    ErrorCheck( vkCreateCommandPool(
        m_device,
        &compute_pool_info,
        nullptr,
        &m_compute_command_pool
    ) );
}

VulkanDevice::~VulkanDevice() {
    vkDestroyCommandPool(
        m_device,
        m_compute_command_pool,
        nullptr
    );

    vkDestroyDevice(
        m_device,
        nullptr
    );
}

在这里,您可以看到在我正在调用的构造函数vkCreateDevice()vkCreateCommandPool()free 函数ErrorCheck()中。截至目前,当我编译并运行它时,我的代码库返回值为 0 且没有错误。但是,在这个类的析构函数中;如果我注释掉其中一个vkDestroy...函数,无论是对于CommandPool还是Device

VulkanDevice::~VulkanDevice() {
    /*
    vkDestroyCommandPool(
        m_device,
        m_compute_command_pool,
        nullptr
    );
    */

    vkDestroyDevice(
        m_device,
        nullptr
    );
}

或者

VulkanDevice::~VulkanDevice() {
    vkDestroyCommandPool(
        m_device,
        m_compute_command_pool,
        nullptr
    );

    /*
    vkDestroyDevice(
        m_device,
        nullptr
    );
    */
}

它会分别给我这些打印到控制台的消息:

VUID-vkDestroyDevice-device-00378(ERROR / SPEC): msgNum: 614466292 - OBJ ERROR : For device 0x42af310, CommandPool objec
t 0x1 has not been destroyed. The spec valid usage text states 'All child objects created on device must have been destr
oyed prior to destroying device' (https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-vkDestroyDevic
e-device-00378)
    Objects: 1
       [0] 0x1, type: 25, name: (null)
Validation(ERROR): msg_code: 614466292:  [ VUID-vkDestroyDevice-device-00378 ]  [ VUID-vkDestroyDevice-device-00378 ] Ob
ject: 0x1 (Type = 25) | OBJ ERROR : For device 0x42af310, CommandPool object 0x1 has not been destroyed. The spec valid
usage text states 'All child objects created on device must have been destroyed prior to destroying device' (https://www
.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#VUID-vkDestroyDevice-device-00378)

C:\Users\...\Vulkan Tutorial.exe (process 1256) exited w
ith code 0.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the conso
le when debugging stops.
Press any key to close this window . . .

UNASSIGNED-ObjectTracker-ObjectLeak(ERROR / SPEC): msgNum: -1 - OBJ ERROR : VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT objec
t 0x4139590 has not been destroyed.
    Objects: 1
       [0] 0x4139590, type: 3, name: (null)
Validation(ERROR): msg_code: -1:  [ UNASSIGNED-ObjectTracker-ObjectLeak ]  [ UNASSIGNED-ObjectTracker-ObjectLeak ] Objec
t: 0x4139590 (Type = 3) | OBJ ERROR : VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT object 0x4139590 has not been destroyed.

C:\Users\...\Vulkan Tutorial.exe (process 2480) exited w
ith code 0.
To automatically close the console when debugging stops, enable Tools->Options->Debugging->Automatically close the conso
le when debugging stops.
Press any key to close this window . . .

希望这能让您对 Vulkan 及其 ValidationLayers 在一般意义上的工作原理有所了解。上面的代码不是我自己的,因为它来自这个Youtube 频道的在线教程。


推荐阅读