Объекты Vulkan VkImageView и VkImage, вызывающие необработанное исключение в SwapChain - PullRequest
0 голосов
/ 02 мая 2020

Я следую vulkan-tutorial , и я успешно рендерил вращающийся квадрат. Я нахожусь в точке на уроках прямо перед применением текстур. Перед тем, как перейти к урокам, я по отдельности модулировал код в структуру интерфейсов. Мне успешно удалось извлечь различные объекты Vulkan из основного класса движка в их собственные классы. Каждый из этих объектов класса имеет как минимум интерфейс с функциями инициализации, создания и очистки.

Я сделал это с помощью класса Buffer, который является абстрактным базовым классом, из которого все мои IndexBuffer, VertexBuffer и UniformBuffer получены. Я сделал это с помощью моего класса CommandPool, классов SyncObjects (VkSemaphore и VkFence), моих конвейеров (пока только MainGraphicsPipeline) и моего SwapChain.

Со всеми этими в своих собственных классах я сейчас хранение этих классов как shared_ptr<Class> или vector<shared_ptr<Class>> в моих классах, которые имеют внутренние экземпляры этих классов. Это поток проектирования, с которым я остался.

Все работало идеально, пока я не начал содержать типы VkImageView в своем собственном классе. В моем классе SwapChain он содержал приватный член:

std::vector<VkImageView> imageViews_ 

и эти функции-члены, которые на них работают:

void SwapChain::cleanupImageViews() {
    for (auto imageView : imageViews_) {
        vkDestroyImageView(*device_, imageView, nullptr);
    }
}

void SwapChain::createImageViews() {
    imageViews_.resize(images_.size());

    for (size_t i = 0; i < images_.size(); i++) {
        VkImageViewCreateInfo createInfo{};
        createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
        createInfo.image = images_[i];
        createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
        createInfo.format = imageFormat_;
        createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
        createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
        createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
        createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
        createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
        createInfo.subresourceRange.baseMipLevel = 0;
        createInfo.subresourceRange.levelCount = 1;
        createInfo.subresourceRange.baseArrayLayer = 0;
        createInfo.subresourceRange.layerCount = 1;

        if (vkCreateImageView(*device_, &createInfo, nullptr, &imageViews_[i]) != VK_SUCCESS) {
            throw std::runtime_error("failed to create image views!");
        }
    }
}

С моим кодом в этом состоянии все работает нормально. Я могу отобразить вращающийся цветной квадрат, я могу изменить размер окна и закрыть окно с 0 ошибками как из Visual Studio, так и из слоев Vulkan.


Когда я переключаюсь на этот шаблон, который я делал ранее:

std::vector<std::shared_ptr<ImageView>> imageViews_;

и мои функции становятся:

void SwapChain::cleanupImageViews() {
    for (auto& imageView : imageViews_ ) {
        imageView->cleanup();
    }
}

void SwapChain::createImageViews() {
    imageViews_.resize(images_.size());

    for(auto& i : imageViews_) {
        i = std::shared_ptr<ImageView>();
        i->initialize(device_);
    }

    for (size_t i = 0; i < images_.size(); i++ ) {
        imagesViews_[i]->create(images_[i], imageFormat_);
    }
}

Сбой при вызове create () для ImageViews дает мне необработанное исключение: нарушение прав на чтение / запись о том, что указатель «this» в моем классе ImageView равен nullptr.


Вот как выглядит мой класс ImageView как:

ImageView.h

#pragma once

#include "utility.h"

namespace ForceEngine {
    namespace vk {

        class ImageView {
        private:
            VkImageView imageView_;
            VkDevice* device_;
            VkImage image_;
            VkFormat format_;

        public:
            ImageView() = default;
            ~ImageView() = default;

            void initialize(VkDevice* device);
            void create(VkImage image, VkFormat format);
            void cleanup();

            VkImageView* get() { return &imageView_; }

        private:
            void createImageView();        
        };

    } // namespace vk
} // namespace ForceEngine

ImageView. cpp

#include "ImageView.h"

namespace ForceEngine {
    namespace vk {
        void ImageView::initialize(VkDevice* device) {
            if (device == nullptr) {
                throw std::runtime_error("failed to initialize ImageView: device was nullptr!");
                device_ = device;
            }
        }

        void ImageView::create(VkImage image, VkFormat format) {
            //if (image == nullptr) throw std::runtime_error("failed to create Image View: image was nullptr!");
            //if (format == nullptr) throw std::runtime_error("failed to create Image View: format was nullptr!");
            image_ = image;  // This is where it is throwing the exception.
            format_ = format;
            createImageView();
        }

        void ImageView::createImageView() {
            VkImageViewCreateInfo createInfo{};
            createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
            createInfo.image = image_;
            createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
            createInfo.format = format_;
            createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
            createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
            createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
            createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
            createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
            createInfo.subresourceRange.baseMipLevel = 0;
            createInfo.subresourceRange.levelCount = 1;
            createInfo.subresourceRange.baseArrayLayer = 0;
            createInfo.subresourceRange.layerCount = 1;

            if (vkCreateImageView(*device_, &createInfo, nullptr, &imageView_) != VK_SUCCESS) {
                throw std::runtime_error("failed to create image views!");
            }
        }

        void ImageView::cleanup() {
            vkDestroyImageView(*device_, imageView_, nullptr);
        }

    } // namespace vk
} // namespace ForceEngine

В пределах мой класс, я попытался иметь image_ в качестве указателя и не указателя и что касается сигнатуры create(), я попытался передать параметры с помощью копирования, ссылки, указателя, ссылки на констант, указателя константы, и др c. и безрезультатно, ничего из вышеперечисленного не сработало. Все продолжает вызывать исключение. Я не знаю, что является причиной нарушения доступа. По какой-то причине класс ImageView неправильно распределяет память для члена image_, так как в нем говорится, что this было nullptr для этого класса или он не может записывать в память и т. Д. c. Тем не менее, я следовал этому же шаблону для всех других моих объектов Vulkan и до сих пор не имел этой проблемы.

Каковы подходы к использованию и правильной настройке VkImageView и VkImage в контексте контекста SwapChain? В настоящее время VkImage все еще хранятся в SwapChain как std::vector<VkImage>. Я могу успешно создать его непосредственно в классе, но когда я пытаюсь извлечь VkImageView из его собственного объекта класса, я начинаю сталкиваться с этой проблемой. , Я изучаю Vulkan через это руководство и начинаю понимать, как он спроектирован, но я все еще не эксперт в API. Прямо сейчас любая помощь будет оценена. И, да, я прошел через отладчик, я посмотрел мои переменные, я наблюдал за стеком вызовов, и на всю жизнь я совершенно ошеломлен. Если вам нужно больше информации, чем это, пожалуйста, не стесняйтесь спрашивать.

1 Ответ

0 голосов
/ 03 мая 2020

Пользователь nicol-bolas указал в разделе комментариев, что у меня было i = std::shared_ptr<ImageView>() и что у меня должно было быть i = std::make_shared<ImageView>(), и да, это правильно, и именно так создаются мои другие независимые классы , Это была упущенная ошибка опечатки. Поэтому я отдаю должное NicolBolas за это. Однако после исправления этой ошибки я смог найти и исправить настоящую ошибку.

Фактическая ошибка, которая вызывала Unhandled Exception, не имела ничего общего с ImageView, VkImageView, VkImage объекты. Настоящий виновник был в самом классе ImageView в его методе initialize(). Я назначал его член device_ в рамках оператора if, где проверял, был ли передан указатель device, nullptr или нет.

У меня изначально было следующее:

void ImageView::initialize(VkDevice* device) {
    if (device == nullptr) { throw std::runtime_error("failed to initialize Image View: device was nullptr!");
        device_ = nullptr;
    }
}

И device_ никогда не устанавливался. Это должно было быть:

void ImageView::initialize(VkDevice* device) {
    if (device == nullptr) throw std::runtime_error("failed to initialize Image View: device was nullptr!");
        device_ = nullptr;
}

Теперь код работает снова, и у меня есть вращающийся цветной квадрат. Код завершается с 0 ошибками и без сообщений от Vulkan Layers.

Я просто пропустил {} в операторе if функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...