c++ 如何在Vulkan中渲染到纹理?

nmpmafwu  于 2023-06-25  发布在  其他
关注(0)|答案(2)|浏览(249)

我需要在我的项目中渲染texttrue。
Pass 1:绘制颜色为(0.5,0.5,0.5,1.0)的颜色正方形,渲染目标为纹理。
第2遍:使用第1遍的纹理绘制一个有纹理的正方形,渲染目标是一个表面。
预期结果:

但我得到了奇怪的结果如下:

使用以下命令创建映像:

VkImage hImageTexture = VK_NULL_HANDLE;
  VkImageCreateInfo imageCreateInfo = {0};
  imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
  imageCreateInfo.pNext = nullptr;
  imageCreateInfo.flags = 0;
  imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
  imageCreateInfo.format = VK_FORMAT_B8G8R8A8_UNORM;
  imageCreateInfo.extent.width = width;
  imageCreateInfo.extent.height = height;
  imageCreateInfo.extent.depth = 1;
  imageCreateInfo.mipLevels = 1;
  imageCreateInfo.arrayLayers = 1;
  imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
  imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
  imageCreateInfo.usage =
    VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
    VK_IMAGE_USAGE_TRANSFER_DST_BIT |
    VK_IMAGE_USAGE_SAMPLED_BIT;
  imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  imageCreateInfo.queueFamilyIndexCount = 0;
  imageCreateInfo.pQueueFamilyIndices = nullptr;
  imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  //
  VkResult res = vkCreateImage(hDevice , &imageCreateInfo , nullptr , &hImageTexture);

使用以下命令创建图像视图:

VkImageView hImageViewTexture = VK_NULL_HANDLE;
  VkImageViewCreateInfo imageViewCreateInfo = {0};
  imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
  imageViewCreateInfo.pNext = nullptr;
  imageViewCreateInfo.flags = 0;
  imageViewCreateInfo.image = hImageTexture;
  imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
  imageViewCreateInfo.format = VK_FORMAT_B8G8R8A8_UNORM;
  imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_R;
  imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_G;
  imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_B;
  imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_A;
  imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  imageViewCreateInfo.subresourceRange.baseMipLevel = 0;
  imageViewCreateInfo.subresourceRange.levelCount = 1;
  imageViewCreateInfo.subresourceRange.baseArrayLayer = 0;
  imageViewCreateInfo.subresourceRange.layerCount = 1;
  VkResult res=vkCreateImageView(
    hDevice,
    &imageViewCreateInfo,
    NULL,
    &hImageViewTexture);

渲染循环如下:

//Pass1
  //Clear texture  color
  vkCmdPipelineBarrier();//Transition layout to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
  vkCmdClearColorImage();//Clear color(0.0 , 0.0 ,0.0 , 1.0)
  vkCmdPipelineBarrier();//Transition layout to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
  //Change texture's barrier
  VkImageMemoryBarrier imageMemoryBarrierForOutput = {0};
  imageMemoryBarrierForOutput.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  imageMemoryBarrierForOutput.pNext = nullptr;
  imageMemoryBarrierForOutput.srcAccessMask = 0;
  imageMemoryBarrierForOutput.dstAccessMask = 
    VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  imageMemoryBarrierForOutput.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  imageMemoryBarrierForOutput.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
  imageMemoryBarrierForOutput.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  imageMemoryBarrierForOutput.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  imageMemoryBarrierForOutput.image = hImageTexture;
  imageMemoryBarrierForOutput.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  imageMemoryBarrierForOutput.subresourceRange.baseMipLevel = 0;
  imageMemoryBarrierForOutput.subresourceRange.levelCount = 1;
  imageMemoryBarrierForOutput.subresourceRange.baseArrayLayer = 0;
  imageMemoryBarrierForOutput.subresourceRange.layerCount = 1;
  vkCmdPipelineBarrier(
    hCommandBuffer,
    VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
    VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
    0,
    0,
    nullptr,
    0,
    nullptr,
    1,
    &imageMemoryBarrierForOutput);
  //draw
  vkCmdBeginRenderPass();
  vkCmdSetViewport();
  vkCmdSetScissor();
  vkCmdBindPipeline();
  vkCmdBindDescriptorSets();
  vkCmdBindVertexBuffers();
  vkCmdBindIndexBuffer();
  vkCmdDrawIndexed();
  vkCmdEndRenderPass();
  //
  //Pass2
  //Clear surface color
  vkCmdPipelineBarrier();//Transition layout to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
  vkCmdClearColorImage();//Clear color(0.5 , 0.5 ,1.0 , 1.0)
  vkCmdPipelineBarrier();//Transition layout to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
  //Change texture's barrier
  VkImageMemoryBarrier imageMemoryBarrierForInput = {0};
  imageMemoryBarrierForInput.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  imageMemoryBarrierForInput.pNext = nullptr;
  imageMemoryBarrierForInput.srcAccessMask = 0;
  imageMemoryBarrierForInput.dstAccessMask = 
    VK_ACCESS_SHADER_READ_BIT |
    VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
  imageMemoryBarrierForInput.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  imageMemoryBarrierForInput.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
  imageMemoryBarrierForInput.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  imageMemoryBarrierForInput.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  imageMemoryBarrierForInput.image = hImageTexture;
  imageMemoryBarrierForInput.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  imageMemoryBarrierForInput.subresourceRange.baseMipLevel = 0;
  imageMemoryBarrierForInput.subresourceRange.levelCount = 1;
  imageMemoryBarrierForInput.subresourceRange.baseArrayLayer = 0;
  imageMemoryBarrierForInput.subresourceRange.layerCount = 1;
  vkCmdPipelineBarrier(
    hCommandBuffer,
    VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
    VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
    0,
    0,
    nullptr,
    0,
    nullptr,
    1,
    &imageMemoryBarrierForInput);
  //draw
  vkCmdBeginRenderPass();
  vkCmdSetViewport();
  vkCmdSetScissor();
  vkCmdBindPipeline();
  vkCmdBindDescriptorSets();
  vkCmdBindVertexBuffers();
  vkCmdBindIndexBuffer();
  vkCmdDrawIndexed();
  vkCmdEndRenderPass();

Pass 1顶点着色器:

#version 450

layout (location=0) in vec4 inPos;
layout (location=0) out vec4 outPos;

void main(void)
{
  outPos = float4(inPos.xy , 0.0 , 1.0);  
  gl_Position = outPos;
}

Pass 1片段着色器:

#version 450

layout (location=0) in vec4 inPos;
layout (location=0) out vec4 outColor;

void main(void)
{
  outColor = float4(0.5 , 0.5 , 0.5 , 1.0);    
}

Pass 2顶点着色器:

#version 450

layout (location=0) in vec4 inPos;
layout (location=1) in vec2 inUV;
//
layout (location=0) out vec4 outPos;
layout (location=1) out vec2 outUV;
//
void main(void)
{
  outPos = inPos;
  outUV = inUV;
  //
  gl_Position=outPos;
}

Pass 2片段着色器:

#version 450
//
layout (location=0) in vec4 inPos;
layout (location=1) in vec2 inUV;
//
layout (binding=1) uniform sampler2D inTex;
layout (location=0) out vec4 outColor;
void main(void)
{
  outColor = texture(inTex , inUV);
}

如果我将图像平铺更改为VK_IMAGE_TILING_LINEAR,则会得到以下结果:

如果将图像平铺更改为VK_IMAGE_TILING_LINEAR而不透明(pass 1为透明),则结果正确!
我犯了什么错?

**编辑:**我添加了一些代码,我如何改变纹理的障碍,在渲染循环。
**编辑:**我在创建渲染过程时设置依赖项如下

VkSubpassDependency subpassDependency[2];
  subpassDependency[0].srcSubpass = VK_SUBPASS_EXTERNAL;
  subpassDependency[0].dstSubpass = 0;
  subpassDependency[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
  subpassDependency[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  subpassDependency[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
  subpassDependency[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  subpassDependency[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
  //
  subpassDependency[1].srcSubpass = 0;
  subpassDependency[1].dstSubpass = VK_SUBPASS_EXTERNAL;
  subpassDependency[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  subpassDependency[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
  subpassDependency[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  subpassDependency[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
  subpassDependency[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

但没什么可改变的

oxf4rvwz

oxf4rvwz1#

这里是一个图形-图形依赖于第一遍输出颜色附件。
第二子通道着色器读取操作必须等待第一子通道颜色附件写入操作完成。

VkSubpassDependency deps[...];
  //other values to handle external dependencies
  ...
  // the src operations will refer to the first subpass
  deps[0].srcSubpass = 0; 
  // the dst operations will refer to the second subpass 
  deps[0].dstSubpass = 1;
  // the operations from the first subpass that will have to be completed
  // the writes to the color attachment in the color attachment output stage 
  deps[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  deps[0].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  // this operations will wait on those specified in the previous lines
  // the reads issued during the fragment shader will have to wait 
  // until all the writes have been completed 
  deps[0].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
  deps[0].dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
  // do not wait for every write to have finished
  // if all writes in a region have been completed
  // then the reads can start (only in that region) 
  deps[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;

这将负责子过程之间的同步以及布局 * 在一个帧 * 中的更改,因为子过程指定附件的布局。
然后,您需要向管道发出信号,表示您打算移动到下一个渲染过程。

//draw
  vkCmdBeginRenderPass();

  vkCmdSetViewport();
  vkCmdSetScissor();
  vkCmdBindPipeline();
  vkCmdBindDescriptorSets();
  vkCmdBindVertexBuffers();
  vkCmdBindIndexBuffer();
  vkCmdDrawIndexed();
  
  vkNextSubpass();
  
  vkCmdSetViewport();
  vkCmdSetScissor();
  vkCmdBindPipeline();
  vkCmdBindDescriptorSets();
  vkCmdBindVertexBuffers();
  vkCmdBindIndexBuffer();
  vkCmdDrawIndexed();

  vkCmdEndRenderPass();

要了解常见的同步操作示例,可以查看vulkan synchronization examples page
您的问题是 * 第一次绘制写入颜色附件。第二次绘制将其作为片段着色器中的输入附件进行读取 *,因为您正在通过将其划分为更多的子过程来在一个渲染过程中完成所有操作。

u5i3ibmn

u5i3ibmn2#

这里的评论建议使用管道屏障,但我不能立即看到您的使用错误。有两种方法可以帮助您诊断此问题:
1.添加debug utils层。如果您没有启用此图层,那么您部分处于黑暗中,因为您将无法获得所需的错误报告。调试层对于诊断错误至关重要:https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_debug_utils.html
1.安装Nsight Graphics并捕获您的应用程序。您可以单步执行每个绘制调用,查看图形状态,并检查渲染目标。您甚至可能会得到一个错误,它将您指向问题。在开发Vulkan代码时,使用这样的调试器将为您节省大量时间。https://developer.nvidia.com/nsight-graphics

相关问题