Reuse fence, use Vulkan result check macro, enabled text overlay

This commit is contained in:
saschawillems 2016-05-29 13:15:16 +02:00
parent f6ef292b38
commit fbed710715

View file

@ -107,6 +107,10 @@ public:
vkTools::ThreadPool threadPool; vkTools::ThreadPool threadPool;
// Fence to wait for all command buffers to finish before
// presenting to the swap chain
VkFence renderFence = {};
// Max. dimension of the ufo mesh for use as the sphere // Max. dimension of the ufo mesh for use as the sphere
// radius for frustum culling // radius for frustum culling
float objectSphereDim; float objectSphereDim;
@ -120,6 +124,7 @@ public:
zoomSpeed = 2.5f; zoomSpeed = 2.5f;
rotationSpeed = 0.5f; rotationSpeed = 0.5f;
rotation = { 0.0f, 37.5f, 0.0f }; rotation = { 0.0f, 37.5f, 0.0f };
enableTextOverlay = true;
title = "Vulkan Example - Multi threaded rendering"; title = "Vulkan Example - Multi threaded rendering";
// Get number of max. concurrrent threads // Get number of max. concurrrent threads
numThreads = std::thread::hardware_concurrency(); numThreads = std::thread::hardware_concurrency();
@ -157,6 +162,8 @@ public:
vkDestroyCommandPool(device, thread.commandPool, nullptr); vkDestroyCommandPool(device, thread.commandPool, nullptr);
vkMeshLoader::freeMeshBufferResources(device, &thread.mesh); vkMeshLoader::freeMeshBufferResources(device, &thread.mesh);
} }
vkDestroyFence(device, renderFence, nullptr);
} }
float rnd(float range) float rnd(float range)
@ -167,8 +174,6 @@ public:
// Create all threads and initialize shader push constants // Create all threads and initialize shader push constants
void prepareMultiThreadedRenderer() void prepareMultiThreadedRenderer()
{ {
// todo : separate func
// Since this demo updates the command buffers on each frame // Since this demo updates the command buffers on each frame
// we don't use the per-framebuffer command buffers from the // we don't use the per-framebuffer command buffers from the
// base class, and create a single primary command buffer instead // base class, and create a single primary command buffer instead
@ -177,11 +182,11 @@ public:
cmdPool, cmdPool,
VK_COMMAND_BUFFER_LEVEL_PRIMARY, VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1); 1);
vkTools::checkResult(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, &primaryCommandBuffer)); VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, &primaryCommandBuffer));
// Create a secondary command buffer for rendering the star sphere // Create a secondary command buffer for rendering the star sphere
cmdBufAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; cmdBufAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY;
vkTools::checkResult(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, &secondaryCommandBuffer)); VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, &secondaryCommandBuffer));
threadData.resize(numThreads); threadData.resize(numThreads);
@ -199,7 +204,7 @@ public:
VkCommandPoolCreateInfo cmdPoolInfo = vkTools::initializers::commandPoolCreateInfo(); VkCommandPoolCreateInfo cmdPoolInfo = vkTools::initializers::commandPoolCreateInfo();
cmdPoolInfo.queueFamilyIndex = swapChain.queueNodeIndex; cmdPoolInfo.queueFamilyIndex = swapChain.queueNodeIndex;
cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; cmdPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
vkTools::checkResult(vkCreateCommandPool(device, &cmdPoolInfo, nullptr, &thread->commandPool)); VK_CHECK_RESULT(vkCreateCommandPool(device, &cmdPoolInfo, nullptr, &thread->commandPool));
// One secondary command buffer per object that is updated by this thread // One secondary command buffer per object that is updated by this thread
thread->commandBuffer.resize(numObjectsPerThread); thread->commandBuffer.resize(numObjectsPerThread);
@ -209,10 +214,9 @@ public:
thread->commandPool, thread->commandPool,
VK_COMMAND_BUFFER_LEVEL_SECONDARY, VK_COMMAND_BUFFER_LEVEL_SECONDARY,
thread->commandBuffer.size()); thread->commandBuffer.size());
vkTools::checkResult(vkAllocateCommandBuffers(device, &secondaryCmdBufAllocateInfo, thread->commandBuffer.data())); VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &secondaryCmdBufAllocateInfo, thread->commandBuffer.data()));
// Unique vertex and index buffers per thread // Unique vertex and index buffers per thread
createBuffer( createBuffer(
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
meshes.ufo.vertices.size, meshes.ufo.vertices.size,
@ -246,6 +250,8 @@ public:
1, 1,
&copyRegion); &copyRegion);
// todo : staging
thread->mesh.indexCount = meshes.ufo.indexCount; thread->mesh.indexCount = meshes.ufo.indexCount;
thread->pushConstBlock.resize(numObjectsPerThread); thread->pushConstBlock.resize(numObjectsPerThread);
@ -301,7 +307,7 @@ public:
VkCommandBuffer cmdBuffer = thread->commandBuffer[cmdBufferIndex]; VkCommandBuffer cmdBuffer = thread->commandBuffer[cmdBufferIndex];
vkTools::checkResult(vkBeginCommandBuffer(cmdBuffer, &commandBufferBeginInfo)); VK_CHECK_RESULT(vkBeginCommandBuffer(cmdBuffer, &commandBufferBeginInfo));
VkViewport viewport = vkTools::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); VkViewport viewport = vkTools::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
vkCmdSetViewport(cmdBuffer, 0, 1, &viewport); vkCmdSetViewport(cmdBuffer, 0, 1, &viewport);
@ -345,7 +351,7 @@ public:
vkCmdBindIndexBuffer(cmdBuffer, thread->mesh.indices.buf, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(cmdBuffer, thread->mesh.indices.buf, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(cmdBuffer, thread->mesh.indexCount, 1, 0, 0, 0); vkCmdDrawIndexed(cmdBuffer, thread->mesh.indexCount, 1, 0, 0, 0);
vkTools::checkResult(vkEndCommandBuffer(cmdBuffer)); VK_CHECK_RESULT(vkEndCommandBuffer(cmdBuffer));
} }
void updateSecondaryCommandBuffer(VkCommandBufferInheritanceInfo inheritanceInfo) void updateSecondaryCommandBuffer(VkCommandBufferInheritanceInfo inheritanceInfo)
@ -355,7 +361,7 @@ public:
commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
commandBufferBeginInfo.pInheritanceInfo = &inheritanceInfo; commandBufferBeginInfo.pInheritanceInfo = &inheritanceInfo;
vkTools::checkResult(vkBeginCommandBuffer(secondaryCommandBuffer, &commandBufferBeginInfo)); VK_CHECK_RESULT(vkBeginCommandBuffer(secondaryCommandBuffer, &commandBufferBeginInfo));
VkViewport viewport = vkTools::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); VkViewport viewport = vkTools::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
vkCmdSetViewport(secondaryCommandBuffer, 0, 1, &viewport); vkCmdSetViewport(secondaryCommandBuffer, 0, 1, &viewport);
@ -386,7 +392,7 @@ public:
vkCmdBindIndexBuffer(secondaryCommandBuffer, meshes.skysphere.indices.buf, 0, VK_INDEX_TYPE_UINT32); vkCmdBindIndexBuffer(secondaryCommandBuffer, meshes.skysphere.indices.buf, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(secondaryCommandBuffer, meshes.skysphere.indexCount, 1, 0, 0, 0); vkCmdDrawIndexed(secondaryCommandBuffer, meshes.skysphere.indexCount, 1, 0, 0, 0);
vkTools::checkResult(vkEndCommandBuffer(secondaryCommandBuffer)); VK_CHECK_RESULT(vkEndCommandBuffer(secondaryCommandBuffer));
} }
// Updates the secondary command buffers using a thread pool // Updates the secondary command buffers using a thread pool
@ -413,7 +419,7 @@ public:
// Set target frame buffer // Set target frame buffer
vkTools::checkResult(vkBeginCommandBuffer(primaryCommandBuffer, &cmdBufInfo)); VK_CHECK_RESULT(vkBeginCommandBuffer(primaryCommandBuffer, &cmdBufInfo));
// The primary command buffer does not contain any rendering commands // The primary command buffer does not contain any rendering commands
// These are stored (and retrieved) from the secondary command buffers // These are stored (and retrieved) from the secondary command buffers
@ -460,44 +466,7 @@ public:
vkCmdEndRenderPass(primaryCommandBuffer); vkCmdEndRenderPass(primaryCommandBuffer);
vkTools::checkResult(vkEndCommandBuffer(primaryCommandBuffer)); VK_CHECK_RESULT(vkEndCommandBuffer(primaryCommandBuffer));
}
void draw()
{
// Get next image in the swap chain (back/front buffer)
vkTools::checkResult(swapChain.acquireNextImage(semaphores.presentComplete, &currentBuffer));
submitPostPresentBarrier(swapChain.buffers[currentBuffer].image);
updateCommandBuffers(frameBuffers[currentBuffer]);
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &primaryCommandBuffer;
// Setup a wait fence
// todo : reuse
VkFence renderFence = {};
VkFenceCreateInfo fenceCreateInfo = vkTools::initializers::fenceCreateInfo(VK_FLAGS_NONE);
vkCreateFence(device, &fenceCreateInfo, NULL, &renderFence);
vkTools::checkResult(vkQueueSubmit(queue, 1, &submitInfo, renderFence));
// Wait for fence to signal that all command buffers are ready
VkResult fenceRes;
do
{
fenceRes = vkWaitForFences(device, 1, &renderFence, VK_TRUE, 100000000);
} while (fenceRes == VK_TIMEOUT);
vkTools::checkResult(fenceRes);
submitPrePresentBarrier(swapChain.buffers[currentBuffer].image);
vkTools::checkResult(swapChain.queuePresent(queue, currentBuffer, semaphores.renderComplete));
vkDestroyFence(device, renderFence, nullptr);
vkTools::checkResult(vkQueueWaitIdle(queue));
} }
void loadMeshes() void loadMeshes()
@ -565,7 +534,7 @@ public:
pPipelineLayoutCreateInfo.pushConstantRangeCount = 1; pPipelineLayoutCreateInfo.pushConstantRangeCount = 1;
pPipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange; pPipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange;
vkTools::checkResult(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout)); VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout));
} }
void preparePipelines() void preparePipelines()
@ -641,14 +610,14 @@ public:
pipelineCreateInfo.stageCount = shaderStages.size(); pipelineCreateInfo.stageCount = shaderStages.size();
pipelineCreateInfo.pStages = shaderStages.data(); pipelineCreateInfo.pStages = shaderStages.data();
vkTools::checkResult(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.phong)); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.phong));
// Star sphere rendering pipeline // Star sphere rendering pipeline
rasterizationState.cullMode = VK_CULL_MODE_FRONT_BIT; rasterizationState.cullMode = VK_CULL_MODE_FRONT_BIT;
depthStencilState.depthWriteEnable = VK_FALSE; depthStencilState.depthWriteEnable = VK_FALSE;
shaderStages[0] = loadShader(getAssetPath() + "shaders/multithreading/starsphere.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[0] = loadShader(getAssetPath() + "shaders/multithreading/starsphere.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getAssetPath() + "shaders/multithreading/starsphere.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); shaderStages[1] = loadShader(getAssetPath() + "shaders/multithreading/starsphere.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
vkTools::checkResult(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.starsphere)); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.starsphere));
} }
void updateMatrices() void updateMatrices()
@ -662,9 +631,35 @@ public:
frustum.update(matrices.projection * matrices.view); frustum.update(matrices.projection * matrices.view);
} }
void draw()
{
VulkanExampleBase::prepareFrame();
updateCommandBuffers(frameBuffers[currentBuffer]);
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &primaryCommandBuffer;
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, renderFence));
// Wait for fence to signal that all command buffers are ready
VkResult fenceRes;
do
{
fenceRes = vkWaitForFences(device, 1, &renderFence, VK_TRUE, 100000000);
} while (fenceRes == VK_TIMEOUT);
VK_CHECK_RESULT(fenceRes);
vkResetFences(device, 1, &renderFence);
VulkanExampleBase::submitFrame();
}
void prepare() void prepare()
{ {
VulkanExampleBase::prepare(); VulkanExampleBase::prepare();
// Create a fence for synchronization
VkFenceCreateInfo fenceCreateInfo = vkTools::initializers::fenceCreateInfo(VK_FLAGS_NONE);
vkCreateFence(device, &fenceCreateInfo, NULL, &renderFence);
loadMeshes(); loadMeshes();
setupVertexDescriptions(); setupVertexDescriptions();
setupPipelineLayout(); setupPipelineLayout();
@ -678,15 +673,18 @@ public:
{ {
if (!prepared) if (!prepared)
return; return;
vkDeviceWaitIdle(device);
draw(); draw();
vkDeviceWaitIdle(device);
} }
virtual void viewChanged() virtual void viewChanged()
{ {
updateMatrices(); updateMatrices();
} }
virtual void getOverlayText(VulkanTextOverlay *textOverlay)
{
textOverlay->addText("Using " + std::to_string(numThreads) + " threads", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
}
}; };
VulkanExample *vulkanExample; VulkanExample *vulkanExample;