我正在尝试按照 vulkan-tutorial.com 的精彩教程学习 Vulkan,但在必须创建交换链时遇到了一些问题。如标题所述,vkCreateSwapchainKHR会产生以下错误:Access violation executing location 0x0000000000000000.
教程建议这可能与蒸汽覆盖层发生冲突。对我来说情况并非如此,因为从教程中复制了整个代码。
我试图找出我的代码出了什么问题,并学习如何调试此类问题,因为我将来不会有参考代码。有罪的线看起来是这样的:
if (vkCreateSwapchainKHR(device, &swapChainCreateInfo, nullptr, &swapChain) != VK_SUCCESS) {
throw std::runtime_error("Could not create swap chain");
}
Run Code Online (Sandbox Code Playgroud)
我在这一行设置了一个断点,以将代码中的参数值与参考代码中的值进行比较。据我所知,没有区别。(当然地址不一样)
我应该在哪里查找代码中的问题?变量swapChain是NULL预期的。一个错误的形成swapChainCreateInfo不应该使vkCreateSwapchainKHR崩溃。它只会让它返回一些不是的东西VK_SUCCESS。并且设备创建没有问题:
if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
throw std::runtime_error("Failed to create logical device");
}
Run Code Online (Sandbox Code Playgroud)
编辑 - 我正在使用验证层VK_LAYER_LUNARG_standard_validation,我的createInfo设置如下。
// Useful functions and structures
VkPhysicalDevice physicalDevice;
VkSurfaceKHR surface;
VkSwapchainKHR swapChain;
struct QueueFamilyIndices {
std::optional<uint32_t> graphicsFamily;
std::optional<uint32_t> …Run Code Online (Sandbox Code Playgroud) Vulkan中RenderPass和Pipeline的逻辑关系是什么?
如果忽略RenderPass,我对渲染过程的理解是先将应用层准备好的顶点数据,然后将纹理数据提交给驱动,然后通过各个阶段的管道,写入Framebuffer后,就可以完成一次渲染。
那么RenderPass的职责是什么?它是为渲染每个阶段(例如格式)提供元数据的抽象,还是有其他作用?
RenderPass 和 Pipeline 是靠感觉的吗?例如,每个流水线都属于一个子通道。或者依赖项,例如流水线的最后一个输出,由 RenderPass 处理。或者是别的什么?
vkGetInstanceProcAddr并且vkGetDeviceProcAddr在API文档中完全遗漏了.但是,他们需要使用交换链执行命令(从而制作任何有意义的Vulkan应用程序).此外,SDK附带的cube/tri演示使用它们非常不一致.
这两种方法是否可以互换,如果没有,有什么区别?
在Vulkan附带的API-Samples中,似乎在调用vkWaitForFences之后总是vkQueueSubmit直接或通过execute_queue_command_buffer(在util_init.hpp中)调用.调用vkWaitForFences将阻止CPU执行,直到GPU完成之前的所有工作vkQueueSubmit.这实际上不允许同时构造多个帧,这(理论上)显着地限制了性能.
是否需要这些调用,如果是这样,是否有另一种方法在构造新帧之前不要求GPU空闲?
我一直在尝试在Vulkan中使用S3TC(BC/DXT)压缩加载压缩图像,但到目前为止我没有太多运气.
以下是Vulkan规范关于压缩图像的内容:
https://www.khronos.org/registry/dataformat/specs/1.1/dataformat.1.1.html#S3TC:
使用S3TC压缩图像格式存储的压缩纹理图像被表示为4×4纹素块的集合,其中每个块包含64或128位纹素数据.该图像被编码为普通的2D光栅图像,其中每个4×4块被视为单个像素.
https://www.khronos.org/registry/vulkan/specs/1.0/xhtml/vkspec.html#resources-images:
对于使用线性平铺创建的图像,rowPitch,arrayPitch和depthPitch描述了线性内存中子资源的布局.对于未压缩格式,rowPitch是相邻行中具有相同x坐标的纹素之间的字节数(y坐标相差一).arrayPitch是纹素之间的字节数,在图像的相邻数组层中具有相同的x和y坐标(数组层值相差一).depthPitch是在3D图像的相邻切片中具有相同x和y坐标的纹素之间的字节数(z坐标相差1).表示为寻址公式,子资源中texel的起始字节具有地址:
//(x,y,z,layer)是texel坐标
address(x,y,z,layer)= layer arrayPitch + z depthPitch + y rowPitch + x texelSize + offset
对于压缩格式,rowPitch是相邻行中压缩块之间的字节数.arrayPitch是相邻阵列层中块之间的字节数.depthPitch是3D图像的相邻切片中的块之间的字节数.
//(x,y,z,layer)是块坐标
address(x,y,z,layer)= layer arrayPitch + z depthPitch + y rowPitch + x blockSize + offset;
对于未创建为数组的图像,未定义arrayPitch.depthPitch仅针对3D图像定义.
对于颜色格式,VkImageSubresource的aspectMask成员必须为VK_IMAGE_ASPECT_COLOR_BIT.对于深度/模板格式,方面必须是VK_IMAGE_ASPECT_DEPTH_BIT或VK_IMAGE_ASPECT_STENCIL_BIT.在分别存储深度和模板方面的实现上,查询每个子资源布局将返回不同的偏移量和大小,表示用于该方面的内存区域.在存储深度和模板方面交错的实现上,返回相同的偏移和大小并表示交叉存储器分配.
我的图像是普通的2D图像(0层,1个mipmap),因此没有arrayPitch或depthPitch.由于硬件直接支持S3TC压缩,因此应该可以在不对其进行解压缩的情况下使用图像数据.在OpenGL中,这可以使用glCompressedTexImage2D来完成,这在过去对我有用.
在OpenGL中,我使用了GL_COMPRESSED_RGBA_S3TC_DXT1_EXT作为图像格式,对于Vulkan,我使用的是VK_FORMAT_BC1_RGBA_UNORM_BLOCK,它应该是等效的.这是我映射图像数据的代码:
auto dds = load_dds("img.dds");
auto *srcData = static_cast<uint8_t*>(dds.data());
auto *destData = static_cast<uint8_t*>(vkImageMapPtr); // Pointer to mapped memory of VkImage
destData += layout.offset(); // layout = VkImageLayout of the image …Run Code Online (Sandbox Code Playgroud) 对于资源转换,您需要知道资源的"之前"和"之后" VkImageLayout(例如,VkImageMemoryBarrier传递给vkCmdPipelineBarrier).Vulkan不保证任何命令缓冲区的执行顺序,除非在API文档中明确说明(从这个答案).但是,vkCmdPipelineBarrier明确地说它在调用之前和之后在命令缓冲区中创建命令之间的依赖关系.因此,当在单个命令缓冲区内转换图像时,可以在任何时刻"知道"图像的布局.
但是,vkQueueSumbit不强制执行命令缓冲区的执行顺序.如果有两个命令缓冲区,每个命令缓冲区都vkCmdPipelineBarrier调用将相同的图像转换为不同的布局,那么这两个操作之间是否存在依赖关系,还是在这种情况下需要显式同步?
https://www.khronos.org/registry/vulkan/specs/1.0/man/html/VkVertexInputBindingDescription.html
- binding是此结构描述的绑定号.
我不确定这是什么意思,例如来自https://github.com/SaschaWillems/Vulkan/blob/master/triangle/triangle.cpp
#define VERTEX_BUFFER_BIND_ID 0
....
vertices.inputAttributes[0].binding = VERTEX_BUFFER_BIND_ID;
vertices.inputAttributes[0].location = 0;
vertices.inputAttributes[0].format = VK_FORMAT_R32G32B32_SFLOAT;
vertices.inputAttributes[0].offset = offsetof(Vertex, position);
// Attribute location 1: Color
vertices.inputAttributes[1].binding = VERTEX_BUFFER_BIND_ID;
vertices.inputAttributes[1].location = 1;
vertices.inputAttributes[1].format = VK_FORMAT_R32G32B32_SFLOAT;
vertices.inputAttributes[1].offset = offsetof(Vertex, color);
Run Code Online (Sandbox Code Playgroud)
并且顶点着色器看起来像这样
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inColor;
layout (binding = 0) uniform UBO
{
mat4 projectionMatrix;
mat4 modelMatrix;
mat4 viewMatrix;
} ubo;
layout …Run Code Online (Sandbox Code Playgroud) 在Mac上支持OpenCL 将在macOS 10.15中结束,因此人们投资PyOpenCL + OpenCL作为进行通用GPU(+ CPU)计算的手段很快就会开始失去一个关键平台.
所以我的问题是:
在尝试为Vulkan构建投影矩阵时,我遇到了矛盾,并且尚未找到投影矩阵应如何将Z从输入向量映射到输出的解释.映射x和y很简单.我的理解是OpenGL Projection矩阵应该将近平截头体平面映射到-1,远远地映射到+1.Vulkan分别为0和+1.映射应该是对数的,允许近场更高的精度.
下面的例子使用near(n)= 1,far(f)= 100.这是使用我为Vulkan规范构造的矩阵的z映射图.它会在渲染中产生错误,但会产生正确的结果,因为我理解它:
lambda z: (f / (f-n) * z - f*n/(f-n)) / z

我在网上找到的最常见的OpenGL投影图,应该从-1到+1:
lambda z: ((-f+n)/(f-n)*z - 2*f*n/(f-n))/-z

这里是我使用的lib生成的一个,用于OpenGL(Rust中的cgmath):

我无法构建一个适当的Vulkan投影矩阵(其中我没有通过谷歌找到),除非我理解z应该映射到什么.我怀疑这是由于着色器后投影矩阵的隐式校正实际上映射到我列出的范围,但如果是这样,我不知道通过项目进入它的范围.
我最近正在学习 Vulkan API,但无法理解VK_SUBPASS_EXTERNAL(分配给VkSubpassDependency::srcSubpass或VkSubpassDependency::dstSubpass)的含义。的官方文件的状态:“如果srcSubpass等于VK_SUBPASS_EXTERNAL,第一同步范围包括比所述vkCmdBeginRenderPass用于开始渲染过程实例,在提交顺序更早发生的命令”。
这是否意味着一个子通道可以依赖于其他渲染通道中的另一个子通道?或者别的什么?