From 9d0fd8ce5a6a34b6f509020527e06ac890d33909 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Tue, 1 Sep 2020 21:51:06 +0200 Subject: [PATCH 01/13] Started work on variable rate shading sample --- .../glsl/variablerateshading/scene.frag | 43 +++ .../glsl/variablerateshading/scene.vert | 37 ++ examples/CMakeLists.txt | 1 + .../variablerateshading.cpp | 332 ++++++++++++++++++ .../variablerateshading/variablerateshading.h | 58 +++ 5 files changed, 471 insertions(+) create mode 100644 data/shaders/glsl/variablerateshading/scene.frag create mode 100644 data/shaders/glsl/variablerateshading/scene.vert create mode 100644 examples/variablerateshading/variablerateshading.cpp create mode 100644 examples/variablerateshading/variablerateshading.h diff --git a/data/shaders/glsl/variablerateshading/scene.frag b/data/shaders/glsl/variablerateshading/scene.frag new file mode 100644 index 00000000..4796f1ca --- /dev/null +++ b/data/shaders/glsl/variablerateshading/scene.frag @@ -0,0 +1,43 @@ +#version 450 + +#extension GL_NV_shading_rate_image : require + +layout (set = 1, binding = 0) uniform sampler2D samplerColorMap; +layout (set = 1, binding = 1) uniform sampler2D samplerNormalMap; + +layout (location = 0) in vec3 inNormal; +layout (location = 1) in vec3 inColor; +layout (location = 2) in vec2 inUV; +layout (location = 3) in vec3 inViewVec; +layout (location = 4) in vec3 inLightVec; +layout (location = 5) in vec4 inTangent; + +layout (location = 0) out vec4 outFragColor; + +layout (constant_id = 0) const bool ALPHA_MASK = false; +layout (constant_id = 1) const float ALPHA_MASK_CUTOFF = 0.0f; + +void main() +{ + vec4 color = texture(samplerColorMap, inUV) * vec4(inColor, 1.0); + + if (ALPHA_MASK) { + if (color.a < ALPHA_MASK_CUTOFF) { + discard; + } + } + + vec3 N = normalize(inNormal); + vec3 T = normalize(inTangent.xyz); + vec3 B = cross(inNormal, inTangent.xyz) * inTangent.w; + mat3 TBN = mat3(T, B, N); + N = TBN * normalize(texture(samplerNormalMap, inUV).xyz * 2.0 - vec3(1.0)); + + const float ambient = 0.1; + vec3 L = normalize(inLightVec); + vec3 V = normalize(inViewVec); + vec3 R = reflect(-L, N); + vec3 diffuse = max(dot(N, L), ambient).rrr; + float specular = pow(max(dot(R, V), 0.0), 32.0); + outFragColor = vec4(diffuse * color.rgb + specular, color.a); +} \ No newline at end of file diff --git a/data/shaders/glsl/variablerateshading/scene.vert b/data/shaders/glsl/variablerateshading/scene.vert new file mode 100644 index 00000000..7bfa122e --- /dev/null +++ b/data/shaders/glsl/variablerateshading/scene.vert @@ -0,0 +1,37 @@ +#version 450 + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec3 inNormal; +layout (location = 2) in vec2 inUV; +layout (location = 3) in vec3 inColor; +layout (location = 4) in vec4 inTangent; + +layout (set = 0, binding = 0) uniform UBOScene +{ + mat4 projection; + mat4 view; + mat4 model; + vec4 lightPos; + vec4 viewPos; +} uboScene; + +layout (location = 0) out vec3 outNormal; +layout (location = 1) out vec3 outColor; +layout (location = 2) out vec2 outUV; +layout (location = 3) out vec3 outViewVec; +layout (location = 4) out vec3 outLightVec; +layout (location = 5) out vec4 outTangent; + +void main() +{ + outNormal = inNormal; + outColor = inColor; + outUV = inUV; + outTangent = inTangent; + gl_Position = uboScene.projection * uboScene.view * uboScene.model * vec4(inPos.xyz, 1.0); + + outNormal = mat3(uboScene.model) * inNormal; + vec4 pos = uboScene.model * vec4(inPos, 1.0); + outLightVec = uboScene.lightPos.xyz - pos.xyz; + outViewVec = uboScene.viewPos.xyz - pos.xyz; +} \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f8311364..12c12e1b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -122,6 +122,7 @@ set(EXAMPLES texturemipmapgen texturesparseresidency triangle + variablerateshading viewportarray vulkanscene ) diff --git a/examples/variablerateshading/variablerateshading.cpp b/examples/variablerateshading/variablerateshading.cpp new file mode 100644 index 00000000..f17ff520 --- /dev/null +++ b/examples/variablerateshading/variablerateshading.cpp @@ -0,0 +1,332 @@ +/* +* Vulkan Example - Variable rate shading +* +* Copyright (C) 2020 by Sascha Willems - www.saschawillems.de +* +* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +*/ + +#include "variablerateshading.h" + +VulkanExample::VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) +{ + title = "Variable rate shading"; + apiVersion = VK_VERSION_1_1; + camera.type = Camera::CameraType::firstperson; + camera.setPosition(glm::vec3(0.0f, 1.0f, 0.0f)); + camera.setRotation(glm::vec3(0.0f, -90.0f, 0.0f)); + camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f); + settings.overlay = true; + enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + enabledDeviceExtensions.push_back(VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME); +} + +VulkanExample::~VulkanExample() +{ + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + shaderData.buffer.destroy(); +} + +void VulkanExample::getEnabledFeatures() +{ + enabledFeatures.samplerAnisotropy = deviceFeatures.samplerAnisotropy; + // POI + enabledPhysicalDeviceShadingRateImageFeaturesNV = {}; + enabledPhysicalDeviceShadingRateImageFeaturesNV.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV; + enabledPhysicalDeviceShadingRateImageFeaturesNV.shadingRateImage = VK_TRUE; + // @todo + deviceCreatepNextChain = &enabledPhysicalDeviceShadingRateImageFeaturesNV; +} + +void VulkanExample::buildCommandBuffers() +{ + VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); + + VkClearValue clearValues[2]; + clearValues[0].color = defaultClearColor; + clearValues[0].color = { { 0.25f, 0.25f, 0.25f, 1.0f } };; + 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; + + const VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f); + const VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0); + + 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); + vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); + vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); + vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); + + // POI: todo + vkCmdBindShadingRateImageNV(drawCmdBuffers[i], shadingRateImage.view, VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV); + + scene.draw(drawCmdBuffers[i], vkglTF::RenderFlags::BindImages, pipelineLayout); + + drawUI(drawCmdBuffers[i]); + vkCmdEndRenderPass(drawCmdBuffers[i]); + VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i])); + } +} + +void VulkanExample::loadAssets() +{ + vkglTF::descriptorBindingFlags = vkglTF::DescriptorBindingFlags::ImageBaseColor | vkglTF::DescriptorBindingFlags::ImageNormalMap; + scene.loadFromFile(getAssetPath() + "models/sponza/sponza.gltf", vulkanDevice, queue, vkglTF::FileLoadingFlags::PreTransformVertices | vkglTF::FileLoadingFlags::FlipY); +} + +void VulkanExample::setupDescriptors() +{ + // Pool + const std::vector poolSizes = { + vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1), + }; + VkDescriptorPoolCreateInfo descriptorPoolInfo = vks::initializers::descriptorPoolCreateInfo(poolSizes, 1); + VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool)); + + // Descriptor set layout + const std::vector setLayoutBindings = { + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), + }; + VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); + + // Pipeline layout + const std::vector setLayouts = { + descriptorSetLayout, + vkglTF::descriptorSetLayoutImage, + }; + VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), 2); + VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout)); + + // Descriptor set + VkDescriptorSetAllocateInfo allocInfo = vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1); + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet)); + std::vector writeDescriptorSets = { + vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &shaderData.buffer.descriptor), + }; + vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); +} + +// [POI] +void VulkanExample::prepareShadingRateImage() +{ + VkImageCreateInfo imageCI{}; + imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCI.imageType = VK_IMAGE_TYPE_2D; + imageCI.format = VK_FORMAT_R8_UINT; + imageCI.extent = { 512, 512, 1 }; + imageCI.mipLevels = 1; + imageCI.arrayLayers = 1; + imageCI.samples = VK_SAMPLE_COUNT_1_BIT; + imageCI.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCI.usage = VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &shadingRateImage.image)); + VkMemoryRequirements memReqs{}; + vkGetImageMemoryRequirements(device, shadingRateImage.image, &memReqs); + + VkMemoryAllocateInfo memAllloc{}; + memAllloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memAllloc.allocationSize = memReqs.size; + memAllloc.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAllloc, nullptr, &shadingRateImage.memory)); + VK_CHECK_RESULT(vkBindImageMemory(device, shadingRateImage.image, shadingRateImage.memory, 0)); + + VkImageViewCreateInfo imageViewCI{}; + imageViewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D; + imageViewCI.image = shadingRateImage.image; + imageViewCI.format = VK_FORMAT_R8_UINT; + imageViewCI.subresourceRange.baseMipLevel = 0; + imageViewCI.subresourceRange.levelCount = 1; + imageViewCI.subresourceRange.baseArrayLayer = 0; + imageViewCI.subresourceRange.layerCount = 1; + imageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + VK_CHECK_RESULT(vkCreateImageView(device, &imageViewCI, nullptr, &shadingRateImage.view)); + + // Populate with shading rate pattern + const size_t bufferSize = 512 * 512 * sizeof(uint8_t); + uint8_t val = VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV; + uint8_t* shadingRatePatternData = new uint8_t[512 * 512]; + memset(shadingRatePatternData, val, bufferSize); + + VkBuffer stagingBuffer; + VkDeviceMemory stagingMemory; + + VkBufferCreateInfo bufferCreateInfo{}; + bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferCreateInfo.size = bufferSize; + bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + VK_CHECK_RESULT(vkCreateBuffer(device, &bufferCreateInfo, nullptr, &stagingBuffer)); + VkMemoryAllocateInfo memAllocInfo{}; + memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memReqs = {}; + vkGetBufferMemoryRequirements(device, stagingBuffer, &memReqs); + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &stagingMemory)); + VK_CHECK_RESULT(vkBindBufferMemory(device, stagingBuffer, stagingMemory, 0)); + + uint8_t* mapped; + VK_CHECK_RESULT(vkMapMemory(device, stagingMemory, 0, memReqs.size, 0, (void**)&mapped)); + memcpy(mapped, shadingRatePatternData, bufferSize); + vkUnmapMemory(device, stagingMemory); + + delete[] shadingRatePatternData; + + // Upload + VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + VkImageSubresourceRange subresourceRange = {}; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresourceRange.levelCount = 1; + subresourceRange.layerCount = 1; + { + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imageMemoryBarrier.srcAccessMask = 0; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imageMemoryBarrier.image = shadingRateImage.image; + imageMemoryBarrier.subresourceRange = subresourceRange; + vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + } + VkBufferImageCopy bufferCopyRegion{}; + bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + bufferCopyRegion.imageSubresource.layerCount = 1; + bufferCopyRegion.imageExtent.width = 512; + bufferCopyRegion.imageExtent.height = 512; + bufferCopyRegion.imageExtent.depth = 1; + vkCmdCopyBufferToImage(copyCmd, stagingBuffer, shadingRateImage.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion); + { + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV; + imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imageMemoryBarrier.dstAccessMask = 0; + imageMemoryBarrier.image = shadingRateImage.image; + imageMemoryBarrier.subresourceRange = subresourceRange; + vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + } + vulkanDevice->flushCommandBuffer(copyCmd, queue, true); + + vkFreeMemory(device, stagingMemory, nullptr); + vkDestroyBuffer(device, stagingBuffer, nullptr); +} + +void VulkanExample::preparePipelines() +{ + VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE); + VkPipelineRasterizationStateCreateInfo rasterizationStateCI = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0); + VkPipelineColorBlendAttachmentState blendAttachmentStateCI = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE); + VkPipelineColorBlendStateCreateInfo colorBlendStateCI = vks::initializers::pipelineColorBlendStateCreateInfo(1, &blendAttachmentStateCI); + VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = vks::initializers::pipelineDepthStencilStateCreateInfo(VK_TRUE, VK_TRUE, VK_COMPARE_OP_LESS_OR_EQUAL); + VkPipelineViewportStateCreateInfo viewportStateCI = vks::initializers::pipelineViewportStateCreateInfo(1, 1, 0); + VkPipelineMultisampleStateCreateInfo multisampleStateCI = vks::initializers::pipelineMultisampleStateCreateInfo(VK_SAMPLE_COUNT_1_BIT, 0); + const std::vector dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + VkPipelineDynamicStateCreateInfo dynamicStateCI = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables.data(), static_cast(dynamicStateEnables.size()), 0); + std::array shaderStages; + + // [POI] Per-Viewport shading rate palette entries + const std::vector shadingRatePaletteEntries = { + VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV, + VK_SHADING_RATE_PALETTE_ENTRY_16_INVOCATIONS_PER_PIXEL_NV, + VK_SHADING_RATE_PALETTE_ENTRY_8_INVOCATIONS_PER_PIXEL_NV, + VK_SHADING_RATE_PALETTE_ENTRY_4_INVOCATIONS_PER_PIXEL_NV, + VK_SHADING_RATE_PALETTE_ENTRY_2_INVOCATIONS_PER_PIXEL_NV, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X1_PIXELS_NV, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV, + VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV, + }; + VkShadingRatePaletteNV shadingRatePalette{}; + shadingRatePalette.shadingRatePaletteEntryCount = static_cast(shadingRatePaletteEntries.size()); + shadingRatePalette.pShadingRatePaletteEntries = shadingRatePaletteEntries.data(); + VkPipelineViewportShadingRateImageStateCreateInfoNV pipelineViewportShadingRateImageStateCI{}; + pipelineViewportShadingRateImageStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV; + pipelineViewportShadingRateImageStateCI.shadingRateImageEnable = VK_TRUE; + pipelineViewportShadingRateImageStateCI.viewportCount = 1; + pipelineViewportShadingRateImageStateCI.pShadingRatePalettes = &shadingRatePalette; + viewportStateCI.pNext = &pipelineViewportShadingRateImageStateCI; + + VkGraphicsPipelineCreateInfo pipelineCI = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0); + pipelineCI.pInputAssemblyState = &inputAssemblyStateCI; + pipelineCI.pRasterizationState = &rasterizationStateCI; + pipelineCI.pColorBlendState = &colorBlendStateCI; + pipelineCI.pMultisampleState = &multisampleStateCI; + pipelineCI.pViewportState = &viewportStateCI; + pipelineCI.pDepthStencilState = &depthStencilStateCI; + pipelineCI.pDynamicState = &dynamicStateCI; + pipelineCI.stageCount = static_cast(shaderStages.size()); + pipelineCI.pStages = shaderStages.data(); + pipelineCI.pVertexInputState = vkglTF::Vertex::getPipelineVertexInputState({ vkglTF::VertexComponent::Position, vkglTF::VertexComponent::Normal, vkglTF::VertexComponent::UV, vkglTF::VertexComponent::Color, vkglTF::VertexComponent::Tangent }); + + shaderStages[0] = loadShader(getShadersPath() + "variablerateshading/scene.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(getShadersPath() + "variablerateshading/scene.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); +} + +void VulkanExample::prepareUniformBuffers() +{ + VK_CHECK_RESULT(vulkanDevice->createBuffer( + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &shaderData.buffer, + sizeof(shaderData.values))); + VK_CHECK_RESULT(shaderData.buffer.map()); + updateUniformBuffers(); +} + +void VulkanExample::updateUniformBuffers() +{ + shaderData.values.projection = camera.matrices.perspective; + shaderData.values.view = camera.matrices.view; + shaderData.values.viewPos = camera.viewPos; + memcpy(shaderData.buffer.mapped, &shaderData.values, sizeof(shaderData.values)); +} + +void VulkanExample::prepare() +{ + VulkanExampleBase::prepare(); + loadAssets(); + + vkCmdBindShadingRateImageNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdBindShadingRateImageNV")); + + prepareShadingRateImage(); + prepareUniformBuffers(); + setupDescriptors(); + preparePipelines(); + buildCommandBuffers(); + prepared = true; +} + +void VulkanExample::render() +{ + renderFrame(); + if (camera.updated) { + updateUniformBuffers(); + } +} + +void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay* overlay) +{ +} + +VULKAN_EXAMPLE_MAIN() \ No newline at end of file diff --git a/examples/variablerateshading/variablerateshading.h b/examples/variablerateshading/variablerateshading.h new file mode 100644 index 00000000..8d7aede2 --- /dev/null +++ b/examples/variablerateshading/variablerateshading.h @@ -0,0 +1,58 @@ +/* +* Vulkan Example - Variable rate shading +* +* Copyright (C) 2020 by Sascha Willems - www.saschawillems.de +* +* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT) +*/ + +#include "vulkanexamplebase.h" +#include "VulkanglTFModel.h" + +#define ENABLE_VALIDATION false + +class VulkanExample : public VulkanExampleBase +{ +public: + vkglTF::Model scene; + + struct ShadingRateImage { + VkImage image; + VkDeviceMemory memory; + VkImageView view; + } shadingRateImage; + + struct ShaderData { + vks::Buffer buffer; + struct Values { + glm::mat4 projection; + glm::mat4 view; + glm::mat4 model = glm::mat4(1.0f); + glm::vec4 lightPos = glm::vec4(0.0f, -2.5f, 0.0f, 1.0f); + glm::vec4 viewPos; + } values; + } shaderData; + + VkPipeline pipeline; + VkPipelineLayout pipelineLayout; + VkDescriptorSet descriptorSet; + VkDescriptorSetLayout descriptorSetLayout; + + VkPhysicalDeviceShadingRateImageFeaturesNV enabledPhysicalDeviceShadingRateImageFeaturesNV; + PFN_vkCmdBindShadingRateImageNV vkCmdBindShadingRateImageNV; + + VulkanExample(); + ~VulkanExample(); + virtual void getEnabledFeatures(); + void buildCommandBuffers(); + void loadglTFFile(std::string filename); + void loadAssets(); + void prepareShadingRateImage(); + void setupDescriptors(); + void preparePipelines(); + void prepareUniformBuffers(); + void updateUniformBuffers(); + void prepare(); + virtual void render(); + virtual void OnUpdateUIOverlay(vks::UIOverlay* overlay); +}; \ No newline at end of file From 236595c940f9726c2a75ce556e982695cdec7be4 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Wed, 2 Sep 2020 19:14:11 +0200 Subject: [PATCH 02/13] Proper shading rate image size based on device properties Fill with different shading rate invocation patters --- .../variablerateshading.cpp | 45 ++++++++++++++++--- .../variablerateshading/variablerateshading.h | 5 ++- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/examples/variablerateshading/variablerateshading.cpp b/examples/variablerateshading/variablerateshading.cpp index f17ff520..758a5409 100644 --- a/examples/variablerateshading/variablerateshading.cpp +++ b/examples/variablerateshading/variablerateshading.cpp @@ -122,19 +122,27 @@ void VulkanExample::setupDescriptors() // [POI] void VulkanExample::prepareShadingRateImage() { + // Shading rate image size depends on shading rate texel size + // For each texel in the target image, there is a corresponding shading texel size width x height block in the shading rate image + const VkExtent3D imageExtent = { width / physicalDeviceShadingRateImagePropertiesNV.shadingRateTexelSize.width, height / physicalDeviceShadingRateImagePropertiesNV.shadingRateTexelSize.height, 1 }; + VkImageCreateInfo imageCI{}; imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageCI.imageType = VK_IMAGE_TYPE_2D; imageCI.format = VK_FORMAT_R8_UINT; - imageCI.extent = { 512, 512, 1 }; + imageCI.extent = imageExtent; imageCI.mipLevels = 1; imageCI.arrayLayers = 1; imageCI.samples = VK_SAMPLE_COUNT_1_BIT; imageCI.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCI.usage = VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV | VK_IMAGE_USAGE_TRANSFER_DST_BIT; VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &shadingRateImage.image)); VkMemoryRequirements memReqs{}; vkGetImageMemoryRequirements(device, shadingRateImage.image, &memReqs); + + VkDeviceSize bufferSize = imageExtent.width * imageExtent.height * sizeof(uint8_t); VkMemoryAllocateInfo memAllloc{}; memAllloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; @@ -156,11 +164,29 @@ void VulkanExample::prepareShadingRateImage() VK_CHECK_RESULT(vkCreateImageView(device, &imageViewCI, nullptr, &shadingRateImage.view)); // Populate with shading rate pattern - const size_t bufferSize = 512 * 512 * sizeof(uint8_t); - uint8_t val = VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV; - uint8_t* shadingRatePatternData = new uint8_t[512 * 512]; + uint8_t val = VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV; + uint8_t* shadingRatePatternData = new uint8_t[bufferSize]; memset(shadingRatePatternData, val, bufferSize); + uint8_t* ptrData = shadingRatePatternData; + for (uint32_t y = 0; y < imageExtent.height; y++) { + for (uint32_t x = 0; x < imageExtent.width; x++) { + const float deltaX = imageExtent.width / 2 - (float)x; + const float deltaY = imageExtent.height / 2 - (float)y; + const float dist = std::sqrt(deltaX * deltaX + deltaY * deltaY); + if (dist <= 16.0f) { + *ptrData = VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV; + } else { + if (dist <= 32.0f) { + *ptrData = VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV; + } else { + *ptrData = VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV; + } + } + ptrData++; + } + } + VkBuffer stagingBuffer; VkDeviceMemory stagingMemory; @@ -206,8 +232,8 @@ void VulkanExample::prepareShadingRateImage() VkBufferImageCopy bufferCopyRegion{}; bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; bufferCopyRegion.imageSubresource.layerCount = 1; - bufferCopyRegion.imageExtent.width = 512; - bufferCopyRegion.imageExtent.height = 512; + bufferCopyRegion.imageExtent.width = imageExtent.width; + bufferCopyRegion.imageExtent.height = imageExtent.height; bufferCopyRegion.imageExtent.depth = 1; vkCmdCopyBufferToImage(copyCmd, stagingBuffer, shadingRateImage.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion); { @@ -309,6 +335,13 @@ void VulkanExample::prepare() vkCmdBindShadingRateImageNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdBindShadingRateImageNV")); + // [POI] + physicalDeviceShadingRateImagePropertiesNV.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV; + VkPhysicalDeviceProperties2 deviceProperties2{}; + deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + deviceProperties2.pNext = &physicalDeviceShadingRateImagePropertiesNV; + vkGetPhysicalDeviceProperties2(physicalDevice, &deviceProperties2); + prepareShadingRateImage(); prepareUniformBuffers(); setupDescriptors(); diff --git a/examples/variablerateshading/variablerateshading.h b/examples/variablerateshading/variablerateshading.h index 8d7aede2..0eda31a7 100644 --- a/examples/variablerateshading/variablerateshading.h +++ b/examples/variablerateshading/variablerateshading.h @@ -28,7 +28,7 @@ public: glm::mat4 projection; glm::mat4 view; glm::mat4 model = glm::mat4(1.0f); - glm::vec4 lightPos = glm::vec4(0.0f, -2.5f, 0.0f, 1.0f); + glm::vec4 lightPos = glm::vec4(0.0f, -5.0f, 0.0f, 1.0f); glm::vec4 viewPos; } values; } shaderData; @@ -38,7 +38,8 @@ public: VkDescriptorSet descriptorSet; VkDescriptorSetLayout descriptorSetLayout; - VkPhysicalDeviceShadingRateImageFeaturesNV enabledPhysicalDeviceShadingRateImageFeaturesNV; + VkPhysicalDeviceShadingRateImagePropertiesNV physicalDeviceShadingRateImagePropertiesNV{}; + VkPhysicalDeviceShadingRateImageFeaturesNV enabledPhysicalDeviceShadingRateImageFeaturesNV{}; PFN_vkCmdBindShadingRateImageNV vkCmdBindShadingRateImageNV; VulkanExample(); From 14aebeddbbc8d270fbb66333a367ceb9ecb6d16d Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Wed, 2 Sep 2020 20:07:37 +0200 Subject: [PATCH 03/13] Toggle for shading rate pattern color visualization --- .../glsl/variablerateshading/scene.frag | 23 +++++++++++++++++++ .../glsl/variablerateshading/scene.vert | 1 + .../variablerateshading.cpp | 16 +++++++++---- .../variablerateshading/variablerateshading.h | 3 +++ 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/data/shaders/glsl/variablerateshading/scene.frag b/data/shaders/glsl/variablerateshading/scene.frag index 4796f1ca..3de8c8a0 100644 --- a/data/shaders/glsl/variablerateshading/scene.frag +++ b/data/shaders/glsl/variablerateshading/scene.frag @@ -12,6 +12,16 @@ layout (location = 3) in vec3 inViewVec; layout (location = 4) in vec3 inLightVec; layout (location = 5) in vec4 inTangent; +layout (set = 0, binding = 0) uniform UBOScene +{ + mat4 projection; + mat4 view; + mat4 model; + vec4 lightPos; + vec4 viewPos; + int colorShadingRates; +} uboScene; + layout (location = 0) out vec4 outFragColor; layout (constant_id = 0) const bool ALPHA_MASK = false; @@ -40,4 +50,17 @@ void main() vec3 diffuse = max(dot(N, L), ambient).rrr; float specular = pow(max(dot(R, V), 0.0), 32.0); outFragColor = vec4(diffuse * color.rgb + specular, color.a); + + if (uboScene.colorShadingRates == 1) { + outFragColor = vec4(diffuse * vec3(1.0) + specular, color.a); + if (gl_FragmentSizeNV.x == 1 && gl_FragmentSizeNV.y == 1) { + outFragColor.rgb *= vec3(0.5, 1.0, 0.5); + } + if (gl_FragmentSizeNV.x == 2 || gl_FragmentSizeNV.y == 2) { + outFragColor.rgb *= vec3(1.0, 1.0, 0.5); + } + if (gl_FragmentSizeNV.x == 4 || gl_FragmentSizeNV.y == 4) { + outFragColor.rgb *= vec3(1.0, 0.5, 0.5); + } + } } \ No newline at end of file diff --git a/data/shaders/glsl/variablerateshading/scene.vert b/data/shaders/glsl/variablerateshading/scene.vert index 7bfa122e..bf4e03ed 100644 --- a/data/shaders/glsl/variablerateshading/scene.vert +++ b/data/shaders/glsl/variablerateshading/scene.vert @@ -13,6 +13,7 @@ layout (set = 0, binding = 0) uniform UBOScene mat4 model; vec4 lightPos; vec4 viewPos; + int colorShadingRates; } uboScene; layout (location = 0) out vec3 outNormal; diff --git a/examples/variablerateshading/variablerateshading.cpp b/examples/variablerateshading/variablerateshading.cpp index 758a5409..66d3eebc 100644 --- a/examples/variablerateshading/variablerateshading.cpp +++ b/examples/variablerateshading/variablerateshading.cpp @@ -16,6 +16,7 @@ VulkanExample::VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) camera.setPosition(glm::vec3(0.0f, 1.0f, 0.0f)); camera.setRotation(glm::vec3(0.0f, -90.0f, 0.0f)); camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f); + camera.setRotationSpeed(0.25f); settings.overlay = true; enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); enabledDeviceExtensions.push_back(VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME); @@ -97,7 +98,7 @@ void VulkanExample::setupDescriptors() // Descriptor set layout const std::vector setLayoutBindings = { - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), + vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0), }; VkDescriptorSetLayoutCreateInfo descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); @@ -171,13 +172,13 @@ void VulkanExample::prepareShadingRateImage() uint8_t* ptrData = shadingRatePatternData; for (uint32_t y = 0; y < imageExtent.height; y++) { for (uint32_t x = 0; x < imageExtent.width; x++) { - const float deltaX = imageExtent.width / 2 - (float)x; - const float deltaY = imageExtent.height / 2 - (float)y; + const float deltaX = (float)imageExtent.width / 2.0f - (float)x; + const float deltaY = (float)imageExtent.height / 2.0f - (float)y; const float dist = std::sqrt(deltaX * deltaX + deltaY * deltaY); - if (dist <= 16.0f) { + if (dist <= 8.0f) { *ptrData = VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV; } else { - if (dist <= 32.0f) { + if (dist <= 16.0f) { *ptrData = VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV; } else { *ptrData = VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV; @@ -325,6 +326,7 @@ void VulkanExample::updateUniformBuffers() shaderData.values.projection = camera.matrices.perspective; shaderData.values.view = camera.matrices.view; shaderData.values.viewPos = camera.viewPos; + shaderData.values.colorShadingRate = colorShadingRate; memcpy(shaderData.buffer.mapped, &shaderData.values, sizeof(shaderData.values)); } @@ -360,6 +362,10 @@ void VulkanExample::render() void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay* overlay) { + if (overlay->checkBox("Color shading rates", &colorShadingRate)) { + updateUniformBuffers(); + } + } VULKAN_EXAMPLE_MAIN() \ No newline at end of file diff --git a/examples/variablerateshading/variablerateshading.h b/examples/variablerateshading/variablerateshading.h index 0eda31a7..4bc4ad13 100644 --- a/examples/variablerateshading/variablerateshading.h +++ b/examples/variablerateshading/variablerateshading.h @@ -22,6 +22,8 @@ public: VkImageView view; } shadingRateImage; + bool colorShadingRate = false; + struct ShaderData { vks::Buffer buffer; struct Values { @@ -30,6 +32,7 @@ public: glm::mat4 model = glm::mat4(1.0f); glm::vec4 lightPos = glm::vec4(0.0f, -5.0f, 0.0f, 1.0f); glm::vec4 viewPos; + int32_t colorShadingRate; } values; } shaderData; From d9612098a7d5bf006d8dd151e5f76e5a97ca0616 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Fri, 4 Sep 2020 09:26:30 +0200 Subject: [PATCH 04/13] Add toggle for shading rate --- .../variablerateshading.cpp | 55 +++++++++++-------- .../variablerateshading/variablerateshading.h | 7 ++- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/examples/variablerateshading/variablerateshading.cpp b/examples/variablerateshading/variablerateshading.cpp index 66d3eebc..f077befd 100644 --- a/examples/variablerateshading/variablerateshading.cpp +++ b/examples/variablerateshading/variablerateshading.cpp @@ -67,11 +67,17 @@ void VulkanExample::buildCommandBuffers() vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport); vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); - vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); - // POI: todo - vkCmdBindShadingRateImageNV(drawCmdBuffers[i], shadingRateImage.view, VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV); + if (enableShadingRate) { + // POI: todo + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.shadingRate); + vkCmdBindShadingRateImageNV(drawCmdBuffers[i], shadingRateImage.view, VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV); + } + else + { + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.base); + } scene.draw(drawCmdBuffers[i], vkglTF::RenderFlags::BindImages, pipelineLayout); @@ -267,7 +273,26 @@ void VulkanExample::preparePipelines() VkPipelineDynamicStateCreateInfo dynamicStateCI = vks::initializers::pipelineDynamicStateCreateInfo(dynamicStateEnables.data(), static_cast(dynamicStateEnables.size()), 0); std::array shaderStages; - // [POI] Per-Viewport shading rate palette entries + VkGraphicsPipelineCreateInfo pipelineCI = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0); + pipelineCI.pInputAssemblyState = &inputAssemblyStateCI; + pipelineCI.pRasterizationState = &rasterizationStateCI; + pipelineCI.pColorBlendState = &colorBlendStateCI; + pipelineCI.pMultisampleState = &multisampleStateCI; + pipelineCI.pViewportState = &viewportStateCI; + pipelineCI.pDepthStencilState = &depthStencilStateCI; + pipelineCI.pDynamicState = &dynamicStateCI; + pipelineCI.stageCount = static_cast(shaderStages.size()); + pipelineCI.pStages = shaderStages.data(); + pipelineCI.pVertexInputState = vkglTF::Vertex::getPipelineVertexInputState({ vkglTF::VertexComponent::Position, vkglTF::VertexComponent::Normal, vkglTF::VertexComponent::UV, vkglTF::VertexComponent::Color, vkglTF::VertexComponent::Tangent }); + + shaderStages[0] = loadShader(getShadersPath() + "variablerateshading/scene.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + shaderStages[1] = loadShader(getShadersPath() + "variablerateshading/scene.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + + // Create pipeline without shading rate + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.base)); + + // Create pipeline with shading rate enabled + // [POI] Possible per-Viewport shading rate palette entries const std::vector shadingRatePaletteEntries = { VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV, VK_SHADING_RATE_PALETTE_ENTRY_16_INVOCATIONS_PER_PIXEL_NV, @@ -291,23 +316,7 @@ void VulkanExample::preparePipelines() pipelineViewportShadingRateImageStateCI.viewportCount = 1; pipelineViewportShadingRateImageStateCI.pShadingRatePalettes = &shadingRatePalette; viewportStateCI.pNext = &pipelineViewportShadingRateImageStateCI; - - VkGraphicsPipelineCreateInfo pipelineCI = vks::initializers::pipelineCreateInfo(pipelineLayout, renderPass, 0); - pipelineCI.pInputAssemblyState = &inputAssemblyStateCI; - pipelineCI.pRasterizationState = &rasterizationStateCI; - pipelineCI.pColorBlendState = &colorBlendStateCI; - pipelineCI.pMultisampleState = &multisampleStateCI; - pipelineCI.pViewportState = &viewportStateCI; - pipelineCI.pDepthStencilState = &depthStencilStateCI; - pipelineCI.pDynamicState = &dynamicStateCI; - pipelineCI.stageCount = static_cast(shaderStages.size()); - pipelineCI.pStages = shaderStages.data(); - pipelineCI.pVertexInputState = vkglTF::Vertex::getPipelineVertexInputState({ vkglTF::VertexComponent::Position, vkglTF::VertexComponent::Normal, vkglTF::VertexComponent::UV, vkglTF::VertexComponent::Color, vkglTF::VertexComponent::Tangent }); - - shaderStages[0] = loadShader(getShadersPath() + "variablerateshading/scene.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - shaderStages[1] = loadShader(getShadersPath() + "variablerateshading/scene.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline)); + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.shadingRate)); } void VulkanExample::prepareUniformBuffers() @@ -362,10 +371,12 @@ void VulkanExample::render() void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay* overlay) { + if (overlay->checkBox("Enable shading rate", &enableShadingRate)) { + buildCommandBuffers(); + } if (overlay->checkBox("Color shading rates", &colorShadingRate)) { updateUniformBuffers(); } - } VULKAN_EXAMPLE_MAIN() \ No newline at end of file diff --git a/examples/variablerateshading/variablerateshading.h b/examples/variablerateshading/variablerateshading.h index 4bc4ad13..5ebc2e72 100644 --- a/examples/variablerateshading/variablerateshading.h +++ b/examples/variablerateshading/variablerateshading.h @@ -22,6 +22,7 @@ public: VkImageView view; } shadingRateImage; + bool enableShadingRate = true; bool colorShadingRate = false; struct ShaderData { @@ -36,7 +37,11 @@ public: } values; } shaderData; - VkPipeline pipeline; + struct Pipelines { + VkPipeline base; + VkPipeline shadingRate; + } pipelines; + VkPipelineLayout pipelineLayout; VkDescriptorSet descriptorSet; VkDescriptorSetLayout descriptorSetLayout; From 85bf87125b4bd3403914b779a2e3109c87f685b1 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sat, 5 Sep 2020 12:12:47 +0200 Subject: [PATCH 05/13] Added additional flags for binding texture maps and only rendering opaque/masked/blended meshes --- base/VulkanglTFModel.cpp | 84 ++++++++++++++++++++++++++++------------ base/VulkanglTFModel.h | 13 ++++++- 2 files changed, 70 insertions(+), 27 deletions(-) diff --git a/base/VulkanglTFModel.cpp b/base/VulkanglTFModel.cpp index 044ccce0..8cae61ea 100644 --- a/base/VulkanglTFModel.cpp +++ b/base/VulkanglTFModel.cpp @@ -16,6 +16,7 @@ VkDescriptorSetLayout vkglTF::descriptorSetLayoutImage = VK_NULL_HANDLE; VkDescriptorSetLayout vkglTF::descriptorSetLayoutUbo = VK_NULL_HANDLE; VkMemoryPropertyFlags vkglTF::memoryPropertyFlags = 0; +uint32_t vkglTF::descriptorBindingFlags = vkglTF::DescriptorBindingFlags::ImageBaseColor; /* We use a custom image loading function with tinyglTF, so we can do custom stuff loading ktx textures @@ -428,7 +429,7 @@ void vkglTF::Texture::fromglTfImage(tinygltf::Image &gltfimage, std::string path /* glTF material */ -void vkglTF::Material::createDescriptorSet(VkDescriptorPool descriptorPool, VkDescriptorSetLayout descriptorSetLayout) +void vkglTF::Material::createDescriptorSet(VkDescriptorPool descriptorPool, VkDescriptorSetLayout descriptorSetLayout, uint32_t descriptorBindingFlags) { VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; @@ -436,19 +437,31 @@ void vkglTF::Material::createDescriptorSet(VkDescriptorPool descriptorPool, VkDe descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayout; descriptorSetAllocInfo.descriptorSetCount = 1; VK_CHECK_RESULT(vkAllocateDescriptorSets(device->logicalDevice, &descriptorSetAllocInfo, &descriptorSet)); - - std::vector imageDescriptors = { - baseColorTexture->descriptor, - }; - - VkWriteDescriptorSet writeDescriptorSet{}; - writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - writeDescriptorSet.descriptorCount = 1; - writeDescriptorSet.dstSet = descriptorSet; - writeDescriptorSet.dstBinding = 0; - writeDescriptorSet.pImageInfo = &baseColorTexture->descriptor; - vkUpdateDescriptorSets(device->logicalDevice, 1, &writeDescriptorSet, 0, nullptr); + std::vector imageDescriptors{}; + std::vector writeDescriptorSets{}; + if (descriptorBindingFlags & DescriptorBindingFlags::ImageBaseColor) { + imageDescriptors.push_back(baseColorTexture->descriptor); + VkWriteDescriptorSet writeDescriptorSet{}; + writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSet.descriptorCount = 1; + writeDescriptorSet.dstSet = descriptorSet; + writeDescriptorSet.dstBinding = static_cast(writeDescriptorSets.size()); + writeDescriptorSet.pImageInfo = &baseColorTexture->descriptor; + writeDescriptorSets.push_back(writeDescriptorSet); + } + if (normalTexture && descriptorBindingFlags & DescriptorBindingFlags::ImageNormalMap) { + imageDescriptors.push_back(normalTexture->descriptor); + VkWriteDescriptorSet writeDescriptorSet{}; + writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + writeDescriptorSet.descriptorCount = 1; + writeDescriptorSet.dstSet = descriptorSet; + writeDescriptorSet.dstBinding = static_cast(writeDescriptorSets.size()); + writeDescriptorSet.pImageInfo = &normalTexture->descriptor; + writeDescriptorSets.push_back(writeDescriptorSet); + } + vkUpdateDescriptorSets(device->logicalDevice, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); } @@ -1210,7 +1223,12 @@ void vkglTF::Model::loadFromFile(std::string filename, vks::VulkanDevice *device { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uboCount }, }; if (imageCount > 0) { - poolSizes.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, imageCount }); + if (descriptorBindingFlags & DescriptorBindingFlags::ImageBaseColor) { + poolSizes.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, imageCount }); + } + if (descriptorBindingFlags & DescriptorBindingFlags::ImageNormalMap) { + poolSizes.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, imageCount }); + } } VkDescriptorPoolCreateInfo descriptorPoolCI{}; descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; @@ -1241,9 +1259,13 @@ void vkglTF::Model::loadFromFile(std::string filename, vks::VulkanDevice *device { // Layout is global, so only create if it hasn't already been created before if (descriptorSetLayoutImage == VK_NULL_HANDLE) { - std::vector setLayoutBindings = { - vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 0), - }; + std::vector setLayoutBindings{}; + if (descriptorBindingFlags & DescriptorBindingFlags::ImageBaseColor) { + setLayoutBindings.push_back(vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, static_cast(setLayoutBindings.size()))); + } + if (descriptorBindingFlags & DescriptorBindingFlags::ImageNormalMap) { + setLayoutBindings.push_back(vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, static_cast(setLayoutBindings.size()))); + } VkDescriptorSetLayoutCreateInfo descriptorLayoutCI{}; descriptorLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; descriptorLayoutCI.bindingCount = static_cast(setLayoutBindings.size()); @@ -1252,11 +1274,10 @@ void vkglTF::Model::loadFromFile(std::string filename, vks::VulkanDevice *device } for (auto& material : materials) { if (material.baseColorTexture != nullptr) { - material.createDescriptorSet(descriptorPool, vkglTF::descriptorSetLayoutImage); + material.createDescriptorSet(descriptorPool, vkglTF::descriptorSetLayoutImage, descriptorBindingFlags); } } } - } void vkglTF::Model::bindBuffers(VkCommandBuffer commandBuffer) @@ -1270,15 +1291,28 @@ void vkglTF::Model::bindBuffers(VkCommandBuffer commandBuffer) void vkglTF::Model::drawNode(Node *node, VkCommandBuffer commandBuffer, uint32_t renderFlags, VkPipelineLayout pipelineLayout, uint32_t bindImageSet) { if (node->mesh) { - for (Primitive *primitive : node->mesh->primitives) { - if (renderFlags & vkglTF::RenderFlags::BindImages) { - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, bindImageSet, 1, &primitive->material.descriptorSet, 0, nullptr); + for (Primitive* primitive : node->mesh->primitives) { + bool skip = false; + const vkglTF::Material& material = primitive->material; + if (renderFlags & RenderFlags::RenderOpaqueNodes) { + skip = (material.alphaMode != Material::ALPHAMODE_OPAQUE); + } + if (renderFlags & RenderFlags::RenderAlphaMaskedNodes) { + skip = (material.alphaMode != Material::ALPHAMODE_MASK); + } + if (renderFlags & RenderFlags::RenderAlphaBlendedNodes) { + skip = (material.alphaMode != Material::ALPHAMODE_BLEND); + } + if (!skip) { + if (renderFlags & RenderFlags::BindImages) { + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, bindImageSet, 1, &material.descriptorSet, 0, nullptr); + } + vkCmdDrawIndexed(commandBuffer, primitive->indexCount, 1, primitive->firstIndex, 0, 0); } - vkCmdDrawIndexed(commandBuffer, primitive->indexCount, 1, primitive->firstIndex, 0, 0); } } for (auto& child : node->children) { - drawNode(child, commandBuffer); + drawNode(child, commandBuffer, renderFlags); } } diff --git a/base/VulkanglTFModel.h b/base/VulkanglTFModel.h index 0f3f3713..3a1fd984 100644 --- a/base/VulkanglTFModel.h +++ b/base/VulkanglTFModel.h @@ -37,9 +37,15 @@ namespace vkglTF { + enum DescriptorBindingFlags { + ImageBaseColor = 0x00000001, + ImageNormalMap = 0x00000002 + }; + extern VkDescriptorSetLayout descriptorSetLayoutImage; extern VkDescriptorSetLayout descriptorSetLayoutUbo; extern VkMemoryPropertyFlags memoryPropertyFlags; + extern uint32_t descriptorBindingFlags; struct Node; @@ -85,7 +91,7 @@ namespace vkglTF VkDescriptorSet descriptorSet = VK_NULL_HANDLE; Material(vks::VulkanDevice* device) : device(device) {}; - void createDescriptorSet(VkDescriptorPool descriptorPool, VkDescriptorSetLayout descriptorSetLayout); + void createDescriptorSet(VkDescriptorPool descriptorPool, VkDescriptorSetLayout descriptorSetLayout, uint32_t descriptorBindingFlags); }; /* @@ -231,7 +237,10 @@ namespace vkglTF }; enum RenderFlags { - BindImages = 0x00000001 + BindImages = 0x00000001, + RenderOpaqueNodes = 0x00000002, + RenderAlphaMaskedNodes = 0x00000004, + RenderAlphaBlendedNodes = 0x00000008 }; /* From 8d896cd04b1babb2a394b90b8b1947df1c672d30 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sat, 5 Sep 2020 12:15:54 +0200 Subject: [PATCH 06/13] Separate oaque and masked pipelines --- .../glsl/variablerateshading/scene.frag | 3 +- .../variablerateshading.cpp | 49 ++++++++++++++----- .../variablerateshading/variablerateshading.h | 11 +++-- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/data/shaders/glsl/variablerateshading/scene.frag b/data/shaders/glsl/variablerateshading/scene.frag index 3de8c8a0..ddc21bdb 100644 --- a/data/shaders/glsl/variablerateshading/scene.frag +++ b/data/shaders/glsl/variablerateshading/scene.frag @@ -43,7 +43,7 @@ void main() mat3 TBN = mat3(T, B, N); N = TBN * normalize(texture(samplerNormalMap, inUV).xyz * 2.0 - vec3(1.0)); - const float ambient = 0.1; + const float ambient = 0.25; vec3 L = normalize(inLightVec); vec3 V = normalize(inViewVec); vec3 R = reflect(-L, N); @@ -52,7 +52,6 @@ void main() outFragColor = vec4(diffuse * color.rgb + specular, color.a); if (uboScene.colorShadingRates == 1) { - outFragColor = vec4(diffuse * vec3(1.0) + specular, color.a); if (gl_FragmentSizeNV.x == 1 && gl_FragmentSizeNV.y == 1) { outFragColor.rgb *= vec3(0.5, 1.0, 0.5); } diff --git a/examples/variablerateshading/variablerateshading.cpp b/examples/variablerateshading/variablerateshading.cpp index f077befd..7d92b44e 100644 --- a/examples/variablerateshading/variablerateshading.cpp +++ b/examples/variablerateshading/variablerateshading.cpp @@ -13,6 +13,7 @@ VulkanExample::VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) title = "Variable rate shading"; apiVersion = VK_VERSION_1_1; camera.type = Camera::CameraType::firstperson; + camera.flipY = true; camera.setPosition(glm::vec3(0.0f, 1.0f, 0.0f)); camera.setRotation(glm::vec3(0.0f, -90.0f, 0.0f)); camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f); @@ -69,17 +70,17 @@ void VulkanExample::buildCommandBuffers() vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor); vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr); + // POI: Bind the image that contains the shading rate patterns if (enableShadingRate) { - // POI: todo - vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.shadingRate); vkCmdBindShadingRateImageNV(drawCmdBuffers[i], shadingRateImage.view, VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV); - } - else - { - vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.base); - } + }; - scene.draw(drawCmdBuffers[i], vkglTF::RenderFlags::BindImages, pipelineLayout); + // Render the scene + Pipelines& pipelines = enableShadingRate ? shadingRatePipelines : basePipelines; + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.opaque); + scene.draw(drawCmdBuffers[i], vkglTF::RenderFlags::BindImages | vkglTF::RenderFlags::RenderOpaqueNodes, pipelineLayout); + vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.masked); + scene.draw(drawCmdBuffers[i], vkglTF::RenderFlags::BindImages | vkglTF::RenderFlags::RenderAlphaMaskedNodes, pipelineLayout); drawUI(drawCmdBuffers[i]); vkCmdEndRenderPass(drawCmdBuffers[i]); @@ -90,7 +91,7 @@ void VulkanExample::buildCommandBuffers() void VulkanExample::loadAssets() { vkglTF::descriptorBindingFlags = vkglTF::DescriptorBindingFlags::ImageBaseColor | vkglTF::DescriptorBindingFlags::ImageNormalMap; - scene.loadFromFile(getAssetPath() + "models/sponza/sponza.gltf", vulkanDevice, queue, vkglTF::FileLoadingFlags::PreTransformVertices | vkglTF::FileLoadingFlags::FlipY); + scene.loadFromFile(getAssetPath() + "models/sponza/sponza.gltf", vulkanDevice, queue, vkglTF::FileLoadingFlags::PreTransformVertices); } void VulkanExample::setupDescriptors() @@ -123,7 +124,7 @@ void VulkanExample::setupDescriptors() std::vector writeDescriptorSets = { vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &shaderData.buffer.descriptor), }; - vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); + vkUpdateDescriptorSets(device, static_cast(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr); } // [POI] @@ -288,8 +289,27 @@ void VulkanExample::preparePipelines() shaderStages[0] = loadShader(getShadersPath() + "variablerateshading/scene.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[1] = loadShader(getShadersPath() + "variablerateshading/scene.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - // Create pipeline without shading rate - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.base)); + // Properties for alpha masked materials will be passed via specialization constants + struct SpecializationData { + bool alphaMask; + float alphaMaskCutoff; + } specializationData; + specializationData.alphaMask = false; + specializationData.alphaMaskCutoff = 0.5f; + const std::vector specializationMapEntries = { + vks::initializers::specializationMapEntry(0, offsetof(SpecializationData, alphaMask), sizeof(SpecializationData::alphaMask)), + vks::initializers::specializationMapEntry(1, offsetof(SpecializationData, alphaMaskCutoff), sizeof(SpecializationData::alphaMaskCutoff)), + }; + VkSpecializationInfo specializationInfo = vks::initializers::specializationInfo(specializationMapEntries, sizeof(specializationData), &specializationData); + shaderStages[1].pSpecializationInfo = &specializationInfo; + + // Create pipeline without shading rate + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &basePipelines.opaque)); + specializationData.alphaMask = true; + rasterizationStateCI.cullMode = VK_CULL_MODE_NONE; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &basePipelines.masked)); + rasterizationStateCI.cullMode = VK_CULL_MODE_BACK_BIT; + specializationData.alphaMask = false; // Create pipeline with shading rate enabled // [POI] Possible per-Viewport shading rate palette entries @@ -316,7 +336,10 @@ void VulkanExample::preparePipelines() pipelineViewportShadingRateImageStateCI.viewportCount = 1; pipelineViewportShadingRateImageStateCI.pShadingRatePalettes = &shadingRatePalette; viewportStateCI.pNext = &pipelineViewportShadingRateImageStateCI; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipelines.shadingRate)); + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &shadingRatePipelines.opaque)); + specializationData.alphaMask = true; + rasterizationStateCI.cullMode = VK_CULL_MODE_NONE; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &shadingRatePipelines.masked)); } void VulkanExample::prepareUniformBuffers() diff --git a/examples/variablerateshading/variablerateshading.h b/examples/variablerateshading/variablerateshading.h index 5ebc2e72..45588c31 100644 --- a/examples/variablerateshading/variablerateshading.h +++ b/examples/variablerateshading/variablerateshading.h @@ -31,16 +31,19 @@ public: glm::mat4 projection; glm::mat4 view; glm::mat4 model = glm::mat4(1.0f); - glm::vec4 lightPos = glm::vec4(0.0f, -5.0f, 0.0f, 1.0f); + glm::vec4 lightPos = glm::vec4(0.0f, 2.5f, 0.0f, 1.0f); glm::vec4 viewPos; int32_t colorShadingRate; } values; } shaderData; struct Pipelines { - VkPipeline base; - VkPipeline shadingRate; - } pipelines; + VkPipeline opaque; + VkPipeline masked; + }; + + Pipelines basePipelines; + Pipelines shadingRatePipelines; VkPipelineLayout pipelineLayout; VkDescriptorSet descriptorSet; From ccadcdd238ad8e6913315760349eea63eee38ca8 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sat, 5 Sep 2020 14:10:02 +0200 Subject: [PATCH 07/13] Shading rate pattern and colorization --- .../glsl/variablerateshading/scene.frag | 29 +++++++++++++++---- .../variablerateshading.cpp | 25 ++++++++++------ 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/data/shaders/glsl/variablerateshading/scene.frag b/data/shaders/glsl/variablerateshading/scene.frag index ddc21bdb..1236713a 100644 --- a/data/shaders/glsl/variablerateshading/scene.frag +++ b/data/shaders/glsl/variablerateshading/scene.frag @@ -53,13 +53,32 @@ void main() if (uboScene.colorShadingRates == 1) { if (gl_FragmentSizeNV.x == 1 && gl_FragmentSizeNV.y == 1) { - outFragColor.rgb *= vec3(0.5, 1.0, 0.5); + outFragColor.rgb *= vec3(0.0, 0.8, 0.4); + return; } - if (gl_FragmentSizeNV.x == 2 || gl_FragmentSizeNV.y == 2) { - outFragColor.rgb *= vec3(1.0, 1.0, 0.5); + if (gl_FragmentSizeNV.x == 2 && gl_FragmentSizeNV.y == 1) { + outFragColor.rgb *= vec3(0.2, 0.6, 1.0); + return; } - if (gl_FragmentSizeNV.x == 4 || gl_FragmentSizeNV.y == 4) { - outFragColor.rgb *= vec3(1.0, 0.5, 0.5); + if (gl_FragmentSizeNV.x == 1 && gl_FragmentSizeNV.y == 2) { + outFragColor.rgb *= vec3(0.0, 0.4, 0.8); + return; + } + if (gl_FragmentSizeNV.x == 2 && gl_FragmentSizeNV.y == 2) { + outFragColor.rgb *= vec3(1.0, 1.0, 0.2); + return; + } + if (gl_FragmentSizeNV.x == 4 && gl_FragmentSizeNV.y == 2) { + outFragColor.rgb *= vec3(0.8, 0.8, 0.0); + return; + } + if (gl_FragmentSizeNV.x == 2 && gl_FragmentSizeNV.y == 4) { + outFragColor.rgb *= vec3(1.0, 0.4, 0.2); + return; + } + if (gl_FragmentSizeNV.x == 4 && gl_FragmentSizeNV.y == 4) { + outFragColor.rgb *= vec3(0.8, 0.0, 0.0); + return; } } } \ No newline at end of file diff --git a/examples/variablerateshading/variablerateshading.cpp b/examples/variablerateshading/variablerateshading.cpp index 7d92b44e..1fa83579 100644 --- a/examples/variablerateshading/variablerateshading.cpp +++ b/examples/variablerateshading/variablerateshading.cpp @@ -171,24 +171,31 @@ void VulkanExample::prepareShadingRateImage() imageViewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; VK_CHECK_RESULT(vkCreateImageView(device, &imageViewCI, nullptr, &shadingRateImage.view)); - // Populate with shading rate pattern - uint8_t val = VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV; + // Populate with lowest possible shading rate pattern + uint8_t val = VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV; uint8_t* shadingRatePatternData = new uint8_t[bufferSize]; memset(shadingRatePatternData, val, bufferSize); + // Create a circular pattern with decreasing sampling rates outwards (max. range, pattern) + std::map patternLookup = { + { 8.0f, VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV }, + { 12.0f, VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X1_PIXELS_NV }, + { 16.0f, VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV }, + { 18.0f, VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV }, + { 20.0f, VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV }, + { 24.0f, VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV } + }; + uint8_t* ptrData = shadingRatePatternData; for (uint32_t y = 0; y < imageExtent.height; y++) { for (uint32_t x = 0; x < imageExtent.width; x++) { const float deltaX = (float)imageExtent.width / 2.0f - (float)x; const float deltaY = (float)imageExtent.height / 2.0f - (float)y; const float dist = std::sqrt(deltaX * deltaX + deltaY * deltaY); - if (dist <= 8.0f) { - *ptrData = VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV; - } else { - if (dist <= 16.0f) { - *ptrData = VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV; - } else { - *ptrData = VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV; + for (auto pattern : patternLookup) { + if (dist <= pattern.first) { + *ptrData = pattern.second; + break; } } ptrData++; From 3643d10cac01478be3be45de374125e05b279d64 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sun, 6 Sep 2020 17:05:38 +0200 Subject: [PATCH 08/13] Fix shading rate image dimensions for resolutions that don't divide by shadingRateTexelSize --- examples/variablerateshading/variablerateshading.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/variablerateshading/variablerateshading.cpp b/examples/variablerateshading/variablerateshading.cpp index 1fa83579..73e77b9d 100644 --- a/examples/variablerateshading/variablerateshading.cpp +++ b/examples/variablerateshading/variablerateshading.cpp @@ -132,7 +132,10 @@ void VulkanExample::prepareShadingRateImage() { // Shading rate image size depends on shading rate texel size // For each texel in the target image, there is a corresponding shading texel size width x height block in the shading rate image - const VkExtent3D imageExtent = { width / physicalDeviceShadingRateImagePropertiesNV.shadingRateTexelSize.width, height / physicalDeviceShadingRateImagePropertiesNV.shadingRateTexelSize.height, 1 }; + VkExtent3D imageExtent{}; + imageExtent.width = static_cast(ceil(width / (float)physicalDeviceShadingRateImagePropertiesNV.shadingRateTexelSize.width)); + imageExtent.height = static_cast(ceil(height / (float)physicalDeviceShadingRateImagePropertiesNV.shadingRateTexelSize.height)); + imageExtent.depth = 1; VkImageCreateInfo imageCI{}; imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; From 08648a417f90f11926d355715571b529fcf43d55 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Fri, 11 Sep 2020 20:57:06 +0200 Subject: [PATCH 09/13] Properly handle resize --- .../variablerateshading.cpp | 21 +++++++++++++++++-- .../variablerateshading/variablerateshading.h | 1 + 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/examples/variablerateshading/variablerateshading.cpp b/examples/variablerateshading/variablerateshading.cpp index 73e77b9d..6e745f1e 100644 --- a/examples/variablerateshading/variablerateshading.cpp +++ b/examples/variablerateshading/variablerateshading.cpp @@ -40,8 +40,26 @@ void VulkanExample::getEnabledFeatures() deviceCreatepNextChain = &enabledPhysicalDeviceShadingRateImageFeaturesNV; } +/* + If the window has been resized, we need to recreate the shading rate image +*/ +void VulkanExample::handleResize() +{ + // Delete allocated resources + vkDestroyImageView(device, shadingRateImage.view, nullptr); + vkDestroyImage(device, shadingRateImage.image, nullptr); + vkFreeMemory(device, shadingRateImage.memory, nullptr); + // Recreate image + prepareShadingRateImage(); +} + void VulkanExample::buildCommandBuffers() { + if (resized) + { + handleResize(); + } + VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkClearValue clearValues[2]; @@ -377,9 +395,8 @@ void VulkanExample::prepare() VulkanExampleBase::prepare(); loadAssets(); - vkCmdBindShadingRateImageNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdBindShadingRateImageNV")); - // [POI] + vkCmdBindShadingRateImageNV = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdBindShadingRateImageNV")); physicalDeviceShadingRateImagePropertiesNV.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV; VkPhysicalDeviceProperties2 deviceProperties2{}; deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; diff --git a/examples/variablerateshading/variablerateshading.h b/examples/variablerateshading/variablerateshading.h index 45588c31..8b7095f0 100644 --- a/examples/variablerateshading/variablerateshading.h +++ b/examples/variablerateshading/variablerateshading.h @@ -56,6 +56,7 @@ public: VulkanExample(); ~VulkanExample(); virtual void getEnabledFeatures(); + void handleResize(); void buildCommandBuffers(); void loadglTFFile(std::string filename); void loadAssets(); From 9a6a0b30b0299d1f11acb1b4874c077d3c30581b Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sat, 12 Sep 2020 09:36:28 +0200 Subject: [PATCH 10/13] Added VRS HLSL shaders Color coding doesn't work properly, as shading rate values don't seem to match with GLSL or DX12 specs --- .../glsl/variablerateshading/scene.frag.spv | Bin 0 -> 7220 bytes .../glsl/variablerateshading/scene.vert.spv | Bin 0 -> 3152 bytes .../hlsl/variablerateshading/scene.frag | 83 ++++++++++++++++++ .../hlsl/variablerateshading/scene.frag.spv | Bin 0 -> 4464 bytes .../hlsl/variablerateshading/scene.vert | 51 +++++++++++ .../hlsl/variablerateshading/scene.vert.spv | Bin 0 -> 2636 bytes 6 files changed, 134 insertions(+) create mode 100644 data/shaders/glsl/variablerateshading/scene.frag.spv create mode 100644 data/shaders/glsl/variablerateshading/scene.vert.spv create mode 100644 data/shaders/hlsl/variablerateshading/scene.frag create mode 100644 data/shaders/hlsl/variablerateshading/scene.frag.spv create mode 100644 data/shaders/hlsl/variablerateshading/scene.vert create mode 100644 data/shaders/hlsl/variablerateshading/scene.vert.spv diff --git a/data/shaders/glsl/variablerateshading/scene.frag.spv b/data/shaders/glsl/variablerateshading/scene.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..bc40abeee6d32c4bae067c9f1a21e329317894d6 GIT binary patch literal 7220 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 Lckxdd$3_1EoDrkB literal 0 HcmV?d00001 From 9aea7d1550f02e0eb596333a3c4a152f33fc36e6 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sat, 12 Sep 2020 12:16:31 +0200 Subject: [PATCH 11/13] Added VRS sample to readme --- README.md | 5 +++++ screenshots/variablerateshading.jpg | Bin 0 -> 159650 bytes 2 files changed, 5 insertions(+) create mode 100644 screenshots/variablerateshading.jpg diff --git a/README.md b/README.md index 933cecae..0ff80b4d 100644 --- a/README.md +++ b/README.md @@ -382,6 +382,11 @@ An updated version using ```VK_EXT_debug_utils``` along with an in-depth tutoria Shows how to render a scene using a negative viewport height, making the Vulkan render setup more similar to other APIs like OpenGL. Also has several options for changing relevant pipeline state, and displaying meshes with OpenGL or Vulkan style coordinates. Details can be found in [this tutorial](https://www.saschawillems.de/tutorials/vulkan/flipping-viewport). +#### [08 - Variable rate shading (VK_NV_shading_rate_image)](examples/variablerateshading/) + +Uses a special image that contains variable shading rates to vary the number of fragment shader invocations across the framebuffer. This makes it possible to lower fragment shader invocations for less important/less noisy parts of the framebuffer. + + ### Misc #### [01 - Vulkan Gears](examples/gears/) diff --git a/screenshots/variablerateshading.jpg b/screenshots/variablerateshading.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4d395bcb7c3cc6d089ef9ee7071e88a09591169c GIT binary patch literal 159650 zcmbUIcRZVa{5A|nDXK;(wO1*vS$j*DUDQ^y6{KP{_Ks0nd(~c5dsm6rsz!|3t5%HI zO2i%!cfP;tx}WQLJ%2s-eRAgIC8s!#&ph78ahx}QZ-~<4OZWFNm z2k(C$M7M}ZZj+Lc-=VlmxBz|+aEpkT_!i;*2>=LJ2NK=~kkHqP z>02|9t(`sig9F6f!_&*#$Ja0HQ+UMZFOgA6$zM}a)6z3CzZVo16_=EjmH(`(hc_S^ zo0@-jb@%il`}zmQCnl$+Xa3I4t*oNg);Bh{ws)|HN5?0pXXh7}|KTDc;QYUj{{`&- z2Nx{?*DXS~kdXa{i|Cd&;UuOdxy>y`O7~ok>^=1UL-7!D`WK1$wVii(B=ip$Y~02u z9`H)8Ji`75?SGK{{|7Ae{}rVe;@&6ZN!8WbNZNnD_g`VFVoGB8NUExV&I9dPIcts;aQOc7pEcI|GE~tj&9X4v z-t6pZwWiFTcS%mK;TX*TQ^D%gt}FqsI6UB2 zs!I}Q@6Vivl~19QQ;OqZfzN#cvqXOU&kb>;tp2faJORj;z%1|2c#<1H->xT>$en;ko)waD{0(i01{D%#L0)$WIlIW9~72jzJ# zX;)-M1UrxJ3=RUTFZGT8{~9gdjh1qu1}cs@ORd*}xt3;o5{P#rS5jW0_aPfb z)=B^yqU*nfbu7ZO7W&I<(_(HeEWRCwk|%*W?8GXK?TH9=D4QUHyO3*{!w;JLPYG%z zCET6HNVo9XTSJi1emhA=+vyz9ExbzQT%;q+_2(l%hhh`6d@Ov-22d~oB2aA~DmZfx zZkCgalLIowpOPlXd$>v>zS(*-m5kG>i%4e<=Bk+`J3q1Z14QbYC8ZB8yb(a$y9}C( z$@~a;2BcpW(`b%*Cj3Nl&VimtQomLI4v$S`Yp9^#wCP5$e7p5|8q=I(7K7Ko-ku9_ zs23e^jYT}Ru-8d_QIM@hpr{RMCS<5u9ouG}Uuvd!@1;I-!gh?iN!r-(6@d=@c{&EHKx@dF1?G6~kGE82Wo0eb%k>3W1K*Kfk8Qx2&>*WGuo z1#h>Q=mlgYEuMiCI*QyWWf^+3w5jEHKhh)jbc;J63(F5b9YT&BH_V@~(erX{zU`l! z&OsQ*cB$ejyv_`}B z8KtpZz%Ml#xXECmontJOkt3 z_cwrC!Zk}E+!K0tYevy&t!shFz;krci}sK&fKASSc>`^nU73(AJV)IGgP|ntho z5ns1Eo3|r@vA+B<-$QqiEZQ+!w((+Q3ri9O8lmEH$iw~`^N80j7m(b(l&0NW_Nn{> ze023r+TCVWQ{_=y;^Frej^NYNnlFmmCmr|NP6qLK$JD08=ELr$9ryk-jP)y@O*2QD z2)|u5a&Qh0g0%^t;LLx>&v9OpA-S7;``Df6%oI#kgE%ga8jGx}IjqH57b!S@xWz_l zkT^+;${;Lw@JnO66fggYPeCW|knyX<;b&!yrt#o59#I_#tVKsK_c-CtQ2R05eeebV zNe2;L%9l;(8;7*&*tfo~{t!6X_}19k)KH&2uglA)LeVQD*yut=#;*Dd7+lf;iK3~C z{&Z!M%Dw5G5!)s^9Jrm&P&u#PYJUUJ$&>=PZ_xRk4tYIjXz=s#@f5at`$+bk6?T;i z#7;~Z6CrnobefSX5&v)|W4t;R?LwjeH0qy^Qvz0bbFepH8-BPXchOmW;reSEHKWUD z{uU9?jppHo#-C~{NDF4W5f!#A5HbTj z0n{Y`l###@&K&)P*T*-2S#bAD&GVGft#M_pDWQRKm)>m~g|rS?YnfWbQ|212DV{@I zu6ya)(E+R z^zx`?65qta51qgt8_8X!lZyN$+Pq2CQy(UIu;DfZi0@I>w(^J-LLY^BG!o#8P4bB5GJOhu&oObLDK(xf~*Llj(xz(fxVSL2g0MJRsU!kQV zm}(dXa|1B@(dtv$Ow~TY4TR{nU*H)}OQ6insOC$NM1i>m(fuIPJKCMlv-Hzt4kc_S zbB*MOM=U9SW+*Ke2Qj=!vvR}!W4`4YWjkkSu`QsVUnXw=6qLd8*?!sHd?l?ZS|W_O zjw;kzv?G58+&PF8i89M$+h0mtPi-Wr%F)*FP83})W(9xr3v@Sr7`yx%nXAFOd06#? z?2l5cUTc4nawG5QrBSgl`%&Y`4FG6%`f*?koMHWzM+CT95sfNCqN>03OMP7|t5e_Q zan*U9;d_jSmtrQOs%%{vGZ-Ho zA@crA>}M3^D%hR$6aIl_#CC{jiphsJ&o;MTe@~V1H!6B92>8oCm&(*hsr8Nm!Lq)v ze~hGmDl~rsU|ca6;&q@+Qk`SO@?IK!2(pvXyxbj5wsm^_ve;)K5UMZUdejenlJqhO z#=WN(_F6L7hz=-8o2mJjDZOxBM>r}5E_O#<=P_wIvgj#oRuM%T^JnF+0{dMunpw_# zos{%hWmgU=+=&yviiY@h0MOM;DjCVFvM*_#jy~R2Y0syU(3_6n3vi_F5_`N7Qt!gn zcKQ)h4}a;1R}#}k)DxQwD;d_5w1i*BTvN=#4WP~8zzVVzhY753%;Pe%*>sT_@K z)xe7_!BIFjz5BblP0i~VX?ez!}O>ij+QIC>IVe zdi3XX=;)52coMYl6bIAXE{yk5hLjXAzPzgfr_E|&TvtsHsFnvv%ygiTD^>-|N>Z*k z--7wprwiR8Ne=I`?H#gf*WlhVUnKf(=9@^(4d9N>ZUIfo zsZL~z+)>+gMgPelM%EmUVOqplYo2n>B2Dnf8^EW6YtE6Q_CcIKG+yEF!LcaK4Pedb2GA)w#AzBpgKfxLr6CzCb|fV#-AcqCzBRPh`l$T&j&eHJ zH4(;IDL@1J8ON6^-7>jsEvgf9Aq~Af_khdCM&ZFuP~)Bjyy|2ARVA+)(Kn*hIB*XseNF_`z)ak!^C7IuuFV8V6hv)XQ zWT&|)SA`wBWa_N8yfJoANnw}$^1^!On7HT1Y$r^sMWZ-_>T@@R^kaWaUD5QC zlo@XVU17>QCbp;jolFn&jl)7?(rUJx6%qH@UhV27!6%|x%p02{x6all0%!LwjU&M; zZ8kG6C+1Y)_1K>8s&?;&;_L4B1N>%Kt9|Zk{lrcu=W9^miE-aA|7f|kG(!21n6;uLOaX`c9O^d$ILyB%^ zA1*vkF95Nsi*b>ZU6}JfInyn27E)mrF;}oYP`qSTwNrH|FXI5SDp~!kn`*IE#kjQW zC!!EtBNWkJCt1vEi-z(oAwk;kHE$}mAN@bd2kr@$U3yjv_WE(86z0%fsW6JoLN5JK zLNfY7@%LRl>=qcFGh2j(OlNr#Zt{VZDo>t)cIdR@y)s9N+oAe*zfpt%62!LW8KPko zJMuYg;cX|#tOt2yvsGy}HEA5H^FG9iwQFlfrc-5_8l`HN_-a2>Hjek2h2Sq`9yLYt z6Xq^(7dbt9{79A%A6{)FBtYhvXh{aS}>4GF%pYte@3c6|Ubu5k_Ywfh*)6q#{6sK5RU zK!vy352l7&xpMe4tUB;znR+E@HDVCHA1Jh$=Hk+=lL18GzkU(38N&s~vkT{3u6%=p zmVeus;-myTwg<%4&nxl5bmlJ@@sW(j2l{W~Qr@mrZ_iu<5&o3x3}Cv@LZ_DS=XbW3KnOx?62;5EYJX%lcwNOJRf%yY*OI-*8yC(Td?(H@J1#?RcgW7nr@*o{S|e)uYEb*(N_8dj z>*s-#s8koVp@AAQo+uso-EGcJUs&hWK%9A|?A1vnu1NIKcfGorb@xL@9<1=3=6BNk zxwXz@mVtb6htyPQF3OPh8TK{E&@syLXHSSAK^_=sDn)`&!o(c2S3L{^{l7N=PLm@?)teX#dBlB*)wG9?uxvFeN0*yX(Y%S;L2WF&#y(o}R-M!Cmb6ztVEx9m z{LwM3O4!kIO7VF>T4vSnK>^i=&k}jnzet1|J)@`AeU7Sgj4FsuhW@>b;T4$3XEOFq zTB<=8{f>HEIsC1p>juC{;FYbw9PvCFT!0$>0Pp$nJTVrwqC19H%d`2aZ=c$JfLD5u z6f;puluzMk?vEH46*!Gk1eA{O)-+$JNN)`XSm}rQg${Q|MPe)3X zJOr~%8DFpIJ_Pu=|_PHw~E~Qzw}v??_@WX7mUY) z&|nDN$*07SQTHL0;vF)b$?r)T%+B+IT*O@1PGl|4Z_;TN$&gL-uB~?1k-UofN&DL; zBA+LK)XQ`@nQ=Ca&Z8DE-dxEwTKCf7(uDcobGMgw5Owr3RCHj8#D@5iWMZ8QHL1K^ zR5qB21pTq*)muMYN7WM-zc&G6+V}qFuMEo^X3p}89EdYrb|@6xd*%HW1FXj@QT8hS zZ+eo$4l(a9ORFNrqd+X-o62e8Hvp{R-g`w%yr00P>m{rI4S)nbuTkQ0eTG-K0nAh+ z!z0yF&Nt+Qa6)77#Xr05@@fs{pY6yfe=R3pFHN^*E+wF4w?~Tn<9o8K`8!W5dHb*2 zylw!+ZYGHinSMJgziV){vMIurzGm+t}@Gi!<;c8-9xph)JYA46HLV$~ zrs1(NZ^l}aou(zs%hOp@SY_hdnC9;E%CiBW!(t;v=XY0Wz9=9Ev388m zx-X}$T~t3sImOPle{HlH=q0dAJC$w8bNcP=eOqaF)tT~Me>Jxu)je(8Tu29b@KcBT zEsKJel?bZiQas*+yqw~4tvAOiI z$KT`9>9fn8<}qPLrDed*%dvShy+A~L_~MaZ7aB<3aGC0a^AP8Ck9C% zd=t{;OH^5S;r3)C?(_yQHlo+6x#N`e-^4J~pYyoh+%|vsy)nQUJ^ihKLqWNNAl3Z| zlClzpS7#I>eJFoMvae9}S$`!Jya5CT>t2~|IZpGoMxpNT=OjHY(BI#mH!`G5(%8Bk zP=^NI8(g(!-Z4v?Q=A8J$IY{be)*b^PSw|U@dcgAPb@VNUNWN4mKg4Ph@2dX(-o4C zkz1Q;`eMlTj$$Z#nOc6MMm~d#?cHi~Men%ScMR>1GTy$0+^I(!MsMDs>al%Ne8K*<7sUrxj-Fa>mb=n>tvNL@0>!N#%7u)NQ^SAp6NFIo{&Ih+P&ZzwUF3gL5U%RmBNRdUF^Dz1~EHFh9C3m*7({>fK~u zOv_s>e#kaC_M0ifMXg9#);q85R|RRYeyzs6ah5FCHp!^rb%xV%!{Us1KX2MQ#fH5Z zI?H?x4p1#aZg~S5$s>(t;i^7sZ+YC}3dMhB-&2EHEhENuYE|sRsS^N3!i@}V(s|iRikkb8@eEccBSb5L5$!hh!x=4+as|vg?C)k>z^MsbHJCBf3yV)#;7~Z(O>Yr46X<_2;R zs0Xd~#E_ zyhSZ@75#>#cD$yFoPs-yBGfv8t`rLR`@UMsU!|BsQ{NddX zvFOr8I*Fg5-urJ_^S;hJPh3AXv19BKWmf)NvFo-S=?p5c)UpdWV-$O3lPN_xwvzt9 z~>` zW@J|&&~V&o1jkENX}OIsJ~K)9)f8)B`{5_UBDW3t18=rR<+d{G!s5B$Z}F{ZMsE(@ zX;0Q&W@jxxLEj;^vvESG2NxJbm8JdNQY?R_8VpzJQUbwA*#H|y0{)UW;(;EWvtPcB)zc-_3bUHI` zgShv$oHaVSrL-zP+IKFvHKrm}ktjQJzp|amktII3B$E}$)AOMHVIYUUf6HIzRik?q zw{QO?b=wPxkn8(}dB&moq;1G+4)`0xvg_!6DlAT)dbgzZo(1Y9NwNjMD81%BWgOX? zrmCgz4)POMW}nZmvJC5B76QOL>6!IK;HOqQ~>WS7T;agCg=rlZ< zilJ4eXh93=5Aud_H#UcZd{%M_gt9}wy}QMkp0+vAhi-x?DS>Q4E3u5~yigD6P%?GJpDJL4n znZ|VHRpg^%Ts0HiH4v!WGK{{MwEskp`h66E72G1y(wWynpb~oj^_63ojpwv2?qYPr z_Sqrd|M6Ap-O8mFaLzs{>J{jJD7k)7XK=gtE7A|}Ecf_29b=$|Dn2|yB@Bet3#}h6 z#>t|k$OzIjdHRTCdVe9iK*L@#GP%nZCeW}bD6g^@4|(=nJP-u|Tg%UBFnq+m|E$z< z1IUB8)#Q*kcknYQdY4x9z1bOTlz9UQhTp&V!qT++_n=e;TytC%PKxq%?praB$%Wnk zc6y8^O@tX;I>wtI6&mWpC0#+iV}{8d))9l|QA7xcaA#YeMpb5>Pj zhb)SSS2nFFd%GIU^QpUYg*tbNQT@z0OseJ93i0kSHceA%E-xFze@^yNYH(y52)DmM zofmzwGxd+MRjkpGh+0^wsIYHHu0;8GTQp2nE_QgFCo(idg8BwHXvnrce)J2m)?=5! zXTi`N*M1i~7;_14s%yb*;3s8X{KA3RHi9N=k;l0OdiEW;9}l1ou9gGx>6+<+O71B5 z$LuDJ)L?+vIXHW~HHx4@!<{3e4j{IE?4+taTM z41zR(&dNYKtD7{Xxzdx;2Lg>LWQ58wP z?AIwPV|L9~LQ7!u8S3rqS@7;e4a1J~(;GnLMVmq(BrR&~N-bQJdmiEcs%bYKCG0%Q ze>ofota^p|QkpFqDQxHbQagg)p(xRw;!6`K_H(d2HuHC5LsNZ%nx`u-wd(RuZhf^H zsl^?hL2OAxRt+wIVD;5n%FF@(UPF?9(xUsW+oYVhpMRB|7qBhx z2ebQOwb*7y1}`TYzh;be9qsSM7)RAuIo|5EKKaa%gNKiWm;SXCN=HftZgD!P$BPKtd{~6&mnooChqkiUy}w(i33Q_?91^?!*dm{{n({MG zsPax?V#4)-fkL2=Uu4y!IvQ)412F+t z?J4_jO8%`TZW!e$H1Q&3agHzeuDaN@?US<&2l>WXndK^>@&g-Rz2p};oy1zR-1cHP zpPRaC4x>~ToD_a4BqNWj%#Fo0_ z9A<`v(*1O;-8L|pXsR3v+cny2cZ_J{5fHDy!$!=Ul7hCf{q>tK9{fq?Dfz{Io@iiqhVszF1eQ})%y=E zh@)+*PNxd+trtypMih5;gT?fF<2ffq+h^ACyY>qNnb$qrWXoW^cq>1})-OS>$Oh|NGnV9r=ek4LLn8j+ z8FckqjwoLa_DU>mTUy7o5+)M)$Y0n*`^;&c1pcklJi@hU1a&PyA(z^R(DicN)>oCt zi~^;jtzS=l>6K8w%RsA8);&Sg!<}Hk=8SVBnkjOYTZ;Qz8QDuQ@j|{$?<4o?>%|4U z(YF%ja>h@61IQY_%Kf3|uOj%v4)AH$ zO|Vr*^D?RVtG^h~d7HYR#P|0Q_O(dqCL|2Ku_J;tp+TPHBQb(6w;^-W(^R&vGTvcV~e zagT`?T-u)m$WMuY^7QMlOpZYM#q+57f7stG)2gcKc_Qk(CA{|$4gatvy61}^5bPTy zzDVcHc&@m{H}IbNDO1ferkL#YwB)15Y(#y0tuGQrdD_nt(SoA%gzVXzLuN#QFStaF zZ^Hk*gDvgaJ5ye-!C+ZtAtXO9NNN-n@a!OPv&TnKtK5OnME>2_>cps)BjvdH!lUw6 z{Im*8YjXqY#)=0%4_kxa8>5~_MSPVW!p}WcW$xBF;q^FLu<_F&x&5A4@867<*A==P z^>hB`#xSbI1y<7s?}qn(+s3kSv&E+g#;GZ3gRs%M%C~+_m^tepjV6x0$5zcP<$Kll z4JgY;B%|zNoSej~-G?dGG7qDz$<7;2#}!(DcOhreht*r_5xpjA9N)q_8H}&gr~b{| zZXK@?&IJ3c(*5eQ^>nVRNbINTB+g$Amd8Zoij3g|`O2ltb9CnS5_?0cgx|GA7#R<$ zNwuyChV`<36i^G8-Y>y&{!Vr%0~LNSkvFOj5@k6yt`$gMZJ>SV#3{2hkc?ne^^scF z|GQ+iLshcyc7$rRF}7+grZS|X*)V2vuB2n!Q(I)u=|ot1XJ9>8kg8jlHNo%WFBTI2 z+|StPU-GUoH38au$z}7FTB~nQ+$A4K*J*n@^F*jyt~rk}tgYOk)YY3bI9Td&B{thZ zF;02z3VSU0SY7UGsr*#ew0J2w#3fGp9zI#S4E8>Ykg(zjd>>f6$ZDxN?5_|^B&N%% zy3FyJ#6C|ttITXs#nH25p%W@zp+=u5UKjR@i#CY{0ywGQj0)mxILJv&ew6zS9M)x4 z9P_8PctUEZGfA3L*$WT^iU}L#fLE<>J}~tuXP4>py0pV#^C&b5tbO&(dz7&rU>dRv zE&|865HD(Xk*%R>t!tgwU#sh=&m7;7_#ELgAfNZqm*F-YnVBfP&bcEL9Y*KGoTgv*%Fv$smb{h zU;>*>V~;g>*Qx@e-`VFxx$G4g#q*CEMfqp^droki;X0<5xG65F$MnHr&a#GC?xxGiqW+?rfxFCC#(7M z7&D)8H}ii1E@%Wp;iJGiNe>Bo(tPgmawFzhfLE0|OW923kG5@Tbenov_L06m%V3PV zKCjP+l=6t*e+)^V*~ov|BMRhJlDTjXecqv&U;1jE?s=aT6_>a$tHhV+cTaf(KO}mg z+f?od&41mqsl$F<$aT=!f=Q zYBuUX8b}<~Jf&-ws%B#Lw3JCBE_7jz4J|??d0bXvL9#jhZSPHkV)>v0{raB4leI|+ z7?nDW*<@VAvFKUjad{DCWmQhT`-rvfL6PxZR1w5Xd)|BOi8Q)mdl8*4^6X%^Q{8zYt4WnUmNHz9)1ON{wkNd1X|3w{Z_i#Z(7z;^EH0dj0aSd1>3rB zQdF_2Xp*rLdFnbx_G%M$d7o2vIkSyv0aklC9iRVrB}fX^mq@5p-V<`BV{RsC=QMa5 z;OWQ>z`jP~d`RR5aCFV8NGy;4?o7oiW(g3gdT93b1&8-R!RW?TWb$9XG=I_-_1Z;e?!?c?jk zT3E&*nQ#mPvc%$~S8hLbPS!^KyHT9voARhe3bJQp@68s4DbM7tMZ4y765)GQh+*J* zYlpEV0rKT6qC#rc99Dtv)~z8`n=PgbeAx=MLJh6HhM6p`2HS-EO&$J$0%7 zRAu+`LX=xN@hNb}!_PQDiQc@H(eGC6cE3d@%J3;a!(1Q&N_Qg%E!#27KG512*7$1% zOLOY9sK1qQ#mJ4J$l;)%FLgyR>H#&~aK8%c+~09wjcW!K%iqxwTv& z=ti#eoMCV$m!`H+R5}MADb_zbEv=ZF*VWH13-G9JTHQVhN)bTLY!s8F2+7EME}SCX z?0NQ*D?Z&!@Q>OR=3VSqM{3SbNh(m;EW8ZlxNiE3j(DLePIJ8dtD5?9;?3xzti1=h zc1=zy@*OlGxp}_>>xhf@my{sHYnvmo>&eqtJgmy%wjs_-D16Dt$Ilt z4>YQ!PHDS_8hRA;H3EE6G-P=X2EWwzCG>8Jb`&zz^ajwcjyRn%xdEt|Oc7+R3#(D* z^LW}DKD^?z9hW_bR_ zkua&wx~fmtgnBy5n7=E_a*0aPdnx8(0ff&|61*zd@u~${2_~Mmtcw2Q{4A6Ieo3St zi==O$CcOlz7{5#t*NTp@N1)?ff*^;Y@iM6$vze-Sry0sK8}%s7#@RZih20ss6-TfTyZ>h&GnN)p;u$1-{r zCk3AFX0GP!q&XjzJ?FC%m*D!fP8UhEUCI!4rO3DRe(}4;LKA1QE(Ht|5ha5T-g3Lc zXDUoI7@7vb7dp}B)6O-2hLJT41y7cZkC&Rkz%N4$%%bNeMoumI)>)}MmorlK;=DLu zl_zLjA6ewXaFSND4Vo(MAQDa+o=kM_hRNZ8m*<7<8=x4Q9G7;Z@;?Jwf3(=JNLMV* z;YST>qfYwn(qd=5j0kiBu4pJDykXg7yil-Cwr%1O%%AeNn#2caFa)qNA`ekRYZ`d_ zHF6X3L`AoRV2s=P60)Lgf?gF7K)>?-iOhTk7DaTXb|c1^Vzcd)^<4UwhO2Rsvog)A z(S)^Y%y@c4548p__PC5P=)}QLAo#H$#$w-FO1%(tR`>*C%nFxaF1+oQd;A;j=xmY` zv}d&{_@Fdao%HeD=F(RR?x@6qvkC<$D(tn27>C06-dUMO(KmAPV&}7x{;w)-tlRN?|)>UYB8Ran}> zCQo4zj6>2P?qJ>))SPvS7aAhNa|7U@_DjArp01)vTf@x`?=NW{>fW+aj;{FAo$;_y zSE%^9KyDy;Cbs~8+iI#prM2q_=8qUJu3{cf+B9x22v;BSuK~qcrzvf>ICQ#eLY{@{ zB?xBtvdAUM z+CHoeXRQlCAAdC43^_SnEt%d2qLfoo*W#zjXD zf@$_&pyNiYyb{V)nINQ-A`0*VvoYZhOd6tl&M`Qb`feXRDPL55l#wc z$Mnd|@%k;y(9!%f?;RuJ>rr_7RcsAA6V}Vub^r`Np^2pRdErX5=;KO=cM18aosL^* zs{G+?yu+WanPL0O&K3ah1Ch20Xsf-+(vH?n#jpIcNi2?=EdsG90GLBJiM|l?m;I`c zLGfZAlsSOGWxI2+d+;=zzY5gjke74+mb&%tklYlkV;72MLef!ii1fFT!W;98e;c9G z)7M-dCaF4<#$yIbxEpf4i9@W~manpWY|bs$eX>lV4L^6eEzF<${dGc24JZz+D~2C1 z|4^l13z?CvNrAi4`h;1Td(KD=y)=9<_>;)j?Z{Vat0nT+vPW^Ow}pAE{EBDRde-YV z4f=OKFMc3?aEmAV8%gpZIysZXuOK$E&bhz)NGB!OS?=ADX zug`@l&8hWx>B{kLWaKDdVKdjk+H9H^{sW$D)aoO-It0G2)8nk++}$hjsUMIH%KbnL zd)|(1tLgEnu5Sc4ViVgFjqE;Yh|Zb*tQF{DB_xdeXmiD^mWq}vI!IC>T9n6n;SOWgl%+8QDv39^+kZngO*ahdW-(+?+6_c8QM^k zy|-U)Ax=<6-kdB!#>u@vy2s#NzN7mcJv zS?`KzR}Q)|>{~f>f8e;S4CcM)Y}ky6F_3KGtoLcr!uGTcx99Rs6P6%WL2a9@g~cv! z66)HY%H0a4i~`az;tBE;7sCW4az@Hh&r@6XZF^fsJgbX~2#1CV`_t|YeGj|C$s|KP$=dX)*Krtq;l*HL@IZLhM4mD;UQ>7wRgmcv$1 zbZiMTGWB~iog8XG!S_)@f($rh28U;;VD5PZ3`3quiRZ$timXm}c#8xZ{l{&Jjdq6w z=k@mOHU5Wch3PKd0EBCA07L{eYq~;h#4PbX^G35_eN);Ks??kf-@Nu-F&yyPFa0ke znUVUR5ivP@`~T80)a;ubH6ofMQ;jOpkSasEDwTw zzHa%F+X>*?_s>VlHsN|CU~-}+t*q&8csl7aG?(C>oR3?m#kO8fh*Ixb%Yg=8{n}Le z55Q{bvh9*e-Mhu?O}KsLLK`=(n9UQP64AxbPbCRv@Yy%WI(K-!Jl;QQV31!OmYn}x z=P5)%WiG^r`-eL!OX59HKK-$ZWora~gX|t|2t3+l_kJ2J-u{#x0ieDOo`*56n4tCN z+nwG`-F0nV($n@7P|`f{B5v?>ts7=HY+#gw4-` zT9q}96gpR1L6Rr7rD{p$D7b+i&13;{ZfTF;Zb6PQgnpaQ9d8X63Bbf(N@hu~PDM!M zU4W(hy1f&8Huwn-6cVbdV_>XnOXmX% z*q`UXV~dncPHH(k;UR_w>nkM#Sj)S1o-va)9i9=a!E&@0CW~Fc_3}T9mhC5-EQvROsQ726&DPgcf)lMHr;wT7k^TwJXN7j#L#9W-*;15Mp6Kqg zsLHI`Ap);`s}KpXzBl0H)ED@d3!(id`BT}=>?U?d&igEEZQAk>NV;I;}gr9@2&dk0iXv{%UP0V?PDUI9fU!jO;;|nCsXm~G zgCJkK;#aQ){%9ejoK3tOCEv#N$GE?dfy`$v?c)dm6WiB$-kE?yR%qUrgPQ76GQ4U{ z8ET>g1Jt}QBUIEqgVFfkgcM0Z#ZHD@ud?-Y3*YHeRkCPjuX8~QR|(l4jY>d56{Xho zGB3gmcui>du@N&AU!Hd;dhKZg~ot?eVThB22A{8V;cvsBZP zMZNKX;?bW(6_zw_cev5Be%{>Bc4MpyoIesixcK&re74plK5wzR^>MEbwHz0l3&<)Q z`?7n8FN-vU!q@rZtBLH*vv;_H5-;XHIaa0Je)b5I8iNP7tB*m-@nZ`#p;AX)8Zz+a zJmVo@iEArusmOIS9?eufp5D`mZsXn&G`D0vc~qCc?Y!iH<{yVs zW;UDhV_qFIBQ>UR)gV?1mk@@-HINbe5j;erKGm#e24Dg zo)Hsq4cnW|f%+80`#1*Zj{9rtJf&KL1>6MF%Y$!X$g+_O97Id7TYfscJ?qrmb8vkr z`4IoL*|H7Hb`$AoN$GsN`#o+-dWMd+ARMPUn^@&UG@!tkYKR-8JAawHwXXsfW*n}H&_jIB<7`u%UY}uFgAJ2x zvf}-TszBbS1N7HD-xYn0-SS$`L}t~EGCq^Mi@Ib}PirtnK=%zZ#U4hm1wZ4FIttHv z*TIp3!QX4~U!r_lA5{*DAH47nf26kcz46HB=uNoJ@DdCs)=p|%_LvPN_L{G9QG~Du zRT=DBEBdWiwAXU1M`|ob5F(a2@R6NJdl0(Vk&NQ{?To5hJ1cL8S{T}_10lg zeP8=9h=P(LA{_#Pl;qH<(k0!XfOL0{prA-eD~)tZ3NQX2-_W(mk*8szO-orPZ z=lQ+=a9zyVXP@1Bt$VF?uhP1uyu*37sh>#d5p1}V#SX$nswgv{u*Q} zto8AktVw-UM9rM@?6P>FV30w*(B2|&f_rOVM|O4JefKy?ZvX;unxP?JzbgbHN&M2m zRfx}bX||dY9qzS;0{mS#&BqWR(z&7{+5M-Y|KLzs_#wq@(kzYHQjMuQnjCEGtowIV z`YX39)i-LOD@^y$;O;q#mWw6U^a-6`6Z;3b6RQy3%?kb>qQV6cZ?vd!vdJ__ys}Bg zsJfQKM==t|QVyk-^7g|y0s0G^tkUhE;zQt!6JdOe0A;i)(*4l6P-vaVe~8niBCPN@ zGvPQqKq}K0l#y@Y@7i6Tu{#5yD=%?_TA229JfB-|=}lwFT2nvR3p+mBY!H$b(nXu* z^&SazS`ar(NSPOkl$P?=r_m0zcvO6I#m%NC)f5ca?r};($FFKIb)@+=_|o!yt?yre ziJoH~JWRnCsSlDH2}TuDR)!$s?{yaV2X&^uuWBmYnxd_5E}Tpo=b;iy&{x+McAj^C zoHcuyL4a3igYN9MU~D9}e11JTanvS<*kfW- z*^h0qlftkN#X(hQx@7s&lHb&AA2fLG9`Dk)cadT|mP%C)JA1TuQ=3(4APz4o=C$KC z_*R_U>R!AWup`@u(7DeBy$c|LE;1Zj4;`IVwFu)mINadQc&h-!FmLE zVb1h`f_#ivb@+>V&mk>4J!Jbch?a6}Lr{8YL)>Wqwd8>u-7Qj;|2)OImg9@2vQ zcv{B`beR=6)TpdxEEOJBcMTD|0!Iw_IfVX$a~NfAp%t{D`1y}<0dbp!nN8TV?{ZHV z{RX^)kKW8t)Fg0rM#;m4&3B)DaxY(3D!Pf;zz!FXGu}RuUs;Q#T4jnm+cnzf@gDRx zc6&B4=IZti>f0Dk_mhY<+%gkK;$+LodUYfY!@6n;cny2+_MOR>b_X$>6=t<|CCb4A zmxY)X!UL9ma1=T_GCgSld95+vV~M1-`X^efeb#93x~XlUsmhD`a-LG{57!?NXxih2 zP0CQC=QYhmhsV0AOU*OxTQ@X*^`l~~cu~^T%fY% z_gvSSVzc(LD28`|$tlPqd$kwnKtCObD8WKA}jToEYm!&MZiVXr%wt}9@-#(u* z`;1T~9ntlsyG5PG%BqbWK*aanHKuN_wMedoSqDcq8R7S6 zuK0t7(8z9y7d1c8cAafZrkCC~cb4oE4|Md5QG%*w8~We5s&N&O%TpgDNt{+Dr>;aJ zPOC|~pH!}C=xVx{Z0b$%ra${aAo)mOcr=%ZzlPWkcOs4v9LXpg-6e7*|JE`&!%~|C<}@SA7H06>t#Q!9~UN(*;!(c*TM6iSWq@!T(z=JeBpbk@JpUUyg>LZ z;A%#ST3iG4t|vn-Yjhey*LIqzbf40RzLWd)<$X(WA4?n<2rQD!bPxPr&AByuuxp7n zt=obX{V{*LX4}L!E4M8(x0|8da(RU4CA~b&^9ZP9irI&U*+nhZn*VEveDhU;0gFiU z7g-Xz+jFLyquU3>SGThJ%cNv^Un8hVrJeeVAhL=*num2;9A1j5znE7h295)Y7=J>P za>SMuB`6qf;NJ~xKCC1xtQE#>stNwiTcD$lL|*EX$SA%}kUz*Y$j4Ef!u_0A^;xWv z<^(=_X4|wqQ%7IXbw#?k^E%;~dEYE$%+$&qtKpCb<=TsVwG#EFG#&{s@qDG4ew_%_ z7YNE&kh5(C=dk0qlu&(N-1wCTrO1Ofwq}%E*^o!s5W$Pw*8@VgaoCd&mMWj`s^mT< zOc&Wz-`34t%trjMKIto^4B63-t{%F2gB?SE;%_L zvc2Iu+1E58jB5!9|%EAkE-1r6X8eFu!>!jKLHC- z6EQ~gGRc7pg^Sac#mmW6m!!AIqYQN9?;7xwerUOxRuT-!Fi3MH_z^|0n==iH2Qx17 zZQjP{raMl+y=bG=&iU8(w2K3?<=acBTAdrDHY@XN6&A7_E@Epzy{+PkD|)A8(=M=g zTcnOpHp!=yTbejz3+?8;!6lWH&g)Y?&_zcoZ6#Yn$~=0Pb-)PvGt0^3o~)g|Ti~2z zcGjcEZfOj=P;|iB{d(C))NbrX&Tf-R+;Aegm}D!DiNsd9%i2Ig()M2F5fIC__M>jS z#KbxYUFm5VR-3DZ!ezJ3e3*ED4jD9O8g{Ey3w5NHZy;|3v@FjVf3?wi+?4-Y zq23AQ^ICyfUIDgDz?A7JODqT8bDcQ`p9eOAiDkxi4UlxO({h)&B8a*hYP|VNi%e`5 zwBW|77dvFsN}}BtUrf<2!T>{-*LT|wSul>r~kshGXc zKg1>qSCh?|e8-f2CHU^H^)OnQTDc>G(TT@G;;2{w?7j2=1IyQ{2Su{u5dYd z)p^&klU&{Fh5tGZEMGZ&9&ruF7_9BEC3gi z{7*?t8I*>jnl82Z{75tAg6c_wZbP1QlO>4v!_!y9ADh1DqAAQ=x>AqO@vjqiz;*3V zoc=F#-xPG zt14GsIxi2G=0l2x*CfB|DOxC-iM?XkSFj=*=)ybBB!`62+$EEpkm4w~i5nI#y3^OV z+^}fgPJQoCnRsTzqi@eFuCiFm?OtVUcgN)jjZK1~6L%G!2RiQabRo!=BX9o!lV$q1 zTWh$5xeroB7@Bh0=w={p9$q-KHoy{dZ|2VTp8J>3hjOm>^_fuxhLS5#Az?rzd3U!jqx<=;?9R@Fdx-ohgFZzuWl!oIth909!1 zZ-l6Z9meK66S_Ljh674fT@Lj3mJd9(O%3=jv35gHS4q368WEwn+9K-tVJFy>u+b@; z)n#65bAR{AA8V#PCKDv&{_o?y zhu(j1o-qOr0^0JoNW~Vc>qNvW#Uriqq-6gvyS`0R)ObJ$b`yDCW`UndBpcB{ zHLY{$E>C~lH?J~R&YI{hE=35d>V|d%P7mdra>BsB5XiZ-s5C5PTheNfg*kM{dllF^ zUMcE61k9qYIJ?cs-~hT8Yk@*ph%-(|h}EuMmTzn4{(Ns=E2URhCJw&GFt;e9O_-!# zp>M}#VT4E(a&p>n^v@uGXPGS@&_-66l~RcKuOkA1uXQ2Q>)1cTS6})3WIRRfa2E!% zGbpF{z4sb%^D^<0eJ;K83CA<&Yn`Wi{;nYjOMhyua`-g*_BxD{SSvNjZe#BgRA&T)&Jm_3a1_k zPZV&;*}ct|7S!Yn8{2wPNs^@6Ny15RxOd}ZZP#ibg4qfyCiM%E$5f0=C!guudieF zSHTDsteIbhpC3=TcFIU#%|)3YXP#hPj8%Dh7P|YT(@W)e5FWi%kt;$+a}uY+OOAjU zH!+CtrEd{(0@`Yj{yu?*MvJhOC-`QgYbH z;7I6MW93xaM}nk|0==EVeW?n?ch6-^oDPI6##~tRsZmm-2!+q82)L{6QAJVpOQS$< zre`1{Hs}{*JH&C-n%xuJn1kN4M&s$C!PgOt48V%2!gi!e)LmxGiU@ zYF_CA>!ylxI`UD1?>u)JJl>MS*M}vU9r>{@%^iEqk#-XBV{g25`P}?781rmdMBrRz z`E0Hw<@7qbP@8tu>mnmeXFt;GsA1vA#Mjr)F!sySXI|l`2&Q_;I#4iHD(ME=a;@o^hxT0nx-s`6sTjGG+w^9O}nwSj645 zhXuT#uF|_IF)cB7VvZ&!@R&?8>=KSqlCT@@!Aic+LHI?`g*Ce7>u#`o5ZH<)A7wM++iRK0g+u1I)c&s836cPQe!B=>ECS}hoZTZHCZ>+X_59J zQT_*K;iVgvD`{`~71k2Mgdw{vnxFdHYkSXajSRyEw)+PsN@+H91ctQ`-CvA9SCrWc zb~#d<{@W&%O(qmNV~wI7HU!N@!>{bFrZfC!q5fY)1g=xCkV5Ic)LvHJ>9nU>d}0Ub z@q5u9ud~5Rz?q?Qlel?)vkHkQOrrZGiNnd`y<7S6(4^xN|MkY_`_elLNV>(p4q7B8 zYAgFw&spVobtIBlS*FqyJ8`TsYWivuBa}AI)ZR{`+1alYo zcbXm1OB8*Y8{EF4pPp)P@^)#NO*Kl9cUQz`_$;MU4AS9Jp|$3(?J)3u#x}P!ymQlP zF!JXFNB%$|u&4BJ_N-FP;94fW*q@Muw1*qk)izlGQ&LKM>pnn_%4rq{;wsl_3el!M z)@!gVBq?$+E*TeD7{V!F4v&#x++igD)i4=X{;qucWI@I5JcCb|$Eyd| zo8|SZu`ps>VsZR}wAI#iMtsPTH0q0Rv~Gao#nhBgKZ}}_>IUib>;{csF|YuUP)D2< z4QVBl^Z2M7LKmJh5;xsL2sVwOEv49KX~F)epWCdPKH+sG=RnG)Qa{}>o*j-=Q^sOJy#hkL4W!ws!x~);I#t^M+uUu!gto}IWE$ZP^wz$)dy5d&pwDt40BExR|QdI%3ao9lYO*JbmX8n15Xxk&Y8+u3ttx!~`aN^Pr00FsO0TQ`Rd*AgFK|#M$xtSPgFq!t zjL402w!4|GG}4;fgT+l(_@FuNtH0*b8ZQ?WG#7!t4*8rc>A_9=PTHoR)WPxUmtL^L z@*hKyzOJn6JDf4m?63G_TDMQUphsmjBJyjA`_W}Tm)TM#*y9u-i^pyR^eD>8yMMZ_ z$hxMieM^`e^CUHo74J(~XC7S|)TCTUsT<%WEfrocyw)lBY9c}`4b$(Y8S+ZK_}i7h zxbXI7pTt={fYCtQ*g)}YMc^EeC|pIP5@*)x4O?|Jy$lpy(eMM#J1<*zY{Z6awLM6^ zbeOX4m#`cd+_|2Fx+p3^T})$8AiS#C`+HM4Zo>y1&4FfrT1Xx3#TGRl94G^}CLIwo zz+T2*6g08w)~f50_obqAI=%OZw>qncC@glAfBlM)Z1?N3!F)F7cn9>!@yqpy1l2@| zm6$hKACCQPuR-fVK7;{`izFrh9~T-y*Jnah%DWJIB>9vzk9iGJ$$BC@=zD@M_gs!a zp#4U`RFK?KJ1To*PnGoTyX+t)Y$H>awOQ3+CX%M=t61=j%rOIOFn3NUPEq;B!|V!r zAdOprVzmEgIEpH;gbnFcMt?bvpsSmzT@2LgUO3rNQcJbo)u%t;+|@1jl!2HqsxWZo zCvr{OCP?2n$;_kSgsmL!^jxl>t18awGEWp+cg^LM5n61-24+Ofa!ozTlobJ$Yk|pA zpFFEJ`gXYL-FoI4NgXSqBJb*FFi?F0J@?L`-kzS8dRfue%Y1L4P@e4&hc_`q$nsU? zwB;feay-zWqzT!!pg3aV%`2>&2)&vnM`i1xweT3k0DC;D)l0wd&t)vjUvEoFS5dU$ ztS|BgL}qzq_Y82MCCVAZP9w!{6;LhezUJc3EimyX##UK2$CEOf)NehGufJ9vuDaS{ zC$FXRN8-7CJH)QBMRBHb6c_Ps4H>=%X$+Fn<5!5b5mwZ&pYN4n|2Ol+S1{iMzhMc0 zB5SRD))tM-TYfQrK)9>@e2e^Pvgown3kfolZtmicq3oUB43)WBa@Tdl3TJn2xEBA> z#RdCFXvR%zkd8`aQjCM>@>f81??wbkTP*FItKkthTxj>ObG{fge!xr~DgK*4<_BXv z+h}1K$V4UwqzbH@N)`BANpkeO)Au98uN9|~hLP+^*Q(F4V~~zZ9aj9;azaf}NyHvd z$6`7tL-WAp2<7n7wg^==M|0xNCXv5F3yH@U(f;u9JD1NCRjUZZFTtO2Qqv4rDNK&c zG3goRbPPu=a<3fdvVJ}K(~ZmAAh>9hi97wZ`biG$d@r$}OB{$WpQfEba;m8CXJJ*5 zmD+Alqev>`ht=HQrcMzuFf}a$3cemgE9bL z9@)ccQ^ofP#r$))SlBuEIY(OEP0_Glkav-P=bC;_bj2x55=@fCHLpSXNbEqWeZJw? ziyF1D+b=GR=?Z9Tsrgj@S}x-isVw2nDNGhZ0}iOW)xR3ELguE#*k){Wx>dI0QnoG0 zLb(-I6cE;Foy&9O;PnlS-c$;JTl1Vwd~q*E2MYSy8qYfwxBd4zxcBnwVqMD#s|Opa zl(%bSlZN8fpqG8wM-OLQ*krupPTprgOWal*)OH=w2V%#!K;bsU7B+^-(zc^7e4sa|NRha$kj+^dJ&wNxfaoGM9ljI!pDXFJAJ^Y>9V zDARq$i??jyYCzmySwi^cfIjBk6|7w+Uy5bzlE`(+*sA~WeV zZzt@oYd)wf#OB;x!Wr zYmI-r^}8NoMAl~$i1ofRfAYcOJO@p7Rz=%u0Nf{T-ZvrvE;cx}H?6(}2d;)CDx z6mf{wBBz8o8ja!jlB}8eTCw@*DS2bDI=vBFbOSD}h^FlHKRA05hcH-t6W}Ia)w{;g z70vV*Y#Z`X9UngJhCj`VZx5qOH-u6~hyyygNEhULYa%>tWOf6_0*{<{N%7PG

d+)^2c$3>3dQx)z9WSi%g(>vH=2jPi_#{ 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

6HQm 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 N@%iASjl!?-{{vPid7J Date: Sat, 12 Sep 2020 12:48:26 +0200 Subject: [PATCH 12/13] Create empty texture to be used with materials that miss e.g. normal maps --- base/VulkanglTFModel.cpp | 110 ++++++++++++++++++++++++++++++++++++++- base/VulkanglTFModel.h | 2 + 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/base/VulkanglTFModel.cpp b/base/VulkanglTFModel.cpp index 8cae61ea..68f4105c 100644 --- a/base/VulkanglTFModel.cpp +++ b/base/VulkanglTFModel.cpp @@ -613,6 +613,110 @@ vkglTF::Texture* vkglTF::Model::getTexture(uint32_t index) return nullptr; } +void vkglTF::Model::createEmptyTexture(VkQueue transferQueue) +{ + emptyTexture.device = device; + emptyTexture.width = 1; + emptyTexture.height = 1; + emptyTexture.layerCount = 1; + emptyTexture.mipLevels = 1; + + size_t bufferSize = emptyTexture.width * emptyTexture.height * 4; + unsigned char* buffer = new unsigned char[bufferSize]; + memset(buffer, 0, bufferSize); + + VkBuffer stagingBuffer; + VkDeviceMemory stagingMemory; + VkBufferCreateInfo bufferCreateInfo = vks::initializers::bufferCreateInfo(); + bufferCreateInfo.size = bufferSize; + // This buffer is used as a transfer source for the buffer copy + bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer)); + + VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo(); + VkMemoryRequirements memReqs; + vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs); + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &stagingMemory)); + VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0)); + + // Copy texture data into staging buffer + uint8_t* data; + VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, stagingMemory, 0, memReqs.size, 0, (void**)&data)); + memcpy(data, buffer, bufferSize); + vkUnmapMemory(device->logicalDevice, stagingMemory); + + VkBufferImageCopy bufferCopyRegion = {}; + bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + bufferCopyRegion.imageSubresource.layerCount = 1; + bufferCopyRegion.imageExtent.width = emptyTexture.width; + bufferCopyRegion.imageExtent.height = emptyTexture.height; + bufferCopyRegion.imageExtent.depth = 1; + + // Create optimal tiled target image + VkImageCreateInfo imageCreateInfo = vks::initializers::imageCreateInfo(); + imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; + imageCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + imageCreateInfo.mipLevels = 1; + imageCreateInfo.arrayLayers = 1; + imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageCreateInfo.extent = { emptyTexture.width, emptyTexture.height, 1 }; + imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &emptyTexture.image)); + + vkGetImageMemoryRequirements(device->logicalDevice, emptyTexture.image, &memReqs); + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &emptyTexture.deviceMemory)); + VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, emptyTexture.image, emptyTexture.deviceMemory, 0)); + + VkImageSubresourceRange subresourceRange{}; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresourceRange.baseMipLevel = 0; + subresourceRange.levelCount = 1; + subresourceRange.layerCount = 1; + + VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + vks::tools::setImageLayout(copyCmd, emptyTexture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresourceRange); + vkCmdCopyBufferToImage(copyCmd, stagingBuffer, emptyTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion); + vks::tools::setImageLayout(copyCmd, emptyTexture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, subresourceRange); + device->flushCommandBuffer(copyCmd, transferQueue); + emptyTexture.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + // Clean up staging resources + vkFreeMemory(device->logicalDevice, stagingMemory, nullptr); + vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr); + + VkSamplerCreateInfo samplerCreateInfo = vks::initializers::samplerCreateInfo(); + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER; + samplerCreateInfo.maxAnisotropy = 1.0f; + VK_CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &emptyTexture.sampler)); + + VkImageViewCreateInfo viewCreateInfo = vks::initializers::imageViewCreateInfo(); + viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + viewCreateInfo.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; + viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; + viewCreateInfo.subresourceRange.levelCount = 1; + viewCreateInfo.image = emptyTexture.image; + VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &emptyTexture.view)); + + emptyTexture.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + emptyTexture.descriptor.imageView = emptyTexture.view; + emptyTexture.descriptor.sampler = emptyTexture.sampler; +} + /* glTF model loading and rendering class */ @@ -637,6 +741,7 @@ vkglTF::Model::~Model() descriptorSetLayoutImage = VK_NULL_HANDLE; } vkDestroyDescriptorPool(device->logicalDevice, descriptorPool, nullptr); + emptyTexture.destroy(); } void vkglTF::Model::loadNode(vkglTF::Node *parent, const tinygltf::Node &node, uint32_t nodeIndex, const tinygltf::Model &model, std::vector& indexBuffer, std::vector& vertexBuffer, float globalscale) @@ -876,6 +981,8 @@ void vkglTF::Model::loadImages(tinygltf::Model &gltfModel, vks::VulkanDevice *de texture.fromglTfImage(image, path, device, transferQueue); textures.push_back(texture); } + // Create an empty texture to be used for empty material images + createEmptyTexture(transferQueue); } void vkglTF::Model::loadMaterials(tinygltf::Model &gltfModel) @@ -900,6 +1007,8 @@ void vkglTF::Model::loadMaterials(tinygltf::Model &gltfModel) } if (mat.additionalValues.find("normalTexture") != mat.additionalValues.end()) { material.normalTexture = getTexture(gltfModel.textures[mat.additionalValues["normalTexture"].TextureIndex()].source); + } else { + material.normalTexture = &emptyTexture; } if (mat.additionalValues.find("emissiveTexture") != mat.additionalValues.end()) { material.emissiveTexture = getTexture(gltfModel.textures[mat.additionalValues["emissiveTexture"].TextureIndex()].source); @@ -924,7 +1033,6 @@ void vkglTF::Model::loadMaterials(tinygltf::Model &gltfModel) } // Push a default material at the end of the list for meshes with no material assigned materials.push_back(Material(device)); - } void vkglTF::Model::loadAnimations(tinygltf::Model &gltfModel) diff --git a/base/VulkanglTFModel.h b/base/VulkanglTFModel.h index 3a1fd984..21d936fc 100644 --- a/base/VulkanglTFModel.h +++ b/base/VulkanglTFModel.h @@ -249,6 +249,8 @@ namespace vkglTF class Model { private: vkglTF::Texture* getTexture(uint32_t index); + vkglTF::Texture emptyTexture; + void createEmptyTexture(VkQueue transferQueue); public: vks::VulkanDevice* device; VkDescriptorPool descriptorPool; From 07970bb1e3ae93413c3ea999f11193664b9f95b1 Mon Sep 17 00:00:00 2001 From: Sascha Willems Date: Sat, 12 Sep 2020 13:06:39 +0200 Subject: [PATCH 13/13] Proper cleanup --- .../variablerateshading/variablerateshading.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/examples/variablerateshading/variablerateshading.cpp b/examples/variablerateshading/variablerateshading.cpp index 6e745f1e..70f26773 100644 --- a/examples/variablerateshading/variablerateshading.cpp +++ b/examples/variablerateshading/variablerateshading.cpp @@ -25,7 +25,15 @@ VulkanExample::VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) VulkanExample::~VulkanExample() { + vkDestroyPipeline(device, basePipelines.masked, nullptr); + vkDestroyPipeline(device, basePipelines.opaque, nullptr); + vkDestroyPipeline(device, shadingRatePipelines.masked, nullptr); + vkDestroyPipeline(device, shadingRatePipelines.opaque, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); + vkDestroyImageView(device, shadingRateImage.view, nullptr); + vkDestroyImage(device, shadingRateImage.image, nullptr); + vkFreeMemory(device, shadingRateImage.memory, nullptr); shaderData.buffer.destroy(); } @@ -36,7 +44,6 @@ void VulkanExample::getEnabledFeatures() enabledPhysicalDeviceShadingRateImageFeaturesNV = {}; enabledPhysicalDeviceShadingRateImageFeaturesNV.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV; enabledPhysicalDeviceShadingRateImageFeaturesNV.shadingRateImage = VK_TRUE; - // @todo deviceCreatepNextChain = &enabledPhysicalDeviceShadingRateImageFeaturesNV; } @@ -211,10 +218,10 @@ void VulkanExample::prepareShadingRateImage() for (uint32_t y = 0; y < imageExtent.height; y++) { for (uint32_t x = 0; x < imageExtent.width; x++) { const float deltaX = (float)imageExtent.width / 2.0f - (float)x; - const float deltaY = (float)imageExtent.height / 2.0f - (float)y; + const float deltaY = ((float)imageExtent.height / 2.0f - (float)y) * ((float)width / (float)height); const float dist = std::sqrt(deltaX * deltaX + deltaY * deltaY); for (auto pattern : patternLookup) { - if (dist <= pattern.first) { + if (dist < pattern.first) { *ptrData = pattern.second; break; }