私は画像描画をサポートするvulkanエンジンをプログラムしようとしています。しかし、フルスクリーンのクワッドにイメージをレンダリングしようとすると、動作しません。私は1週間以上コードをデバッグしようとしましたが、動作させることができません。私はstb_image
で画像をロードしています。ここではそのためのコードは次のとおりです。vulkanで画像を描画するときにバグがあります
errno = 0;
m_imageData = stbi_load(filename.c_str(), &m_width, &m_height, &m_channels, STBI_rgb_alpha);
if (m_imageData == nullptr) {
String error = stbi_failure_reason();
console::printErr("Image loading failed!\nImage: "_d + filename + "\nFailure reason: " + error + "\n" + strerror(errno));
}
それから私は、このメソッドにm_imageData
を渡す:
m_device = vulkanManager.getDevice().getDevice();
m_imageSize = width * height * 4;
VkImageCreateInfo imageCreateInfo;
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCreateInfo.pNext = nullptr;
imageCreateInfo.flags = 0;
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = VK_FORMAT_R8G8B8A8_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_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 result = vkCreateImage(m_device, &imageCreateInfo, nullptr, &m_image);
debug::Assert_Vulkan(result);
void* stagingBufferMemory;
VulkanBuffer stagingBuffer((uint)m_imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
stagingBuffer.mapMemory(&stagingBufferMemory, 0);
memcpy(stagingBufferMemory, pixels, m_imageSize);
stagingBuffer.unmapMemory();
VkMemoryRequirements imageMemRequirements;
vkGetImageMemoryRequirements(m_device, m_image, &imageMemRequirements);
VkMemoryAllocateInfo imageMemAllocInfo;
imageMemAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
imageMemAllocInfo.pNext = nullptr;
imageMemAllocInfo.allocationSize = imageMemRequirements.size;
imageMemAllocInfo.memoryTypeIndex = vulkanManager.findMemoryTypeIndex(imageMemRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
result = vkAllocateMemory(m_device, &imageMemAllocInfo, nullptr, &m_imageMemory);
debug::Assert_Vulkan(result);
vkBindImageMemory(m_device, m_image, m_imageMemory, 0);
VulkanCommandBuffer copyBufferToImage(vulkanManager.getDevice().getGraphicsQueueIndex());
copyBufferToImage.startCmdBuffer(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
VkBufferImageCopy region;
region.bufferOffset = 0;
region.bufferRowLength = 0;
region.bufferImageHeight = 0;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageOffset = { 0, 0, 0 };
region.imageExtent = { width, height, 1 };
vkCmdCopyBufferToImage(copyBufferToImage.getCommandBuffer(), stagingBuffer.getBuffer(), m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
copyBufferToImage.endCmdBuffer();
transitionImageLayout(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
copyBufferToImage.execute();
transitionImageLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
stagingBuffer.destroy();
transitionImageLayoutはヘルパー関数です:
void VulkanImage::transitionImageLayout(VkImageLayout oldLayout, VkImageLayout newLayout)
{
VulkanCommandBuffer cmdBuffer(vulkanManager.getDevice().getGraphicsQueueIndex());
cmdBuffer.startCmdBuffer(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
VkPipelineStageFlags srcStage, dstStage;
VkImageMemoryBarrier memoryBarrier;
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
memoryBarrier.srcAccessMask = 0;
memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
srcStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
dstStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
}
else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
}
memoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
memoryBarrier.pNext = nullptr;
memoryBarrier.oldLayout = oldLayout;
memoryBarrier.newLayout = newLayout;
memoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
memoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
memoryBarrier.image = m_image;
memoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
memoryBarrier.subresourceRange.baseArrayLayer = 0;
memoryBarrier.subresourceRange.baseMipLevel = 0;
memoryBarrier.subresourceRange.layerCount = 1;
memoryBarrier.subresourceRange.levelCount = 1;
vkCmdPipelineBarrier(
cmdBuffer.getCommandBuffer(),
srcStage, dstStage,
0,
0, nullptr,
0, nullptr,
1, &memoryBarrier
);
cmdBuffer.endCmdBuffer();
cmdBuffer.execute();
}
VulkanCommandBuffer
とVulkanBuffer
はのための単なるラッパーですVkBuffer
およびVkCommandBuffer
。
すべての画像のロードが終わると、私はimageViewを作成して、フラグメントシェーダーのディスクリプタをイメージで更新します。しかし、私がプログラムを実行すると、スクリーン上に白い部分しかありません。しかし、フラグメントシェーダに色を1つだけ描画すると、シェーダが動作しています。あなたの質問に答えるためにlink(x64のデバッグ構成でビルド)
検証レイヤーを使用していますか? – krOoze
コードはうまく見えますが、Vulkanでは問題のある箇所を見つけにくいです。バリデーションレイヤーとは何ですか?コンパイル可能なプロジェクトの形式でコードをお持ちですか?このフラグメントだけを分析するよりも、プロジェクト全体をデバッグする方がはるかに簡単です。たぶん、問題は別の場所、たとえば記述子セットの中にあるかもしれません。 – Ekzuzy
あなたはそうかもしれません。質問を編集し、Visual Studioプロジェクトをzipダウンロードとしてリンクします。 – Max