| /*------------------------------------------------------------------------- |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2018 Google Inc. |
| * Copyright (c) 2018 The Khronos Group Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Tests for subpass dependency |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "vktRenderPassSubpassDependencyTests.hpp" |
| #include "vktRenderPassTestsUtil.hpp" |
| |
| #include "vktTestCaseUtil.hpp" |
| #include "vktTestGroupUtil.hpp" |
| #include "vkImageUtil.hpp" |
| #include "vkQueryUtil.hpp" |
| #include "vkRefUtil.hpp" |
| #include "vkCmdUtil.hpp" |
| #include "vkObjUtil.hpp" |
| #include "vkBuilderUtil.hpp" |
| |
| #include "tcuImageCompare.hpp" |
| #include "tcuResultCollector.hpp" |
| #include "tcuTestLog.hpp" |
| #include "tcuTextureUtil.hpp" |
| |
| #include "rrRenderer.hpp" |
| #include "deRandom.hpp" |
| #include "deMath.h" |
| |
| using namespace vk; |
| |
| using tcu::UVec4; |
| using tcu::Vec2; |
| using tcu::UVec2; |
| using tcu::Vec4; |
| |
| using tcu::ConstPixelBufferAccess; |
| using tcu::PixelBufferAccess; |
| |
| using tcu::TestLog; |
| |
| using std::string; |
| using std::vector; |
| using de::SharedPtr; |
| |
| typedef de::SharedPtr<Unique<VkImage> > SharedPtrVkImage; |
| typedef de::SharedPtr<Unique<VkImageView> > SharedPtrVkImageView; |
| typedef de::SharedPtr<Unique<VkPipeline> > SharedPtrVkPipeline; |
| typedef de::SharedPtr<Unique<VkSampler> > SharedPtrVkSampler; |
| typedef de::SharedPtr<Unique<VkRenderPass> > SharedPtrVkRenderPass; |
| typedef de::SharedPtr<Unique<VkFramebuffer> > SharedPtrVkFramebuffer; |
| typedef de::SharedPtr<Unique<VkDescriptorPool> > SharedPtrVkDescriptorPool; |
| typedef de::SharedPtr<Unique<VkDescriptorSetLayout> > SharedPtrVkDescriptorLayout; |
| typedef de::SharedPtr<Unique<VkDescriptorSet> > SharedPtrVkDescriptorSet; |
| typedef de::SharedPtr<Unique<VkPipelineLayout> > SharedPtrVkPipelineLayout; |
| typedef de::SharedPtr<Unique<VkPipeline> > SharedPtrVkPipeline; |
| |
| namespace vkt |
| { |
| namespace |
| { |
| using namespace renderpass; |
| |
| template<typename T> |
| inline SharedPtr<Unique<T> > makeSharedPtr(Move<T> move) |
| { |
| return SharedPtr<Unique<T> >(new Unique<T>(move)); |
| } |
| |
| // Reference renderer shaders |
| class DepthVertShader : public rr::VertexShader |
| { |
| public: |
| DepthVertShader (void) |
| : rr::VertexShader (1, 1) |
| { |
| m_inputs[0].type = rr::GENERICVECTYPE_FLOAT; |
| m_outputs[0].type = rr::GENERICVECTYPE_FLOAT; |
| } |
| |
| void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const |
| { |
| for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) |
| { |
| packets[packetNdx]->position = rr::readVertexAttribFloat(inputs[0], |
| packets[packetNdx]->instanceNdx, |
| packets[packetNdx]->vertexNdx); |
| |
| packets[packetNdx]->outputs[0] = rr::readVertexAttribFloat(inputs[0], |
| packets[packetNdx]->instanceNdx, |
| packets[packetNdx]->vertexNdx); |
| } |
| } |
| }; |
| |
| class DepthFragShader : public rr::FragmentShader |
| { |
| public: |
| DepthFragShader (void) |
| : rr::FragmentShader(1, 1) |
| { |
| m_inputs[0].type = rr::GENERICVECTYPE_FLOAT; |
| m_outputs[0].type = rr::GENERICVECTYPE_FLOAT; |
| } |
| |
| void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const |
| { |
| for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) |
| { |
| rr::FragmentPacket& packet = packets[packetNdx]; |
| for (deUint32 fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx) |
| { |
| const tcu::Vec4 vtxPosition = rr::readVarying<float>(packet, context, 0, fragNdx); |
| |
| rr::writeFragmentDepth(context, packetNdx, fragNdx, 0, vtxPosition.z()); |
| } |
| } |
| } |
| }; |
| |
| class SelfDependencyBackwardsVertShader : public rr::VertexShader |
| { |
| public: |
| SelfDependencyBackwardsVertShader (void) |
| : rr::VertexShader (1, 0) |
| { |
| m_inputs[0].type = rr::GENERICVECTYPE_FLOAT; |
| } |
| |
| void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const |
| { |
| for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) |
| { |
| packets[packetNdx]->position = rr::readVertexAttribFloat(inputs[0], |
| packets[packetNdx]->instanceNdx, |
| packets[packetNdx]->vertexNdx); |
| } |
| } |
| }; |
| |
| class SelfDependencyBackwardsFragShader : public rr::FragmentShader |
| { |
| public: |
| SelfDependencyBackwardsFragShader (void) |
| : rr::FragmentShader(0, 1) |
| { |
| m_outputs[0].type = rr::GENERICVECTYPE_FLOAT; |
| } |
| |
| void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const |
| { |
| DE_UNREF(packets); |
| |
| for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) |
| for (deUint32 fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx) |
| rr::writeFragmentOutput<tcu::Vec4>(context, packetNdx, fragNdx, 0, tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); |
| } |
| }; |
| |
| de::MovePtr<Allocation> createBufferMemory (const DeviceInterface& vk, |
| VkDevice device, |
| Allocator& allocator, |
| VkBuffer buffer) |
| { |
| de::MovePtr<Allocation> allocation (allocator.allocate(getBufferMemoryRequirements(vk, device, buffer), MemoryRequirement::HostVisible)); |
| |
| VK_CHECK(vk.bindBufferMemory(device, buffer, allocation->getMemory(), allocation->getOffset())); |
| |
| return allocation; |
| } |
| |
| Move<VkImageView> createImageView (const DeviceInterface& vk, |
| VkDevice device, |
| VkImageViewCreateFlags flags, |
| VkImage image, |
| VkImageViewType viewType, |
| VkFormat format, |
| VkComponentMapping components, |
| VkImageSubresourceRange subresourceRange) |
| { |
| const VkImageViewCreateInfo pCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| flags, // VkImageViewCreateFlags flags |
| image, // VkImage image |
| viewType, // VkImageViewType viewType |
| format, // VkFormat format |
| components, // VkComponentMapping components |
| subresourceRange, // VkImageSubresourceRange subresourceRange |
| }; |
| |
| return createImageView(vk, device, &pCreateInfo); |
| } |
| |
| vector<SharedPtrVkImageView> createImageViews (const DeviceInterface& vkd, |
| VkDevice device, |
| vector<SharedPtrVkImage> images, |
| VkFormat format, |
| VkImageAspectFlags aspect) |
| { |
| vector<SharedPtrVkImageView> imageViews; |
| |
| for (size_t imageViewNdx = 0; imageViewNdx < images.size(); imageViewNdx++) |
| { |
| const VkImageSubresourceRange range = |
| { |
| aspect, // VkImageAspectFlags aspectMask |
| 0u, // uint32_t baseMipLevel |
| 1u, // uint32_t levelCount |
| 0u, // uint32_t baseArrayLayer |
| 1u // uint32_t layerCount |
| }; |
| |
| imageViews.push_back(makeSharedPtr(createImageView(vkd, device, 0u, **images[imageViewNdx], VK_IMAGE_VIEW_TYPE_2D, format, makeComponentMappingRGBA(), range))); |
| } |
| |
| return imageViews; |
| } |
| |
| Move<VkBuffer> createBuffer (const DeviceInterface& vkd, |
| VkDevice device, |
| VkFormat format, |
| deUint32 width, |
| deUint32 height) |
| { |
| const VkBufferUsageFlags bufferUsage (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); |
| const VkDeviceSize pixelSize = mapVkFormat(format).getPixelSize(); |
| const VkBufferCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkBufferCreateFlags flags |
| width * height * pixelSize, // VkDeviceSize size |
| bufferUsage, // VkBufferUsageFlags usage |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode |
| 0u, // uint32_t queueFamilyIndexCount |
| DE_NULL // const uint32_t* pQueueFamilyIndices |
| }; |
| |
| return createBuffer(vkd, device, &createInfo); |
| } |
| |
| vector<SharedPtrVkDescriptorLayout> createDescriptorSetLayouts (const DeviceInterface& vkd, |
| VkDevice device, |
| vector<SharedPtrVkSampler>& samplers) |
| { |
| vector<SharedPtrVkDescriptorLayout> layouts; |
| |
| for (size_t layoutNdx = 0; layoutNdx < samplers.size(); layoutNdx++) |
| { |
| const VkDescriptorSetLayoutBinding bindings = |
| { |
| 0u, // uint32_t binding |
| VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, // VkDescriptorType descriptorType |
| 1u, // uint32_t descriptorCount |
| VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags stageFlags |
| &**samplers[layoutNdx] // const VkSampler* pImmutableSamplers |
| }; |
| |
| const VkDescriptorSetLayoutCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkDescriptorSetLayoutCreateFlags flags |
| 1u, // uint32_t bindingCount |
| &bindings // const VkDescriptorSetLayoutBinding* pBindings |
| }; |
| |
| layouts.push_back(makeSharedPtr(createDescriptorSetLayout(vkd, device, &createInfo))); |
| } |
| |
| return layouts; |
| } |
| |
| vector<SharedPtrVkDescriptorPool> createDescriptorPools (const DeviceInterface& vkd, |
| VkDevice device, |
| vector<SharedPtrVkDescriptorLayout>& layouts, |
| VkDescriptorType type) |
| { |
| vector<SharedPtrVkDescriptorPool> descriptorPools; |
| |
| for (size_t poolNdx = 0; poolNdx < layouts.size(); poolNdx++) |
| { |
| const VkDescriptorPoolSize size = |
| { |
| type, // VkDescriptorType type |
| 1u // uint32_t descriptorCount |
| }; |
| |
| const VkDescriptorPoolCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, // VkDescriptorPoolCreateFlags flags |
| 1u, // uint32_t maxSets |
| 1u, // uint32_t poolSizeCount |
| &size // const VkDescriptorPoolSize* pPoolSizes |
| }; |
| |
| descriptorPools.push_back(makeSharedPtr(createDescriptorPool(vkd, device, &createInfo))); |
| } |
| |
| return descriptorPools; |
| } |
| |
| Move<VkDescriptorSet> makeDescriptorSet (const DeviceInterface& vk, |
| const VkDevice device, |
| const VkDescriptorPool descriptorPool, |
| const VkDescriptorSetLayout setLayout) |
| { |
| const VkDescriptorSetAllocateInfo info = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| descriptorPool, // VkDescriptorPool descriptorPool; |
| 1u, // deUint32 descriptorSetCount; |
| &setLayout // const VkDescriptorSetLayout* pSetLayouts; |
| }; |
| return allocateDescriptorSet(vk, device, &info); |
| } |
| |
| struct ExternalTestConfig |
| { |
| ExternalTestConfig (VkFormat format_, |
| UVec2 imageSize_, |
| vector<RenderPass> renderPasses_, |
| RenderPassType renderPassType_, |
| deUint32 blurKernel_ = 4) |
| : format (format_) |
| , imageSize (imageSize_) |
| , renderPasses (renderPasses_) |
| , renderPassType (renderPassType_) |
| , blurKernel (blurKernel_) |
| { |
| } |
| |
| VkFormat format; |
| UVec2 imageSize; |
| vector<RenderPass> renderPasses; |
| RenderPassType renderPassType; |
| deUint32 blurKernel; |
| }; |
| |
| class ExternalDependencyTestInstance : public TestInstance |
| { |
| public: |
| ExternalDependencyTestInstance (Context& context, ExternalTestConfig testConfig); |
| ~ExternalDependencyTestInstance (void); |
| |
| vector<SharedPtrVkImage> createAndAllocateImages (const DeviceInterface& vk, |
| VkDevice device, |
| Allocator& allocator, |
| vector<de::SharedPtr<Allocation> >& imageMemories, |
| deUint32 universalQueueFamilyIndex, |
| VkFormat format, |
| deUint32 width, |
| deUint32 height, |
| vector<RenderPass> renderPasses); |
| |
| vector<SharedPtrVkSampler> createSamplers (const DeviceInterface& vkd, |
| const VkDevice device, |
| vector<RenderPass>& renderPasses); |
| |
| vector<SharedPtrVkRenderPass> createRenderPasses (const DeviceInterface& vkd, |
| VkDevice device, |
| vector<RenderPass> renderPassInfos, |
| const RenderPassType renderPassType); |
| |
| vector<SharedPtrVkFramebuffer> createFramebuffers (const DeviceInterface& vkd, |
| VkDevice device, |
| vector<SharedPtrVkRenderPass>& renderPasses, |
| vector<SharedPtrVkImageView>& dstImageViews, |
| deUint32 width, |
| deUint32 height); |
| |
| vector<SharedPtrVkPipelineLayout> createRenderPipelineLayouts (const DeviceInterface& vkd, |
| VkDevice device, |
| vector<SharedPtrVkRenderPass>& renderPasses, |
| vector<SharedPtrVkDescriptorLayout>& descriptorSetLayouts); |
| |
| vector<SharedPtrVkPipeline> createRenderPipelines (const DeviceInterface& vkd, |
| VkDevice device, |
| vector<SharedPtrVkRenderPass>& renderPasses, |
| vector<SharedPtrVkPipelineLayout>& pipelineLayouts, |
| const BinaryCollection& binaryCollection, |
| deUint32 width, |
| deUint32 height); |
| |
| vector<SharedPtrVkDescriptorSet> createDescriptorSets (const DeviceInterface& vkd, |
| VkDevice device, |
| vector<SharedPtrVkDescriptorPool>& pools, |
| vector<SharedPtrVkDescriptorLayout>& layouts, |
| vector<SharedPtrVkImageView>& imageViews, |
| vector<SharedPtrVkSampler>& samplers); |
| |
| tcu::TestStatus iterate (void); |
| |
| template<typename RenderpassSubpass> |
| tcu::TestStatus iterateInternal (void); |
| |
| private: |
| const bool m_extensionSupported; |
| const RenderPassType m_renderPassType; |
| |
| const deUint32 m_width; |
| const deUint32 m_height; |
| const deUint32 m_blurKernel; |
| const VkFormat m_format; |
| |
| vector<de::SharedPtr<Allocation> > m_imageMemories; |
| vector<SharedPtrVkImage> m_images; |
| vector<SharedPtrVkImageView> m_imageViews; |
| vector<SharedPtrVkSampler> m_samplers; |
| |
| const Unique<VkBuffer> m_dstBuffer; |
| const de::UniquePtr<Allocation> m_dstBufferMemory; |
| |
| vector<SharedPtrVkRenderPass> m_renderPasses; |
| vector<SharedPtrVkFramebuffer> m_framebuffers; |
| |
| vector<SharedPtrVkDescriptorLayout> m_subpassDescriptorSetLayouts; |
| vector<SharedPtrVkDescriptorPool> m_subpassDescriptorPools; |
| vector<SharedPtrVkDescriptorSet> m_subpassDescriptorSets; |
| |
| vector<SharedPtrVkPipelineLayout> m_renderPipelineLayouts; |
| vector<SharedPtrVkPipeline> m_renderPipelines; |
| |
| const Unique<VkCommandPool> m_commandPool; |
| tcu::ResultCollector m_resultCollector; |
| }; |
| |
| ExternalDependencyTestInstance::ExternalDependencyTestInstance (Context& context, ExternalTestConfig testConfig) |
| : TestInstance (context) |
| , m_extensionSupported ((testConfig.renderPassType == RENDERPASS_TYPE_RENDERPASS2) && context.requireDeviceExtension("VK_KHR_create_renderpass2")) |
| , m_renderPassType (testConfig.renderPassType) |
| , m_width (testConfig.imageSize.x()) |
| , m_height (testConfig.imageSize.y()) |
| , m_blurKernel (testConfig.blurKernel) |
| , m_format (testConfig.format) |
| , m_images (createAndAllocateImages(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), m_imageMemories, context.getUniversalQueueFamilyIndex(), m_format, m_width, m_height, testConfig.renderPasses)) |
| , m_imageViews (createImageViews(context.getDeviceInterface(), context.getDevice(), m_images, m_format, VK_IMAGE_ASPECT_COLOR_BIT)) |
| , m_samplers (createSamplers(context.getDeviceInterface(), context.getDevice(), testConfig.renderPasses)) |
| , m_dstBuffer (createBuffer(context.getDeviceInterface(), context.getDevice(), m_format, m_width, m_height)) |
| , m_dstBufferMemory (createBufferMemory(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), *m_dstBuffer)) |
| , m_renderPasses (createRenderPasses(context.getDeviceInterface(), context.getDevice(), testConfig.renderPasses, testConfig.renderPassType)) |
| , m_framebuffers (createFramebuffers(context.getDeviceInterface(), context.getDevice(), m_renderPasses, m_imageViews, m_width, m_height)) |
| , m_subpassDescriptorSetLayouts (createDescriptorSetLayouts(context.getDeviceInterface(), context.getDevice(), m_samplers)) |
| , m_subpassDescriptorPools (createDescriptorPools(context.getDeviceInterface(), context.getDevice(), m_subpassDescriptorSetLayouts, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)) |
| , m_subpassDescriptorSets (createDescriptorSets(context.getDeviceInterface(), context.getDevice(), m_subpassDescriptorPools, m_subpassDescriptorSetLayouts, m_imageViews, m_samplers)) |
| , m_renderPipelineLayouts (createRenderPipelineLayouts(context.getDeviceInterface(), context.getDevice(), m_renderPasses, m_subpassDescriptorSetLayouts)) |
| , m_renderPipelines (createRenderPipelines(context.getDeviceInterface(), context.getDevice(), m_renderPasses, m_renderPipelineLayouts, context.getBinaryCollection(), m_width, m_height)) |
| , m_commandPool (createCommandPool(context.getDeviceInterface(), context.getDevice(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, context.getUniversalQueueFamilyIndex())) |
| { |
| } |
| |
| ExternalDependencyTestInstance::~ExternalDependencyTestInstance (void) |
| { |
| } |
| |
| vector<SharedPtrVkImage> ExternalDependencyTestInstance::createAndAllocateImages (const DeviceInterface& vk, |
| VkDevice device, |
| Allocator& allocator, |
| vector<de::SharedPtr<Allocation> >& imageMemories, |
| deUint32 universalQueueFamilyIndex, |
| VkFormat format, |
| deUint32 width, |
| deUint32 height, |
| vector<RenderPass> renderPasses) |
| { |
| vector<SharedPtrVkImage> images; |
| |
| for (size_t imageNdx = 0; imageNdx < renderPasses.size(); imageNdx++) |
| { |
| const VkExtent3D imageExtent = |
| { |
| width, // uint32_t width |
| height, // uint32_t height |
| 1u // uint32_t depth |
| }; |
| |
| const VkImageCreateInfo imageCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkImageCreateFlags flags |
| VK_IMAGE_TYPE_2D, // VkImageType imageType |
| format, // VkFormat format |
| imageExtent, // VkExtent3D extent |
| 1u, // uint32_t mipLevels |
| 1u, // uint32_t arrayLayers |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling |
| VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
| | VK_IMAGE_USAGE_SAMPLED_BIT |
| | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode |
| 1u, // uint32_t queueFamilyIndexCount |
| &universalQueueFamilyIndex, // const uint32_t* pQueueFamilyIndices |
| VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout |
| }; |
| |
| images.push_back(makeSharedPtr(vk::createImage(vk, device, &imageCreateInfo, DE_NULL))); |
| imageMemories.push_back((de::SharedPtr<Allocation>)allocator.allocate(getImageMemoryRequirements(vk, device, **images[imageNdx]), MemoryRequirement::Any).release()); |
| VK_CHECK(vk.bindImageMemory(device, **images[imageNdx], imageMemories[imageNdx]->getMemory(), imageMemories[imageNdx]->getOffset())); |
| } |
| |
| return images; |
| } |
| |
| vector<SharedPtrVkSampler> ExternalDependencyTestInstance::createSamplers (const DeviceInterface& vkd, |
| const VkDevice device, |
| vector<RenderPass>& renderPasses) |
| { |
| vector<SharedPtrVkSampler> samplers; |
| |
| for (size_t samplerNdx = 0; samplerNdx < renderPasses.size() - 1; samplerNdx++) |
| { |
| const VkSamplerCreateInfo samplerInfo = |
| { |
| VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkSamplerCreateFlags flags |
| VK_FILTER_NEAREST, // VkFilter magFilter |
| VK_FILTER_NEAREST, // VkFilter minFilter |
| VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeU |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeV |
| VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW |
| 0.0f, // float mipLodBias |
| VK_FALSE, // VkBool32 anisotropyEnable |
| 1.0f, // float maxAnisotropy |
| VK_FALSE, // VkBool32 compareEnable |
| VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp |
| 0.0f, // float minLod |
| 0.0f, // float maxLod |
| VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor |
| VK_FALSE, // VkBool32 unnormalizedCoordinates |
| }; |
| |
| samplers.push_back(makeSharedPtr(createSampler(vkd, device, &samplerInfo))); |
| } |
| |
| return samplers; |
| } |
| |
| vector<SharedPtrVkRenderPass> ExternalDependencyTestInstance::createRenderPasses (const DeviceInterface& vkd, |
| VkDevice device, |
| vector<RenderPass> renderPassInfos, |
| const RenderPassType renderPassType) |
| { |
| vector<SharedPtrVkRenderPass> renderPasses; |
| |
| for (size_t renderPassNdx = 0; renderPassNdx < renderPassInfos.size(); renderPassNdx++) |
| { |
| renderPasses.push_back(makeSharedPtr(createRenderPass(vkd, device, renderPassInfos[renderPassNdx], renderPassType))); |
| } |
| |
| return renderPasses; |
| } |
| |
| vector<SharedPtrVkFramebuffer> ExternalDependencyTestInstance::createFramebuffers (const DeviceInterface& vkd, |
| VkDevice device, |
| vector<SharedPtrVkRenderPass>& renderPasses, |
| vector<SharedPtrVkImageView>& dstImageViews, |
| deUint32 width, |
| deUint32 height) |
| { |
| vector<SharedPtrVkFramebuffer> framebuffers; |
| |
| for (size_t renderPassNdx = 0; renderPassNdx < renderPasses.size(); renderPassNdx++) |
| { |
| VkRenderPass renderPass (**renderPasses[renderPassNdx]); |
| |
| const VkFramebufferCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkFramebufferCreateFlags flags |
| renderPass, // VkRenderPass renderPass |
| 1u, // uint32_t attachmentCount |
| &**dstImageViews[renderPassNdx], // const VkImageView* pAttachments |
| width, // uint32_t width |
| height, // uint32_t height |
| 1u // uint32_t layers |
| }; |
| |
| framebuffers.push_back(makeSharedPtr(createFramebuffer(vkd, device, &createInfo))); |
| } |
| |
| return framebuffers; |
| } |
| |
| vector<SharedPtrVkDescriptorSet> ExternalDependencyTestInstance::createDescriptorSets (const DeviceInterface& vkd, |
| VkDevice device, |
| vector<SharedPtrVkDescriptorPool>& pools, |
| vector<SharedPtrVkDescriptorLayout>& layouts, |
| vector<SharedPtrVkImageView>& imageViews, |
| vector<SharedPtrVkSampler>& samplers) |
| { |
| vector<SharedPtrVkDescriptorSet> descriptorSets; |
| |
| for (size_t setNdx = 0; setNdx < layouts.size(); setNdx++) |
| { |
| const VkDescriptorSetAllocateInfo allocateInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| **pools[setNdx], // VkDescriptorPool descriptorPool |
| 1u, // uint32_t descriptorSetCount |
| &**layouts[setNdx] // const VkDescriptorSetLayout* pSetLayouts |
| }; |
| |
| descriptorSets.push_back(makeSharedPtr(allocateDescriptorSet(vkd, device, &allocateInfo))); |
| |
| { |
| const VkDescriptorImageInfo imageInfo = |
| { |
| **samplers[setNdx], // VkSampler sampler |
| **imageViews[setNdx], // VkImageView imageView |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout imageLayout |
| }; |
| |
| const VkWriteDescriptorSet write = |
| { |
| VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| **descriptorSets[setNdx], // VkDescriptorSet dstSet |
| 0u, // uint32_t dstBinding |
| 0u, // uint32_t dstArrayElement |
| 1u, // uint32_t descriptorCount |
| VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, // VkDescriptorType descriptorType |
| &imageInfo, // const VkDescriptorImageInfo* pImageInfo |
| DE_NULL, // const VkDescriptorBufferInfo* pBufferInfo |
| DE_NULL // const VkBufferView* pTexelBufferView |
| }; |
| |
| vkd.updateDescriptorSets(device, 1u, &write, 0u, DE_NULL); |
| } |
| } |
| |
| return descriptorSets; |
| } |
| |
| vector<SharedPtrVkPipelineLayout> ExternalDependencyTestInstance::createRenderPipelineLayouts (const DeviceInterface& vkd, |
| VkDevice device, |
| vector<SharedPtrVkRenderPass>& renderPasses, |
| vector<SharedPtrVkDescriptorLayout>& descriptorSetLayouts) |
| { |
| vector<SharedPtrVkPipelineLayout> pipelineLayouts; |
| |
| for (size_t renderPassNdx = 0; renderPassNdx < renderPasses.size(); renderPassNdx++) |
| { |
| const VkPipelineLayoutCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (vk::VkPipelineLayoutCreateFlags)0, // VkPipelineLayoutCreateFlags flags |
| renderPassNdx > 0 ? 1u : 0u, // deUint32 setLayoutCount |
| renderPassNdx > 0 ? &**descriptorSetLayouts[renderPassNdx - 1] : DE_NULL, // const VkDescriptorSetLayout* pSetLayouts |
| 0u, // deUint32 pushConstantRangeCount |
| DE_NULL // const VkPushConstantRange* pPushConstantRanges |
| }; |
| |
| pipelineLayouts.push_back(makeSharedPtr(createPipelineLayout(vkd, device, &createInfo))); |
| } |
| |
| return pipelineLayouts; |
| } |
| |
| vector<SharedPtrVkPipeline> ExternalDependencyTestInstance::createRenderPipelines (const DeviceInterface& vkd, |
| VkDevice device, |
| vector<SharedPtrVkRenderPass>& renderPasses, |
| vector<SharedPtrVkPipelineLayout>& pipelineLayouts, |
| const BinaryCollection& binaryCollection, |
| deUint32 width, |
| deUint32 height) |
| { |
| vector<SharedPtrVkPipeline> pipelines; |
| |
| for (size_t renderPassNdx = 0; renderPassNdx < renderPasses.size(); renderPassNdx++) |
| { |
| const Unique<VkShaderModule> vertexShaderModule (createShaderModule(vkd, device, binaryCollection.get("quad-vert-" + de::toString(renderPassNdx)), 0u)); |
| const Unique<VkShaderModule> fragmentShaderModule (createShaderModule(vkd, device, binaryCollection.get("quad-frag-" + de::toString(renderPassNdx)), 0u)); |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputState = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkPipelineVertexInputStateCreateFlags)0u, // VkPipelineVertexInputStateCreateFlags flags |
| 0u, // uint32_t vertexBindingDescriptionCount |
| DE_NULL, // const VkVertexInputBindingDescription* pVertexBindingDescriptions |
| 0u, // uint32_t vertexAttributeDescriptionCount |
| DE_NULL // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions |
| }; |
| |
| const std::vector<VkViewport> viewports (1, makeViewport(tcu::UVec2(width, height))); |
| const std::vector<VkRect2D> scissors (1, makeRect2D(tcu::UVec2(width, height))); |
| const VkRenderPass renderPass (**renderPasses[renderPassNdx]); |
| const VkPipelineLayout layout (**pipelineLayouts[renderPassNdx]); |
| |
| pipelines.push_back(makeSharedPtr(makeGraphicsPipeline(vkd, // const DeviceInterface& vk |
| device, // const VkDevice device |
| layout, // const VkPipelineLayout pipelineLayout |
| *vertexShaderModule, // const VkShaderModule vertexShaderModule |
| DE_NULL, // const VkShaderModule tessellationControlShaderModule |
| DE_NULL, // const VkShaderModule tessellationEvalShaderModule |
| DE_NULL, // const VkShaderModule geometryShaderModule |
| *fragmentShaderModule, // const VkShaderModule fragmentShaderModule |
| renderPass, // const VkRenderPass renderPass |
| viewports, // const std::vector<VkViewport>& viewports |
| scissors, // const std::vector<VkRect2D>& scissors |
| VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology |
| 0u, // const deUint32 subpass |
| 0u, // const deUint32 patchControlPoints |
| &vertexInputState))); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo |
| } |
| |
| return pipelines; |
| } |
| |
| tcu::TestStatus ExternalDependencyTestInstance::iterate (void) |
| { |
| switch (m_renderPassType) |
| { |
| case RENDERPASS_TYPE_LEGACY: |
| return iterateInternal<RenderpassSubpass1>(); |
| case RENDERPASS_TYPE_RENDERPASS2: |
| return iterateInternal<RenderpassSubpass2>(); |
| default: |
| TCU_THROW(InternalError, "Impossible"); |
| } |
| } |
| |
| template<typename RenderpassSubpass> |
| tcu::TestStatus ExternalDependencyTestInstance::iterateInternal (void) |
| { |
| const DeviceInterface& vkd (m_context.getDeviceInterface()); |
| const Unique<VkCommandBuffer> commandBuffer (allocateCommandBuffer(vkd, m_context.getDevice(), *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| const typename RenderpassSubpass::SubpassBeginInfo subpassBeginInfo (DE_NULL, VK_SUBPASS_CONTENTS_INLINE); |
| const typename RenderpassSubpass::SubpassEndInfo subpassEndInfo (DE_NULL); |
| |
| beginCommandBuffer(vkd, *commandBuffer); |
| |
| for (size_t renderPassNdx = 0; renderPassNdx < m_renderPasses.size(); renderPassNdx++) |
| { |
| // Begin render pass |
| { |
| VkRect2D renderArea = |
| { |
| { 0u, 0u }, // VkOffset2D offset |
| { m_width, m_height } // VkExtent2D extent |
| }; |
| |
| const VkRenderPassBeginInfo beginInfo = |
| { |
| VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| **m_renderPasses[renderPassNdx], // VkRenderPass renderPass |
| **m_framebuffers[renderPassNdx], // VkFramebuffer framebuffer |
| renderArea, // VkRect2D renderArea |
| 0u, // uint32_t clearValueCount |
| DE_NULL // const VkClearValue* pClearValues |
| }; |
| |
| RenderpassSubpass::cmdBeginRenderPass(vkd, *commandBuffer, &beginInfo, &subpassBeginInfo); |
| } |
| |
| vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **m_renderPipelines[renderPassNdx]); |
| |
| // Use results from the previous pass as input texture |
| if (renderPassNdx > 0) |
| vkd.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **m_renderPipelineLayouts[renderPassNdx], 0, 1, &**m_subpassDescriptorSets[renderPassNdx - 1], 0, DE_NULL); |
| |
| vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u); |
| |
| RenderpassSubpass::cmdEndRenderPass(vkd, *commandBuffer, &subpassEndInfo); |
| } |
| |
| // Memory barrier between rendering and copy |
| { |
| VkImageSubresourceRange imageSubresourceRange = |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask |
| 0u, // uint32_t baseMipLevel |
| 1u, // uint32_t levelCount |
| 0u, // uint32_t baseArrayLayer |
| 1u // uint32_t layerCount |
| }; |
| |
| const VkImageMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask |
| VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask |
| VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // VkImageLayout oldLayout |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex |
| **m_images[m_renderPasses.size() - 1], // VkImage image |
| imageSubresourceRange // VkImageSubresourceRange subresourceRange |
| }; |
| |
| vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier); |
| } |
| |
| // Copy image memory to buffer |
| { |
| const VkImageSubresourceLayers imageSubresourceLayers = |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask |
| 0u, // deUint32 mipLevel |
| 0u, // deUint32 baseArrayLayer |
| 1u // deUint32 layerCount |
| }; |
| |
| const VkBufferImageCopy region = |
| { |
| 0u, // VkDeviceSize bufferOffset |
| 0u, // uint32_t bufferRowLength |
| 0u, // uint32_t bufferImageHeight |
| imageSubresourceLayers, // VkImageSubresourceLayers imageSubresource |
| { 0u, 0u, 0u }, // VkOffset3D imageOffset |
| { m_width, m_height, 1u } // VkExtent3D imageExtent |
| }; |
| |
| vkd.cmdCopyImageToBuffer(*commandBuffer, **m_images[m_renderPasses.size() - 1], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *m_dstBuffer, 1u, ®ion); |
| } |
| |
| // Memory barrier between copy and host access |
| { |
| const VkBufferMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask |
| VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex |
| *m_dstBuffer, // VkBuffer buffer |
| 0u, // VkDeviceSize offset |
| VK_WHOLE_SIZE // VkDeviceSize size |
| }; |
| |
| vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &barrier, 0u, DE_NULL); |
| } |
| |
| endCommandBuffer(vkd, *commandBuffer); |
| submitCommandsAndWait(vkd, m_context.getDevice(), m_context.getUniversalQueue(), *commandBuffer); |
| invalidateMappedMemoryRange(vkd, m_context.getDevice(), m_dstBufferMemory->getMemory(), m_dstBufferMemory->getOffset(), VK_WHOLE_SIZE); |
| |
| { |
| const tcu::TextureFormat format (mapVkFormat(m_format)); |
| const void* const ptr (m_dstBufferMemory->getHostPtr()); |
| const tcu::ConstPixelBufferAccess access (format, m_width, m_height, 1, ptr); |
| tcu::TextureLevel reference (format, m_width, m_height); |
| tcu::TextureLevel textureA (format, m_width, m_height); |
| tcu::TextureLevel textureB (format, m_width, m_height); |
| |
| for (deUint32 renderPassNdx = 0; renderPassNdx < m_renderPasses.size(); renderPassNdx++) |
| { |
| // First pass renders four quads of different color, which will be blurred in the following passes |
| if (renderPassNdx == 0) |
| { |
| for (deUint32 y = 0; y < m_height; y++) |
| for (deUint32 x = 0; x < m_width; x++) |
| { |
| if (x <= (m_width - 1) / 2 && y <= (m_height - 1) / 2) |
| textureA.getAccess().setPixel(Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y); |
| else if (x > (m_width - 1) / 2 && y <= (m_height - 1) / 2) |
| textureA.getAccess().setPixel(Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y); |
| else if (x <= (m_width - 1) / 2 && y > (m_height - 1) / 2) |
| textureA.getAccess().setPixel(Vec4(0.0f, 0.0f, 1.0f, 1.0f), x, y); |
| else |
| textureA.getAccess().setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), x, y); |
| } |
| } |
| // Blur previous pass |
| else |
| { |
| for (deUint32 y = 0; y < m_height; y++) |
| for (deUint32 x = 0; x < m_width; x++) |
| { |
| Vec4 blurColor (Vec4(0.0)); |
| |
| for (deUint32 sampleNdx = 0; sampleNdx < (m_blurKernel + 1); sampleNdx++) |
| { |
| if (renderPassNdx % 2 == 0) |
| { |
| // Do a horizontal blur |
| blurColor += 0.12f * textureB.getAccess().getPixel(deClamp32((deInt32)x - (m_blurKernel / 2) + sampleNdx, 0u, m_width - 1u), y); |
| } |
| else |
| { |
| // Do a vertical blur |
| blurColor += 0.12f * textureA.getAccess().getPixel(x, deClamp32((deInt32)y - (m_blurKernel / 2) + sampleNdx, 0u, m_height - 1u)); |
| } |
| } |
| |
| renderPassNdx % 2 == 0 ? textureA.getAccess().setPixel(blurColor, x, y) : textureB.getAccess().setPixel(blurColor, x, y); |
| } |
| } |
| } |
| |
| reference = m_renderPasses.size() % 2 == 0 ? textureB : textureA; |
| |
| { |
| // Allow error of 4 times the minimum presentable difference |
| const Vec4 threshold (4.0f * 1.0f / ((UVec4(1u) << tcu::getTextureFormatMantissaBitDepth(format).cast<deUint32>()) - 1u).cast<float>()); |
| |
| if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "", "", reference.getAccess(), access, threshold, tcu::COMPARE_LOG_ON_ERROR)) |
| m_resultCollector.fail("Compare failed."); |
| } |
| } |
| |
| return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage()); |
| } |
| |
| struct SubpassTestConfig |
| { |
| SubpassTestConfig (VkFormat format_, |
| UVec2 imageSize_, |
| RenderPass renderPass_, |
| RenderPassType renderPassType_) |
| : format (format_) |
| , imageSize (imageSize_) |
| , renderPass (renderPass_) |
| , renderPassType (renderPassType_) |
| { |
| } |
| |
| VkFormat format; |
| UVec2 imageSize; |
| RenderPass renderPass; |
| RenderPassType renderPassType; |
| }; |
| |
| class SubpassDependencyTestInstance : public TestInstance |
| { |
| public: |
| SubpassDependencyTestInstance (Context& context, |
| SubpassTestConfig testConfig); |
| |
| ~SubpassDependencyTestInstance (void); |
| |
| vector<SharedPtrVkImage> createAndAllocateImages (const DeviceInterface& vk, |
| VkDevice device, |
| Allocator& allocator, |
| vector<de::SharedPtr<Allocation> >& imageMemories, |
| deUint32 universalQueueFamilyIndex, |
| RenderPass renderPassInfo, |
| VkFormat format, |
| deUint32 width, |
| deUint32 height); |
| |
| vector<SharedPtrVkPipelineLayout> createRenderPipelineLayouts (const DeviceInterface& vkd, |
| VkDevice device, |
| RenderPass renderPassInfo, |
| vector<SharedPtrVkDescriptorLayout> descriptorSetLayouts); |
| |
| vector<SharedPtrVkPipeline> createRenderPipelines (const DeviceInterface& vkd, |
| VkDevice device, |
| RenderPass renderPassInfo, |
| VkRenderPass renderPass, |
| vector<SharedPtrVkPipelineLayout>& pipelineLayouts, |
| const BinaryCollection& binaryCollection, |
| VkFormat format, |
| deUint32 width, |
| deUint32 height); |
| |
| Move<VkFramebuffer> createFramebuffer (const DeviceInterface& vkd, |
| VkDevice device, |
| RenderPass renderPassInfo, |
| VkRenderPass renderPass, |
| vector<SharedPtrVkImageView>& dstImageViews, |
| deUint32 width, |
| deUint32 height); |
| |
| vector<SharedPtrVkDescriptorLayout> createDescriptorSetLayouts (const DeviceInterface& vkd, |
| VkDevice device, |
| RenderPass renderPassInfo); |
| |
| vector<SharedPtrVkDescriptorSet> createDescriptorSets (const DeviceInterface& vkd, |
| VkDevice device, |
| VkFormat format, |
| vector<SharedPtrVkDescriptorPool>& pools, |
| vector<SharedPtrVkDescriptorLayout>& layouts, |
| vector<SharedPtrVkImageView>& imageViews); |
| |
| tcu::TextureLevel getRepresentableDepthChannel (const ConstPixelBufferAccess& access); |
| |
| bool verifyDepth (const ConstPixelBufferAccess& reference, |
| const ConstPixelBufferAccess& result, |
| const float threshold); |
| |
| bool verifyStencil (const ConstPixelBufferAccess& reference, |
| const ConstPixelBufferAccess& result); |
| |
| tcu::TestStatus iterate (void); |
| |
| template<typename RenderpassSubpass> |
| tcu::TestStatus iterateInternal (void); |
| |
| private: |
| const bool m_extensionSupported; |
| const RenderPass m_renderPassInfo; |
| const RenderPassType m_renderPassType; |
| |
| const deUint32 m_width; |
| const deUint32 m_height; |
| const VkFormat m_format; |
| |
| vector<de::SharedPtr<Allocation> > m_imageMemories; |
| vector<SharedPtrVkImage> m_images; |
| vector<SharedPtrVkImageView> m_imageViews; |
| |
| const Unique<VkBuffer> m_primaryBuffer; |
| const Unique<VkBuffer> m_secondaryBuffer; |
| const de::UniquePtr<Allocation> m_primaryBufferMemory; |
| const de::UniquePtr<Allocation> m_secondaryBufferMemory; |
| |
| const Unique<VkRenderPass> m_renderPass; |
| const Unique<VkFramebuffer> m_framebuffer; |
| |
| vector<SharedPtrVkDescriptorLayout> m_subpassDescriptorSetLayouts; |
| vector<SharedPtrVkDescriptorPool> m_subpassDescriptorPools; |
| vector<SharedPtrVkDescriptorSet> m_subpassDescriptorSets; |
| |
| vector<SharedPtrVkPipelineLayout> m_renderPipelineLayouts; |
| vector<SharedPtrVkPipeline> m_renderPipelines; |
| |
| const Unique<VkCommandPool> m_commandPool; |
| tcu::ResultCollector m_resultCollector; |
| }; |
| |
| SubpassDependencyTestInstance::SubpassDependencyTestInstance (Context& context, SubpassTestConfig testConfig) |
| : TestInstance (context) |
| , m_extensionSupported ((testConfig.renderPassType == RENDERPASS_TYPE_RENDERPASS2) && context.requireDeviceExtension("VK_KHR_create_renderpass2")) |
| , m_renderPassInfo (testConfig.renderPass) |
| , m_renderPassType (testConfig.renderPassType) |
| , m_width (testConfig.imageSize.x()) |
| , m_height (testConfig.imageSize.y()) |
| , m_format (testConfig.format) |
| , m_images (createAndAllocateImages(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), m_imageMemories, context.getUniversalQueueFamilyIndex(), m_renderPassInfo, m_format, m_width, m_height)) |
| , m_imageViews (createImageViews(context.getDeviceInterface(), context.getDevice(), m_images, m_format, isDepthStencilFormat(m_format) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT)) |
| , m_primaryBuffer (createBuffer(context.getDeviceInterface(), context.getDevice(), m_format, m_width, m_height)) |
| , m_secondaryBuffer (createBuffer(context.getDeviceInterface(), context.getDevice(), m_format, m_width, m_height)) |
| , m_primaryBufferMemory (createBufferMemory(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), *m_primaryBuffer)) |
| , m_secondaryBufferMemory (createBufferMemory(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), *m_secondaryBuffer)) |
| , m_renderPass (createRenderPass(context.getDeviceInterface(), context.getDevice(), m_renderPassInfo, testConfig.renderPassType)) |
| , m_framebuffer (createFramebuffer(context.getDeviceInterface(), context.getDevice(), m_renderPassInfo, *m_renderPass, m_imageViews, m_width, m_height)) |
| , m_subpassDescriptorSetLayouts (createDescriptorSetLayouts(context.getDeviceInterface(), context.getDevice(), m_renderPassInfo)) |
| , m_subpassDescriptorPools (createDescriptorPools(context.getDeviceInterface(), context.getDevice(), m_subpassDescriptorSetLayouts, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)) |
| , m_subpassDescriptorSets (createDescriptorSets(context.getDeviceInterface(), context.getDevice(), m_format, m_subpassDescriptorPools, m_subpassDescriptorSetLayouts, m_imageViews)) |
| , m_renderPipelineLayouts (createRenderPipelineLayouts(context.getDeviceInterface(), context.getDevice(), m_renderPassInfo, m_subpassDescriptorSetLayouts)) |
| , m_renderPipelines (createRenderPipelines(context.getDeviceInterface(), context.getDevice(), m_renderPassInfo, *m_renderPass, m_renderPipelineLayouts, context.getBinaryCollection(), m_format, m_width, m_height)) |
| , m_commandPool (createCommandPool(context.getDeviceInterface(), context.getDevice(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, context.getUniversalQueueFamilyIndex())) |
| { |
| } |
| |
| SubpassDependencyTestInstance::~SubpassDependencyTestInstance (void) |
| { |
| } |
| |
| vector<SharedPtrVkImage> SubpassDependencyTestInstance::createAndAllocateImages (const DeviceInterface& vk, |
| VkDevice device, |
| Allocator& allocator, |
| vector<de::SharedPtr<Allocation> >& imageMemories, |
| deUint32 universalQueueFamilyIndex, |
| RenderPass renderPassInfo, |
| VkFormat format, |
| deUint32 width, |
| deUint32 height) |
| { |
| // Verify format support |
| { |
| const VkFormatFeatureFlags flags = isDepthStencilFormat(m_format) ? VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT : VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; |
| const VkFormatProperties properties = vk::getPhysicalDeviceFormatProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice(), format); |
| |
| if ((properties.optimalTilingFeatures & flags) != flags) |
| TCU_THROW(NotSupportedError, "Format not supported"); |
| } |
| |
| vector<SharedPtrVkImage> images; |
| |
| for (size_t imageNdx = 0; imageNdx < renderPassInfo.getAttachments().size(); imageNdx++) |
| { |
| const VkExtent3D imageExtent = |
| { |
| width, // uint32_t width |
| height, // uint32_t height |
| 1u // uint32_t depth |
| }; |
| |
| VkImageUsageFlags usage = ((isDepthStencilFormat(format) |
| ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
| : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) |
| | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
| | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT); |
| |
| const VkImageCreateInfo imageCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkImageCreateFlags flags |
| VK_IMAGE_TYPE_2D, // VkImageType imageType |
| format, // VkFormat format |
| imageExtent, // VkExtent3D extent |
| 1u, // uint32_t mipLevels |
| 1u, // uint32_t arrayLayers |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling |
| usage, // VkImageUsageFlags usage |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode |
| 1u, // uint32_t queueFamilyIndexCount |
| &universalQueueFamilyIndex, // const uint32_t* pQueueFamilyIndices |
| VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout |
| }; |
| |
| images.push_back(makeSharedPtr(vk::createImage(vk, device, &imageCreateInfo, DE_NULL))); |
| imageMemories.push_back((de::SharedPtr<Allocation>)allocator.allocate(getImageMemoryRequirements(vk, device, **images[imageNdx]), MemoryRequirement::Any).release()); |
| VK_CHECK(vk.bindImageMemory(device, **images[imageNdx], imageMemories[imageNdx]->getMemory(), imageMemories[imageNdx]->getOffset())); |
| } |
| |
| return images; |
| } |
| |
| vector<SharedPtrVkPipelineLayout> SubpassDependencyTestInstance::createRenderPipelineLayouts (const DeviceInterface& vkd, |
| VkDevice device, |
| RenderPass renderPassInfo, |
| vector<SharedPtrVkDescriptorLayout> descriptorSetLayouts) |
| { |
| vector<SharedPtrVkPipelineLayout> pipelineLayouts; |
| vector<VkDescriptorSetLayout> descriptorSetLayoutHandles; |
| const size_t descriptorSetLayoutCount = descriptorSetLayouts.size(); |
| |
| for (size_t descriptorSetLayoutNdx = 0; descriptorSetLayoutNdx < descriptorSetLayoutCount; descriptorSetLayoutNdx++) |
| descriptorSetLayoutHandles.push_back(**descriptorSetLayouts.at(descriptorSetLayoutNdx)); |
| |
| for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); subpassNdx++) |
| { |
| const VkPipelineLayoutCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (vk::VkPipelineLayoutCreateFlags)0, // VkPipelineLayoutCreateFlags flags |
| (deUint32)descriptorSetLayoutCount, // deUint32 setLayoutCount |
| descriptorSetLayoutHandles.data(), // const VkDescriptorSetLayout* pSetLayouts |
| 0u, // deUint32 pushConstantRangeCount |
| DE_NULL // const VkPushConstantRange* pPushConstantRanges |
| }; |
| |
| pipelineLayouts.push_back(makeSharedPtr(createPipelineLayout(vkd, device, &createInfo))); |
| } |
| |
| return pipelineLayouts; |
| } |
| |
| vector<SharedPtrVkPipeline> SubpassDependencyTestInstance::createRenderPipelines (const DeviceInterface& vkd, |
| VkDevice device, |
| RenderPass renderPassInfo, |
| VkRenderPass renderPass, |
| vector<SharedPtrVkPipelineLayout>& pipelineLayouts, |
| const BinaryCollection& binaryCollection, |
| VkFormat format, |
| deUint32 width, |
| deUint32 height) |
| { |
| vector<SharedPtrVkPipeline> pipelines; |
| |
| for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); subpassNdx++) |
| { |
| const Unique<VkShaderModule> vertexShaderModule (createShaderModule(vkd, device, binaryCollection.get("subpass-vert-" + de::toString(subpassNdx)), 0u)); |
| const Unique<VkShaderModule> fragmentShaderModule (createShaderModule(vkd, device, binaryCollection.get("subpass-frag-" + de::toString(subpassNdx)), 0u)); |
| |
| const VkVertexInputBindingDescription vertexBinding0 = |
| { |
| 0u, // deUint32 binding; |
| sizeof(Vec4), // deUint32 strideInBytes; |
| VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate stepRate; |
| }; |
| |
| VkVertexInputAttributeDescription attr0 = |
| { |
| 0u, // deUint32 location; |
| 0u, // deUint32 binding; |
| VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; |
| 0u // deUint32 offsetInBytes; |
| }; |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputState = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkPipelineVertexInputStateCreateFlags)0u, // VkPipelineVertexInputStateCreateFlags flags |
| 1u, // uint32_t vertexBindingDescriptionCount |
| &vertexBinding0, // const VkVertexInputBindingDescription* pVertexBindingDescriptions |
| 1u, // uint32_t vertexAttributeDescriptionCount |
| &attr0 // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions |
| }; |
| |
| const VkStencilOpState stencilOpState = |
| { |
| VK_STENCIL_OP_KEEP, // stencilFailOp |
| VK_STENCIL_OP_KEEP, // stencilPassOp |
| VK_STENCIL_OP_KEEP, // stencilDepthFailOp |
| VK_COMPARE_OP_ALWAYS, // stencilCompareOp |
| 0x0u, // stencilCompareMask |
| 0x0u, // stencilWriteMask |
| 0u // stencilReference |
| }; |
| |
| const VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkPipelineDepthStencilStateCreateFlags flags |
| VK_TRUE, // VkBool32 depthTestEnable |
| VK_TRUE, // VkBool32 depthWriteEnable |
| VK_COMPARE_OP_LESS_OR_EQUAL, // VkCompareOp depthCompareOp |
| VK_FALSE, // VkBool32 depthBoundsTestEnable |
| VK_TRUE, // VkBool32 stencilTestEnable |
| stencilOpState, // VkStencilOpState front |
| stencilOpState, // VkStencilOpState back |
| 0.0f, // float minDepthBounds |
| 1.0f, // float maxDepthBounds |
| }; |
| |
| const std::vector<VkViewport> viewports (1, makeViewport(tcu::UVec2(width, height))); |
| const std::vector<VkRect2D> scissors (1, makeRect2D(tcu::UVec2(width, height))); |
| const VkPipelineLayout layout (**pipelineLayouts[subpassNdx]); |
| const VkPipelineDepthStencilStateCreateInfo depthStencilCreateInfo (isDepthStencilFormat(format) |
| ? depthStencilStateCreateInfo |
| : VkPipelineDepthStencilStateCreateInfo()); |
| |
| pipelines.push_back(makeSharedPtr(makeGraphicsPipeline(vkd, // const DeviceInterface& vk |
| device, // const VkDevice device |
| layout, // const VkPipelineLayout pipelineLayout |
| *vertexShaderModule, // const VkShaderModule vertexShaderModule |
| DE_NULL, // const VkShaderModule tessellationControlShaderModule |
| DE_NULL, // const VkShaderModule tessellationEvalShaderModule |
| DE_NULL, // const VkShaderModule geometryShaderModule |
| *fragmentShaderModule, // const VkShaderModule fragmentShaderModule |
| renderPass, // const VkRenderPass renderPass |
| viewports, // const std::vector<VkViewport>& viewports |
| scissors, // const std::vector<VkRect2D>& scissors |
| VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology |
| (deUint32)subpassNdx, // const deUint32 subpass |
| 0u, // const deUint32 patchControlPoints |
| &vertexInputState, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo |
| DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo |
| DE_NULL, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo |
| &depthStencilCreateInfo, // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo |
| DE_NULL))); // const VkPipelineDynamicStateCreateInfo* pDynamicState |
| } |
| |
| return pipelines; |
| } |
| |
| Move<VkFramebuffer> SubpassDependencyTestInstance::createFramebuffer (const DeviceInterface& vkd, |
| VkDevice device, |
| RenderPass renderPassInfo, |
| VkRenderPass renderPass, |
| vector<SharedPtrVkImageView>& dstImageViews, |
| deUint32 width, |
| deUint32 height) |
| { |
| const size_t attachmentCount (renderPassInfo.getAttachments().size()); |
| vector<VkImageView> attachmentHandles; |
| |
| for (deUint32 attachmentNdx = 0; attachmentNdx < attachmentCount; attachmentNdx++) |
| attachmentHandles.push_back(**dstImageViews.at(attachmentNdx)); |
| |
| const VkFramebufferCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkFramebufferCreateFlags flags |
| renderPass, // VkRenderPass renderPass |
| (deUint32)attachmentCount, // uint32_t attachmentCount |
| attachmentHandles.data(), // const VkImageView* pAttachments |
| width, // uint32_t width |
| height, // uint32_t height |
| 1u // uint32_t layers |
| }; |
| |
| return vk::createFramebuffer(vkd, device, &createInfo); |
| } |
| |
| vector<SharedPtrVkDescriptorLayout> SubpassDependencyTestInstance::createDescriptorSetLayouts (const DeviceInterface& vkd, |
| VkDevice device, |
| RenderPass renderPassInfo) |
| { |
| vector<SharedPtrVkDescriptorLayout> layouts; |
| |
| size_t attachmentCount = renderPassInfo.getAttachments().size(); |
| |
| for (size_t layoutNdx = 0; layoutNdx < attachmentCount - 1; layoutNdx++) |
| { |
| const VkDescriptorSetLayoutBinding bindings = |
| { |
| 0u, // uint32_t binding |
| VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, // VkDescriptorType descriptorType |
| 1u, // uint32_t descriptorCount |
| VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags stageFlags |
| DE_NULL // const VkSampler* pImmutableSamplers |
| }; |
| |
| const VkDescriptorSetLayoutCreateInfo createInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkDescriptorSetLayoutCreateFlags flags |
| 1u, // uint32_t bindingCount |
| &bindings // const VkDescriptorSetLayoutBinding* pBindings |
| }; |
| |
| layouts.push_back(makeSharedPtr(createDescriptorSetLayout(vkd, device, &createInfo))); |
| } |
| |
| return layouts; |
| } |
| |
| vector<SharedPtrVkDescriptorSet> SubpassDependencyTestInstance::createDescriptorSets (const DeviceInterface& vkd, |
| VkDevice device, |
| VkFormat format, |
| vector<SharedPtrVkDescriptorPool>& pools, |
| vector<SharedPtrVkDescriptorLayout>& layouts, |
| vector<SharedPtrVkImageView>& imageViews) |
| { |
| vector<SharedPtrVkDescriptorSet> descriptorSets; |
| |
| for (size_t setNdx = 0; setNdx < layouts.size(); setNdx++) |
| { |
| const VkDescriptorSetAllocateInfo allocateInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| **pools[setNdx], // VkDescriptorPool descriptorPool |
| 1u, // uint32_t descriptorSetCount |
| &**layouts[setNdx] // const VkDescriptorSetLayout* pSetLayouts |
| }; |
| |
| descriptorSets.push_back(makeSharedPtr(allocateDescriptorSet(vkd, device, &allocateInfo))); |
| |
| { |
| VkImageLayout imageLayout = isDepthStencilFormat(format) |
| ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL |
| : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
| |
| const VkDescriptorImageInfo imageInfo = |
| { |
| DE_NULL, // VkSampler sampler |
| **imageViews[setNdx], // VkImageView imageView |
| imageLayout // VkImageLayout imageLayout |
| }; |
| |
| const VkWriteDescriptorSet write = |
| { |
| VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| **descriptorSets[setNdx], // VkDescriptorSet dstSet |
| 0u, // uint32_t dstBinding |
| 0u, // uint32_t dstArrayElement |
| 1u, // uint32_t descriptorCount |
| VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, // VkDescriptorType descriptorType |
| &imageInfo, // const VkDescriptorImageInfo* pImageInfo |
| DE_NULL, // const VkDescriptorBufferInfo* pBufferInfo |
| DE_NULL // const VkBufferView* pTexelBufferView |
| }; |
| |
| vkd.updateDescriptorSets(device, 1u, &write, 0u, DE_NULL); |
| } |
| } |
| |
| return descriptorSets; |
| } |
| |
| tcu::TextureLevel SubpassDependencyTestInstance::getRepresentableDepthChannel (const ConstPixelBufferAccess& access) |
| { |
| tcu::TextureLevel depthChannel (mapVkFormat(VK_FORMAT_R8G8B8_UNORM), access.getWidth(), access.getHeight()); |
| |
| for (int y = 0; y < access.getHeight(); y++) |
| for (int x = 0; x < access.getWidth(); x++) |
| depthChannel.getAccess().setPixel(tcu::Vec4(access.getPixDepth(x, y)), x, y); |
| |
| return depthChannel; |
| } |
| |
| bool SubpassDependencyTestInstance::verifyDepth (const ConstPixelBufferAccess& reference, |
| const ConstPixelBufferAccess& result, |
| const float threshold) |
| { |
| tcu::TestLog& log (m_context.getTestContext().getLog()); |
| |
| return tcu::floatThresholdCompare(log, // log |
| "Depth channel", // imageSetName |
| "Depth compare", // imageSetDesc |
| getRepresentableDepthChannel(reference), // reference |
| getRepresentableDepthChannel(result), // result |
| Vec4(threshold), // threshold |
| tcu::COMPARE_LOG_RESULT); // logMode |
| } |
| |
| bool SubpassDependencyTestInstance::verifyStencil (const ConstPixelBufferAccess& reference, |
| const ConstPixelBufferAccess& result) |
| { |
| tcu::TextureLevel stencilErrorImage (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), result.getWidth(), result.getHeight()); |
| tcu::TestLog& log (m_context.getTestContext().getLog()); |
| bool stencilOk (DE_TRUE); |
| |
| for (int y = 0; y < result.getHeight(); y++) |
| for (int x = 0; x < result.getWidth(); x++) |
| { |
| if (result.getPixStencil(x, y) != reference.getPixStencil(x, y)) |
| { |
| stencilErrorImage.getAccess().setPixel(Vec4(1.0f, 0.0f, 0.0f, 1.0f), x, y); |
| stencilOk = DE_FALSE; |
| } |
| else |
| stencilErrorImage.getAccess().setPixel(Vec4(0.0f, 1.0f, 0.0f, 1.0f), x, y); |
| } |
| |
| log << tcu::TestLog::ImageSet("Stencil compare", "Stencil compare") |
| << tcu::TestLog::Image("Result stencil channel", "Result stencil channel", result) |
| << tcu::TestLog::Image("Reference stencil channel", "Reference stencil channel", reference); |
| |
| if (!stencilOk) |
| log << tcu::TestLog::Image("Stencil error mask", "Stencil error mask", stencilErrorImage); |
| |
| log << tcu::TestLog::EndImageSet; |
| |
| return stencilOk; |
| } |
| |
| tcu::TestStatus SubpassDependencyTestInstance::iterate (void) |
| { |
| switch (m_renderPassType) |
| { |
| case RENDERPASS_TYPE_LEGACY: |
| return iterateInternal<RenderpassSubpass1>(); |
| case RENDERPASS_TYPE_RENDERPASS2: |
| return iterateInternal<RenderpassSubpass2>(); |
| default: |
| TCU_THROW(InternalError, "Impossible"); |
| } |
| } |
| |
| template<typename RenderpassSubpass> |
| tcu::TestStatus SubpassDependencyTestInstance::iterateInternal (void) |
| { |
| de::Random rand (5); |
| const DeviceInterface& vkd (m_context.getDeviceInterface()); |
| const Unique<VkCommandBuffer> commandBuffer (allocateCommandBuffer(vkd, m_context.getDevice(), *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| const typename RenderpassSubpass::SubpassBeginInfo subpassBeginInfo (DE_NULL, VK_SUBPASS_CONTENTS_INLINE); |
| const typename RenderpassSubpass::SubpassEndInfo subpassEndInfo (DE_NULL); |
| const size_t attachmentCount (m_renderPassInfo.getAttachments().size()); |
| const size_t subpassCount (m_renderPassInfo.getSubpasses().size()); |
| vector<VkClearValue> clearValues; |
| vector<Vec4> vertexData; |
| |
| beginCommandBuffer(vkd, *commandBuffer); |
| |
| // Begin render pass |
| { |
| VkRect2D renderArea = |
| { |
| { 0u, 0u }, // VkOffset2D offset |
| { m_width, m_height } // VkExtent2D extent |
| }; |
| |
| for (size_t attachmentNdx = 0; attachmentNdx < attachmentCount; attachmentNdx++) |
| clearValues.push_back(isDepthStencilFormat(m_format) ? makeClearValueDepthStencil(1.0f, 255u) : makeClearValueColor(Vec4(1.0f, 0.0f, 0.0f, 1.0f))); |
| |
| const VkRenderPassBeginInfo beginInfo = |
| { |
| VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| *m_renderPass, // VkRenderPass renderPass |
| *m_framebuffer, // VkFramebuffer framebuffer |
| renderArea, // VkRect2D renderArea |
| (deUint32)attachmentCount, // uint32_t clearValueCount |
| clearValues.data() // const VkClearValue* pClearValues |
| }; |
| |
| RenderpassSubpass::cmdBeginRenderPass(vkd, *commandBuffer, &beginInfo, &subpassBeginInfo); |
| } |
| |
| // Generate vertices for 128 triangles with pseudorandom positions and depths values |
| for (int primitiveNdx = 0; primitiveNdx < 128; primitiveNdx++) |
| { |
| float primitiveDepth = rand.getFloat(); |
| |
| for (int vertexNdx = 0; vertexNdx < 3; vertexNdx++) |
| { |
| float x = 2.0f * rand.getFloat() - 1.0f; |
| float y = 2.0f * rand.getFloat() - 1.0f; |
| |
| vertexData.push_back(Vec4(x, y, primitiveDepth, 1.0f)); |
| } |
| } |
| |
| const size_t singleVertexDataSize = sizeof(Vec4); |
| const size_t vertexCount = vertexData.size(); |
| const size_t vertexDataSize = vertexCount * singleVertexDataSize; |
| const deUint32 queueFamilyIndices = m_context.getUniversalQueueFamilyIndex(); |
| |
| const VkBufferCreateInfo vertexBufferParams = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkBufferCreateFlags flags; |
| (VkDeviceSize)vertexDataSize, // VkDeviceSize size; |
| VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 1u, // deUint32 queueFamilyCount; |
| &queueFamilyIndices, // const deUint32* pQueueFamilyIndices; |
| }; |
| |
| const Unique<VkBuffer> vertexBuffer (createBuffer(vkd, m_context.getDevice(), &vertexBufferParams)); |
| const de::UniquePtr<Allocation> vertexBufferMemory (m_context.getDefaultAllocator().allocate(getBufferMemoryRequirements(vkd, m_context.getDevice(), *vertexBuffer), MemoryRequirement::HostVisible)); |
| |
| VK_CHECK(vkd.bindBufferMemory(m_context.getDevice(), *vertexBuffer, vertexBufferMemory->getMemory(), vertexBufferMemory->getOffset())); |
| |
| const VkDeviceSize bindingOffset = 0; |
| vkd.cmdBindVertexBuffers(*commandBuffer, 0u, 1u, &vertexBuffer.get(), &bindingOffset); |
| |
| for (size_t subpassNdx = 0; subpassNdx < subpassCount; subpassNdx++) |
| { |
| if (subpassNdx > 0) |
| { |
| RenderpassSubpass::cmdNextSubpass(vkd, *commandBuffer, &subpassBeginInfo, &subpassEndInfo); |
| vkd.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **m_renderPipelineLayouts[subpassNdx], 0, 1, &**m_subpassDescriptorSets[subpassNdx - 1], 0, DE_NULL); |
| } |
| |
| vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **m_renderPipelines[subpassNdx]); |
| |
| if (subpassNdx == 0) |
| { |
| // Upload vertex data |
| { |
| void* vertexBufPtr = vertexBufferMemory->getHostPtr(); |
| deMemcpy(vertexBufPtr, vertexData.data(), vertexDataSize); |
| flushAlloc(vkd, m_context.getDevice(), *vertexBufferMemory); |
| } |
| |
| vkd.cmdDraw(*commandBuffer, (deUint32)vertexData.size(), 1u, 0u, 0u); |
| } |
| else |
| vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u); |
| } |
| |
| RenderpassSubpass::cmdEndRenderPass(vkd, *commandBuffer, &subpassEndInfo); |
| |
| // Memory barrier between rendering and copy |
| { |
| const VkImageAspectFlags imageAspectFlags = isDepthStencilFormat(m_format) |
| ? VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_COLOR_BIT; |
| const VkAccessFlags srcAccessMask = isDepthStencilFormat(m_format) |
| ? VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT : VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; |
| const VkImageLayout oldLayout = isDepthStencilFormat(m_format) |
| ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; |
| const VkPipelineStageFlags srcStageMask = isDepthStencilFormat(m_format) |
| ? VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT : VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; |
| |
| VkImageSubresourceRange imageSubresourceRange = |
| { |
| imageAspectFlags, // VkImageAspectFlags aspectMask |
| 0u, // uint32_t baseMipLevel |
| 1u, // uint32_t levelCount |
| 0u, // uint32_t baseArrayLayer |
| 1u // uint32_t layerCount |
| }; |
| |
| const VkImageMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| srcAccessMask, // VkAccessFlags srcAccessMask |
| VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask |
| oldLayout, // VkImageLayout oldLayout |
| VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex |
| **m_images[attachmentCount - 1], // VkImage image |
| imageSubresourceRange // VkImageSubresourceRange subresourceRange |
| }; |
| |
| vkd.cmdPipelineBarrier(*commandBuffer, srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier); |
| } |
| |
| // Copy image memory to buffer |
| { |
| if (isDepthStencilFormat(m_format)) |
| { |
| // Copy depth |
| const VkImageSubresourceLayers subresourceLayersDepth = |
| { |
| VK_IMAGE_ASPECT_DEPTH_BIT, // VkImageAspectFlags aspectMask |
| 0u, // deUint32 mipLevel |
| 0u, // deUint32 baseArrayLayer |
| 1u // deUint32 layerCount |
| }; |
| |
| const VkBufferImageCopy regionDepth = |
| { |
| 0u, // VkDeviceSize bufferOffset |
| 0u, // uint32_t bufferRowLength |
| 0u, // uint32_t bufferImageHeight |
| subresourceLayersDepth, // VkImageSubresourceLayers imageSubresource |
| { 0u, 0u, 0u }, // VkOffset3D imageOffset |
| { m_width, m_height, 1u } // VkExtent3D imageExtent |
| }; |
| |
| vkd.cmdCopyImageToBuffer(*commandBuffer, **m_images[attachmentCount - 1], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *m_primaryBuffer, 1u, ®ionDepth); |
| |
| // Copy stencil |
| const VkImageSubresourceLayers subresourceLayersStencil = |
| { |
| VK_IMAGE_ASPECT_STENCIL_BIT, // VkImageAspectFlags aspectMask |
| 0u, // deUint32 mipLevel |
| 0u, // deUint32 baseArrayLayer |
| 1u // deUint32 layerCount |
| }; |
| |
| const VkBufferImageCopy regionStencil = |
| { |
| 0u, // VkDeviceSize bufferOffset |
| 0u, // uint32_t bufferRowLength |
| 0u, // uint32_t bufferImageHeight |
| subresourceLayersStencil, // VkImageSubresourceLayers imageSubresource |
| { 0u, 0u, 0u }, // VkOffset3D imageOffset |
| { m_width, m_height, 1u } // VkExtent3D imageExtent |
| }; |
| |
| vkd.cmdCopyImageToBuffer(*commandBuffer, **m_images[attachmentCount - 1], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *m_secondaryBuffer, 1u, ®ionStencil); |
| } |
| else |
| { |
| // Copy color |
| const VkImageSubresourceLayers imageSubresourceLayers = |
| { |
| VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask |
| 0u, // deUint32 mipLevel |
| 0u, // deUint32 baseArrayLayer |
| 1u // deUint32 layerCount |
| }; |
| |
| const VkBufferImageCopy region = |
| { |
| 0u, // VkDeviceSize bufferOffset |
| 0u, // uint32_t bufferRowLength |
| 0u, // uint32_t bufferImageHeight |
| imageSubresourceLayers, // VkImageSubresourceLayers imageSubresource |
| { 0u, 0u, 0u }, // VkOffset3D imageOffset |
| { m_width, m_height, 1u } // VkExtent3D imageExtent |
| }; |
| |
| vkd.cmdCopyImageToBuffer(*commandBuffer, **m_images[attachmentCount - 1], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *m_primaryBuffer, 1u, ®ion); |
| } |
| } |
| |
| // Memory barrier between copy and host access |
| { |
| const VkBufferMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask |
| VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex |
| *m_primaryBuffer, // VkBuffer buffer |
| 0u, // VkDeviceSize offset |
| VK_WHOLE_SIZE // VkDeviceSize size |
| }; |
| |
| vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &barrier, 0u, DE_NULL); |
| |
| if (isDepthStencilFormat(m_format)) |
| { |
| const VkBufferMemoryBarrier stencilBarrier = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask |
| VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex |
| VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex |
| *m_secondaryBuffer, // VkBuffer buffer |
| 0u, // VkDeviceSize offset |
| VK_WHOLE_SIZE // VkDeviceSize size |
| }; |
| |
| vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &stencilBarrier, 0u, DE_NULL); |
| } |
| } |
| |
| endCommandBuffer(vkd, *commandBuffer); |
| submitCommandsAndWait(vkd, m_context.getDevice(), m_context.getUniversalQueue(), *commandBuffer); |
| invalidateMappedMemoryRange(vkd, m_context.getDevice(), m_primaryBufferMemory->getMemory(), m_primaryBufferMemory->getOffset(), VK_WHOLE_SIZE); |
| invalidateMappedMemoryRange(vkd, m_context.getDevice(), m_secondaryBufferMemory->getMemory(), m_secondaryBufferMemory->getOffset(), VK_WHOLE_SIZE); |
| |
| // Verify result |
| { |
| const tcu::TextureFormat format (mapVkFormat(m_format)); |
| |
| if (isDepthStencilFormat(m_format)) |
| { |
| const void* const ptrDepth (m_primaryBufferMemory->getHostPtr()); |
| const void* const ptrStencil (m_secondaryBufferMemory->getHostPtr()); |
| tcu::TextureLevel reference (format, m_width, m_height); |
| tcu::TextureLevel colorBuffer (mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), m_width, m_height); |
| const tcu::ConstPixelBufferAccess resultDepthAccess (getDepthCopyFormat(m_format), m_width, m_height, 1, ptrDepth); |
| const tcu::ConstPixelBufferAccess resultStencilAccess (getStencilCopyFormat(m_format), m_width, m_height, 1, ptrStencil); |
| const PixelBufferAccess referenceDepthAccess (tcu::getEffectiveDepthStencilAccess(reference.getAccess(), tcu::Sampler::MODE_DEPTH)); |
| const PixelBufferAccess referenceStencilAccess (tcu::getEffectiveDepthStencilAccess(reference.getAccess(), tcu::Sampler::MODE_STENCIL)); |
| |
| tcu::clearDepth(referenceDepthAccess, 1.0f); |
| tcu::clearStencil(referenceStencilAccess, 255); |
| |
| // Setup and run reference renderer |
| { |
| const DepthVertShader vertShader; |
| const DepthFragShader fragShader; |
| const rr::Renderer renderer; |
| const rr::Program program (&vertShader, &fragShader); |
| const rr::MultisamplePixelBufferAccess depthBuffer (rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(referenceDepthAccess)); |
| const rr::MultisamplePixelBufferAccess colorBufferAccess (rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(colorBuffer.getAccess())); |
| const rr::RenderTarget renderTarget (rr::MultisamplePixelBufferAccess(colorBufferAccess), depthBuffer, rr::MultisamplePixelBufferAccess()); |
| const rr::PrimitiveType primitiveType (rr::PRIMITIVETYPE_TRIANGLES); |
| const rr::PrimitiveList primitiveList (rr::PrimitiveList(primitiveType, (deUint32)vertexData.size(), 0)); |
| rr::RenderState renderState ((rr::ViewportState(depthBuffer)), m_context.getDeviceProperties().limits.subPixelPrecisionBits); |
| |
| const rr::VertexAttrib vertices = rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &vertexData[0]); |
| |
| renderState.fragOps.depthTestEnabled = DE_TRUE; |
| renderState.fragOps.depthFunc = rr::TESTFUNC_LEQUAL; |
| |
| renderer.draw(rr::DrawCommand(renderState, |
| renderTarget, |
| program, |
| 1u, |
| &vertices, |
| primitiveList)); |
| } |
| |
| for (size_t subpassNdx = 0; subpassNdx < subpassCount - 1; subpassNdx++) |
| { |
| for (int y = 0; y < reference.getHeight(); y++) |
| for (int x = 0; x < reference.getWidth(); x++) |
| reference.getAccess().setPixDepth(reference.getAccess().getPixDepth(x, y) - 0.02f, x, y); |
| } |
| |
| // Threshold size of subpass count multiplied by the minimum representable difference is allowed for depth compare |
| const float depthThreshold ((float)subpassCount * (1.0f / ((UVec4(1u) << tcu::getTextureFormatMantissaBitDepth( |
| resultDepthAccess.getFormat()).cast<deUint32>()) - 1u).cast<float>().x())); |
| |
| if (!verifyDepth(reference.getAccess(), resultDepthAccess, depthThreshold)) |
| m_resultCollector.fail("Depth compare failed."); |
| |
| if (!verifyStencil(referenceStencilAccess, resultStencilAccess)) |
| m_resultCollector.fail("Stencil compare failed."); |
| } |
| else |
| DE_FATAL("Not implemented"); |
| } |
| |
| return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage()); |
| } |
| |
| struct SubpassSelfDependencyBackwardsTestConfig |
| { |
| SubpassSelfDependencyBackwardsTestConfig (VkFormat format_, |
| UVec2 imageSize_, |
| RenderPassType renderPassType_) |
| : format (format_) |
| , imageSize (imageSize_) |
| , renderPassType (renderPassType_) |
| { |
| } |
| |
| VkFormat format; |
| UVec2 imageSize; |
| RenderPassType renderPassType; |
| }; |
| |
| class SubpassSelfDependencyBackwardsTestInstance : public TestInstance |
| { |
| public: |
| SubpassSelfDependencyBackwardsTestInstance (Context& context, |
| SubpassSelfDependencyBackwardsTestConfig testConfig); |
| |
| ~SubpassSelfDependencyBackwardsTestInstance (void); |
| |
| tcu::TestStatus iterate (void); |
| |
| template<typename RenderpassSubpass> |
| tcu::TestStatus iterateInternal (void); |
| |
| private: |
| const bool m_extensionSupported; |
| const bool m_featuresSupported; |
| const RenderPassType m_renderPassType; |
| |
| const deUint32 m_width; |
| const deUint32 m_height; |
| const VkFormat m_format; |
| tcu::ResultCollector m_resultCollector; |
| }; |
| |
| SubpassSelfDependencyBackwardsTestInstance::SubpassSelfDependencyBackwardsTestInstance (Context& context, SubpassSelfDependencyBackwardsTestConfig testConfig) |
| : TestInstance (context) |
| , m_extensionSupported ((testConfig.renderPassType == RENDERPASS_TYPE_RENDERPASS2) && context.requireDeviceExtension("VK_KHR_create_renderpass2")) |
| , m_featuresSupported (context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER)) |
| , m_renderPassType (testConfig.renderPassType) |
| , m_width (testConfig.imageSize.x()) |
| , m_height (testConfig.imageSize.y()) |
| , m_format (testConfig.format) |
| { |
| } |
| |
| SubpassSelfDependencyBackwardsTestInstance::~SubpassSelfDependencyBackwardsTestInstance (void) |
| { |
| } |
| |
| tcu::TestStatus SubpassSelfDependencyBackwardsTestInstance::iterate (void) |
| { |
| switch (m_renderPassType) |
| { |
| case RENDERPASS_TYPE_LEGACY: |
| return iterateInternal<RenderpassSubpass1>(); |
| case RENDERPASS_TYPE_RENDERPASS2: |
| return iterateInternal<RenderpassSubpass2>(); |
| default: |
| TCU_THROW(InternalError, "Impossible"); |
| } |
| } |
| |
| template<typename RenderpassSubpass> |
| tcu::TestStatus SubpassSelfDependencyBackwardsTestInstance::iterateInternal (void) |
| { |
| de::Random rand (5); |
| const DeviceInterface& vkd (m_context.getDeviceInterface()); |
| const VkDevice device = m_context.getDevice(); |
| const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); |
| const Unique<VkCommandPool> commandPool (createCommandPool(vkd, m_context.getDevice(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex)); |
| const Unique<VkCommandBuffer> commandBuffer (allocateCommandBuffer(vkd, m_context.getDevice(), *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); |
| const typename RenderpassSubpass::SubpassBeginInfo subpassBeginInfo (DE_NULL, VK_SUBPASS_CONTENTS_INLINE); |
| const typename RenderpassSubpass::SubpassEndInfo subpassEndInfo (DE_NULL); |
| vector<Vec4> vertexData; |
| Move<VkImage> outputImage; |
| de::MovePtr<Allocation> outputImageAllocation; |
| Move<VkImageView> outputImageView; |
| Move<VkPipelineLayout> pipelineLayout; |
| Move<VkPipeline> renderPipeline; |
| Move<VkFramebuffer> framebuffer; |
| Move<VkRenderPass> renderPass; |
| Move<VkBuffer> indirectBuffer; |
| de::MovePtr<Allocation> indirectBufferMemory; |
| Move<VkBuffer> resultBuffer; |
| de::MovePtr<Allocation> resultBufferMemory; |
| const VkDeviceSize indirectBufferSize = 4 * sizeof(deUint32); |
| Move<VkBuffer> vertexBuffer; |
| de::MovePtr<Allocation> vertexBufferMemory; |
| |
| // Create output image. |
| { |
| const VkExtent3D imageExtent = |
| { |
| m_width, // uint32_t width |
| m_height, // uint32_t height |
| 1u // uint32_t depth |
| }; |
| |
| VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
| |
| const VkImageCreateInfo imageCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkImageCreateFlags flags |
| VK_IMAGE_TYPE_2D, // VkImageType imageType |
| m_format, // VkFormat format |
| imageExtent, // VkExtent3D extent |
| 1u, // uint32_t mipLevels |
| 1u, // uint32_t arrayLayers |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling |
| usage, // VkImageUsageFlags usage |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode |
| 1u, // uint32_t queueFamilyIndexCount |
| &queueFamilyIndex, // const uint32_t* pQueueFamilyIndices |
| VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout |
| }; |
| |
| outputImage = createImage(vkd, device, &imageCreateInfo, DE_NULL); |
| outputImageAllocation = m_context.getDefaultAllocator().allocate(getImageMemoryRequirements(vkd, device, *outputImage), MemoryRequirement::Any); |
| VK_CHECK(vkd.bindImageMemory(device, *outputImage, outputImageAllocation->getMemory(), outputImageAllocation->getOffset())); |
| } |
| |
| // Create indirect buffer and initialize. |
| { |
| const VkBufferUsageFlags bufferUsage (VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); |
| const VkBufferCreateInfo bufferCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkBufferCreateFlags flags |
| indirectBufferSize, // VkDeviceSize size |
| bufferUsage, // VkBufferUsageFlags usage |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode |
| 0u, // uint32_t queueFamilyIndexCount |
| DE_NULL // const uint32_t* pQueueFamilyIndices |
| }; |
| |
| indirectBuffer = createBuffer(vkd, device, &bufferCreateInfo); |
| indirectBufferMemory = createBufferMemory(vkd, device, m_context.getDefaultAllocator(), *indirectBuffer); |
| |
| VkDrawIndirectCommand drawIndirectCommand = |
| { |
| 64u, // deUint32 vertexCount |
| 1u, // deUint32 instanceCount |
| 0u, // deUint32 firstVertex |
| 0u, // deUint32 firstInstance |
| }; |
| |
| deMemcpy(indirectBufferMemory->getHostPtr(), (void*)&drawIndirectCommand, sizeof(VkDrawIndirectCommand)); |
| flushAlloc(vkd, device, *indirectBufferMemory); |
| } |
| |
| // Create result buffer. |
| { |
| resultBuffer = createBuffer(vkd, device, m_format, m_width, m_height); |
| resultBufferMemory = createBufferMemory(vkd, device, m_context.getDefaultAllocator(), *resultBuffer); |
| } |
| |
| // Create descriptor set layout. |
| Unique<VkDescriptorSetLayout> descriptorSetLayout (DescriptorSetLayoutBuilder() |
| .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_GEOMETRY_BIT) |
| .build(vkd, device)); |
| // Create descriptor pool. |
| Unique<VkDescriptorPool> descriptorPool (DescriptorPoolBuilder() |
| .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u) |
| .build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u)); |
| // Create descriptor set. |
| Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout)); |
| |
| // Update descriptor set information. |
| { |
| VkDescriptorBufferInfo descIndirectBuffer = makeDescriptorBufferInfo(*indirectBuffer, 0, indirectBufferSize); |
| |
| DescriptorSetUpdateBuilder() |
| .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descIndirectBuffer) |
| .update(vkd, device); |
| } |
| |
| // Create render pipeline layout. |
| { |
| const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (vk::VkPipelineLayoutCreateFlags)0, // VkPipelineLayoutCreateFlags flags |
| 1u, // deUint32 setLayoutCount |
| &*descriptorSetLayout, // const VkDescriptorSetLayout* pSetLayouts |
| 0u, // deUint32 pushConstantRangeCount |
| DE_NULL // const VkPushConstantRange* pPushConstantRanges |
| }; |
| |
| pipelineLayout = createPipelineLayout(vkd, device, &pipelineLayoutCreateInfo); |
| } |
| |
| // Create render pass. |
| { |
| vector<Attachment> attachments; |
| vector<AttachmentReference> colorAttachmentReferences; |
| |
| attachments.push_back(Attachment(m_format, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); |
| colorAttachmentReferences.push_back(AttachmentReference(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); |
| |
| const vector<Subpass> subpasses (1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector<deUint32>())); |
| vector<SubpassDependency> deps; |
| |
| deps.push_back(SubpassDependency(0u, // deUint32 srcPass |
| 0u, // deUint32 dstPass |
| VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, // VkPipelineStageFlags srcStageMask |
| VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, // VkPipelineStageFlags dstStageMask |
| VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags srcAccessMask |
| VK_ACCESS_INDIRECT_COMMAND_READ_BIT, // VkAccessFlags dstAccessMask |
| 0)); // VkDependencyFlags flags |
| |
| renderPass = createRenderPass(vkd, device, RenderPass(attachments, subpasses, deps), m_renderPassType); |
| } |
| |
| // Create render pipeline. |
| { |
| const Unique<VkShaderModule> vertexShaderModule (createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u)); |
| const Unique<VkShaderModule> geometryShaderModule (createShaderModule(vkd, device, m_context.getBinaryCollection().get("geom"), 0u)); |
| const Unique<VkShaderModule> fragmentShaderModule (createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u)); |
| |
| const VkVertexInputBindingDescription vertexBinding0 = |
| { |
| 0u, // deUint32 binding; |
| sizeof(Vec4), // deUint32 strideInBytes; |
| VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate stepRate; |
| }; |
| |
| VkVertexInputAttributeDescription attr0 = |
| { |
| 0u, // deUint32 location; |
| 0u, // deUint32 binding; |
| VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; |
| 0u // deUint32 offsetInBytes; |
| }; |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputState = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| (VkPipelineVertexInputStateCreateFlags)0u, // VkPipelineVertexInputStateCreateFlags flags |
| 1u, // uint32_t vertexBindingDescriptionCount |
| &vertexBinding0, // const VkVertexInputBindingDescription* pVertexBindingDescriptions |
| 1u, // uint32_t vertexAttributeDescriptionCount |
| &attr0 // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions |
| }; |
| |
| const std::vector<VkViewport> viewports (1, makeViewport(tcu::UVec2(m_width, m_height))); |
| const std::vector<VkRect2D> scissors (1, makeRect2D(tcu::UVec2(m_width, m_height))); |
| |
| renderPipeline = makeGraphicsPipeline(vkd, // const DeviceInterface& vk |
| device, // const VkDevice device |
| *pipelineLayout, // const VkPipelineLayout pipelineLayout |
| *vertexShaderModule, // const VkShaderModule vertexShaderModule |
| DE_NULL, // const VkShaderModule tessellationControlShaderModule |
| DE_NULL, // const VkShaderModule tessellationEvalShaderModule |
| *geometryShaderModule, // const VkShaderModule geometryShaderModule |
| *fragmentShaderModule, // const VkShaderModule fragmentShaderModule |
| *renderPass, // const VkRenderPass renderPass |
| viewports, // const std::vector<VkViewport>& viewports |
| scissors, // const std::vector<VkRect2D>& scissors |
| VK_PRIMITIVE_TOPOLOGY_POINT_LIST, // const VkPrimitiveTopology topology |
| 0u, // const deUint32 subpass |
| 0u, // const deUint32 patchControlPoints |
| &vertexInputState); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo |
| } |
| |
| // Create framebuffer. |
| { |
| const VkImageViewCreateInfo imageViewCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkImageViewCreateFlags flags |
| *outputImage, // VkImage image |
| VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType |
| m_format, // VkFormat format |
| makeComponentMappingRGBA(), // VkComponentMapping components |
| { // VkImageSubresourceRange subresourceRange |
| VK_IMAGE_ASPECT_COLOR_BIT, |
| 0u, |
| 1u, |
| 0u, |
| 1u |
| } |
| }; |
| outputImageView = createImageView(vkd, device, &imageViewCreateInfo); |
| |
| const VkFramebufferCreateInfo framebufferCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| 0u, // VkFramebufferCreateFlags flags |
| *renderPass, // VkRenderPass renderPass |
| 1u, // uint32_t attachmentCount |
| &*outputImageView, // const VkImageView* pAttachments |
| m_width, // uint32_t width |
| m_height, // uint32_t height |
| 1u // uint32_t layers |
| }; |
| |
| framebuffer = vk::createFramebuffer(vkd, device, &framebufferCreateInfo); |
| } |
| |
| // Generate random point locations (pixel centered to make reference comparison easier). |
| for (int primitiveNdx = 0; primitiveNdx < 128; primitiveNdx++) |
| { |
| vertexData.push_back(Vec4((float)((rand.getUint32() % m_width) * 2) / (float)m_width - 1.0f, |
| (float)((rand.getUint32() % m_height) * 2) / (float)m_height - 1.0f, |
| 1.0f, 1.0f)); |
| } |
| |
| // Upload vertex data. |
| { |
| const size_t vertexDataSize = vertexData.size() * sizeof(Vec4); |
| |
| const VkBufferCreateInfo vertexBufferParams = |
| { |
| VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; |
| DE_NULL, // const void* pNext; |
| 0u, // VkBufferCreateFlags flags; |
| (VkDeviceSize)vertexDataSize, // VkDeviceSize size; |
| VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 1u, // deUint32 queueFamilyCount; |
| &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; |
| }; |
| |
| vertexBuffer = createBuffer(vkd, m_context.getDevice(), &vertexBufferParams); |
| vertexBufferMemory = createBufferMemory(vkd, device, m_context.getDefaultAllocator(), *vertexBuffer); |
| |
| deMemcpy(vertexBufferMemory->getHostPtr(), vertexData.data(), vertexDataSize); |
| flushAlloc(vkd, device, *vertexBufferMemory); |
| } |
| |
| beginCommandBuffer(vkd, *commandBuffer); |
| vkd.cmdBindPipeline(*commandBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *renderPipeline); |
| vkd.cmdBindDescriptorSets(*commandBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL); |
| |
| // Begin render pass. |
| { |
| VkRect2D renderArea = |
| { |
| { 0u, 0u }, // VkOffset2D offset |
| { m_width, m_height } // VkExtent2D extent |
| }; |
| |
| VkClearValue clearValue = makeClearValueColor(Vec4(0.0f, 1.0f, 0.0f, 1.0f)); |
| |
| const VkRenderPassBeginInfo beginInfo = |
| { |
| VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| *renderPass, // VkRenderPass renderPass |
| *framebuffer, // VkFramebuffer framebuffer |
| renderArea, // VkRect2D renderArea |
| 1u, // uint32_t clearValueCount |
| &clearValue // const VkClearValue* pClearValues |
| }; |
| |
| RenderpassSubpass::cmdBeginRenderPass(vkd, *commandBuffer, &beginInfo, &subpassBeginInfo); |
| } |
| |
| const VkDeviceSize bindingOffset = 0; |
| vkd.cmdBindVertexBuffers(*commandBuffer, 0u, 1u, &vertexBuffer.get(), &bindingOffset); |
| |
| vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *renderPipeline); |
| |
| // The first indirect draw: Draw the first 64 items. |
| vkd.cmdDrawIndirect(*commandBuffer, *indirectBuffer, 0u, 1u, 0u); |
| |
| // Barrier for indirect buffer. |
| { |
| const VkMemoryBarrier barrier = |
| { |
| VK_STRUCTURE_TYPE_MEMORY_BARRIER, // VkStructureType sType |
| DE_NULL, // const void* pNext |
| VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags srcAccessMask |
| VK_ACCESS_INDIRECT_COMMAND_READ_BIT // VkAccessFlags dstAccessMask |
| }; |
| |
| vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, 0u, 1u, &barrier, 0u, DE_NULL, 0u, DE_NULL); |
| } |
| |
| // The second indirect draw: Draw the last 64 items. |
| vkd.cmdDrawIndirect(*commandBuffer, *indirectBuffer, 0u, 1u, 0u); |
| |
| RenderpassSubpass::cmdEndRenderPass(vkd, *commandBuffer, &subpassEndInfo); |
| |
| // Copy results to a buffer. |
| copyImageToBuffer(vkd, *commandBuffer, *outputImage, *resultBuffer, tcu::IVec2(m_width, m_height)); |
| |
| endCommandBuffer(vkd, *commandBuffer); |
| submitCommandsAndWait(vkd, m_context.getDevice(), m_context.getUniversalQueue(), *commandBuffer); |
| invalidateMappedMemoryRange(vkd, m_context.getDevice(), resultBufferMemory->getMemory(), resultBufferMemory->getOffset(), VK_WHOLE_SIZE); |
| |
| // Verify result. |
| { |
| const tcu::TextureFormat format (mapVkFormat(m_format)); |
| |
| const void* const ptrResult (resultBufferMemory->getHostPtr()); |
| tcu::TextureLevel reference (format, m_width, m_height); |
| const tcu::ConstPixelBufferAccess resultAccess (format, m_width, m_height, 1, ptrResult); |
| const PixelBufferAccess referenceAccess (reference.getAccess()); |
| |
| |
| // Setup and run reference renderer. |
| { |
| vector<Vec4> triangles; |
| const float offset = 0.03f; |
| |
| // Convert points into triangles to have quads similar to what GPU is producing from geometry shader. |
| for (size_t vtxIdx = 0; vtxIdx < vertexData.size(); vtxIdx++) |
| { |
| triangles.push_back(vertexData[vtxIdx] + tcu::Vec4(-offset, offset, 0.0f, 0.0f)); |
| triangles.push_back(vertexData[vtxIdx] + tcu::Vec4(-offset, -offset, 0.0f, 0.0f)); |
| triangles.push_back(vertexData[vtxIdx] + tcu::Vec4(offset, offset, 0.0f, 0.0f)); |
| |
| triangles.push_back(vertexData[vtxIdx] + tcu::Vec4(-offset, -offset, 0.0f, 0.0f)); |
| triangles.push_back(vertexData[vtxIdx] + tcu::Vec4(offset, offset, 0.0f, 0.0f)); |
| triangles.push_back(vertexData[vtxIdx] + tcu::Vec4(offset, -offset, 0.0f, 0.0f)); |
| } |
| |
| const SelfDependencyBackwardsVertShader vertShader; |
| const SelfDependencyBackwardsFragShader fragShader; |
| const rr::Renderer renderer; |
| const rr::Program program (&vertShader, &fragShader); |
| const rr::MultisamplePixelBufferAccess msAccess (rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(referenceAccess)); |
| const rr::RenderTarget renderTarget (msAccess); |
| const rr::PrimitiveType primitiveType (rr::PRIMITIVETYPE_TRIANGLES); |
| const rr::PrimitiveList primitiveList (rr::PrimitiveList(primitiveType, (deUint32)triangles.size(), 0)); |
| const rr::ViewportState viewportState (msAccess); |
| const rr::RenderState renderState (viewportState, m_context.getDeviceProperties().limits.subPixelPrecisionBits); |
| const rr::VertexAttrib vertices = rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &triangles[0]); |
| |
| tcu::clear(referenceAccess, tcu::UVec4(0, 255, 0, 255)); |
| renderer.draw(rr::DrawCommand(renderState, renderTarget, program, 1u, &vertices, primitiveList)); |
| } |
| |
| if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), // log |
| "Color buffer", // imageSetName |
| "", // imageSetDesc |
| referenceAccess, // reference |
| resultAccess, // result |
| Vec4(0.01f), // threshold |
| tcu::COMPARE_LOG_RESULT)) // logMode |
| { |
| m_resultCollector.fail("Image compare failed."); |
| } |
| } |
| |
| return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage()); |
| } |
| |
| // Shader programs for testing dependencies between render pass instances |
| struct ExternalPrograms |
| { |
| void init (vk::SourceCollections& dst, ExternalTestConfig testConfig) const |
| { |
| for (size_t renderPassNdx = 0; renderPassNdx < testConfig.renderPasses.size(); renderPassNdx++) |
| { |
| dst.glslSources.add("quad-vert-" + de::toString(renderPassNdx)) << glu::VertexSource( |
| "#version 450\n" |
| "layout(location = 0) out highp vec2 vtxTexCoords;\n" |
| "highp float;\n" |
| "void main (void)\n" |
| "{\n" |
| " vec4 position;" |
| " position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n" |
| " ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n" |
| " gl_Position = position;\n" |
| " vtxTexCoords = position.xy / 2.0 + vec2(0.5);" |
| "}\n"); |
| |
| // First pass renders four quads of different color |
| if (renderPassNdx == 0) |
| { |
| dst.glslSources.add("quad-frag-" + de::toString(renderPassNdx)) << glu::FragmentSource( |
| "#version 450\n" |
| "layout(location = 0) in highp vec2 vtxTexCoords;\n" |
| "layout(location = 0) out highp vec4 o_color;\n" |
| "void main (void)\n" |
| "{\n" |
| " if (gl_FragCoord.x <= " + de::toString(testConfig.imageSize.x() / 2) + " && gl_FragCoord.y <= " + de::toString(testConfig.imageSize.y() / 2) + ")\n" |
| " o_color = vec4(1.0, 0.0, 0.0, 1.0);\n" |
| " else if (gl_FragCoord.x > " + de::toString(testConfig.imageSize.x() / 2) + " && gl_FragCoord.y <= " + de::toString(testConfig.imageSize.y() / 2) + ")\n" |
| " o_color = vec4(0.0, 1.0, 0.0, 1.0);\n" |
| " else if (gl_FragCoord.x <= " + de::toString(testConfig.imageSize.x() / 2) + " && gl_FragCoord.y > " + de::toString(testConfig.imageSize.y() / 2) + ")\n" |
| " o_color = vec4(0.0, 0.0, 1.0, 1.0);\n" |
| " else\n" |
| " o_color = vec4(0.0, 0.0, 0.0, 1.0);\n" |
| "" |
| "}\n"); |
| } |
| else |
| { |
| if (renderPassNdx % 2 == 0) |
| { |
| // Blur previous pass horizontally |
| dst.glslSources.add("quad-frag-" + de::toString(renderPassNdx)) << glu::FragmentSource( |
| "#version 450\n" |
| "layout(binding = 0) uniform sampler2D previousPass;\n" |
| "layout(location = 0) in highp vec2 vtxTexCoords;\n" |
| "layout(location = 0) out highp vec4 o_color;\n" |
| "void main (void)\n" |
| "{\n" |
| " vec2 step = vec2(1.0 / " + de::toString(testConfig.imageSize.x()) + ", 1.0 / " + de::toString(testConfig.imageSize.y()) + ");\n" |
| " vec2 minCoord = vec2(0.0, 0.0);\n" |
| " vec2 maxCoord = vec2(1.0, 1.0);\n" |
| " vec4 blurColor = vec4(0.0);\n" |
| " for(int sampleNdx = 0; sampleNdx < " + de::toString(testConfig.blurKernel + 1) + "; sampleNdx++)\n" |
| " {\n" |
| " vec2 sampleCoord = vec2((vtxTexCoords.x - " + de::toString(testConfig.blurKernel / 2) + " * step.x) + step.x * sampleNdx, vtxTexCoords.y);\n" |
| " blurColor += 0.12 * texture(previousPass, clamp(sampleCoord, minCoord, maxCoord));\n" |
| " }\n" |
| " o_color = blurColor;\n" |
| "}\n"); |
| } |
| else |
| { |
| // Blur previous pass vertically |
| dst.glslSources.add("quad-frag-" + de::toString(renderPassNdx)) << glu::FragmentSource( |
| "#version 450\n" |
| "layout(binding = 0) uniform highp sampler2D previousPass;\n" |
| "layout(location = 0) in highp vec2 vtxTexCoords;\n" |
| "layout(location = 0) out highp vec4 o_color;\n" |
| "void main (void)\n" |
| "{\n" |
| " vec2 step = vec2(1.0 / " + de::toString(testConfig.imageSize.x()) + ", 1.0 / " + de::toString(testConfig.imageSize.y()) + ");\n" |
| " vec2 minCoord = vec2(0.0, 0.0);\n" |
| " vec2 maxCoord = vec2(1.0, 1.0);\n" |
| " vec4 blurColor = vec4(0.0);\n" |
| " for(int sampleNdx = 0; sampleNdx < " + de::toString(testConfig.blurKernel + 1) + "; sampleNdx++)\n" |
| " {\n" |
| " vec2 sampleCoord = vec2(vtxTexCoords.x, (vtxTexCoords.y - " + de::toString(testConfig.blurKernel / 2) + " * step.y) + step.y * sampleNdx);\n" |
| " blurColor += 0.12 * texture(previousPass, clamp(sampleCoord, minCoord, maxCoord));\n" |
| " }\n" |
| " o_color = blurColor;\n" |
| "}\n"); |
| } |
| } |
| } |
| } |
| }; |
| |
| // Shader programs for testing dependencies between subpasses |
| struct SubpassPrograms |
| { |
| void init (vk::SourceCollections& dst, SubpassTestConfig testConfig) const |
| { |
| size_t subpassCount = testConfig.renderPass.getSubpasses().size(); |
| |
| for (size_t subpassNdx = 0; subpassNdx < subpassCount; subpassNdx++) |
| { |
| if (subpassNdx == 0) |
| { |
| dst.glslSources.add("subpass-vert-" + de::toString(subpassNdx)) << glu::VertexSource( |
| "#version 450\n" |
| "highp float;\n" |
| "layout(location = 0) in highp vec4 position;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = position;\n" |
| "}\n"); |
| } |
| else |
| { |
| dst.glslSources.add("subpass-vert-" + de::toString(subpassNdx)) << glu::VertexSource( |
| "#version 450\n" |
| "highp float;\n" |
| "void main (void)\n" |
| "{\n" |
| " vec4 position;" |
| " position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n" |
| " ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n" |
| " gl_Position = position;\n" |
| "}\n"); |
| } |
| |
| if (isDepthStencilFormat(testConfig.format)) |
| { |
| if (subpassNdx == 0) |
| { |
| // Empty fragment shader: Fragment depth unmodified. |
| dst.glslSources.add("subpass-frag-" + de::toString(subpassNdx)) << glu::FragmentSource( |
| "#version 450\n" |
| "void main (void)\n" |
| "{\n" |
| "}\n"); |
| } |
| else |
| { |
| // Use fragment depth from previous depth rendering result. |
| dst.glslSources.add("subpass-frag-" + de::toString(subpassNdx)) << glu::FragmentSource( |
| "#version 450\n" |
| "layout (input_attachment_index = 0, binding = 0) uniform subpassInput depthStencil;\n" |
| "void main (void)\n" |
| "{\n" |
| " float inputDepth = subpassLoad(depthStencil).x;\n" |
| " gl_FragDepth = inputDepth - 0.02;\n" |
| "}\n"); |
| } |
| } |
| else |
| DE_FATAL("Unimplemented"); |
| } |
| } |
| }; |
| |
| // Shader programs for testing backwards subpass self dependency from geometry stage to indirect draw |
| struct SubpassSelfDependencyBackwardsPrograms |
| { |
| void init (vk::SourceCollections& dst, SubpassSelfDependencyBackwardsTestConfig testConfig) const |
| { |
| DE_UNREF(testConfig); |
| |
| dst.glslSources.add("vert") << glu::VertexSource( |
| "#version 450\n" |
| "layout(location = 0) in highp vec4 position;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = position;\n" |
| "}\n"); |
| |
| dst.glslSources.add("geom") << glu::GeometrySource( |
| "#version 450\n" |
| "layout(points) in;\n" |
| "layout(triangle_strip, max_vertices = 4) out;\n" |
| "\n" |
| "in gl_PerVertex {\n" |
| " vec4 gl_Position;\n" |
| "} gl_in[];\n" |
| "\n" |
| "out gl_PerVertex {\n" |
| " vec4 gl_Position;\n" |
| "};\n" |
| "layout (binding = 0) buffer IndirectBuffer\n" |
| "{\n" |
| " uint vertexCount;\n" |
| " uint instanceCount;\n" |
| " uint firstVertex;\n" |
| " uint firstInstance;\n" |
| "} indirectBuffer;\n" |
| "\n" |
| "void main (void) {\n" |
| " vec4 p = gl_in[0].gl_Position;\n" |
| " float offset = 0.03f;\n" |
| " gl_Position = p + vec4(-offset, offset, 0, 0);\n" |
| " EmitVertex();\n" |
| " gl_Position = p + vec4(-offset, -offset, 0, 0);\n" |
| " EmitVertex();\n" |
| " gl_Position = p + vec4(offset, offset, 0, 0);\n" |
| " EmitVertex();\n" |
| " gl_Position = p + vec4(offset, -offset, 0, 0);\n" |
| " EmitVertex();\n" |
| " EndPrimitive();\n" |
| " indirectBuffer.vertexCount = 64;\n" |
| " indirectBuffer.instanceCount = 1;\n" |
| " indirectBuffer.firstVertex = 64;\n" |
| " indirectBuffer.firstInstance = 0;\n" |
| "}\n"); |
| |
| dst.glslSources.add("frag") << glu::FragmentSource( |
| "#version 450\n" |
| "layout(location = 0) out highp vec4 fragColor;\n" |
| "void main (void)\n" |
| "{\n" |
| " fragColor = vec4(1, 0, 0, 1);\n" |
| "}\n"); |
| } |
| }; |
| |
| std::string formatToName (VkFormat format) |
| { |
| const std::string formatStr = de::toString(format); |
| const std::string prefix = "VK_FORMAT_"; |
| |
| DE_ASSERT(formatStr.substr(0, prefix.length()) == prefix); |
| |
| return de::toLower(formatStr.substr(prefix.length())); |
| } |
| |
| void initTests (tcu::TestCaseGroup* group, const RenderPassType renderPassType) |
| { |
| tcu::TestContext& testCtx(group->getTestContext()); |
| |
| // Test external subpass dependencies |
| { |
| const deUint32 renderPassCounts[] = { 2u, 3u, 5u}; |
| |
| const UVec2 renderSizes[] = |
| { |
| UVec2(64, 64), |
| UVec2(128, 128), |
| UVec2(512, 512) |
| }; |
| |
| de::MovePtr<tcu::TestCaseGroup> externalGroup (new tcu::TestCaseGroup(testCtx, "external_subpass", "external_subpass")); |
| |
| for (size_t renderSizeNdx = 0; renderSizeNdx < DE_LENGTH_OF_ARRAY(renderSizes); renderSizeNdx++) |
| { |
| string groupName ("render_size_" + de::toString(renderSizes[renderSizeNdx].x()) + "_" + de::toString(renderSizes[renderSizeNdx].y())); |
| de::MovePtr<tcu::TestCaseGroup> renderSizeGroup (new tcu::TestCaseGroup(testCtx, groupName.c_str(), groupName.c_str())); |
| |
| for (size_t renderPassCountNdx = 0; renderPassCountNdx < DE_LENGTH_OF_ARRAY(renderPassCounts); renderPassCountNdx++) |
| { |
| vector<RenderPass> renderPasses; |
| |
| for (size_t renderPassNdx = 0; renderPassNdx < renderPassCounts[renderPassCountNdx]; renderPassNdx++) |
| { |
| vector<Attachment> attachments; |
| vector<AttachmentReference> colorAttachmentReferences; |
| |
| const VkFormat format (VK_FORMAT_R8G8B8A8_UNORM); |
| const VkSampleCountFlagBits sampleCount (VK_SAMPLE_COUNT_1_BIT); |
| const VkAttachmentLoadOp loadOp (VK_ATTACHMENT_LOAD_OP_DONT_CARE); |
| const VkAttachmentStoreOp storeOp (VK_ATTACHMENT_STORE_OP_STORE); |
| const VkAttachmentLoadOp stencilLoadOp (VK_ATTACHMENT_LOAD_OP_DONT_CARE); |
| const VkAttachmentStoreOp stencilStoreOp (VK_ATTACHMENT_STORE_OP_DONT_CARE); |
| const VkImageLayout initialLayout (VK_IMAGE_LAYOUT_UNDEFINED); |
| const VkImageLayout finalLayout (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| const VkImageLayout subpassLayout (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); |
| |
| attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalLayout)); |
| colorAttachmentReferences.push_back(AttachmentReference((deUint32)0, subpassLayout)); |
| |
| const VkImageLayout depthStencilLayout (VK_IMAGE_LAYOUT_GENERAL); |
| const vector<Subpass> subpasses (1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), |
| AttachmentReference(VK_ATTACHMENT_UNUSED, depthStencilLayout), vector<deUint32>())); |
| vector<SubpassDependency> deps; |
| |
| deps.push_back(SubpassDependency(VK_SUBPASS_EXTERNAL, // deUint32 srcPass |
| 0, // deUint32 dstPass |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask |
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags dstStageMask |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask |
| VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags dstAccessMask |
| 0)); // VkDependencyFlags flags |
| |
| deps.push_back(SubpassDependency(0, // deUint32 srcPass |
| VK_SUBPASS_EXTERNAL, // deUint32 dstPass |
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags srcStageMask |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags dstStageMask |
| VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags srcAccessMask |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask |
| 0)); // VkDependencyFlags flags |
| |
| RenderPass renderPass (attachments, subpasses, deps); |
| |
| renderPasses.push_back(renderPass); |
| } |
| |
| const deUint32 blurKernel (12u); |
| const ExternalTestConfig testConfig (VK_FORMAT_R8G8B8A8_UNORM, renderSizes[renderSizeNdx], renderPasses, renderPassType, blurKernel); |
| const string testName ("render_passes_" + de::toString(renderPassCounts[renderPassCountNdx])); |
| |
| renderSizeGroup->addChild(new InstanceFactory1<ExternalDependencyTestInstance, ExternalTestConfig, ExternalPrograms>(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName.c_str(), testName.c_str(), testConfig)); |
| } |
| |
| externalGroup->addChild(renderSizeGroup.release()); |
| } |
| |
| group->addChild(externalGroup.release()); |
| } |
| |
| // Test implicit subpass dependencies |
| { |
| const deUint32 renderPassCounts[] = { 2u, 3u, 5u }; |
| |
| de::MovePtr<tcu::TestCaseGroup> implicitGroup (new tcu::TestCaseGroup(testCtx, "implicit_dependencies", "implicit_dependencies")); |
| |
| for (size_t renderPassCountNdx = 0; renderPassCountNdx < DE_LENGTH_OF_ARRAY(renderPassCounts); renderPassCountNdx++) |
| { |
| vector<RenderPass> renderPasses; |
| |
| for (size_t renderPassNdx = 0; renderPassNdx < renderPassCounts[renderPassCountNdx]; renderPassNdx++) |
| { |
| vector<Attachment> attachments; |
| vector<AttachmentReference> colorAttachmentReferences; |
| |
| const VkFormat format (VK_FORMAT_R8G8B8A8_UNORM); |
| const VkSampleCountFlagBits sampleCount (VK_SAMPLE_COUNT_1_BIT); |
| const VkAttachmentLoadOp loadOp (VK_ATTACHMENT_LOAD_OP_DONT_CARE); |
| const VkAttachmentStoreOp storeOp (VK_ATTACHMENT_STORE_OP_STORE); |
| const VkAttachmentLoadOp stencilLoadOp (VK_ATTACHMENT_LOAD_OP_DONT_CARE); |
| const VkAttachmentStoreOp stencilStoreOp (VK_ATTACHMENT_STORE_OP_DONT_CARE); |
| const VkImageLayout initialLayout (VK_IMAGE_LAYOUT_UNDEFINED); |
| const VkImageLayout finalLayout (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); |
| const VkImageLayout subpassLayout (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); |
| |
| attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalLayout)); |
| colorAttachmentReferences.push_back(AttachmentReference((deUint32)0, subpassLayout)); |
| |
| const VkImageLayout depthStencilLayout (VK_IMAGE_LAYOUT_GENERAL); |
| const vector<Subpass> subpasses (1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector<AttachmentReference>(), colorAttachmentReferences, vector<AttachmentReference>(), AttachmentReference(VK_ATTACHMENT_UNUSED, depthStencilLayout), vector<deUint32>())); |
| vector<SubpassDependency> deps; |
| |
| // The first render pass lets the implementation add all subpass dependencies implicitly. |
| // On the following passes only the dependency from external to first subpass is defined as |
| // we need to make sure we have the image ready from previous render pass. In this case |
| // the dependency from subpass 0 to external is added implicitly by the implementation. |
| if (renderPassNdx > 0) |
| { |
| deps.push_back(SubpassDependency(VK_SUBPASS_EXTERNAL, // deUint32 srcPass |
| 0, // deUint32 dstPass |
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask |
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags dstStageMask |
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask |
| VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags dstAccessMask |
| 0)); // VkDependencyFlags flags |
| } |
| |
| RenderPass renderPass (attachments, subpasses, deps); |
| |
| renderPasses.push_back(renderPass); |
| } |
| |
| const deUint32 blurKernel (12u); |
| const ExternalTestConfig testConfig (VK_FORMAT_R8G8B8A8_UNORM, UVec2(128, 128), renderPasses, renderPassType, blurKernel); |
| const string testName ("render_passes_" + de::toString(renderPassCounts[renderPassCountNdx])); |
| |
| implicitGroup->addChild(new InstanceFactory1<ExternalDependencyTestInstance, ExternalTestConfig, ExternalPrograms>(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName.c_str(), testName.c_str(), testConfig)); |
| } |
| |
| group->addChild(implicitGroup.release()); |
| } |
| |
| // Test late fragment operations using depth_stencil attachments in multipass rendering |
| { |
| const UVec2 renderSizes[] = |
| { |
| UVec2(32, 32), |
| UVec2(64, 64), |
| UVec2(128, 128) |
| }; |
| |
| const deUint32 subpassCounts[] = { 2u, 3u, 5u }; |
| |
| // Implementations must support at least one of the following formats |
| // for depth_stencil attachments |
| const VkFormat formats[] = |
| { |
| VK_FORMAT_D24_UNORM_S8_UINT, |
| VK_FORMAT_D32_SFLOAT_S8_UINT |
| }; |
| |
| de::MovePtr<tcu::TestCaseGroup> lateFragmentTestsGroup (new tcu::TestCaseGroup(testCtx, "late_fragment_tests", "wait for late fragment tests")); |
| |
| for (size_t renderSizeNdx = 0; renderSizeNdx < DE_LENGTH_OF_ARRAY(renderSizes); renderSizeNdx++) |
| { |
| string renderSizeGroupName ("render_size_" + de::toString(renderSizes[renderSizeNdx].x()) + "_" + de::toString(renderSizes[renderSizeNdx].y())); |
| de::MovePtr<tcu::TestCaseGroup> renderSizeGroup (new tcu::TestCaseGroup(testCtx, renderSizeGroupName.c_str(), renderSizeGroupName.c_str())); |
| |
| for (size_t subpassCountNdx = 0; subpassCountNdx < DE_LENGTH_OF_ARRAY(subpassCounts); subpassCountNdx++) |
| { |
| string subpassGroupName ("subpass_count_" + de::toString(subpassCounts[subpassCountNdx])); |
| de::MovePtr<tcu::TestCaseGroup> subpassCountGroup (new tcu::TestCaseGroup(testCtx, subpassGroupName.c_str(), subpassGroupName.c_str())); |
| |
| for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++) |
| { |
| const deUint32 subpassCount (subpassCounts[subpassCountNdx]); |
| const deUint32 attachmentCount (subpassCount); |
| vector<Subpass> subpasses; |
| vector<Attachment> attachments; |
| vector<SubpassDependency> deps; |
| |
| // Attachments |
| for (size_t attachmentNdx = 0; attachmentNdx < attachmentCount; attachmentNdx++) |
| { |
| const VkFormat format (formats[formatNdx]); |
| const VkSampleCountFlagBits sampleCount (VK_SAMPLE_COUNT_1_BIT); |
| const VkAttachmentLoadOp loadOp (VK_ATTACHMENT_LOAD_OP_CLEAR); |
| const VkAttachmentStoreOp storeOp ((attachmentNdx == attachmentCount - 1) |
| ? VK_ATTACHMENT_STORE_OP_STORE |
| : VK_ATTACHMENT_STORE_OP_DONT_CARE); |
| const VkAttachmentLoadOp stencilLoadOp (VK_ATTACHMENT_LOAD_OP_CLEAR); |
| const VkAttachmentStoreOp stencilStoreOp ((attachmentNdx == attachmentCount - 1) |
| ? VK_ATTACHMENT_STORE_OP_STORE |
| : VK_ATTACHMENT_STORE_OP_DONT_CARE); |
| const VkImageLayout initialLayout (VK_IMAGE_LAYOUT_UNDEFINED); |
| const VkImageLayout finalLayout (VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL); |
| |
| attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalLayout)); |
| } |
| |
| // Subpasses |
| for (size_t subpassNdx = 0; subpassNdx < subpassCount; subpassNdx++) |
| { |
| vector<AttachmentReference> inputAttachmentReferences; |
| const VkImageAspectFlags inputAttachmentAspectMask ((renderPassType == RENDERPASS_TYPE_RENDERPASS2) |
| ? static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT) |
| : static_cast<VkImageAspectFlags>(0)); |
| |
| // Input attachment references |
| if (subpassNdx > 0) |
| inputAttachmentReferences.push_back(AttachmentReference((deUint32)subpassNdx - 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, inputAttachmentAspectMask)); |
| |
| subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, inputAttachmentReferences, vector<AttachmentReference>(), vector<AttachmentReference>(), AttachmentReference((deUint32)subpassNdx, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), vector<deUint32>())); |
| |
| // Subpass dependencies from current subpass to previous subpass. |
| // Subpasses will wait for the late fragment operations before reading the contents |
| // of previous subpass. |
| if (subpassNdx > 0) |
| { |
| deps.push_back(SubpassDependency((deUint32)subpassNdx - 1, // deUint32 srcPass |
| (deUint32)subpassNdx, // deUint32 dstPass |
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags srcStageMask |
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
| | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags dstStageMask |
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask |
| VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, // VkAccessFlags dstAccessMask |
| VK_DEPENDENCY_BY_REGION_BIT)); // VkDependencyFlags flags |
| } |
| } |
| |
| const RenderPass renderPass (attachments, subpasses, deps); |
| const SubpassTestConfig testConfig (formats[formatNdx], renderSizes[renderSizeNdx], renderPass, renderPassType); |
| const string format (formatToName(formats[formatNdx]).c_str()); |
| |
| subpassCountGroup->addChild(new InstanceFactory1<SubpassDependencyTestInstance, SubpassTestConfig, SubpassPrograms>(testCtx, tcu::NODETYPE_SELF_VALIDATE, format, format, testConfig)); |
| } |
| |
| renderSizeGroup->addChild(subpassCountGroup.release()); |
| } |
| |
| lateFragmentTestsGroup->addChild(renderSizeGroup.release()); |
| } |
| |
| group->addChild(lateFragmentTestsGroup.release()); |
| } |
| |
| // Test subpass self dependency |
| { |
| const UVec2 renderSizes[] = |
| { |
| UVec2(64, 64), |
| UVec2(128, 128), |
| UVec2(512, 512) |
| }; |
| |
| de::MovePtr<tcu::TestCaseGroup> selfDependencyGroup (new tcu::TestCaseGroup(testCtx, "self_dependency", "self_dependency")); |
| |
| for (size_t renderSizeNdx = 0; renderSizeNdx < DE_LENGTH_OF_ARRAY(renderSizes); renderSizeNdx++) |
| { |
| string groupName ("render_size_" + de::toString(renderSizes[renderSizeNdx].x()) + "_" + de::toString(renderSizes[renderSizeNdx].y())); |
| de::MovePtr<tcu::TestCaseGroup> renderSizeGroup (new tcu::TestCaseGroup(testCtx, groupName.c_str(), groupName.c_str())); |
| |
| const SubpassSelfDependencyBackwardsTestConfig testConfig (VK_FORMAT_R8G8B8A8_UNORM, renderSizes[renderSizeNdx], renderPassType); |
| renderSizeGroup->addChild(new InstanceFactory1<SubpassSelfDependencyBackwardsTestInstance, SubpassSelfDependencyBackwardsTestConfig, SubpassSelfDependencyBackwardsPrograms>(testCtx, tcu::NODETYPE_SELF_VALIDATE, "geometry_to_indirectdraw", "", testConfig)); |
| |
| selfDependencyGroup->addChild(renderSizeGroup.release()); |
| } |
| |
| group->addChild(selfDependencyGroup.release()); |
| } |
| } |
| } // anonymous |
| |
| tcu::TestCaseGroup* createRenderPassSubpassDependencyTests (tcu::TestContext& testCtx) |
| { |
| return createTestGroup(testCtx, "subpass_dependencies", "Subpass dependency tests", initTests, RENDERPASS_TYPE_LEGACY); |
| } |
| |
| tcu::TestCaseGroup* createRenderPass2SubpassDependencyTests (tcu::TestContext& testCtx) |
| { |
| return createTestGroup(testCtx, "subpass_dependencies", "Subpass dependency tests", initTests, RENDERPASS_TYPE_RENDERPASS2); |
| } |
| } // vkt |