我在关注 vulkan-tutorial 而我已经成功地渲染了一个旋转的方块。我现在正处于课程中应用纹理之前的阶段。在课程内继续之前,我一直在将代码模块化,一次一个接口框架。我已经成功地将各种Vulkan对象从主引擎类中提取出来,变成自己的类。这些类的每个对象都有一个接口,至少有一个初始化、创建和清理功能。
我已经用一个Buffer类完成了这个工作,它是一个抽象的基类,我的IndexBuffer、VertexBuffer和UniformBuffer都是由它派生出来的。我已经用我的CommandPool类、SyncObjects(VkSemaphore和VkFence)类、我的Pipelines(目前只有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!");
}
}
}
在这种状态下,我的代码一切都很正常。我能够渲染一个旋转的彩色方块,我可以调整窗口的大小并关闭窗口,从Visual Studio和Vulkan Layers都没有出现错误。
当我改成我之前做过的这种模式。
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_);
}
}
当它调用ImageViews的create()时失败了,给了我一个未处理的异常: 访问读写违规,说明我的ImageView类中的 "this "指针是... ... 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()
我试过通过复制、引用、指针、const reference、const pointer等方式传递参数,但无济于事,以上方式都没有用。所有的东西都一直引起异常。我不知道是什么原因导致了访问违规。由于某种原因,ImageView类没有正确地分配内存给 image_
委员,因为它指出: this
是 nullptr
的类,或者它不能写入内存等等。然而,我对所有其他Vulkan对象都遵循同样的模式,直到现在才发现这个问题。
VkImageView和VkImage在SwapChain中的用法和正确设置是什么?目前,VkImageView和VkImage在SwapChain中的使用和正确设置是怎样的?VkImage
在 SwapChain 中仍然以下列形式存储着 std::vector<VkImage>
我可以直接在类内成功创建它,但是当我试图将VkImageView提取出来变成自己的类对象时,我就开始遇到这个问题。我正在通过这个教程学习Vulkan,我开始掌握它是如何设计的,但我仍然不是API专家。现在,任何帮助都将被感激。而且,是的,我已经通过调试器,我已经观察了我的变量,我已经观察了调用堆栈,我的生活,我完全被绊倒了。如果你需要更多的信息,请不要犹豫地问。
用户 尼古拉斯 在评论区指出,我已经 i = std::shared_ptr<ImageView>()
而我应该有 i = std::make_shared<ImageView>()
是的,这是正确的,我的其他独立类也是这样创建的。这是一个被忽略的打字错误。所以我把功劳归于 NicolBolas 为的。然而,在修复了这个bug之后,它让我找到并修复了真正的bug。
真正的bug是导致 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;
}
现在代码又开始工作了,我有一个旋转的彩色方块。代码退出时没有出现任何错误,Vulkan Layers也没有任何消息。
我只是忽略了 {}
在函数的if语句中。