Vulkan API — урок 7. Validation layers (слои валидации, слои проверок)

Что такое validation layers?

Vulkan API построен вокруг идеи минимального использования драйверов и иных, впустую нагружающих железо, средств. В том числе вулкан содержит минимум проверок на ошибки по умолчанию. Даже простейшие ошибки, такие как установка неправильного значения перечисления или передача нулевого указателя во время запроса параметра, могут привести к непредсказуемому поведению программы или вылету с ошибкой. Именно поэтому вы должны так тщательно подходить ко всему, что делаете в данном API, ведь очень просто сделать множество мелких ошибок, как например использовать новые фичи GPU, забыв запросить их в момент создания логического устройства.

Однако это не означает, что все эти проверки не могут быть добавлены лично вами. В Vulkan встроена элегантная система проверок, называемая validation layers. Validation layers опциональный компонент, который, как говорилось ранее, необходимо подключать вручную. Общий вид операций в Validation layers:

  • Проверка значений параметров с целью найти ошибку
  • Отслеживание процесса создания и уничтожения объектов для обнаружения утечек памяти
  • Проверка потокобезопасности путем отслеживания передачи вызовов между потоками
  • Запись логов по каждому вызову и передача их на стандартный вывод
  • Трассировка вызовов Vulkan для профилирования и воспроизведения

Пример реализации функции в диагностическом validation layer выглядит примерно так:

VkResult vkCreateInstance(
    const VkInstanceCreateInfo* pCreateInfo,
    const VkAllocationCallbacks* pAllocator,
    VkInstance* instance) {
    if (pCreateInfo == nullptr || instance == nullptr) {
        log("Null pointer passed to required parameter!");
        return VK_ERROR_INITIALIZATION_FAILED;
    }

    return real_vkCreateInstance(pCreateInfo, pAllocator, instance);
}

Validation layers могут быть без проблем группироваться, для того что бы включить весь необходимый вам функционал. Вы можете просто включить validation layers для тестовой версии ПО.

Внимание! Validation layers могут быть доступны если они были установлены в систему. К примеру LunarG validation layers доступны лишь есть вы установили на свой компьютер соответствующий SDK.

Ранее использовались два типа validation layers, для Instance и для конкретных устройств. Идея заключалась в том, что бы разделить проверки на глобальные и локальные соответственно. Но на данный момент слои для конкретных устройств несколько устарели. Спецификация продолжает рекомендовать включать validation layers на уровне устройств, во многом для обеспечения совместимости, которая требуется для некоторых реализаций. Мы же будет просто указывать те же слои, что на instance и на логические устройсва, о чем поговорим в соответствующей главе.

Использование validation layers.

Итак, давайте рассмотрим как включить стандартные диагностические слои доступные в Vulkan SDK. Примерно как и расширения, validation layers необходимо активировать специфическими именами. Вместо того, что бы явно указывать все полезные слои, SDK позволяет использовать VK_LAYER_LUNARG_standard_validation, который и включает целый ряд полезных слоев.

Для начала добавим переменную, которая и будут говорить о том, надо ли использовать слои или нет. Её значение основываться на макросе NDEBUG, являющийся частью стандарта и означает «not debug».

const int WIDTH = 800;
const int HEIGHT = 600;

const std::vector<const char*> validationLayers = {
    "VK_LAYER_LUNARG_standard_validation"
};

#ifdef NDEBUG
    const bool enableValidationLayers = false;
#else
    const bool enableValidationLayers = true;
#endif

Далее добавляем новую функцию checkValidationLayerSupport, которая проверяет все запрошенные слои на доступность. Вызываем её два раза, первый раз для получения количества, потом уже самих расширений.

bool checkValidationLayerSupport() {
    uint32_t layerCount;
    vkEnumerateInstanceLayerProperties(&layerCount, nullptr);

    std::vector<VkLayerProperties> availableLayers(layerCount);
    vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());

    return false;
}

Затем проверяем все ли слои в validationLayers включены в availableLayers. Для функции strcmp необходимо включить <cstring>.

for (const char* layerName : validationLayers) {
    bool layerFound = false;

    for (const auto& layerProperties : availableLayers) {
        if (strcmp(layerName, layerProperties.layerName) == 0) {
            layerFound = true;
            break;
        }
    }

    if (!layerFound) {
        return false;
    }
}

return true;

Ну что же, сейчас мы можем использовать эту функцию в createInstance:

void createInstance() {
    if (enableValidationLayers && !checkValidationLayerSupport()) {
        throw std::runtime_error("validation layers requested, but not available!");
    }

    ...
}

Теперь следует запустить программу в режиме дебага и убедиться, что ошибок нет. Если они все же появятся, то следует убедиться, правильно ли установлен Vulkan SDK. Если слоев нет вообще или слишком мало, то ищите решение тут.

 И в конце модифицируем инициализацию структур VkInstanceCreateInfo, так что бы она включала слои валидации при необходимости.

if (enableValidationLayers) {
    createInfo.enabledLayerCount = validationLayers.size();
    createInfo.ppEnabledLayerNames = validationLayers.data();
} else {
    createInfo.enabledLayerCount = 0;
}

Main Admin

7 Comments

    • Вообще это экземпляр чего либо, но более точное значение может зависеть от контекста. К примеру в уроке номер 5 более точно раскрыто значение в данном конкретном случае.

  1. Код не компилится (С2797) :
    const std::vector validationLayers = {
    «VK_LAYER_LUNARG_standard_validation»
    };

    Решение:
    const std::vector validationLayers = decltype(validationLayers) {
    «VK_LAYER_LUNARG_standard_validation»
    };

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *