使用几何着色器进行图层渲染似乎只输出图像数组的第一层
Layer rendering using geometry shader seems to only output the first layer of an image array
我正在尝试对图像阵列进行一些分层渲染,并在屏幕上显示其中一层。
但无论我做什么,只有第一层被正确渲染和显示,每次我尝试显示第一层以外的另一层时,我除了黑屏什么也得不到。
所以我试着打包了大部分必要的信息,希望有人能发现我的错误。
首先,我用这些参数创建了一个图像:
VkImageCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
info.imageType = VK_IMAGE_TYPE_2D;
info.format = VK_FORMAT_R8G8B8A8_UNORM;
info.extent = { WindowWidth, WindowHeight, 1 };
info.mipLevels = 1;
info.arrayLayers = 6;
info.samples = VK_SAMPLE_COUNT_1_BIT;
info.tiling = VK_IMAGE_TILING_OPTIMAL;
info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkImage myImage = createImage(info);
我省略了整个内存分配和绑定体操,因为我认为它与这里无关。
然后,我使用了两个图像视图:
- 具有整个 {0, 6} 层范围的一个,将用于几何着色器中的层渲染
- 另一个只有一层,将用于在我选择的给定层获取数据
这是我创建它们的方式:
VkImageViewCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
info.image = myImage;
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
info.format = VK_FORMAT_R8G8B8A8_UNORM;
info.components = Identity;
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.baseMipLevel = 0;
info.subresourceRange.levelCount = 1;
info.subresourceRange.baseArrayLayer = 0;
info.subresourceRange.layerCount = 6;
VkImageView imageView6Layers = createImageView(info);
VkImageViewCreateInfo info2 = info;
info2.subresourceRange.baseArrayLayer = 1; // Target the layer 1 for example
info2.subresourceRange.layerCount = 1;
VkImageView imageView1Layer = createImageView(info2);
至此,我已经构建了两个渲染通道来划分过程:
首先使用几何着色器在一次绘制调用中渲染所有图像层,使用第一个图像视图
第二次从第二个图像视图中获取数据,并将它们输出到交换链图像
这是第一个渲染通道(用于分层渲染):
// 6 layers image view
VkAttachmentDescription attachment{};
attachment.format = VK_FORMAT_R8G8B8A8_UNORM;
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference colorAttachment{};
colorAttachment.attachment = 0;
colorAttachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachment;
VkRenderPassCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.attachmentCount = 1;
info.pAttachments = &attachment;
info.subpassCount = 1;
info.pSubpasses = &subpass;
VkRenderPass renderPass6Layers = createRenderPass(info);
这是第二个渲染过程(获取数据,并将其输出到交换链图像):
VkAttachmentDescription attachments[2]{};
// Swapchain image
attachments[0].format = swpachainImageFormat;
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
// 1 layer image view
attachments[1].format = VK_FORMAT_R8G8B8A8_UNORM;
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[1].initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkAttachmentReference colorAttachment{};
colorAttachment.attachment = 0;
colorAttachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference inputAttachment{};
inputAttachment.attachment = 1;
inputAttachment.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachment;
subpass.inputAttachmentCount = 1;
subpass.pInputAttachments = &inputAttachment;
VkRenderPassCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.attachmentCount = 2;
info.pAttachments = attachments;
info.subpassCount = 1;
info.pSubpasses = &subpass;
VkRenderPass renderPass1Layer = createRenderPass(info);
然后是第一个子通道中使用的着色器:
顶点着色器:
#version 450
layout (location = 0) in vec3 iModelPos;
void main()
{
gl_Position = vec4(iModelPos, 1);
}
几何着色器:
#version 450
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
void main()
{
for (int i = 0; i < 6; ++i)
{
for (int j = 0; j < gl_in.length(); j++)
{
gl_Layer = i;
// Assume I have everything necessary to compute the matrix
gl_Position = PVM * gl_in[j].gl_Position;
EmitVertex();
}
EndPrimitive();
}
}
片段着色器:
#version 450
layout (location = 0) out vec4 oColor;
void main()
{
oColor = vec4(1,1,1,1);
}
第二个子通道中使用的着色器:
顶点着色器(简单地在整个屏幕上输出一个四边形):
#version 450
layout (location = 0) in vec3 iModelPos;
void main()
{
gl_Position = vec4(iModelPos, 1);
}
片段着色器(在图像层中获取数据):
#version 450
// Assume it's bound here
layout (input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput ImageLayer;
layout (location = 0) out vec4 oColor;
void main()
{
oColor = subpassLoad(ImageLayer);
}
最后是我的主图:
int main(void)
{
/* ... */
{
VkCommandBufferBeginInfo info{};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuffer, &info);
}
VkFramebuffer framebuffer6Layers{}
{
VkFramebufferCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
info.renderPass = renderPass6Layers;
info.attachmentCount = 1;
info.pAttachments = &imageView6Layers;
info.width = WindowWidth;
info.height = WindowHeight;
info.layers = 6;
framebuffer6Layers = createFramebuffer(info);
}
{
VkClearValue clearValues = {0,0,0,1};
VkRenderPassBeginInfo info{};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = renderPass6Layers;
info.framebuffer = framebuffer6Layers;
info.renderArea = { WindowWidth, WindowHeight };
info.clearValueCount = 1;
info.pClearValues = &clearValues;
vkCmdBeginRenderPass(cmdBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
}
/* binds */
vkCmdDraw(cmdBuffer, objectVertices.count(), 1, 0, 0);
vkCmdEndRenderPass(cmdBuffer);
vkEndCommandBuffer(cmdBuffer);
/* submit cmdBuffer and wait for rendering to finish */
{
VkCommandBufferBeginInfo info{};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuffer, &info);
}
{
VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.image = myImage;
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 6;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
vkCmdPipelineBarrier(cmdBuffer,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, nullptr,
0, nullptr,
1, &barrier);
}
VkFramebuffer framebuffer1Layer{};
{
VkImageView attachments[2]{};
attachments[0] = swapchainImageView;
attachments[1] = imageView1Layer;
VkFramebufferCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
info.renderPass = renderPass1Layer;
info.attachmentCount = 2;
info.pAttachments = attachments;
info.width = WindowWidth;
info.height = WindowHeight;
info.layers = 1;
framebuffer1Layer = createFramebuffer(info);
}
{
VkClearValue clearValues = {0,0,0,1};
VkRenderPassBeginInfo info{};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = renderPass1Layer;
info.framebuffer = framebuffer1Layer;
info.renderArea = { WindowWidth, WindowHeight };
info.clearValueCount = 1;
info.pClearValues = &clearValues;
vkCmdBeginRenderPass(cmdBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
}
/* binds */
vkCmdDraw(quadVertices.count(), 1, 0, 0);
vkCmdEndRenderPass(cmdBuffer);
vkEndCommandBuffer(cmdBuffer);
/* submit cmdBuffer, wait for rendering to finish and present the swapchain image */
/* ... */
}
我没有包含一些信息,例如帧缓冲区创建。
感觉已经给了很多信息了,希望有大佬指点一下,或者指点一下。
编辑 1:
验证层正在运行,不输出任何内容。
编辑 2:
我发现出于某些原因我实际上总是只创建一个层的帧缓冲区,这解释了为什么验证层从不抱怨。
为了在帧缓冲区中使用正确的层数,我将过程分为两个渲染过程,并在两者之间添加了一个图像屏障(参见上面编辑的过程)。
但是它并没有解决问题,当我尝试显示另一个图像层而不是第一个图像层时仍然黑屏,并且在显示第一层时正确结果。
验证层现在也不抱怨了,我按照要求添加了帧缓冲区创建细节。
编辑 3:
我尝试使用组合图像采样器统一代替输入附件,但没有成功。当我尝试显示第一层时它仍然有效,但我从其他层得到相同的黑屏。
我从第二个渲染过程中删除了附件并因此更新了内存屏障。
这是第二个渲染通道的更新:
// Swapchain image
VkAttachmentDescription attachment{};
attachment.format = swpachainImageFormat;
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference colorAttachment{};
colorAttachment.attachment = 0;
colorAttachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachment;
VkRenderPassCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.attachmentCount = 1;
info.pAttachments = &attachment;
info.subpassCount = 1;
info.pSubpasses = &subpass;
VkRenderPass renderPass1Layer = createRenderPass(info);
这是新的片段着色器:
// Assume it's bound here
layout (set = 0, binding = 0) uniform sampler2D ImageLayer;
layout (location = 0) out vec4 oColor;
void main()
{
// Assume that I have the viewport from an uniform buffer.
const vec2 uv = gl_FragCoord.xy / Viewport;
oColor = texture(ImageLayer, uv);
}
uv 值是正确的,当我尝试输出 vec4(uv, 0, 1) 时,我在屏幕上得到了预期的颜色,对于我尝试显示的每个图像层:
黑色,红色,
绿色、黄色
图像屏障的变化如下:
barrier.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT;
例如图像使用标志或描述符集布局也有一些变化,但我没有在此处包括它们。
我终于弄清楚出了什么问题。
layout (triangle_strip, max_vertices = 3) out;
我的几何着色器中的这条线导致了第三个顶点之后的其他顶点
默默丢弃。因此,我的着色器能够写入的唯一层是第一个层。
我已经解决了这个问题:
layout (triangle_strip, max_vertices = 18) out;
我想在 6 个图层上绘制一个三角形(3 个顶点),因此 max_vertices = 3 x 6 = 18。
另一个问题在我的编辑 3 中解决了。我的帧缓冲区只创建了一层而不是所需的 6 层,使得几何着色器 静默 只写在第一层上.似乎当您尝试在大于您在帧缓冲区中提供的层数的层上写入时,着色器会自动在层 0 上写入。
我正在尝试对图像阵列进行一些分层渲染,并在屏幕上显示其中一层。 但无论我做什么,只有第一层被正确渲染和显示,每次我尝试显示第一层以外的另一层时,我除了黑屏什么也得不到。 所以我试着打包了大部分必要的信息,希望有人能发现我的错误。
首先,我用这些参数创建了一个图像:
VkImageCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
info.imageType = VK_IMAGE_TYPE_2D;
info.format = VK_FORMAT_R8G8B8A8_UNORM;
info.extent = { WindowWidth, WindowHeight, 1 };
info.mipLevels = 1;
info.arrayLayers = 6;
info.samples = VK_SAMPLE_COUNT_1_BIT;
info.tiling = VK_IMAGE_TILING_OPTIMAL;
info.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VkImage myImage = createImage(info);
我省略了整个内存分配和绑定体操,因为我认为它与这里无关。
然后,我使用了两个图像视图: - 具有整个 {0, 6} 层范围的一个,将用于几何着色器中的层渲染 - 另一个只有一层,将用于在我选择的给定层获取数据
这是我创建它们的方式:
VkImageViewCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
info.image = myImage;
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
info.format = VK_FORMAT_R8G8B8A8_UNORM;
info.components = Identity;
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
info.subresourceRange.baseMipLevel = 0;
info.subresourceRange.levelCount = 1;
info.subresourceRange.baseArrayLayer = 0;
info.subresourceRange.layerCount = 6;
VkImageView imageView6Layers = createImageView(info);
VkImageViewCreateInfo info2 = info;
info2.subresourceRange.baseArrayLayer = 1; // Target the layer 1 for example
info2.subresourceRange.layerCount = 1;
VkImageView imageView1Layer = createImageView(info2);
至此,我已经构建了两个渲染通道来划分过程:
首先使用几何着色器在一次绘制调用中渲染所有图像层,使用第一个图像视图
第二次从第二个图像视图中获取数据,并将它们输出到交换链图像
这是第一个渲染通道(用于分层渲染):
// 6 layers image view
VkAttachmentDescription attachment{};
attachment.format = VK_FORMAT_R8G8B8A8_UNORM;
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference colorAttachment{};
colorAttachment.attachment = 0;
colorAttachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachment;
VkRenderPassCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.attachmentCount = 1;
info.pAttachments = &attachment;
info.subpassCount = 1;
info.pSubpasses = &subpass;
VkRenderPass renderPass6Layers = createRenderPass(info);
这是第二个渲染过程(获取数据,并将其输出到交换链图像):
VkAttachmentDescription attachments[2]{};
// Swapchain image
attachments[0].format = swpachainImageFormat;
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
// 1 layer image view
attachments[1].format = VK_FORMAT_R8G8B8A8_UNORM;
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[1].initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
attachments[1].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkAttachmentReference colorAttachment{};
colorAttachment.attachment = 0;
colorAttachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference inputAttachment{};
inputAttachment.attachment = 1;
inputAttachment.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachment;
subpass.inputAttachmentCount = 1;
subpass.pInputAttachments = &inputAttachment;
VkRenderPassCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.attachmentCount = 2;
info.pAttachments = attachments;
info.subpassCount = 1;
info.pSubpasses = &subpass;
VkRenderPass renderPass1Layer = createRenderPass(info);
然后是第一个子通道中使用的着色器:
顶点着色器:
#version 450
layout (location = 0) in vec3 iModelPos;
void main()
{
gl_Position = vec4(iModelPos, 1);
}
几何着色器:
#version 450
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
void main()
{
for (int i = 0; i < 6; ++i)
{
for (int j = 0; j < gl_in.length(); j++)
{
gl_Layer = i;
// Assume I have everything necessary to compute the matrix
gl_Position = PVM * gl_in[j].gl_Position;
EmitVertex();
}
EndPrimitive();
}
}
片段着色器:
#version 450
layout (location = 0) out vec4 oColor;
void main()
{
oColor = vec4(1,1,1,1);
}
第二个子通道中使用的着色器:
顶点着色器(简单地在整个屏幕上输出一个四边形):
#version 450
layout (location = 0) in vec3 iModelPos;
void main()
{
gl_Position = vec4(iModelPos, 1);
}
片段着色器(在图像层中获取数据):
#version 450
// Assume it's bound here
layout (input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput ImageLayer;
layout (location = 0) out vec4 oColor;
void main()
{
oColor = subpassLoad(ImageLayer);
}
最后是我的主图:
int main(void)
{
/* ... */
{
VkCommandBufferBeginInfo info{};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuffer, &info);
}
VkFramebuffer framebuffer6Layers{}
{
VkFramebufferCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
info.renderPass = renderPass6Layers;
info.attachmentCount = 1;
info.pAttachments = &imageView6Layers;
info.width = WindowWidth;
info.height = WindowHeight;
info.layers = 6;
framebuffer6Layers = createFramebuffer(info);
}
{
VkClearValue clearValues = {0,0,0,1};
VkRenderPassBeginInfo info{};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = renderPass6Layers;
info.framebuffer = framebuffer6Layers;
info.renderArea = { WindowWidth, WindowHeight };
info.clearValueCount = 1;
info.pClearValues = &clearValues;
vkCmdBeginRenderPass(cmdBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
}
/* binds */
vkCmdDraw(cmdBuffer, objectVertices.count(), 1, 0, 0);
vkCmdEndRenderPass(cmdBuffer);
vkEndCommandBuffer(cmdBuffer);
/* submit cmdBuffer and wait for rendering to finish */
{
VkCommandBufferBeginInfo info{};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(cmdBuffer, &info);
}
{
VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.image = myImage;
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 6;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
vkCmdPipelineBarrier(cmdBuffer,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, nullptr,
0, nullptr,
1, &barrier);
}
VkFramebuffer framebuffer1Layer{};
{
VkImageView attachments[2]{};
attachments[0] = swapchainImageView;
attachments[1] = imageView1Layer;
VkFramebufferCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
info.renderPass = renderPass1Layer;
info.attachmentCount = 2;
info.pAttachments = attachments;
info.width = WindowWidth;
info.height = WindowHeight;
info.layers = 1;
framebuffer1Layer = createFramebuffer(info);
}
{
VkClearValue clearValues = {0,0,0,1};
VkRenderPassBeginInfo info{};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.renderPass = renderPass1Layer;
info.framebuffer = framebuffer1Layer;
info.renderArea = { WindowWidth, WindowHeight };
info.clearValueCount = 1;
info.pClearValues = &clearValues;
vkCmdBeginRenderPass(cmdBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
}
/* binds */
vkCmdDraw(quadVertices.count(), 1, 0, 0);
vkCmdEndRenderPass(cmdBuffer);
vkEndCommandBuffer(cmdBuffer);
/* submit cmdBuffer, wait for rendering to finish and present the swapchain image */
/* ... */
}
我没有包含一些信息,例如帧缓冲区创建。 感觉已经给了很多信息了,希望有大佬指点一下,或者指点一下。
编辑 1:
验证层正在运行,不输出任何内容。
编辑 2:
我发现出于某些原因我实际上总是只创建一个层的帧缓冲区,这解释了为什么验证层从不抱怨。
为了在帧缓冲区中使用正确的层数,我将过程分为两个渲染过程,并在两者之间添加了一个图像屏障(参见上面编辑的过程)。 但是它并没有解决问题,当我尝试显示另一个图像层而不是第一个图像层时仍然黑屏,并且在显示第一层时正确结果。
验证层现在也不抱怨了,我按照要求添加了帧缓冲区创建细节。
编辑 3:
我尝试使用组合图像采样器统一代替输入附件,但没有成功。当我尝试显示第一层时它仍然有效,但我从其他层得到相同的黑屏。
我从第二个渲染过程中删除了附件并因此更新了内存屏障。
这是第二个渲染通道的更新:
// Swapchain image
VkAttachmentDescription attachment{};
attachment.format = swpachainImageFormat;
attachment.samples = VK_SAMPLE_COUNT_1_BIT;
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference colorAttachment{};
colorAttachment.attachment = 0;
colorAttachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachment;
VkRenderPassCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
info.attachmentCount = 1;
info.pAttachments = &attachment;
info.subpassCount = 1;
info.pSubpasses = &subpass;
VkRenderPass renderPass1Layer = createRenderPass(info);
这是新的片段着色器:
// Assume it's bound here
layout (set = 0, binding = 0) uniform sampler2D ImageLayer;
layout (location = 0) out vec4 oColor;
void main()
{
// Assume that I have the viewport from an uniform buffer.
const vec2 uv = gl_FragCoord.xy / Viewport;
oColor = texture(ImageLayer, uv);
}
uv 值是正确的,当我尝试输出 vec4(uv, 0, 1) 时,我在屏幕上得到了预期的颜色,对于我尝试显示的每个图像层:
黑色,红色,
绿色、黄色
图像屏障的变化如下:
barrier.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT;
例如图像使用标志或描述符集布局也有一些变化,但我没有在此处包括它们。
我终于弄清楚出了什么问题。
layout (triangle_strip, max_vertices = 3) out;
我的几何着色器中的这条线导致了第三个顶点之后的其他顶点 默默丢弃。因此,我的着色器能够写入的唯一层是第一个层。
我已经解决了这个问题:
layout (triangle_strip, max_vertices = 18) out;
我想在 6 个图层上绘制一个三角形(3 个顶点),因此 max_vertices = 3 x 6 = 18。
另一个问题在我的编辑 3 中解决了。我的帧缓冲区只创建了一层而不是所需的 6 层,使得几何着色器 静默 只写在第一层上.似乎当您尝试在大于您在帧缓冲区中提供的层数的层上写入时,着色器会自动在层 0 上写入。