Explicit depth/stencil attachment setup in triangle example, code cleanup
This commit is contained in:
parent
176513be2d
commit
f7f5f57e2c
2 changed files with 150 additions and 29 deletions
|
|
@ -254,7 +254,7 @@ public:
|
||||||
// Creates a new (graphics) command pool object storing command buffers
|
// Creates a new (graphics) command pool object storing command buffers
|
||||||
void createCommandPool();
|
void createCommandPool();
|
||||||
// Setup default depth and stencil views
|
// Setup default depth and stencil views
|
||||||
void setupDepthStencil();
|
virtual void setupDepthStencil();
|
||||||
// Create framebuffers for all requested swap chain images
|
// Create framebuffers for all requested swap chain images
|
||||||
// Can be overriden in derived class to setup a custom framebuffer (e.g. for MSAA)
|
// Can be overriden in derived class to setup a custom framebuffer (e.g. for MSAA)
|
||||||
virtual void setupFrameBuffer();
|
virtual void setupFrameBuffer();
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,57 @@ public:
|
||||||
vkFreeMemory(device, uniformDataVS.memory, nullptr);
|
vkFreeMemory(device, uniformDataVS.memory, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We are going to use several temporary command buffers for setup stuff
|
||||||
|
// like submitting barriers for layout translations of buffer copies
|
||||||
|
// This function will allocate a single (primary) command buffer from the
|
||||||
|
// examples' command buffer pool and if begin is set to true it will
|
||||||
|
// also start the buffer so we can directly put commands into it
|
||||||
|
VkCommandBuffer getCommandBuffer(bool begin)
|
||||||
|
{
|
||||||
|
VkCommandBuffer cmdBuffer;
|
||||||
|
|
||||||
|
VkCommandBufferAllocateInfo cmdBufAllocateInfo = {};
|
||||||
|
cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
cmdBufAllocateInfo.commandPool = cmdPool;
|
||||||
|
cmdBufAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
|
cmdBufAllocateInfo.commandBufferCount = 1;
|
||||||
|
|
||||||
|
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, &cmdBuffer));
|
||||||
|
|
||||||
|
// If requested, also start the new command buffer
|
||||||
|
if (begin)
|
||||||
|
{
|
||||||
|
VkCommandBufferBeginInfo cmdBufInfo = vkTools::initializers::commandBufferBeginInfo();
|
||||||
|
VK_CHECK_RESULT(vkBeginCommandBuffer(cmdBuffer, &cmdBufInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmdBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will end the command buffer and submit it to the examples' queue
|
||||||
|
// Then waits for the queue to become idle so our submission is finished
|
||||||
|
// and then deletes the command buffer
|
||||||
|
// For use with setup command buffers created by getCommandBuffer
|
||||||
|
void flushCommandBuffer(VkCommandBuffer commandBuffer)
|
||||||
|
{
|
||||||
|
assert(commandBuffer != VK_NULL_HANDLE);
|
||||||
|
|
||||||
|
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
|
||||||
|
|
||||||
|
VkSubmitInfo submitInfo = {};
|
||||||
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
submitInfo.commandBufferCount = 1;
|
||||||
|
submitInfo.pCommandBuffers = &commandBuffer;
|
||||||
|
|
||||||
|
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
|
||||||
|
VK_CHECK_RESULT(vkQueueWaitIdle(queue));
|
||||||
|
|
||||||
|
if (free)
|
||||||
|
{
|
||||||
|
vkFreeCommandBuffers(device, cmdPool, 1, &commandBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Build separate command buffers for every framebuffer image
|
// Build separate command buffers for every framebuffer image
|
||||||
// Unlike in OpenGL all rendering commands are recorded once
|
// Unlike in OpenGL all rendering commands are recorded once
|
||||||
// into command buffers that are then resubmitted to the queue
|
// into command buffers that are then resubmitted to the queue
|
||||||
|
|
@ -395,16 +446,6 @@ public:
|
||||||
StagingBuffer indices;
|
StagingBuffer indices;
|
||||||
} stagingBuffers;
|
} stagingBuffers;
|
||||||
|
|
||||||
// Buffer copies are done on the queue, so we need a command buffer for them
|
|
||||||
VkCommandBufferAllocateInfo cmdBufInfo = {};
|
|
||||||
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
||||||
cmdBufInfo.commandPool = cmdPool;
|
|
||||||
cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
|
||||||
cmdBufInfo.commandBufferCount = 1;
|
|
||||||
|
|
||||||
VkCommandBuffer copyCommandBuffer;
|
|
||||||
VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufInfo, ©CommandBuffer));
|
|
||||||
|
|
||||||
// Vertex buffer
|
// Vertex buffer
|
||||||
VkBufferCreateInfo vertexBufferInfo = {};
|
VkBufferCreateInfo vertexBufferInfo = {};
|
||||||
vertexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
vertexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
|
|
@ -462,17 +503,21 @@ public:
|
||||||
cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
cmdBufferBeginInfo.pNext = NULL;
|
cmdBufferBeginInfo.pNext = NULL;
|
||||||
|
|
||||||
VkBufferCopy copyRegion = {};
|
// Buffer copies have to be submitted to a queue, so we need a command buffer for them
|
||||||
|
// Note that some devices offer a dedicated transfer queue (with only the transfer bit set)
|
||||||
|
// If you do lots of copies (especially at runtime) it's advised to use such a queu instead
|
||||||
|
// of a generalized graphics queue (that also supports transfers)
|
||||||
|
VkCommandBuffer copyCmd = getCommandBuffer(true);
|
||||||
|
|
||||||
// Put buffer region copies into command buffer
|
// Put buffer region copies into command buffer
|
||||||
// Note that the staging buffer must not be deleted before the copies
|
// Note that the staging buffer must not be deleted before the copies have been submitted and executed
|
||||||
// have been submitted and executed
|
|
||||||
VK_CHECK_RESULT(vkBeginCommandBuffer(copyCommandBuffer, &cmdBufferBeginInfo));
|
VkBufferCopy copyRegion = {};
|
||||||
|
|
||||||
// Vertex buffer
|
// Vertex buffer
|
||||||
copyRegion.size = vertexBufferSize;
|
copyRegion.size = vertexBufferSize;
|
||||||
vkCmdCopyBuffer(
|
vkCmdCopyBuffer(
|
||||||
copyCommandBuffer,
|
copyCmd,
|
||||||
stagingBuffers.vertices.buffer,
|
stagingBuffers.vertices.buffer,
|
||||||
vertices.buf,
|
vertices.buf,
|
||||||
1,
|
1,
|
||||||
|
|
@ -480,24 +525,13 @@ public:
|
||||||
// Index buffer
|
// Index buffer
|
||||||
copyRegion.size = indexBufferSize;
|
copyRegion.size = indexBufferSize;
|
||||||
vkCmdCopyBuffer(
|
vkCmdCopyBuffer(
|
||||||
copyCommandBuffer,
|
copyCmd,
|
||||||
stagingBuffers.indices.buffer,
|
stagingBuffers.indices.buffer,
|
||||||
indices.buf,
|
indices.buf,
|
||||||
1,
|
1,
|
||||||
©Region);
|
©Region);
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkEndCommandBuffer(copyCommandBuffer));
|
flushCommandBuffer(copyCmd);
|
||||||
|
|
||||||
// Submit copies to the queue
|
|
||||||
VkSubmitInfo copySubmitInfo = {};
|
|
||||||
copySubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
||||||
copySubmitInfo.commandBufferCount = 1;
|
|
||||||
copySubmitInfo.pCommandBuffers = ©CommandBuffer;
|
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, ©SubmitInfo, VK_NULL_HANDLE));
|
|
||||||
VK_CHECK_RESULT(vkQueueWaitIdle(queue));
|
|
||||||
|
|
||||||
vkFreeCommandBuffers(device, cmdPool, 1, ©CommandBuffer);
|
|
||||||
|
|
||||||
// Destroy staging buffers
|
// Destroy staging buffers
|
||||||
vkDestroyBuffer(device, stagingBuffers.vertices.buffer, nullptr);
|
vkDestroyBuffer(device, stagingBuffers.vertices.buffer, nullptr);
|
||||||
|
|
@ -671,6 +705,93 @@ public:
|
||||||
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, NULL);
|
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the depth (and stencil) buffer attachments used by our framebuffers
|
||||||
|
// Note : Override of virtual function in the base class and called from within VulkanExampleBase::prepare
|
||||||
|
void setupDepthStencil()
|
||||||
|
{
|
||||||
|
// Create an optimal image used as the depth stencil attachment
|
||||||
|
VkImageCreateInfo image = {};
|
||||||
|
image.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
|
image.imageType = VK_IMAGE_TYPE_2D;
|
||||||
|
image.format = depthFormat;
|
||||||
|
// Use example's height and width
|
||||||
|
image.extent = { width, height, 1 };
|
||||||
|
image.mipLevels = 1;
|
||||||
|
image.arrayLayers = 1;
|
||||||
|
image.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
image.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||||
|
image.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||||
|
image.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
VK_CHECK_RESULT(vkCreateImage(device, &image, nullptr, &depthStencil.image));
|
||||||
|
|
||||||
|
// Allocate memory for the image (device local) and bind it to our image
|
||||||
|
VkMemoryAllocateInfo memAlloc = {};
|
||||||
|
memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
|
VkMemoryRequirements memReqs;
|
||||||
|
vkGetImageMemoryRequirements(device, depthStencil.image, &memReqs);
|
||||||
|
memAlloc.allocationSize = memReqs.size;
|
||||||
|
memAlloc.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, &depthStencil.mem));
|
||||||
|
VK_CHECK_RESULT(vkBindImageMemory(device, depthStencil.image, depthStencil.mem, 0));
|
||||||
|
|
||||||
|
// We need to do an initial layout transition before we can use this image
|
||||||
|
// as the depth (and stencil) attachment
|
||||||
|
// Note that this may be ignored by implementations that don't care about image layout
|
||||||
|
// transitions, but it's crucial for those that do
|
||||||
|
|
||||||
|
VkCommandBuffer layoutCmd = getCommandBuffer(true);
|
||||||
|
|
||||||
|
vkTools::setImageLayout(
|
||||||
|
setupCmdBuffer,
|
||||||
|
depthStencil.image,
|
||||||
|
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT,
|
||||||
|
VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||||
|
|
||||||
|
// Add a present memory barrier to the end of the command buffer
|
||||||
|
// This will transform the frame buffer color attachment to a
|
||||||
|
// new layout for presenting it to the windowing system integration
|
||||||
|
VkImageMemoryBarrier imageMemoryBarrier = {};
|
||||||
|
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
imageMemoryBarrier.srcAccessMask = VK_FLAGS_NONE;
|
||||||
|
imageMemoryBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||||
|
// Transform layout from undefined (initial) to depth/stencil attachment (usage)
|
||||||
|
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
|
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, 1 };
|
||||||
|
imageMemoryBarrier.image = depthStencil.image;
|
||||||
|
|
||||||
|
vkCmdPipelineBarrier(
|
||||||
|
layoutCmd,
|
||||||
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
||||||
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
|
||||||
|
VK_FLAGS_NONE,
|
||||||
|
0, nullptr,
|
||||||
|
0, nullptr,
|
||||||
|
1, &imageMemoryBarrier);
|
||||||
|
|
||||||
|
flushCommandBuffer(layoutCmd);
|
||||||
|
|
||||||
|
// Create a view for ourt depth stencil image
|
||||||
|
// In Vulkan we can't access the images directly, but rather through views
|
||||||
|
// that describe a sub resource range
|
||||||
|
// So you can actually have multiple views for a single image if required
|
||||||
|
VkImageViewCreateInfo depthStencilView = {};
|
||||||
|
depthStencilView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
|
depthStencilView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
depthStencilView.format = depthFormat;
|
||||||
|
depthStencilView.subresourceRange = {};
|
||||||
|
depthStencilView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
depthStencilView.subresourceRange.baseMipLevel = 0;
|
||||||
|
depthStencilView.subresourceRange.levelCount = 1;
|
||||||
|
depthStencilView.subresourceRange.baseArrayLayer = 0;
|
||||||
|
depthStencilView.subresourceRange.layerCount = 1;
|
||||||
|
depthStencilView.image = depthStencil.image;
|
||||||
|
VK_CHECK_RESULT(vkCreateImageView(device, &depthStencilView, nullptr, &depthStencil.view));
|
||||||
|
}
|
||||||
|
|
||||||
// Create a frame buffer for each swap chain image
|
// Create a frame buffer for each swap chain image
|
||||||
// Note : Override of virtual function in the base class and called from within VulkanExampleBase::prepare
|
// Note : Override of virtual function in the base class and called from within VulkanExampleBase::prepare
|
||||||
void setupFrameBuffer()
|
void setupFrameBuffer()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue