Implicit surface rendering via ray tracing
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

318 lines
14 KiB

/*
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#include "images_vk.hpp"
#include <cassert>
namespace nvvk {
VkImageMemoryBarrier makeImageMemoryBarrier(VkImage img,
VkAccessFlags srcAccess,
VkAccessFlags dstAccess,
VkImageLayout oldLayout,
VkImageLayout newLayout,
VkImageAspectFlags aspectMask)
{
VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
barrier.srcAccessMask = srcAccess;
barrier.dstAccessMask = dstAccess;
barrier.oldLayout = oldLayout;
barrier.newLayout = newLayout;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = img;
barrier.subresourceRange = {0};
barrier.subresourceRange.aspectMask = aspectMask;
barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
return barrier;
}
///////////////////////////////////////////////////////////////////////////////
// Return the access flag for an image layout
VkAccessFlags accessFlagsForImageLayout(VkImageLayout layout)
{
switch(layout)
{
case VK_IMAGE_LAYOUT_PREINITIALIZED:
return VK_ACCESS_HOST_WRITE_BIT;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
return VK_ACCESS_TRANSFER_WRITE_BIT;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
return VK_ACCESS_TRANSFER_READ_BIT;
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
return VK_ACCESS_SHADER_READ_BIT;
default:
return VkAccessFlags();
}
}
VkPipelineStageFlags pipelineStageForLayout(VkImageLayout layout)
{
switch(layout)
{
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
return VK_PIPELINE_STAGE_TRANSFER_BIT;
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; // We do this to allow queue other than graphic
// return VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; // We do this to allow queue other than graphic
// return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
case VK_IMAGE_LAYOUT_PREINITIALIZED:
return VK_PIPELINE_STAGE_HOST_BIT;
case VK_IMAGE_LAYOUT_UNDEFINED:
return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
default:
return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
}
}
void cmdBarrierImageLayout(VkCommandBuffer cmdbuffer,
VkImage image,
VkImageLayout oldImageLayout,
VkImageLayout newImageLayout,
const VkImageSubresourceRange& subresourceRange)
{
// Create an image barrier to change the layout
VkImageMemoryBarrier imageMemoryBarrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
imageMemoryBarrier.oldLayout = oldImageLayout;
imageMemoryBarrier.newLayout = newImageLayout;
imageMemoryBarrier.image = image;
imageMemoryBarrier.subresourceRange = subresourceRange;
imageMemoryBarrier.srcAccessMask = accessFlagsForImageLayout(oldImageLayout);
imageMemoryBarrier.dstAccessMask = accessFlagsForImageLayout(newImageLayout);
// Fix for a validation issue - should be needed when VkImage sharing mode is VK_SHARING_MODE_EXCLUSIVE
// and the values of srcQueueFamilyIndex and dstQueueFamilyIndex are equal, no ownership transfer is performed,
// and the barrier operates as if they were both set to VK_QUEUE_FAMILY_IGNORED.
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
VkPipelineStageFlags srcStageMask = pipelineStageForLayout(oldImageLayout);
VkPipelineStageFlags destStageMask = pipelineStageForLayout(newImageLayout);
vkCmdPipelineBarrier(cmdbuffer, srcStageMask, destStageMask, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
}
void cmdBarrierImageLayout(VkCommandBuffer cmdbuffer, VkImage image, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkImageAspectFlags aspectMask)
{
VkImageSubresourceRange subresourceRange;
subresourceRange.aspectMask = aspectMask;
subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
subresourceRange.baseMipLevel = 0;
subresourceRange.baseArrayLayer = 0;
cmdBarrierImageLayout(cmdbuffer, image, oldImageLayout, newImageLayout, subresourceRange);
}
VkImageCreateInfo makeImage2DCreateInfo(const VkExtent2D& size, VkFormat format, VkImageUsageFlags usage, bool mipmaps)
{
VkImageCreateInfo icInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
icInfo.imageType = VK_IMAGE_TYPE_2D;
icInfo.format = format;
icInfo.samples = VK_SAMPLE_COUNT_1_BIT;
icInfo.mipLevels = mipmaps ? mipLevels(size) : 1;
icInfo.arrayLayers = 1;
icInfo.extent.width = size.width;
icInfo.extent.height = size.height;
icInfo.extent.depth = 1;
icInfo.usage = usage | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
return icInfo;
}
VkImageViewCreateInfo makeImage2DViewCreateInfo(VkImage image,
VkFormat format /*= VK_FORMAT_R8G8B8A8_UNORM*/,
VkImageAspectFlags aspectFlags /*= VK_IMAGE_ASPECT_COLOR_BIT*/,
uint32_t levels /*= 1*/,
const void* pNextImageView /*= nullptr*/)
{
VkImageViewCreateInfo viewInfo{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
viewInfo.pNext = pNextImageView;
viewInfo.image = image;
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = format;
viewInfo.subresourceRange.aspectMask = aspectFlags;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = levels;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = 1;
return viewInfo;
}
VkImageViewCreateInfo makeImageViewCreateInfo(VkImage image, const VkImageCreateInfo& imageInfo, bool isCube)
{
VkImageViewCreateInfo viewInfo{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
viewInfo.pNext = nullptr;
viewInfo.image = image;
switch(imageInfo.imageType)
{
case VK_IMAGE_TYPE_1D:
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_1D;
break;
case VK_IMAGE_TYPE_2D:
viewInfo.viewType = isCube ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D;
break;
case VK_IMAGE_TYPE_3D:
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_3D;
break;
default:
assert(0);
}
viewInfo.format = imageInfo.format;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewInfo.subresourceRange.baseMipLevel = 0;
viewInfo.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
viewInfo.subresourceRange.baseArrayLayer = 0;
viewInfo.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
return viewInfo;
}
VkImageCreateInfo makeImage3DCreateInfo(const VkExtent3D& size, VkFormat format, VkImageUsageFlags usage, bool mipmaps)
{
VkImageCreateInfo icInfo = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
icInfo.imageType = VK_IMAGE_TYPE_3D;
icInfo.format = format;
icInfo.mipLevels = mipmaps ? mipLevels(size) : 1;
icInfo.arrayLayers = 1;
icInfo.samples = VK_SAMPLE_COUNT_1_BIT;
icInfo.extent.width = size.width;
icInfo.extent.height = size.height;
icInfo.extent.depth = size.depth;
icInfo.usage = usage | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
return icInfo;
}
VkImageCreateInfo makeImageCubeCreateInfo(const VkExtent2D& size, VkFormat format, VkImageUsageFlags usage, bool mipmaps)
{
VkImageCreateInfo icInfo{VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
icInfo.imageType = VK_IMAGE_TYPE_2D;
icInfo.format = format;
icInfo.mipLevels = mipmaps ? mipLevels(size) : 1;
icInfo.arrayLayers = 6;
icInfo.samples = VK_SAMPLE_COUNT_1_BIT;
icInfo.extent.width = size.width;
icInfo.extent.height = size.height;
icInfo.extent.depth = 1;
icInfo.usage = usage | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
icInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
return icInfo;
}
// This mipmap generation relies on blitting
// A more sophisticated version could be done with computer shader
// We will publish how to in the future
void cmdGenerateMipmaps(VkCommandBuffer cmdBuf, VkImage image, VkFormat imageFormat, const VkExtent2D& size, uint32_t levelCount, uint32_t layerCount, VkImageLayout currentLayout)
{
// Transfer the top level image to a layout 'eTransferSrcOptimal` and its access to 'eTransferRead'
VkImageMemoryBarrier barrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.layerCount = layerCount;
barrier.subresourceRange.levelCount = 1;
barrier.image = image;
barrier.oldLayout = currentLayout;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.srcAccessMask = accessFlagsForImageLayout(currentLayout);
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
vkCmdPipelineBarrier(cmdBuf, pipelineStageForLayout(currentLayout), VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0,
nullptr, 1, &barrier);
if(levelCount > 1)
{
// transfer remaining mips to DST optimal
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.subresourceRange.baseMipLevel = 1;
barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
vkCmdPipelineBarrier(cmdBuf, pipelineStageForLayout(currentLayout), VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr,
0, nullptr, 1, &barrier);
};
int32_t mipWidth = size.width;
int32_t mipHeight = size.height;
for(uint32_t i = 1; i < levelCount; i++)
{
VkImageBlit blit;
blit.srcOffsets[0] = {0, 0, 0};
blit.srcOffsets[1] = {mipWidth, mipHeight, 1};
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.srcSubresource.mipLevel = i - 1;
blit.srcSubresource.baseArrayLayer = 0;
blit.srcSubresource.layerCount = layerCount;
blit.dstOffsets[0] = {0, 0, 0};
blit.dstOffsets[1] = {mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1};
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.dstSubresource.mipLevel = i;
blit.dstSubresource.baseArrayLayer = 0;
blit.dstSubresource.layerCount = layerCount;
vkCmdBlitImage(cmdBuf, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
&blit, VK_FILTER_LINEAR);
// Next
{
// Transition the current miplevel into a eTransferSrcOptimal layout, to be used as the source for the next one.
barrier.subresourceRange.baseMipLevel = i;
barrier.subresourceRange.levelCount = 1;
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0,
nullptr, 1, &barrier);
}
if(mipWidth > 1)
mipWidth /= 2;
if(mipHeight > 1)
mipHeight /= 2;
}
// Transition all miplevels (now in VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) back to currentLayout
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.newLayout = currentLayout;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
barrier.dstAccessMask = accessFlagsForImageLayout(currentLayout);
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, pipelineStageForLayout(currentLayout), 0, 0, nullptr, 0,
nullptr, 1, &barrier);
}
} // namespace nvvk