| /*------------------------------------------------------------------------ |
| * Vulkan Conformance Tests |
| * ------------------------ |
| * |
| * Copyright (c) 2021 The Khronos Group Inc. |
| * Copyright (c) 2021 Valve Corporation. |
| * |
| * 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 Pipeline Bind Point Tests |
| *//*--------------------------------------------------------------------*/ |
| #include "vktPipelineBindPointTests.hpp" |
| #include "vktPipelineImageUtil.hpp" |
| |
| #include "vkObjUtil.hpp" |
| #include "vkBuilderUtil.hpp" |
| #include "vkCmdUtil.hpp" |
| #include "vkTypeUtil.hpp" |
| #include "vkRefUtil.hpp" |
| #include "vkBarrierUtil.hpp" |
| #include "vkBufferWithMemory.hpp" |
| #include "vkImageWithMemory.hpp" |
| #include "vkRayTracingUtil.hpp" |
| |
| #include "tcuVector.hpp" |
| |
| #include <algorithm> |
| #include <string> |
| #include <sstream> |
| #include <type_traits> |
| #include <utility> |
| |
| namespace vkt |
| { |
| namespace pipeline |
| { |
| |
| namespace |
| { |
| |
| using namespace vk; |
| |
| // These operations will be tried in different orders. |
| // To avoid combinatory explosions, we'll only use two pipeline types per test, which means 2 pipeline bind operations and 2 related set bind operations. |
| // The following types will be mixed: (graphics, compute), (graphics, ray tracing) and (compute, ray tracing). |
| enum class SetupOp |
| { |
| BIND_GRAPHICS_PIPELINE = 0, |
| BIND_COMPUTE_PIPELINE = 1, |
| BIND_RAYTRACING_PIPELINE = 2, |
| BIND_GRAPHICS_SET = 3, |
| BIND_COMPUTE_SET = 4, |
| BIND_RAYTRACING_SET = 5, |
| OP_COUNT = 6, |
| }; |
| |
| // How to bind each set. |
| enum class SetUpdateType |
| { |
| WRITE = 0, |
| PUSH = 1, |
| PUSH_WITH_TEMPLATE = 2, |
| TYPE_COUNT = 3, |
| }; |
| |
| // Types of operations to dispatch. They will be tried in different orders and are related to the setup sequence. |
| enum class DispatchOp |
| { |
| DRAW = 0, |
| COMPUTE = 1, |
| TRACE_RAYS = 2, |
| OP_COUNT = 3, |
| }; |
| |
| constexpr auto kTestBindPoints = 2; // Two bind points per test. |
| constexpr auto kSetupSequenceSize = kTestBindPoints * 2; // For each bind point: bind pipeline and bind set. |
| constexpr auto kDispatchSequenceSize = kTestBindPoints; // Dispatch two types of work, matching the bind points being used. |
| |
| using SetupSequence = tcu::Vector<SetupOp, kSetupSequenceSize>; |
| using DispatchSequence = tcu::Vector<DispatchOp, kDispatchSequenceSize>; |
| |
| // Test parameters. |
| struct TestParams |
| { |
| SetUpdateType graphicsSetUpdateType; |
| SetUpdateType computeSetUpdateType; |
| SetUpdateType rayTracingSetUpdateType; |
| SetupSequence setupSequence; |
| DispatchSequence dispatchSequence; |
| |
| protected: |
| bool hasSetupOp (SetupOp op) const |
| { |
| for (int i = 0; i < decltype(setupSequence)::SIZE; ++i) |
| { |
| if (setupSequence[i] == op) |
| return true; |
| } |
| return false; |
| } |
| |
| bool hasAnyOf (const std::vector<SetupOp>& opVec) const |
| { |
| for (const auto& op : opVec) |
| { |
| if (hasSetupOp(op)) |
| return true; |
| } |
| return false; |
| } |
| |
| public: |
| bool hasGraphics (void) const |
| { |
| const std::vector<SetupOp> setupOps {SetupOp::BIND_GRAPHICS_PIPELINE, SetupOp::BIND_GRAPHICS_SET}; |
| return hasAnyOf(setupOps); |
| } |
| |
| bool hasCompute (void) const |
| { |
| const std::vector<SetupOp> setupOps {SetupOp::BIND_COMPUTE_PIPELINE, SetupOp::BIND_COMPUTE_SET}; |
| return hasAnyOf(setupOps); |
| } |
| |
| bool hasRayTracing (void) const |
| { |
| const std::vector<SetupOp> setupOps {SetupOp::BIND_RAYTRACING_PIPELINE, SetupOp::BIND_RAYTRACING_SET}; |
| return hasAnyOf(setupOps); |
| } |
| |
| }; |
| |
| // Expected output values in each buffer. |
| constexpr deUint32 kExpectedBufferValueGraphics = 1u; |
| constexpr deUint32 kExpectedBufferValueCompute = 2u; |
| constexpr deUint32 kExpectedBufferValueRayTracing = 3u; |
| |
| class BindPointTest : public vkt::TestCase |
| { |
| public: |
| BindPointTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params); |
| virtual ~BindPointTest (void) {} |
| |
| virtual void checkSupport (Context& context) const; |
| virtual void initPrograms (vk::SourceCollections& programCollection) const; |
| virtual TestInstance* createInstance (Context& context) const; |
| |
| protected: |
| TestParams m_params; |
| }; |
| |
| class BindPointInstance : public vkt::TestInstance |
| { |
| public: |
| BindPointInstance (Context& context, const TestParams& params); |
| virtual ~BindPointInstance (void) {} |
| |
| virtual tcu::TestStatus iterate (void); |
| |
| protected: |
| TestParams m_params; |
| }; |
| |
| BindPointTest::BindPointTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params) |
| : vkt::TestCase (testCtx, name, description) |
| , m_params (params) |
| {} |
| |
| void BindPointTest::checkSupport (Context& context) const |
| { |
| if (m_params.graphicsSetUpdateType != SetUpdateType::WRITE || m_params.computeSetUpdateType != SetUpdateType::WRITE) |
| { |
| context.requireDeviceFunctionality("VK_KHR_push_descriptor"); |
| |
| if (m_params.graphicsSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE || m_params.computeSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE) |
| context.requireDeviceFunctionality("VK_KHR_descriptor_update_template"); |
| } |
| |
| if (m_params.hasRayTracing()) |
| context.requireDeviceFunctionality("VK_KHR_ray_tracing_pipeline"); |
| } |
| |
| void BindPointTest::initPrograms (vk::SourceCollections& programCollection) const |
| { |
| // The flags array will only have 1 element. |
| const std::string descriptorDecl = "layout(set=0, binding=0, std430) buffer BufferBlock { uint flag[]; } outBuffer;\n"; |
| |
| if (m_params.hasGraphics()) |
| { |
| std::ostringstream vert; |
| vert |
| << "#version 450\n" |
| << "\n" |
| << "void main()\n" |
| << "{\n" |
| // Full-screen clockwise triangle fan with 4 vertices. |
| << " const float x = (-1.0+2.0*(((gl_VertexIndex+1)&2)>>1));\n" |
| << " const float y = (-1.0+2.0*(( gl_VertexIndex &2)>>1));\n" |
| << " gl_Position = vec4(x, y, 0.0, 1.0);\n" |
| << "}\n" |
| ; |
| |
| // Note: the color attachment will be a 1x1 image, so gl_FragCoord.xy is (0.5, 0.5). |
| std::ostringstream frag; |
| frag |
| << "#version 450\n" |
| << descriptorDecl |
| << "layout(location=0) out vec4 outColor;\n" |
| << "\n" |
| << "void main()\n" |
| << "{\n" |
| << " const uint xCoord = uint(trunc(gl_FragCoord.x));\n" |
| << " const uint yCoord = uint(trunc(gl_FragCoord.y));\n" |
| << " outBuffer.flag[xCoord + yCoord] = " << kExpectedBufferValueGraphics << "u;\n" |
| << " outColor = vec4(0.0, 1.0, 0.0, 1.0);\n" |
| << "}\n" |
| ; |
| |
| programCollection.glslSources.add("vert") << glu::VertexSource(vert.str()); |
| programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str()); |
| } |
| |
| if (m_params.hasCompute()) |
| { |
| // Note: we will only dispatch 1 group. |
| std::ostringstream comp; |
| comp |
| << "#version 450\n" |
| << descriptorDecl |
| << "layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n" |
| << "\n" |
| << "void main()\n" |
| << "{\n" |
| << " const uint index = gl_GlobalInvocationID.x + gl_GlobalInvocationID.y + gl_GlobalInvocationID.z;\n" |
| << " outBuffer.flag[index] = " << kExpectedBufferValueCompute << "u;\n" |
| << "}\n" |
| ; |
| |
| programCollection.glslSources.add("comp") << glu::ComputeSource(comp.str()); |
| } |
| |
| if (m_params.hasRayTracing()) |
| { |
| // We will only call the ray gen shader once. |
| std::ostringstream rgen; |
| rgen |
| << "#version 460\n" |
| << "#extension GL_EXT_ray_tracing : require\n" |
| << descriptorDecl |
| << "\n" |
| << "void main()\n" |
| << "{\n" |
| << " const uint index = gl_LaunchIDEXT.x + gl_LaunchIDEXT.y + gl_LaunchIDEXT.z;\n" |
| << " outBuffer.flag[index] = " << kExpectedBufferValueRayTracing << "u;\n" |
| << "}\n" |
| ; |
| |
| const vk::ShaderBuildOptions buildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true); |
| programCollection.glslSources.add("rgen") << glu::RaygenSource(updateRayTracingGLSL(rgen.str())) << buildOptions; |
| } |
| } |
| |
| vkt::TestInstance* BindPointTest::createInstance (Context& context) const |
| { |
| return new BindPointInstance(context, m_params); |
| } |
| |
| BindPointInstance::BindPointInstance (Context& context, const TestParams& params) |
| : vkt::TestInstance (context) |
| , m_params (params) |
| {} |
| |
| Move<VkDescriptorSetLayout> makeSetLayout(const DeviceInterface& vkd, VkDevice device, VkShaderStageFlags stages, bool push) |
| { |
| VkDescriptorSetLayoutCreateFlags createFlags = 0u; |
| if (push) |
| createFlags |= VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR; |
| |
| DescriptorSetLayoutBuilder builder; |
| builder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stages); |
| return builder.build(vkd, device, createFlags); |
| } |
| |
| void zeroOutAndFlush (const DeviceInterface& vkd, VkDevice device, BufferWithMemory& buffer, VkDeviceSize bufferSize) |
| { |
| auto& alloc = buffer.getAllocation(); |
| void* hostPtr = alloc.getHostPtr(); |
| |
| deMemset(hostPtr, 0, static_cast<size_t>(bufferSize)); |
| flushAlloc(vkd, device, alloc); |
| } |
| |
| void makePoolAndSet (const DeviceInterface& vkd, VkDevice device, VkDescriptorSetLayout layout, Move<VkDescriptorPool>& pool, Move<VkDescriptorSet>& set) |
| { |
| DescriptorPoolBuilder poolBuilder; |
| poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); |
| pool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u); |
| set = makeDescriptorSet(vkd, device, pool.get(), layout); |
| } |
| |
| void writeSetUpdate (const DeviceInterface& vkd, VkDevice device, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size, VkDescriptorSet set) |
| { |
| DescriptorSetUpdateBuilder updateBuilder; |
| const auto bufferInfo = makeDescriptorBufferInfo(buffer, offset, size); |
| updateBuilder.writeSingle(set, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &bufferInfo); |
| updateBuilder.update(vkd, device); |
| } |
| |
| Move<VkDescriptorUpdateTemplate> makeUpdateTemplate (const DeviceInterface& vkd, VkDevice device, VkDescriptorSetLayout setLayout, VkPipelineBindPoint bindPoint, VkPipelineLayout pipelineLayout) |
| { |
| const auto templateEntry = makeDescriptorUpdateTemplateEntry(0u, 0u, 1u, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, static_cast<deUintptr>(0), static_cast<deUintptr>(sizeof(VkDescriptorBufferInfo))); |
| const VkDescriptorUpdateTemplateCreateInfo templateCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkDescriptorUpdateTemplateCreateFlags flags; |
| 1u, // deUint32 descriptorUpdateEntryCount; |
| &templateEntry, // const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries; |
| VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR, // VkDescriptorUpdateTemplateType templateType; |
| setLayout, // VkDescriptorSetLayout descriptorSetLayout; |
| bindPoint, // VkPipelineBindPoint pipelineBindPoint; |
| pipelineLayout, // VkPipelineLayout pipelineLayout; |
| 0u, // deUint32 set; |
| }; |
| return createDescriptorUpdateTemplate(vkd, device, &templateCreateInfo); |
| } |
| |
| void pushBufferDescriptor(const DeviceInterface& vkd, VkCommandBuffer cmdBuffer, VkPipelineBindPoint bindPoint, VkPipelineLayout layout, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size) |
| { |
| const auto bufferInfo = makeDescriptorBufferInfo(buffer, offset, size); |
| const VkWriteDescriptorSet write = |
| { |
| VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| DE_NULL, // VkDescriptorSet dstSet; |
| 0u, // deUint32 dstBinding; |
| 0u, // deUint32 dstArrayElement; |
| 1u, // deUint32 descriptorCount; |
| VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, // VkDescriptorType descriptorType; |
| nullptr, // const VkDescriptorImageInfo* pImageInfo; |
| &bufferInfo, // const VkDescriptorBufferInfo* pBufferInfo; |
| nullptr, // const VkBufferView* pTexelBufferView; |
| }; |
| vkd.cmdPushDescriptorSetKHR(cmdBuffer, bindPoint, layout, 0u, 1u, &write); |
| } |
| |
| void verifyBufferContents (const DeviceInterface& vkd, VkDevice device, const BufferWithMemory& buffer, const std::string& bufferName, deUint32 expected) |
| { |
| auto& bufferAlloc = buffer.getAllocation(); |
| const auto dataPtr = reinterpret_cast<deUint32*>(bufferAlloc.getHostPtr()); |
| deUint32 data; |
| |
| invalidateAlloc(vkd, device, bufferAlloc); |
| deMemcpy(&data, dataPtr, sizeof(data)); |
| |
| if (data != expected) |
| { |
| std::ostringstream msg; |
| msg << "Invalid value found in " << bufferName << " buffer: expected " << expected << " and found " << data; |
| TCU_FAIL(msg.str()); |
| } |
| } |
| |
| VkBufferMemoryBarrier makeBufferBarrier (VkBuffer buffer, VkDeviceSize offset, VkDeviceSize size) |
| { |
| return makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, buffer, offset, size); |
| } |
| |
| void recordBufferBarrier (const DeviceInterface& vkd, VkCommandBuffer cmdBuffer, VkPipelineStageFlagBits stage, const VkBufferMemoryBarrier& barrier) |
| { |
| vkd.cmdPipelineBarrier(cmdBuffer, stage, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, nullptr, 1u, &barrier, 0u, nullptr); |
| } |
| |
| tcu::TestStatus BindPointInstance::iterate (void) |
| { |
| const auto& vki = m_context.getInstanceInterface(); |
| const auto physDev = m_context.getPhysicalDevice(); |
| const auto& vkd = m_context.getDeviceInterface(); |
| const auto device = m_context.getDevice(); |
| const auto qIndex = m_context.getUniversalQueueFamilyIndex(); |
| const auto queue = m_context.getUniversalQueue(); |
| auto& alloc = m_context.getDefaultAllocator(); |
| |
| const auto imageFormat = VK_FORMAT_R8G8B8A8_UNORM; |
| const auto imageExtent = makeExtent3D(1u, 1u, 1u); |
| const auto imageType = VK_IMAGE_TYPE_2D; |
| const auto imageViewType = VK_IMAGE_VIEW_TYPE_2D; |
| const auto imageUsage = static_cast<VkImageUsageFlags>(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); |
| |
| const auto viewport = makeViewport(imageExtent); |
| const auto scissor = makeRect2D(imageExtent); |
| |
| const auto hasGraphics = m_params.hasGraphics(); |
| const auto hasCompute = m_params.hasCompute(); |
| const auto hasRayTracing = m_params.hasRayTracing(); |
| |
| // Storage buffers. |
| const auto bufferSize = static_cast<VkDeviceSize>(sizeof(deUint32)); |
| const auto bufferCreateInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); |
| |
| using BufferWithMemoryPtr = de::MovePtr<BufferWithMemory>; |
| using ImageWithMemoryPtr = de::MovePtr<ImageWithMemory>; |
| |
| BufferWithMemoryPtr graphicsBuffer; |
| BufferWithMemoryPtr computeBuffer; |
| BufferWithMemoryPtr rayTracingBuffer; |
| |
| if (hasGraphics) graphicsBuffer = BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible)); |
| if (hasCompute) computeBuffer = BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible)); |
| if (hasRayTracing) rayTracingBuffer = BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible)); |
| |
| if (hasGraphics) zeroOutAndFlush(vkd, device, *graphicsBuffer, bufferSize); |
| if (hasCompute) zeroOutAndFlush(vkd, device, *computeBuffer, bufferSize); |
| if (hasRayTracing) zeroOutAndFlush(vkd, device, *rayTracingBuffer, bufferSize); |
| |
| ImageWithMemoryPtr colorAttachment; |
| Move<VkImageView> colorAttachmentView; |
| |
| if (hasGraphics) |
| { |
| // Color attachment. |
| const VkImageCreateInfo imageCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkImageCreateFlags flags; |
| imageType, // VkImageType imageType; |
| imageFormat, // VkFormat format; |
| imageExtent, // VkExtent3D extent; |
| 1u, // deUint32 mipLevels; |
| 1u, // deUint32 arrayLayers; |
| VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; |
| VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; |
| imageUsage, // VkImageUsageFlags usage; |
| VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; |
| 1u, // deUint32 queueFamilyIndexCount; |
| &qIndex, // const deUint32* pQueueFamilyIndices; |
| VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; |
| }; |
| |
| const auto subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u); |
| colorAttachment = ImageWithMemoryPtr(new ImageWithMemory(vkd, device, alloc, imageCreateInfo, MemoryRequirement::Any)); |
| colorAttachmentView = makeImageView(vkd, device, colorAttachment->get(), imageViewType, imageFormat, subresourceRange); |
| } |
| |
| // Command buffer and pool. |
| const auto cmdPool = makeCommandPool(vkd, device, qIndex); |
| const auto cmdBufferPtr = allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY); |
| const auto cmdBuffer = cmdBufferPtr.get(); |
| |
| // Set and pipeline layouts. |
| Move<VkDescriptorSetLayout> graphicsSetLayout; |
| Move<VkDescriptorSetLayout> computeSetLayout; |
| Move<VkDescriptorSetLayout> rayTracingSetLayout; |
| |
| if (hasGraphics) graphicsSetLayout = makeSetLayout(vkd, device, VK_SHADER_STAGE_FRAGMENT_BIT, (m_params.graphicsSetUpdateType != SetUpdateType::WRITE)); |
| if (hasCompute) computeSetLayout = makeSetLayout(vkd, device, VK_SHADER_STAGE_COMPUTE_BIT, (m_params.computeSetUpdateType != SetUpdateType::WRITE)); |
| if (hasRayTracing) rayTracingSetLayout = makeSetLayout(vkd, device, VK_SHADER_STAGE_RAYGEN_BIT_KHR, (m_params.rayTracingSetUpdateType != SetUpdateType::WRITE)); |
| |
| Move<VkPipelineLayout> graphicsPipelineLayout; |
| Move<VkPipelineLayout> computePipelineLayout; |
| Move<VkPipelineLayout> rayTracingPipelineLayout; |
| |
| if (hasGraphics) graphicsPipelineLayout = makePipelineLayout(vkd, device, graphicsSetLayout.get()); |
| if (hasCompute) computePipelineLayout = makePipelineLayout(vkd, device, computeSetLayout.get()); |
| if (hasRayTracing) rayTracingPipelineLayout = makePipelineLayout(vkd, device, rayTracingSetLayout.get()); |
| |
| // Shader modules. |
| Move<VkShaderModule> vertShader; |
| Move<VkShaderModule> fragShader; |
| Move<VkShaderModule> compShader; |
| Move<VkShaderModule> rgenShader; |
| |
| if (hasGraphics) vertShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u); |
| if (hasGraphics) fragShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u); |
| if (hasCompute) compShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("comp"), 0u); |
| if (hasRayTracing) rgenShader = createShaderModule(vkd, device, m_context.getBinaryCollection().get("rgen"), 0u); |
| |
| Move<VkRenderPass> renderPass; |
| Move<VkFramebuffer> framebuffer; |
| Move<VkPipeline> graphicsPipeline; |
| |
| if (hasGraphics) |
| { |
| // Render pass and framebuffer. |
| renderPass = makeRenderPass(vkd, device, imageFormat); |
| framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorAttachmentView.get(), imageExtent.width, imageExtent.height); |
| |
| // Graphics pipeline. |
| std::vector<VkViewport> viewports(1u, viewport); |
| std::vector<VkRect2D> scissors(1u, scissor); |
| |
| const VkPipelineVertexInputStateCreateInfo vertexInputState = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType |
| nullptr, // const void* pNext |
| 0u, // VkPipelineVertexInputStateCreateFlags flags |
| 0u, // deUint32 vertexBindingDescriptionCount |
| nullptr, // const VkVertexInputBindingDescription* pVertexBindingDescriptions |
| 0u, // deUint32 vertexAttributeDescriptionCount |
| nullptr, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions |
| }; |
| |
| graphicsPipeline = makeGraphicsPipeline(vkd, device, graphicsPipelineLayout.get(), |
| vertShader.get(), DE_NULL, DE_NULL, DE_NULL, fragShader.get(), // Shaders. |
| renderPass.get(), viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, 0u, 0u, &vertexInputState); |
| } |
| |
| // Compute pipeline. |
| Move<VkPipeline> computePipeline; |
| |
| if (hasCompute) |
| { |
| const VkPipelineShaderStageCreateInfo computeShaderStageInfo = |
| { |
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkPipelineShaderStageCreateFlags flags; |
| VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage; |
| compShader.get(), // VkShaderModule module; |
| "main", // const char* pName; |
| nullptr, // const VkSpecializationInfo* pSpecializationInfo; |
| }; |
| |
| const VkComputePipelineCreateInfo computePipelineCreateInfo = |
| { |
| VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType; |
| nullptr, // const void* pNext; |
| 0u, // VkPipelineCreateFlags flags; |
| computeShaderStageInfo, // VkPipelineShaderStageCreateInfo stage; |
| computePipelineLayout.get(), // VkPipelineLayout layout; |
| DE_NULL, // VkPipeline basePipelineHandle; |
| 0u, // deInt32 basePipelineIndex; |
| }; |
| |
| computePipeline = createComputePipeline(vkd, device, DE_NULL, &computePipelineCreateInfo); |
| } |
| |
| // Ray tracing pipeline and shader binding tables. |
| using RayTracingPipelineHelperPtr = de::MovePtr<RayTracingPipeline>; |
| |
| RayTracingPipelineHelperPtr rayTracingPipelineHelper; |
| Move<VkPipeline> rayTracingPipeline; |
| BufferWithMemoryPtr raygenSBT; |
| |
| VkStridedDeviceAddressRegionKHR raygenSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0); |
| VkStridedDeviceAddressRegionKHR missSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0); |
| VkStridedDeviceAddressRegionKHR hitSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0); |
| VkStridedDeviceAddressRegionKHR callableSBTRegion = makeStridedDeviceAddressRegionKHR(DE_NULL, 0, 0); |
| |
| if (hasRayTracing) |
| { |
| const auto rtProperties = makeRayTracingProperties(vki, physDev); |
| const auto shaderGroupHandleSize = rtProperties->getShaderGroupHandleSize(); |
| const auto shaderGroupBaseAlignment = rtProperties->getShaderGroupBaseAlignment(); |
| rayTracingPipelineHelper = RayTracingPipelineHelperPtr(new RayTracingPipeline()); |
| |
| rayTracingPipelineHelper->addShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenShader, 0); |
| rayTracingPipeline = rayTracingPipelineHelper->createPipeline(vkd, device, rayTracingPipelineLayout.get()); |
| |
| raygenSBT = rayTracingPipelineHelper->createShaderBindingTable(vkd, device, rayTracingPipeline.get(), alloc, shaderGroupHandleSize, shaderGroupBaseAlignment, 0, 1); |
| raygenSBTRegion = makeStridedDeviceAddressRegionKHR(getBufferDeviceAddress(vkd, device, raygenSBT->get(), 0), shaderGroupHandleSize, shaderGroupHandleSize); |
| } |
| |
| // Descriptor pools and sets if needed. |
| Move<VkDescriptorPool> graphicsDescriptorPool; |
| Move<VkDescriptorPool> computeDescriptorPool; |
| Move<VkDescriptorPool> rayTracingDescriptorPool; |
| Move<VkDescriptorSet> graphicsDescritorSet; |
| Move<VkDescriptorSet> computeDescriptorSet; |
| Move<VkDescriptorSet> rayTracingDescriptorSet; |
| |
| if (m_params.graphicsSetUpdateType == SetUpdateType::WRITE) |
| { |
| makePoolAndSet(vkd, device, graphicsSetLayout.get(), graphicsDescriptorPool, graphicsDescritorSet); |
| writeSetUpdate(vkd, device, graphicsBuffer->get(), 0ull, bufferSize, graphicsDescritorSet.get()); |
| } |
| |
| if (m_params.computeSetUpdateType == SetUpdateType::WRITE) |
| { |
| makePoolAndSet(vkd, device, computeSetLayout.get(), computeDescriptorPool, computeDescriptorSet); |
| writeSetUpdate(vkd, device, computeBuffer->get(), 0ull, bufferSize, computeDescriptorSet.get()); |
| } |
| |
| if (m_params.rayTracingSetUpdateType == SetUpdateType::WRITE) |
| { |
| makePoolAndSet(vkd, device, rayTracingSetLayout.get(), rayTracingDescriptorPool, rayTracingDescriptorSet); |
| writeSetUpdate(vkd, device, rayTracingBuffer->get(), 0ull, bufferSize, rayTracingDescriptorSet.get()); |
| } |
| |
| // Templates if needed. |
| Move<VkDescriptorUpdateTemplate> graphicsUpdateTemplate; |
| Move<VkDescriptorUpdateTemplate> computeUpdateTemplate; |
| Move<VkDescriptorUpdateTemplate> rayTracingUpdateTemplate; |
| |
| if (m_params.graphicsSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE) |
| graphicsUpdateTemplate = makeUpdateTemplate(vkd, device, graphicsSetLayout.get(), VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout.get()); |
| |
| if (m_params.computeSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE) |
| computeUpdateTemplate = makeUpdateTemplate(vkd, device, computeSetLayout.get(), VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout.get()); |
| |
| if (m_params.rayTracingSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE) |
| rayTracingUpdateTemplate = makeUpdateTemplate(vkd, device, rayTracingSetLayout.get(), VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rayTracingPipelineLayout.get()); |
| |
| beginCommandBuffer(vkd, cmdBuffer); |
| |
| // Helper flags to check the test has been specified properly. |
| bool boundGraphicsPipeline = false; |
| bool boundGraphicsSet = false; |
| bool boundComputePipeline = false; |
| bool boundComputeSet = false; |
| bool boundRayTracingPipeline = false; |
| bool boundRayTracingSet = false; |
| |
| // Setup operations in desired order. |
| for (int i = 0; i < decltype(m_params.setupSequence)::SIZE; ++i) |
| { |
| const auto& setupOp = m_params.setupSequence[i]; |
| switch (setupOp) |
| { |
| case SetupOp::BIND_GRAPHICS_PIPELINE: |
| vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get()); |
| boundGraphicsPipeline = true; |
| break; |
| |
| case SetupOp::BIND_COMPUTE_PIPELINE: |
| vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline.get()); |
| boundComputePipeline = true; |
| break; |
| |
| case SetupOp::BIND_RAYTRACING_PIPELINE: |
| vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rayTracingPipeline.get()); |
| boundRayTracingPipeline = true; |
| break; |
| |
| case SetupOp::BIND_GRAPHICS_SET: |
| if (m_params.graphicsSetUpdateType == SetUpdateType::WRITE) |
| vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout.get(), 0u, 1u, &graphicsDescritorSet.get(), 0u, nullptr); |
| else if (m_params.graphicsSetUpdateType == SetUpdateType::PUSH) |
| pushBufferDescriptor(vkd, cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipelineLayout.get(), graphicsBuffer->get(), 0ull, bufferSize); |
| else if (m_params.graphicsSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE) |
| { |
| const auto bufferInfo = makeDescriptorBufferInfo(graphicsBuffer->get(), 0ull, bufferSize); |
| vkd.cmdPushDescriptorSetWithTemplateKHR(cmdBuffer, graphicsUpdateTemplate.get(), graphicsPipelineLayout.get(), 0u, &bufferInfo); |
| } |
| else |
| DE_ASSERT(false); |
| boundGraphicsSet = true; |
| break; |
| |
| case SetupOp::BIND_COMPUTE_SET: |
| if (m_params.computeSetUpdateType == SetUpdateType::WRITE) |
| vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout.get(), 0u, 1u, &computeDescriptorSet.get(), 0u, nullptr); |
| else if (m_params.computeSetUpdateType == SetUpdateType::PUSH) |
| pushBufferDescriptor(vkd, cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipelineLayout.get(), computeBuffer->get(), 0ull, bufferSize); |
| else if (m_params.computeSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE) |
| { |
| const auto bufferInfo = makeDescriptorBufferInfo(computeBuffer->get(), 0ull, bufferSize); |
| vkd.cmdPushDescriptorSetWithTemplateKHR(cmdBuffer, computeUpdateTemplate.get(), computePipelineLayout.get(), 0u, &bufferInfo); |
| } |
| else |
| DE_ASSERT(false); |
| boundComputeSet = true; |
| break; |
| |
| case SetupOp::BIND_RAYTRACING_SET: |
| if (m_params.rayTracingSetUpdateType == SetUpdateType::WRITE) |
| vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rayTracingPipelineLayout.get(), 0u, 1u, &rayTracingDescriptorSet.get(), 0u, nullptr); |
| else if (m_params.rayTracingSetUpdateType == SetUpdateType::PUSH) |
| pushBufferDescriptor(vkd, cmdBuffer, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rayTracingPipelineLayout.get(), rayTracingBuffer->get(), 0ull, bufferSize); |
| else if (m_params.rayTracingSetUpdateType == SetUpdateType::PUSH_WITH_TEMPLATE) |
| { |
| const auto bufferInfo = makeDescriptorBufferInfo(rayTracingBuffer->get(), 0ull, bufferSize); |
| vkd.cmdPushDescriptorSetWithTemplateKHR(cmdBuffer, rayTracingUpdateTemplate.get(), rayTracingPipelineLayout.get(), 0u, &bufferInfo); |
| } |
| else |
| DE_ASSERT(false); |
| boundRayTracingSet = true; |
| break; |
| |
| default: |
| DE_ASSERT(false); |
| break; |
| } |
| } |
| |
| // Avoid warning in release builds. |
| DE_UNREF(boundGraphicsPipeline); |
| DE_UNREF(boundGraphicsSet); |
| DE_UNREF(boundComputePipeline); |
| DE_UNREF(boundComputeSet); |
| DE_UNREF(boundRayTracingPipeline); |
| DE_UNREF(boundRayTracingSet); |
| |
| // Dispatch operations in desired order. |
| for (int i = 0; i < decltype(m_params.dispatchSequence)::SIZE; ++i) |
| { |
| const auto& dispatchOp = m_params.dispatchSequence[i]; |
| switch (dispatchOp) |
| { |
| case DispatchOp::DRAW: |
| DE_ASSERT(boundGraphicsPipeline && boundGraphicsSet); |
| beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissor, tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); |
| vkd.cmdDraw(cmdBuffer, 4u, 1u, 0u, 0u); |
| endRenderPass(vkd, cmdBuffer); |
| break; |
| |
| case DispatchOp::COMPUTE: |
| DE_ASSERT(boundComputePipeline && boundComputeSet); |
| vkd.cmdDispatch(cmdBuffer, 1u, 1u, 1u); |
| break; |
| |
| case DispatchOp::TRACE_RAYS: |
| DE_ASSERT(boundRayTracingPipeline && boundRayTracingSet); |
| cmdTraceRays(vkd, cmdBuffer, &raygenSBTRegion, &missSBTRegion, &hitSBTRegion, &callableSBTRegion, 1u, 1u, 1u); |
| break; |
| |
| default: |
| DE_ASSERT(false); |
| break; |
| } |
| } |
| |
| if (hasGraphics) |
| { |
| const auto graphicsBufferBarrier = makeBufferBarrier(graphicsBuffer->get(), 0ull, bufferSize); |
| recordBufferBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, graphicsBufferBarrier); |
| } |
| if (hasCompute) |
| { |
| const auto computeBufferBarrier = makeBufferBarrier(computeBuffer->get(), 0ull, bufferSize); |
| recordBufferBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, computeBufferBarrier); |
| } |
| if (hasRayTracing) |
| { |
| const auto rayTracingBufferBarrier = makeBufferBarrier(rayTracingBuffer->get(), 0ull, bufferSize); |
| recordBufferBarrier(vkd, cmdBuffer, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, rayTracingBufferBarrier); |
| } |
| |
| endCommandBuffer(vkd, cmdBuffer); |
| submitCommandsAndWait(vkd, device, queue, cmdBuffer); |
| |
| // Verify storage buffers. |
| if (hasGraphics) verifyBufferContents(vkd, device, *graphicsBuffer, "graphics", kExpectedBufferValueGraphics); |
| if (hasCompute) verifyBufferContents(vkd, device, *computeBuffer, "compute", kExpectedBufferValueCompute); |
| if (hasRayTracing) verifyBufferContents(vkd, device, *rayTracingBuffer, "raytracing", kExpectedBufferValueRayTracing); |
| |
| // Verify color attachment. |
| if (hasGraphics) |
| { |
| const auto textureLevel = readColorAttachment(vkd, device, queue, qIndex, alloc, colorAttachment->get(), imageFormat, tcu::UVec2(imageExtent.width, imageExtent.height)); |
| const auto pixelBuffer = textureLevel->getAccess(); |
| const auto iWidth = static_cast<int>(imageExtent.width); |
| const auto iHeight = static_cast<int>(imageExtent.height); |
| const tcu::Vec4 expectedColor (0.0f, 1.0f, 0.0f, 1.0f); |
| |
| for (int y = 0; y < iHeight; ++y) |
| for (int x = 0; x < iWidth; ++x) |
| { |
| const auto value = pixelBuffer.getPixel(x, y); |
| if (value != expectedColor) |
| { |
| std::ostringstream msg; |
| msg << "Unexpected color found in attachment: expected " << expectedColor << " but found " << value; |
| TCU_FAIL(msg.str()); |
| } |
| } |
| } |
| |
| return tcu::TestStatus::pass("Pass"); |
| } |
| |
| // Auxiliar string conversion functions. |
| |
| std::string toString(SetUpdateType updateType) |
| { |
| switch (updateType) |
| { |
| case SetUpdateType::WRITE: return "write"; |
| case SetUpdateType::PUSH: return "push"; |
| case SetUpdateType::PUSH_WITH_TEMPLATE: return "template_push"; |
| default: DE_ASSERT(false); break; |
| } |
| |
| return ""; |
| } |
| |
| std::string toString(const SetupSequence& setupSequence) |
| { |
| std::ostringstream out; |
| |
| out << "setup"; |
| for (int i = 0; i < std::remove_reference<decltype(setupSequence)>::type::SIZE; ++i) |
| { |
| out << "_"; |
| switch (setupSequence[i]) |
| { |
| case SetupOp::BIND_GRAPHICS_PIPELINE: out << "gp"; break; |
| case SetupOp::BIND_COMPUTE_PIPELINE: out << "cp"; break; |
| case SetupOp::BIND_RAYTRACING_PIPELINE: out << "rp"; break; |
| case SetupOp::BIND_GRAPHICS_SET: out << "gs"; break; |
| case SetupOp::BIND_COMPUTE_SET: out << "cs"; break; |
| case SetupOp::BIND_RAYTRACING_SET: out << "rs"; break; |
| default: DE_ASSERT(false); break; |
| } |
| } |
| |
| return out.str(); |
| } |
| |
| std::string toString(const DispatchSequence& dispatchSequence) |
| { |
| std::ostringstream out; |
| |
| out << "cmd"; |
| for (int i = 0; i < std::remove_reference<decltype(dispatchSequence)>::type::SIZE; ++i) |
| { |
| out << "_"; |
| switch (dispatchSequence[i]) |
| { |
| case DispatchOp::COMPUTE: out << "dispatch"; break; |
| case DispatchOp::DRAW: out << "draw"; break; |
| case DispatchOp::TRACE_RAYS: out << "tracerays"; break; |
| default: DE_ASSERT(false); break; |
| } |
| } |
| |
| return out.str(); |
| } |
| |
| std::string toString(VkPipelineBindPoint point) |
| { |
| if (point == VK_PIPELINE_BIND_POINT_GRAPHICS) return "graphics"; |
| if (point == VK_PIPELINE_BIND_POINT_COMPUTE) return "compute"; |
| if (point == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) return "raytracing"; |
| |
| DE_ASSERT(false); |
| return ""; |
| } |
| |
| } // anonymous |
| |
| tcu::TestCaseGroup* createBindPointTests (tcu::TestContext& testCtx) |
| { |
| using GroupPtr = de::MovePtr<tcu::TestCaseGroup>; |
| using BindPointPair = tcu::Vector<VkPipelineBindPoint, kTestBindPoints>; |
| |
| GroupPtr bindPointGroup(new tcu::TestCaseGroup(testCtx, "bind_point", "Tests checking bind points are independent and used properly")); |
| |
| // Bind point combinations to test. |
| const BindPointPair testPairs[] = |
| { |
| BindPointPair(VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_COMPUTE), |
| BindPointPair(VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR), |
| BindPointPair(VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR), |
| }; |
| |
| for (int testPairIdx = 0; testPairIdx < DE_LENGTH_OF_ARRAY(testPairs); ++testPairIdx) |
| { |
| const auto& testPair = testPairs[testPairIdx]; |
| |
| // Default values. Two of them will be overwritten later. |
| TestParams params; |
| params.graphicsSetUpdateType = SetUpdateType::TYPE_COUNT; |
| params.computeSetUpdateType = SetUpdateType::TYPE_COUNT; |
| params.rayTracingSetUpdateType = SetUpdateType::TYPE_COUNT; |
| |
| // What to test based on the test pair. |
| // Note: updateTypePtrs will tell us which of the set update type members above we need to vary (graphics, compute, ray tracing). |
| SetUpdateType* updateTypePtrs [kTestBindPoints] = { nullptr, nullptr }; |
| SetupOp pipelineBinds [kTestBindPoints] = { SetupOp::OP_COUNT, SetupOp::OP_COUNT }; |
| SetupOp setBinds [kTestBindPoints] = { SetupOp::OP_COUNT, SetupOp::OP_COUNT }; |
| DispatchOp dispatches [kTestBindPoints] = { DispatchOp::OP_COUNT, DispatchOp::OP_COUNT }; |
| |
| for (int elemIdx = 0; elemIdx < std::remove_reference<decltype(testPair)>::type::SIZE; ++elemIdx) |
| { |
| if (testPair[elemIdx] == VK_PIPELINE_BIND_POINT_GRAPHICS) |
| { |
| updateTypePtrs[elemIdx] = ¶ms.graphicsSetUpdateType; // Test different graphics set update types. |
| pipelineBinds[elemIdx] = SetupOp::BIND_GRAPHICS_PIPELINE; |
| setBinds[elemIdx] = SetupOp::BIND_GRAPHICS_SET; |
| dispatches[elemIdx] = DispatchOp::DRAW; |
| } |
| else if (testPair[elemIdx] == VK_PIPELINE_BIND_POINT_COMPUTE) |
| { |
| updateTypePtrs[elemIdx] = ¶ms.computeSetUpdateType; // Test different compute set update types. |
| pipelineBinds[elemIdx] = SetupOp::BIND_COMPUTE_PIPELINE; |
| setBinds[elemIdx] = SetupOp::BIND_COMPUTE_SET; |
| dispatches[elemIdx] = DispatchOp::COMPUTE; |
| } |
| else if (testPair[elemIdx] == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) |
| { |
| updateTypePtrs[elemIdx] = ¶ms.rayTracingSetUpdateType; // Test different ray tracing set update types. |
| pipelineBinds[elemIdx] = SetupOp::BIND_RAYTRACING_PIPELINE; |
| setBinds[elemIdx] = SetupOp::BIND_RAYTRACING_SET; |
| dispatches[elemIdx] = DispatchOp::TRACE_RAYS; |
| } |
| } |
| |
| const std::string pairName = toString(testPair[0]) + "_" + toString(testPair[1]); |
| GroupPtr pairGroup (new tcu::TestCaseGroup(testCtx, pairName.c_str(), "")); |
| |
| // Combine two update types. |
| for (int firstUpdateTypeIdx = 0; firstUpdateTypeIdx < static_cast<int>(SetUpdateType::TYPE_COUNT); ++firstUpdateTypeIdx) |
| for (int secondUpdateTypeIdx = 0; secondUpdateTypeIdx < static_cast<int>(SetUpdateType::TYPE_COUNT); ++ secondUpdateTypeIdx) |
| { |
| const auto firstUpdateType = static_cast<SetUpdateType>(firstUpdateTypeIdx); |
| const auto secondUpdateType = static_cast<SetUpdateType>(secondUpdateTypeIdx); |
| const std::string updateGroupName = toString(firstUpdateType) + "_" + toString(secondUpdateType); |
| GroupPtr updateGroup (new tcu::TestCaseGroup(testCtx, updateGroupName.c_str(), "")); |
| |
| // Change update types of the relevant sets. |
| *updateTypePtrs[0] = firstUpdateType; |
| *updateTypePtrs[1] = secondUpdateType; |
| |
| // Prepare initial permutation of test parameters. |
| params.setupSequence[0] = pipelineBinds[0]; |
| params.setupSequence[1] = pipelineBinds[1]; |
| params.setupSequence[2] = setBinds[0]; |
| params.setupSequence[3] = setBinds[1]; |
| |
| // Permutate setup sequence and dispatch sequence. |
| const auto ssBegin = params.setupSequence.m_data; |
| const auto ssEnd = ssBegin + decltype(params.setupSequence)::SIZE; |
| do |
| { |
| const auto setupGroupName = toString(params.setupSequence); |
| GroupPtr setupGroup (new tcu::TestCaseGroup(testCtx, setupGroupName.c_str(), "")); |
| |
| // Reset dispatch sequence permutation. |
| params.dispatchSequence = dispatches; |
| |
| const auto dsBegin = params.dispatchSequence.m_data; |
| const auto dsEnd = dsBegin + decltype(params.dispatchSequence)::SIZE; |
| do |
| { |
| const auto testName = toString(params.dispatchSequence); |
| setupGroup->addChild(new BindPointTest(testCtx, testName, "", params)); |
| } while (std::next_permutation(dsBegin, dsEnd)); |
| |
| updateGroup->addChild(setupGroup.release()); |
| |
| } while (std::next_permutation(ssBegin, ssEnd)); |
| |
| pairGroup->addChild(updateGroup.release()); |
| } |
| |
| bindPointGroup->addChild(pairGroup.release()); |
| } |
| |
| |
| return bindPointGroup.release(); |
| } |
| |
| } // pipeline |
| } // vkt |
| |