diff --git a/examples/conservativeraster/conservativeraster.cpp b/examples/conservativeraster/conservativeraster.cpp index cd80b350..5571316a 100644 --- a/examples/conservativeraster/conservativeraster.cpp +++ b/examples/conservativeraster/conservativeraster.cpp @@ -5,7 +5,7 @@ * * Uses an offscreen buffer with lower resolution to demonstrate the effect of conservative rasterization * -* Copyright (C) 2018 by Sascha Willems - www.saschawillems.de +* Copyright by Sascha Willems - www.saschawillems.de * * This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) */ @@ -95,8 +95,6 @@ public: VkRenderPass renderPass; VkSampler sampler; VkDescriptorImageInfo descriptor; - VkCommandBuffer commandBuffer = VK_NULL_HANDLE; - VkSemaphore semaphore = VK_NULL_HANDLE; } offscreenPass; VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) @@ -145,19 +143,12 @@ public: uniformBuffers.scene.destroy(); triangle.vertices.destroy(); triangle.indices.destroy(); - - vkFreeCommandBuffers(device, cmdPool, 1, &offscreenPass.commandBuffer); - vkDestroySemaphore(device, offscreenPass.semaphore, nullptr); } void getEnabledFeatures() { - if (deviceFeatures.fillModeNonSolid) { - enabledFeatures.fillModeNonSolid = VK_TRUE; - }; - if (deviceFeatures.wideLines) { - enabledFeatures.wideLines = VK_TRUE; - }; + enabledFeatures.fillModeNonSolid = deviceFeatures.fillModeNonSolid; + enabledFeatures.wideLines = deviceFeatures.wideLines; } /* @@ -284,18 +275,18 @@ public: dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; dependencies[0].dstSubpass = 0; - dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; - dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; dependencies[1].srcSubpass = 0; dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; // Create the actual renderpass @@ -329,99 +320,95 @@ public: offscreenPass.descriptor.imageView = offscreenPass.color.view; offscreenPass.descriptor.sampler = offscreenPass.sampler; } - - // Sets up the command buffer that renders the scene to the offscreen frame buffer - void buildOffscreenCommandBuffer() - { - if (offscreenPass.commandBuffer == VK_NULL_HANDLE) { - offscreenPass.commandBuffer = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, false); - } - if (offscreenPass.semaphore == VK_NULL_HANDLE) { - VkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo(); - VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &offscreenPass.semaphore)); - } - - VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); - - VkClearValue clearValues[2]; - clearValues[0].color = { { 0.25f, 0.25f, 0.25f, 0.0f } }; - clearValues[1].depthStencil = { 1.0f, 0 }; - - VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); - renderPassBeginInfo.renderPass = offscreenPass.renderPass; - renderPassBeginInfo.framebuffer = offscreenPass.frameBuffer; - renderPassBeginInfo.renderArea.extent.width = offscreenPass.width; - renderPassBeginInfo.renderArea.extent.height = offscreenPass.height; - renderPassBeginInfo.clearValueCount = 2; - renderPassBeginInfo.pClearValues = clearValues; - - VK_CHECK_RESULT(vkBeginCommandBuffer(offscreenPass.commandBuffer, &cmdBufInfo)); - - VkViewport viewport = vks::initializers::viewport((float)offscreenPass.width, (float)offscreenPass.height, 0.0f, 1.0f); - vkCmdSetViewport(offscreenPass.commandBuffer, 0, 1, &viewport); - - VkRect2D scissor = vks::initializers::rect2D(offscreenPass.width, offscreenPass.height, 0, 0); - vkCmdSetScissor(offscreenPass.commandBuffer, 0, 1, &scissor); - - vkCmdBeginRenderPass(offscreenPass.commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - - vkCmdBindDescriptorSets(offscreenPass.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.scene, 0, 1, &descriptorSets.scene, 0, nullptr); - vkCmdBindPipeline(offscreenPass.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, conservativeRasterEnabled ? pipelines.triangleConservativeRaster : pipelines.triangle); - - VkDeviceSize offsets[1] = { 0 }; - vkCmdBindVertexBuffers(offscreenPass.commandBuffer, 0, 1, &triangle.vertices.buffer, offsets); - vkCmdBindIndexBuffer(offscreenPass.commandBuffer, triangle.indices.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdSetViewport(offscreenPass.commandBuffer, 0, 1, &viewport); - vkCmdDrawIndexed(offscreenPass.commandBuffer, triangle.indexCount, 1, 0, 0, 0); - - vkCmdEndRenderPass(offscreenPass.commandBuffer); - - VK_CHECK_RESULT(vkEndCommandBuffer(offscreenPass.commandBuffer)); - } - + void buildCommandBuffers() { VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); - VkClearValue clearValues[2]; - clearValues[0].color = { { 0.25f, 0.25f, 0.25f, 0.25f } }; - clearValues[1].depthStencil = { 1.0f, 0 }; - - VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); - renderPassBeginInfo.renderPass = renderPass; - renderPassBeginInfo.renderArea.offset.x = 0; - renderPassBeginInfo.renderArea.offset.y = 0; - renderPassBeginInfo.renderArea.extent.width = width; - renderPassBeginInfo.renderArea.extent.height = height; - renderPassBeginInfo.clearValueCount = 2; - renderPassBeginInfo.pClearValues = clearValues; - for (int32_t i = 0; i < drawCmdBuffers.size(); ++i) { - renderPassBeginInfo.framebuffer = frameBuffers[i]; - VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo)); - vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); - vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); - VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0); - vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); - // Low-res triangle from offscreen framebuffer - vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.fullscreen); - vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.fullscreen, 0, 1, &descriptorSets.fullscreen, 0, nullptr); - vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0); + /* + First render pass: Render a low res triangle to an offscreen framebuffer to use for visualization in second pass + */ + { + VkClearValue clearValues[2]; + clearValues[0].color = { { 0.25f, 0.25f, 0.25f, 0.0f } }; + clearValues[1].depthStencil = { 1.0f, 0 }; - // Overlay actual triangle - VkDeviceSize offsets[1] = { 0 }; - vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &triangle.vertices.buffer, offsets); - vkCmdBindIndexBuffer(drawCmdBuffers[i], triangle.indices.buffer, 0, VK_INDEX_TYPE_UINT32); - vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.triangleOverlay); - vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.scene, 0, 1, &descriptorSets.scene, 0, nullptr); - vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0); + VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); + renderPassBeginInfo.renderPass = offscreenPass.renderPass; + renderPassBeginInfo.framebuffer = offscreenPass.frameBuffer; + renderPassBeginInfo.renderArea.extent.width = offscreenPass.width; + renderPassBeginInfo.renderArea.extent.height = offscreenPass.height; + renderPassBeginInfo.clearValueCount = 2; + renderPassBeginInfo.pClearValues = clearValues; - drawUI(drawCmdBuffers[i]); + VkViewport viewport = vks::initializers::viewport((float)offscreenPass.width, (float)offscreenPass.height, 0.0f, 1.0f); + vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); - vkCmdEndRenderPass(drawCmdBuffers[i]); + VkRect2D scissor = vks::initializers::rect2D(offscreenPass.width, offscreenPass.height, 0, 0); + vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); + + vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.scene, 0, 1, &descriptorSets.scene, 0, nullptr); + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, conservativeRasterEnabled ? pipelines.triangleConservativeRaster : pipelines.triangle); + + VkDeviceSize offsets[1] = { 0 }; + vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &triangle.vertices.buffer, offsets); + vkCmdBindIndexBuffer(drawCmdBuffers[i], triangle.indices.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); + vkCmdDrawIndexed(drawCmdBuffers[i], triangle.indexCount, 1, 0, 0, 0); + + vkCmdEndRenderPass(drawCmdBuffers[i]); + } + + /* + Note: Explicit synchronization is not required between the render pass, as this is done implicit via sub pass dependencies + */ + + /* + Second render pass: Render scene with conservative rasterization + */ + { + VkClearValue clearValues[2]; + clearValues[0].color = { { 0.25f, 0.25f, 0.25f, 0.25f } }; + clearValues[1].depthStencil = { 1.0f, 0 }; + + VkRenderPassBeginInfo renderPassBeginInfo = vks::initializers::renderPassBeginInfo(); + renderPassBeginInfo.framebuffer = frameBuffers[i]; + renderPassBeginInfo.renderPass = renderPass; + renderPassBeginInfo.renderArea.offset.x = 0; + renderPassBeginInfo.renderArea.offset.y = 0; + renderPassBeginInfo.renderArea.extent.width = width; + renderPassBeginInfo.renderArea.extent.height = height; + renderPassBeginInfo.clearValueCount = 2; + renderPassBeginInfo.pClearValues = clearValues; + + vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); + vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); + VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0); + vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); + + // Low-res triangle from offscreen framebuffer + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.fullscreen); + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.fullscreen, 0, 1, &descriptorSets.fullscreen, 0, nullptr); + vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0); + + // Overlay actual triangle + VkDeviceSize offsets[1] = { 0 }; + vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &triangle.vertices.buffer, offsets); + vkCmdBindIndexBuffer(drawCmdBuffers[i], triangle.indices.buffer, 0, VK_INDEX_TYPE_UINT32); + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.triangleOverlay); + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayouts.scene, 0, 1, &descriptorSets.scene, 0, nullptr); + vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0); + + drawUI(drawCmdBuffers[i]); + + vkCmdEndRenderPass(drawCmdBuffers[i]); + } VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); } @@ -690,30 +677,9 @@ public: void draw() { VulkanExampleBase::prepareFrame(); - - // Offscreen rendering - - // Wait for swap chain presentation to finish - submitInfo.pWaitSemaphores = &semaphores.presentComplete; - // Signal ready with offscreen semaphore - submitInfo.pSignalSemaphores = &offscreenPass.semaphore; - - // Submit work submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &offscreenPass.commandBuffer; - VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - - // Scene rendering - - // Wait for offscreen semaphore - submitInfo.pWaitSemaphores = &offscreenPass.semaphore; - // Signal ready with render complete semaphpre - submitInfo.pSignalSemaphores = &semaphores.renderComplete; - - // Submit work submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer]; VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE)); - VulkanExampleBase::submitFrame(); } @@ -728,7 +694,6 @@ public: setupDescriptorPool(); setupDescriptorSet(); buildCommandBuffers(); - buildOffscreenCommandBuffer(); prepared = true; } @@ -737,29 +702,26 @@ public: if (!prepared) return; draw(); - } - - virtual void viewChanged() - { - updateUniformBuffersScene(); + if (camera.updated) + updateUniformBuffersScene(); } virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) { if (overlay->header("Settings")) { if (overlay->checkBox("Conservative rasterization", &conservativeRasterEnabled)) { - buildOffscreenCommandBuffer(); + buildCommandBuffers(); } } if (overlay->header("Device properties")) { - overlay->text("maxExtraPrimitiveOverestimationSize: %f", conservativeRasterProps.maxExtraPrimitiveOverestimationSize); + overlay->text("maxExtraPrimitiveOverestimationSize: %f", conservativeRasterProps.maxExtraPrimitiveOverestimationSize); overlay->text("extraPrimitiveOverestimationSizeGranularity: %f", conservativeRasterProps.extraPrimitiveOverestimationSizeGranularity); - overlay->text("primitiveUnderestimation: %s", conservativeRasterProps.primitiveUnderestimation ? "yes" : "no"); - overlay->text("conservativePointAndLineRasterization: %s", conservativeRasterProps.conservativePointAndLineRasterization ? "yes" : "no"); - overlay->text("degenerateTrianglesRasterized: %s", conservativeRasterProps.degenerateTrianglesRasterized ? "yes" : "no"); - overlay->text("degenerateLinesRasterized: %s", conservativeRasterProps.degenerateLinesRasterized ? "yes" : "no"); - overlay->text("fullyCoveredFragmentShaderInputVariable: %s", conservativeRasterProps.fullyCoveredFragmentShaderInputVariable ? "yes" : "no"); - overlay->text("conservativeRasterizationPostDepthCoverage: %s", conservativeRasterProps.conservativeRasterizationPostDepthCoverage ? "yes" : "no"); + overlay->text("primitiveUnderestimation: %s", conservativeRasterProps.primitiveUnderestimation ? "yes" : "no"); + overlay->text("conservativePointAndLineRasterization: %s", conservativeRasterProps.conservativePointAndLineRasterization ? "yes" : "no"); + overlay->text("degenerateTrianglesRasterized: %s", conservativeRasterProps.degenerateTrianglesRasterized ? "yes" : "no"); + overlay->text("degenerateLinesRasterized: %s", conservativeRasterProps.degenerateLinesRasterized ? "yes" : "no"); + overlay->text("fullyCoveredFragmentShaderInputVariable: %s", conservativeRasterProps.fullyCoveredFragmentShaderInputVariable ? "yes" : "no"); + overlay->text("conservativeRasterizationPostDepthCoverage: %s", conservativeRasterProps.conservativeRasterizationPostDepthCoverage ? "yes" : "no"); } }