--- /dev/null
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2020 The Khronos Group Inc.
+ * Copyright (c) 2020 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 Vulkan Concurrent Query Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktQueryPoolConcurrentTests.hpp"
+
+#include "vktTestCase.hpp"
+
+#include "vktDrawImageObjectUtil.hpp"
+#include "vktDrawBufferObjectUtil.hpp"
+#include "vktDrawCreateInfoUtil.hpp"
+#include "vkBuilderUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "vkTypeUtil.hpp"
+#include "vkCmdUtil.hpp"
+#include "vkQueryUtil.hpp"
+
+#include "tcuTestLog.hpp"
+#include "tcuImageCompare.hpp"
+
+#include <memory>
+
+namespace vkt
+{
+
+namespace QueryPool
+{
+
+using namespace Draw;
+
+namespace
+{
+
+enum QueryType
+{
+ QUERY_TYPE_OCCLUSION = vk::VK_QUERY_TYPE_OCCLUSION,
+ QUERY_TYPE_PIPELINE_STATISTICS = vk::VK_QUERY_TYPE_PIPELINE_STATISTICS,
+ QUERY_TYPE_TIMESTAMP = vk::VK_QUERY_TYPE_TIMESTAMP,
+ NUM_QUERY_POOLS = 3
+};
+
+struct StateObjects
+{
+ StateObjects (const vk::DeviceInterface&vk, vkt::Context &context, const int numVertices, vk::VkPrimitiveTopology primitive);
+ void setVertices (const vk::DeviceInterface&vk, std::vector<tcu::Vec4> vertices);
+
+ enum
+ {
+ WIDTH = 128,
+ HEIGHT = 128
+ };
+
+ vkt::Context &m_context;
+
+ vk::Move<vk::VkPipeline> m_pipeline;
+ vk::Move<vk::VkPipelineLayout> m_pipelineLayout;
+
+ de::SharedPtr<Image> m_colorAttachmentImage, m_DepthImage;
+ vk::Move<vk::VkImageView> m_attachmentView;
+ vk::Move<vk::VkImageView> m_depthiew;
+
+ vk::Move<vk::VkRenderPass> m_renderPass;
+ vk::Move<vk::VkFramebuffer> m_framebuffer;
+
+ de::SharedPtr<Buffer> m_vertexBuffer;
+
+ vk::VkFormat m_colorAttachmentFormat;
+};
+
+StateObjects::StateObjects (const vk::DeviceInterface&vk, vkt::Context &context, const int numVertices, vk::VkPrimitiveTopology primitive)
+ : m_context(context)
+ , m_colorAttachmentFormat(vk::VK_FORMAT_R8G8B8A8_UNORM)
+
+{
+ vk::VkFormat depthFormat = vk::VK_FORMAT_D16_UNORM;
+ const vk::VkDevice device = m_context.getDevice();
+
+ //attachment images and views
+ {
+ vk::VkExtent3D imageExtent =
+ {
+ WIDTH, // width;
+ HEIGHT, // height;
+ 1 // depth;
+ };
+
+ const ImageCreateInfo colorImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, imageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL,
+ vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
+
+ m_colorAttachmentImage = Image::createAndAlloc(vk, device, colorImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
+
+ const ImageViewCreateInfo attachmentViewInfo(m_colorAttachmentImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
+ m_attachmentView = vk::createImageView(vk, device, &attachmentViewInfo);
+
+ ImageCreateInfo depthImageCreateInfo(vk::VK_IMAGE_TYPE_2D, depthFormat, imageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL,
+ vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
+
+ m_DepthImage = Image::createAndAlloc(vk, device, depthImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
+
+ // Construct a depth view from depth image
+ const ImageViewCreateInfo depthViewInfo(m_DepthImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, depthFormat);
+ m_depthiew = vk::createImageView(vk, device, &depthViewInfo);
+ }
+
+ {
+ // Renderpass and Framebuffer
+
+ RenderPassCreateInfo renderPassCreateInfo;
+ renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat, // format
+ vk::VK_SAMPLE_COUNT_1_BIT, // samples
+ vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // loadOp
+ vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // storeOp
+ vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp
+ vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilLoadOp
+ vk::VK_IMAGE_LAYOUT_GENERAL, // initialLauout
+ vk::VK_IMAGE_LAYOUT_GENERAL)); // finalLayout
+
+ renderPassCreateInfo.addAttachment(AttachmentDescription(depthFormat, // format
+ vk::VK_SAMPLE_COUNT_1_BIT, // samples
+ vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // loadOp
+ vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // storeOp
+ vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp
+ vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilLoadOp
+ vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // initialLauout
+ vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); // finalLayout
+
+ const vk::VkAttachmentReference colorAttachmentReference =
+ {
+ 0, // attachment
+ vk::VK_IMAGE_LAYOUT_GENERAL // layout
+ };
+
+ const vk::VkAttachmentReference depthAttachmentReference =
+ {
+ 1, // attachment
+ vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // layout
+ };
+
+ renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
+ 0, // flags
+ 0, // inputCount
+ DE_NULL, // pInputAttachments
+ 1, // colorCount
+ &colorAttachmentReference, // pColorAttachments
+ DE_NULL, // pResolveAttachments
+ depthAttachmentReference, // depthStencilAttachment
+ 0, // preserveCount
+ DE_NULL)); // preserveAttachments
+
+ m_renderPass = vk::createRenderPass(vk, device, &renderPassCreateInfo);
+
+ std::vector<vk::VkImageView> attachments(2);
+ attachments[0] = *m_attachmentView;
+ attachments[1] = *m_depthiew;
+
+ FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, attachments, WIDTH, HEIGHT, 1);
+ m_framebuffer = vk::createFramebuffer(vk, device, &framebufferCreateInfo);
+ }
+
+ {
+ // Pipeline
+
+ vk::Unique<vk::VkShaderModule> vs(vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
+ vk::Unique<vk::VkShaderModule> fs(vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
+
+ const PipelineCreateInfo::ColorBlendState::Attachment attachmentState;
+
+ const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
+ m_pipelineLayout = vk::createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
+
+ const vk::VkVertexInputBindingDescription vf_binding_desc =
+ {
+ 0, // binding;
+ 4 * (deUint32)sizeof(float), // stride;
+ vk::VK_VERTEX_INPUT_RATE_VERTEX // inputRate
+ };
+
+ const vk::VkVertexInputAttributeDescription vf_attribute_desc =
+ {
+ 0, // location;
+ 0, // binding;
+ vk::VK_FORMAT_R32G32B32A32_SFLOAT, // format;
+ 0 // offset;
+ };
+
+ const vk::VkPipelineVertexInputStateCreateInfo vf_info =
+ { // sType;
+ vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // pNext;
+ NULL, // flags;
+ 0u, // vertexBindingDescriptionCount;
+ 1, // pVertexBindingDescriptions;
+ &vf_binding_desc, // vertexAttributeDescriptionCount;
+ 1, // pVertexAttributeDescriptions;
+ &vf_attribute_desc
+ };
+
+ PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
+ pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
+ pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
+ pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(primitive));
+ pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &attachmentState));
+ const vk::VkViewport viewport = vk::makeViewport(WIDTH, HEIGHT);
+ const vk::VkRect2D scissor = vk::makeRect2D(WIDTH, HEIGHT);
+ pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
+ pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState(true, true, vk::VK_COMPARE_OP_GREATER_OR_EQUAL));
+ pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
+ pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
+ pipelineCreateInfo.addState(vf_info);
+ m_pipeline = vk::createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
+ }
+
+ {
+ // Vertex buffer
+ const size_t kBufferSize = numVertices * sizeof(tcu::Vec4);
+ m_vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(kBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
+ }
+}
+
+void StateObjects::setVertices (const vk::DeviceInterface&vk, std::vector<tcu::Vec4> vertices)
+{
+ const vk::VkDevice device = m_context.getDevice();
+
+ tcu::Vec4 *ptr = reinterpret_cast<tcu::Vec4*>(m_vertexBuffer->getBoundMemory().getHostPtr());
+ std::copy(vertices.begin(), vertices.end(), ptr);
+
+ vk::flushAlloc(vk, device, m_vertexBuffer->getBoundMemory());
+}
+
+class PrimaryCommandBufferConcurrentTestInstance : public vkt::TestInstance
+{
+public:
+ PrimaryCommandBufferConcurrentTestInstance (vkt::Context &context);
+ ~PrimaryCommandBufferConcurrentTestInstance (void);
+private:
+ tcu::TestStatus iterate (void);
+
+ enum
+ {
+ NUM_QUERIES_IN_POOL = 2,
+ QUERY_INDEX_CAPTURE_EMPTY = 0,
+ QUERY_INDEX_CAPTURE_DRAWCALL = 1,
+ NUM_VERTICES_IN_DRAWCALL = 3
+ };
+
+ std::unique_ptr<StateObjects> m_stateObjects;
+ vk::Move<vk::VkQueryPool> m_queryPools[NUM_QUERY_POOLS];
+ deBool m_supportedQueryType[NUM_QUERY_POOLS];
+};
+
+PrimaryCommandBufferConcurrentTestInstance::PrimaryCommandBufferConcurrentTestInstance (vkt::Context &context)
+ : TestInstance (context)
+{
+ // Check support for multiple query types
+ {
+ for(deUint32 poolNdx = 0; poolNdx < NUM_QUERY_POOLS; poolNdx++)
+ m_supportedQueryType[poolNdx] = DE_FALSE;
+
+ deUint32 numSupportedQueryTypes = 0;
+ m_supportedQueryType[QUERY_TYPE_OCCLUSION] = DE_TRUE;
+ numSupportedQueryTypes++;
+
+ if (context.getDeviceFeatures().pipelineStatisticsQuery)
+ {
+ m_supportedQueryType[QUERY_TYPE_PIPELINE_STATISTICS] = DE_TRUE;
+ numSupportedQueryTypes++;
+ }
+
+ // Check support for timestamp queries
+ {
+ const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
+ const std::vector<vk::VkQueueFamilyProperties> queueProperties = vk::getPhysicalDeviceQueueFamilyProperties(context.getInstanceInterface(), context.getPhysicalDevice());
+
+ DE_ASSERT(queueFamilyIndex < (deUint32)queueProperties.size());
+
+ if (queueProperties[queueFamilyIndex].timestampValidBits)
+ {
+ m_supportedQueryType[QUERY_TYPE_TIMESTAMP] = DE_TRUE;
+ numSupportedQueryTypes++;
+ }
+ }
+ if (numSupportedQueryTypes < 2)
+ throw tcu::NotSupportedError("Device does not support multiple query types");
+ }
+
+ m_stateObjects = std::unique_ptr<StateObjects>(new StateObjects(m_context.getDeviceInterface(), m_context, NUM_VERTICES_IN_DRAWCALL, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
+
+ const vk::VkDevice device = m_context.getDevice();
+ const vk::DeviceInterface& vk = m_context.getDeviceInterface();
+
+ for(deUint32 poolNdx = 0; poolNdx < NUM_QUERY_POOLS; poolNdx++)
+ {
+ if (!m_supportedQueryType[poolNdx])
+ continue;
+
+ vk::VkQueryPoolCreateInfo queryPoolCreateInfo =
+ {
+ vk::VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
+ DE_NULL,
+ 0u,
+ static_cast<vk::VkQueryType>(poolNdx),
+ NUM_QUERIES_IN_POOL,
+ 0u,
+ };
+ if (poolNdx == QUERY_TYPE_PIPELINE_STATISTICS)
+ queryPoolCreateInfo.pipelineStatistics = vk::VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT;
+
+ m_queryPools[poolNdx] = createQueryPool(vk, device, &queryPoolCreateInfo, /*pAllocator*/ DE_NULL);
+ }
+
+ std::vector<tcu::Vec4> vertices(NUM_VERTICES_IN_DRAWCALL);
+ vertices[0] = tcu::Vec4(0.5, 0.5, 0.0, 1.0);
+ vertices[1] = tcu::Vec4(0.5, 0.0, 0.0, 1.0);
+ vertices[2] = tcu::Vec4(0.0, 0.5, 0.0, 1.0);
+ m_stateObjects->setVertices(vk, vertices);
+}
+
+PrimaryCommandBufferConcurrentTestInstance::~PrimaryCommandBufferConcurrentTestInstance (void)
+{
+}
+
+tcu::TestStatus PrimaryCommandBufferConcurrentTestInstance::iterate (void)
+{
+ tcu::TestLog &log = m_context.getTestContext().getLog();
+ const vk::VkDevice device = m_context.getDevice();
+ const vk::VkQueue queue = m_context.getUniversalQueue();
+ const vk::DeviceInterface& vk = m_context.getDeviceInterface();
+
+ const CmdPoolCreateInfo cmdPoolCreateInfo (m_context.getUniversalQueueFamilyIndex());
+ vk::Move<vk::VkCommandPool> cmdPool = vk::createCommandPool(vk, device, &cmdPoolCreateInfo);
+
+ vk::Unique<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
+
+ beginCommandBuffer(vk, *cmdBuffer);
+
+ initialTransitionColor2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
+ vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
+ initialTransitionDepth2DImage(vk, *cmdBuffer, m_stateObjects->m_DepthImage->object(), vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+ vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
+
+ std::vector<vk::VkClearValue> renderPassClearValues(2);
+ deMemset(&renderPassClearValues[0], 0, static_cast<int>(renderPassClearValues.size()) * sizeof(vk::VkClearValue));
+
+ for (deUint32 poolNdx = 0u; poolNdx < NUM_QUERY_POOLS; poolNdx++)
+ {
+ if (m_supportedQueryType[poolNdx])
+ vk.cmdResetQueryPool(*cmdBuffer, *m_queryPools[poolNdx], 0u, NUM_QUERIES_IN_POOL);
+ }
+
+ beginRenderPass(vk, *cmdBuffer, *m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, vk::makeRect2D(0, 0, StateObjects::WIDTH, StateObjects::HEIGHT), (deUint32)renderPassClearValues.size(), &renderPassClearValues[0]);
+
+ vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
+
+ vk::VkBuffer vertexBuffer = m_stateObjects->m_vertexBuffer->object();
+ const vk::VkDeviceSize vertexBufferOffset = 0;
+ vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
+
+ // Begin all queries
+ for (deUint32 poolNdx = 0u; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
+ {
+ if (m_supportedQueryType[poolNdx])
+ vk.cmdBeginQuery(*cmdBuffer, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_EMPTY, 0u);
+ }
+
+ // End first capture (should not have any result). Start the second one.
+ for (deUint32 poolNdx = 0u; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
+ {
+ if (m_supportedQueryType[poolNdx])
+ {
+ vk.cmdEndQuery(*cmdBuffer, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_EMPTY);
+ vk.cmdBeginQuery(*cmdBuffer, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_DRAWCALL, 0u);
+ }
+ }
+
+ vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, 0, 0);
+
+ if (m_supportedQueryType[QUERY_TYPE_TIMESTAMP])
+ vk.cmdWriteTimestamp(*cmdBuffer, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, *m_queryPools[QUERY_TYPE_TIMESTAMP], QUERY_INDEX_CAPTURE_DRAWCALL);
+
+ for (deUint32 poolNdx = 0u; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
+ {
+ if (m_supportedQueryType[poolNdx])
+ vk.cmdEndQuery(*cmdBuffer, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_DRAWCALL);
+ }
+
+ endRenderPass(vk, *cmdBuffer);
+
+ transition2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_ASPECT_COLOR_BIT,
+ vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+ vk::VK_ACCESS_TRANSFER_READ_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
+
+ endCommandBuffer(vk, *cmdBuffer);
+
+ submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
+
+ deUint64 queryResults[NUM_QUERIES_IN_POOL] = { 0 };
+ size_t queryResultsSize = sizeof(queryResults);
+ bool passed = true;
+
+ // Occlusion and pipeline statistics queries verification
+ for (deUint32 poolNdx = 0; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
+ {
+ if (m_supportedQueryType[poolNdx] == DE_FALSE)
+ continue;
+ vk::VkResult queryResult = vk.getQueryPoolResults(device, *m_queryPools[poolNdx], 0, NUM_QUERIES_IN_POOL, queryResultsSize, queryResults, sizeof(queryResults[0]), vk::VK_QUERY_RESULT_64_BIT);
+
+ if (queryResult == vk::VK_NOT_READY)
+ {
+ TCU_FAIL("Query result not available, but vkWaitIdle() was called.");
+ }
+
+ VK_CHECK(queryResult);
+ std::string name = (poolNdx == QUERY_TYPE_OCCLUSION) ? "OcclusionQueryResults" : "PipelineStatisticsQueryResults";
+ std::string desc = (poolNdx == QUERY_TYPE_OCCLUSION) ? "Occlusion query results" : "PipelineStatistics query results";
+ log << tcu::TestLog::Section(name, desc);
+ for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(queryResults); ++ndx)
+ {
+ log << tcu::TestLog::Message << "query[slot == " << ndx
+ << "] result == " << queryResults[ndx] << tcu::TestLog::EndMessage;
+ }
+
+
+ for (deUint32 queryNdx = 0; queryNdx < DE_LENGTH_OF_ARRAY(queryResults); ++queryNdx)
+ {
+ if (queryNdx == QUERY_INDEX_CAPTURE_EMPTY && queryResults[queryNdx] != 0u)
+ {
+ log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
+ "wrong value of query for index "
+ << queryNdx << ", expected any zero value, got "
+ << queryResults[0] << "." << tcu::TestLog::EndMessage;
+ passed = false;
+ }
+
+ if (queryNdx != QUERY_INDEX_CAPTURE_EMPTY && queryResults[queryNdx] == 0)
+ {
+ log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
+ "wrong value of query for index "
+ << queryNdx << ", expected any non-zero value, got "
+ << queryResults[0] << "." << tcu::TestLog::EndMessage;
+ passed = false;
+ }
+ }
+ log << tcu::TestLog::EndSection;
+ }
+
+ // Timestamp query verification
+ if (m_supportedQueryType[QUERY_TYPE_TIMESTAMP])
+ {
+ std::pair<deUint64, deUint64> queryResultsWithAvailabilityBit[NUM_QUERIES_IN_POOL];
+ size_t queryResultsWithAvailabilityBitSize = sizeof(queryResultsWithAvailabilityBit);
+ vk::VkResult queryResult = vk.getQueryPoolResults(device, *m_queryPools[QUERY_TYPE_TIMESTAMP], 0, NUM_QUERIES_IN_POOL, queryResultsWithAvailabilityBitSize, &queryResultsWithAvailabilityBit[0], sizeof(queryResultsWithAvailabilityBit[0]), vk::VK_QUERY_RESULT_64_BIT | vk::VK_QUERY_RESULT_WITH_AVAILABILITY_BIT);
+
+ if (queryResult != vk::VK_NOT_READY)
+ {
+ TCU_FAIL("We don't have available one query, it should return VK_NOT_READY");
+ }
+
+ log << tcu::TestLog::Section("TimestampQueryResults",
+ "Timestamp query results");
+ for (int ndx = 0; ndx < NUM_QUERIES_IN_POOL; ++ndx)
+ {
+ log << tcu::TestLog::Message << "query[slot == " << ndx
+ << "] result == " << queryResultsWithAvailabilityBit[ndx].first << tcu::TestLog::EndMessage;
+ }
+
+
+ for (deUint32 queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; ++queryNdx)
+ {
+ if (queryNdx == QUERY_INDEX_CAPTURE_EMPTY && (queryResultsWithAvailabilityBit[queryNdx].first != 0u || queryResultsWithAvailabilityBit[queryNdx].second != 0u))
+ {
+ log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
+ "either wrong value of query for index "
+ << queryNdx << " (expected any zero value, got "
+ << queryResultsWithAvailabilityBit[queryNdx].first << ") or the result is available (" << queryResultsWithAvailabilityBit[queryNdx].second << ")"
+ << tcu::TestLog::EndMessage;
+ passed = false;
+ }
+
+ if (queryNdx != QUERY_INDEX_CAPTURE_EMPTY && (queryResultsWithAvailabilityBit[queryNdx].first == 0u || queryResultsWithAvailabilityBit[queryNdx].second == 0u))
+ {
+ log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
+ "either wrong value of query for index "
+ << queryNdx << " (expected any non-zero value, got "
+ << queryResults[0] << ") or result is unavailable." << tcu::TestLog::EndMessage;
+ passed = false;
+ }
+ }
+ log << tcu::TestLog::EndSection;
+ }
+
+ if (passed)
+ {
+ return tcu::TestStatus(QP_TEST_RESULT_PASS, "Query result verification passed");
+ }
+ return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Query result verification failed");
+}
+
+class SecondaryCommandBufferConcurrentTestInstance : public vkt::TestInstance
+{
+public:
+ SecondaryCommandBufferConcurrentTestInstance (vkt::Context &context);
+ ~SecondaryCommandBufferConcurrentTestInstance (void);
+private:
+ tcu::TestStatus iterate (void);
+
+ enum
+ {
+ NUM_QUERIES_IN_POOL = 2,
+ QUERY_INDEX_CAPTURE_EMPTY = 0,
+ QUERY_INDEX_CAPTURE_DRAWCALL = 1,
+ NUM_VERTICES_IN_DRAWCALL = 3
+ };
+
+ std::unique_ptr<StateObjects> m_stateObjects;
+ vk::Move<vk::VkQueryPool> m_queryPools[NUM_QUERY_POOLS];
+ deBool m_supportedQueryType[NUM_QUERY_POOLS];
+
+};
+
+SecondaryCommandBufferConcurrentTestInstance::SecondaryCommandBufferConcurrentTestInstance (vkt::Context &context)
+ : TestInstance (context)
+{
+ // Check support for multiple query types
+ {
+ for(deUint32 poolNdx = 0; poolNdx < NUM_QUERY_POOLS; poolNdx++)
+ m_supportedQueryType[poolNdx] = DE_FALSE;
+
+ deUint32 numSupportedQueryTypes = 0;
+ m_supportedQueryType[QUERY_TYPE_OCCLUSION] = DE_TRUE;
+ numSupportedQueryTypes++;
+
+ if (context.getDeviceFeatures().pipelineStatisticsQuery)
+ {
+ m_supportedQueryType[QUERY_TYPE_PIPELINE_STATISTICS] = DE_TRUE;
+ numSupportedQueryTypes++;
+ }
+
+ // Check support for timestamp queries
+ {
+ const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
+ const std::vector<vk::VkQueueFamilyProperties> queueProperties = vk::getPhysicalDeviceQueueFamilyProperties(context.getInstanceInterface(), context.getPhysicalDevice());
+
+ DE_ASSERT(queueFamilyIndex < (deUint32)queueProperties.size());
+
+ if (queueProperties[queueFamilyIndex].timestampValidBits)
+ {
+ m_supportedQueryType[QUERY_TYPE_TIMESTAMP] = DE_TRUE;
+ numSupportedQueryTypes++;
+ }
+ }
+ if (numSupportedQueryTypes < 2)
+ throw tcu::NotSupportedError("Device does not support multiple query types");
+ }
+
+ m_stateObjects = std::unique_ptr<StateObjects>(new StateObjects(m_context.getDeviceInterface(), m_context, NUM_VERTICES_IN_DRAWCALL, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
+
+ const vk::VkDevice device = m_context.getDevice();
+ const vk::DeviceInterface& vk = m_context.getDeviceInterface();
+
+ for(deUint32 poolNdx = 0; poolNdx < NUM_QUERY_POOLS; poolNdx++)
+ {
+ if (!m_supportedQueryType[poolNdx])
+ continue;
+
+ vk::VkQueryPoolCreateInfo queryPoolCreateInfo =
+ {
+ vk::VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
+ DE_NULL,
+ 0u,
+ static_cast<vk::VkQueryType>(poolNdx),
+ NUM_QUERIES_IN_POOL,
+ 0u,
+ };
+ if (poolNdx == QUERY_TYPE_PIPELINE_STATISTICS)
+ queryPoolCreateInfo.pipelineStatistics = vk::VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT;
+
+ m_queryPools[poolNdx] = createQueryPool(vk, device, &queryPoolCreateInfo, /*pAllocator*/ DE_NULL);
+ }
+
+ std::vector<tcu::Vec4> vertices(NUM_VERTICES_IN_DRAWCALL);
+ vertices[0] = tcu::Vec4(0.5, 0.5, 0.0, 1.0);
+ vertices[1] = tcu::Vec4(0.5, 0.0, 0.0, 1.0);
+ vertices[2] = tcu::Vec4(0.0, 0.5, 0.0, 1.0);
+ m_stateObjects->setVertices(vk, vertices);
+}
+
+SecondaryCommandBufferConcurrentTestInstance::~SecondaryCommandBufferConcurrentTestInstance (void)
+{
+}
+
+void beginSecondaryCommandBuffer (const vk::DeviceInterface& vk,
+ const vk::VkCommandBuffer secondaryCmdBuffer,
+ const vk::VkCommandBufferInheritanceInfo bufferInheritanceInfo)
+{
+ const vk::VkCommandBufferUsageFlags flags = bufferInheritanceInfo.renderPass != DE_NULL
+ ? (vk::VkCommandBufferUsageFlags)vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT
+ : (vk::VkCommandBufferUsageFlags)0u;
+ const vk::VkCommandBufferBeginInfo beginInfo =
+ {
+ vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // sType
+ DE_NULL, // pNext
+ flags, // flags
+ &bufferInheritanceInfo, // pInheritanceInfo
+ };
+ VK_CHECK(vk.beginCommandBuffer(secondaryCmdBuffer, &beginInfo));
+}
+
+tcu::TestStatus SecondaryCommandBufferConcurrentTestInstance::iterate (void)
+{
+ tcu::TestLog &log = m_context.getTestContext().getLog();
+ const vk::VkDevice device = m_context.getDevice();
+ const vk::VkQueue queue = m_context.getUniversalQueue();
+ const vk::DeviceInterface& vk = m_context.getDeviceInterface();
+
+ const CmdPoolCreateInfo cmdPoolCreateInfo (m_context.getUniversalQueueFamilyIndex());
+ vk::Move<vk::VkCommandPool> cmdPool = vk::createCommandPool(vk, device, &cmdPoolCreateInfo);
+
+ vk::Unique<vk::VkCommandBuffer> cmdBufferPrimary (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
+ vk::Unique<vk::VkCommandBuffer> cmdBufferSecondary (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY));
+
+ // Secondary command buffer recording.
+ {
+ // Begin secondary command buffer
+ const vk::VkCommandBufferInheritanceInfo secCmdBufInheritInfo =
+ {
+ vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
+ DE_NULL,
+ *m_stateObjects->m_renderPass, // renderPass
+ 0u, // subpass
+ *m_stateObjects->m_framebuffer, // framebuffer
+ VK_TRUE, // occlusionQueryEnable
+ (vk::VkQueryControlFlags)0u, // queryFlags
+ (vk::VkQueryPipelineStatisticFlags)0u, // pipelineStatistics
+ };
+ beginSecondaryCommandBuffer(vk, *cmdBufferSecondary, secCmdBufInheritInfo);
+
+ vk.cmdBindPipeline(*cmdBufferSecondary, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
+ vk::VkBuffer vertexBuffer = m_stateObjects->m_vertexBuffer->object();
+ const vk::VkDeviceSize vertexBufferOffset = 0;
+ vk.cmdBindVertexBuffers(*cmdBufferSecondary, 0, 1, &vertexBuffer, &vertexBufferOffset);
+
+ // Run pipeline statistics queries capture in the second command buffer
+ if (m_supportedQueryType[QUERY_TYPE_PIPELINE_STATISTICS])
+ vk.cmdBeginQuery(*cmdBufferSecondary, *m_queryPools[QUERY_TYPE_PIPELINE_STATISTICS], QUERY_INDEX_CAPTURE_DRAWCALL, 0u);
+
+ // Timestamp query happening in the secondary command buffer
+ if (m_supportedQueryType[QUERY_TYPE_TIMESTAMP])
+ vk.cmdWriteTimestamp(*cmdBufferSecondary, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, *m_queryPools[QUERY_TYPE_TIMESTAMP], QUERY_INDEX_CAPTURE_DRAWCALL);
+
+ vk.cmdDraw(*cmdBufferSecondary, NUM_VERTICES_IN_DRAWCALL, 1, 0, 0);
+
+ if (m_supportedQueryType[QUERY_TYPE_PIPELINE_STATISTICS])
+ vk.cmdEndQuery(*cmdBufferSecondary, *m_queryPools[QUERY_TYPE_PIPELINE_STATISTICS], QUERY_INDEX_CAPTURE_DRAWCALL);
+
+ endCommandBuffer(vk, *cmdBufferSecondary);
+ }
+
+ // Primary command buffer recording
+ {
+ beginCommandBuffer(vk, *cmdBufferPrimary);
+
+ initialTransitionColor2DImage(vk, *cmdBufferPrimary, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
+ vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
+ initialTransitionDepth2DImage(vk, *cmdBufferPrimary, m_stateObjects->m_DepthImage->object(), vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+ vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
+
+ std::vector<vk::VkClearValue> renderPassClearValues(2);
+ deMemset(&renderPassClearValues[0], 0, static_cast<int>(renderPassClearValues.size()) * sizeof(vk::VkClearValue));
+
+ for (deUint32 poolNdx = 0u; poolNdx < NUM_QUERY_POOLS; poolNdx++)
+ {
+ if (m_supportedQueryType[poolNdx])
+ vk.cmdResetQueryPool(*cmdBufferPrimary, *m_queryPools[poolNdx], 0u, NUM_QUERIES_IN_POOL);
+ }
+
+ for (deUint32 poolNdx = 0u; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
+ {
+ if (m_supportedQueryType[poolNdx])
+ vk.cmdBeginQuery(*cmdBufferPrimary, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_EMPTY, 0u);
+ }
+
+ for (deUint32 poolNdx = 0u; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
+ {
+ if (m_supportedQueryType[poolNdx])
+ vk.cmdEndQuery(*cmdBufferPrimary, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_EMPTY);
+ }
+
+ // Run oclussion queries capture in the primary command buffer, inherit the counters for the secondary command buffer
+ if (m_supportedQueryType[QUERY_TYPE_OCCLUSION])
+ vk.cmdBeginQuery(*cmdBufferPrimary, *m_queryPools[QUERY_TYPE_OCCLUSION], QUERY_INDEX_CAPTURE_DRAWCALL, 0u);
+
+ beginRenderPass(vk, *cmdBufferPrimary, *m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, vk::makeRect2D(0, 0, StateObjects::WIDTH, StateObjects::HEIGHT), (deUint32)renderPassClearValues.size(), &renderPassClearValues[0], vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
+
+ vk.cmdExecuteCommands(*cmdBufferPrimary, 1u, &cmdBufferSecondary.get());
+
+ endRenderPass(vk, *cmdBufferPrimary);
+
+ if (m_supportedQueryType[QUERY_TYPE_OCCLUSION])
+ vk.cmdEndQuery(*cmdBufferPrimary, *m_queryPools[QUERY_TYPE_OCCLUSION], QUERY_INDEX_CAPTURE_DRAWCALL);
+
+ transition2DImage(vk, *cmdBufferPrimary,
+ m_stateObjects->m_colorAttachmentImage->object(),
+ vk::VK_IMAGE_ASPECT_COLOR_BIT,
+ vk::VK_IMAGE_LAYOUT_GENERAL,
+ vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+ vk::VK_ACCESS_TRANSFER_READ_BIT,
+ vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+ vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
+
+ endCommandBuffer(vk, *cmdBufferPrimary);
+ }
+
+ submitCommandsAndWait(vk, device, queue, cmdBufferPrimary.get());
+
+ deUint64 queryResults[NUM_QUERIES_IN_POOL] = { 0 };
+ size_t queryResultsSize = sizeof(queryResults);
+ bool passed = true;
+
+ // Occlusion and pipeline statistics queries verification
+ for (deUint32 poolNdx = 0; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
+ {
+ if (!m_supportedQueryType[poolNdx])
+ continue;
+ vk::VkResult queryResult = vk.getQueryPoolResults(device, *m_queryPools[poolNdx], 0, NUM_QUERIES_IN_POOL, queryResultsSize, queryResults, sizeof(queryResults[0]), vk::VK_QUERY_RESULT_64_BIT);
+
+ if (queryResult == vk::VK_NOT_READY)
+ {
+ TCU_FAIL("Query result not available, but vkWaitIdle() was called.");
+ }
+
+ VK_CHECK(queryResult);
+ std::string name = (poolNdx == QUERY_TYPE_OCCLUSION) ? "OcclusionQueryResults" : "PipelineStatisticsQueryResults";
+ std::string desc = (poolNdx == QUERY_TYPE_OCCLUSION) ? "Occlusion query results" : "PipelineStatistics query results";
+ log << tcu::TestLog::Section(name, desc);
+ for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(queryResults); ++ndx)
+ {
+ log << tcu::TestLog::Message << "query[slot == " << ndx
+ << "] result == " << queryResults[ndx] << tcu::TestLog::EndMessage;
+ }
+
+ for (deUint32 queryNdx = 0; queryNdx < DE_LENGTH_OF_ARRAY(queryResults); ++queryNdx)
+ {
+ if (queryNdx == QUERY_INDEX_CAPTURE_EMPTY && queryResults[queryNdx] != 0u)
+ {
+ log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
+ "wrong value of query for index "
+ << queryNdx << ", expected any zero value, got "
+ << queryResults[0] << "." << tcu::TestLog::EndMessage;
+ passed = false;
+ }
+
+ if (queryNdx != QUERY_INDEX_CAPTURE_EMPTY && queryResults[queryNdx] == 0)
+ {
+ log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
+ "wrong value of query for index "
+ << queryNdx << ", expected any non-zero value, got "
+ << queryResults[0] << "." << tcu::TestLog::EndMessage;
+ passed = false;
+ }
+ }
+ log << tcu::TestLog::EndSection;
+ }
+
+ // Timestamp query verification
+ if (m_supportedQueryType[QUERY_TYPE_TIMESTAMP])
+ {
+ std::pair<deUint64, deUint64> queryResultsWithAvailabilityBit[NUM_QUERIES_IN_POOL];
+ size_t queryResultsWithAvailabilityBitSize = sizeof(queryResultsWithAvailabilityBit);
+ vk::VkResult queryResult = vk.getQueryPoolResults(device, *m_queryPools[QUERY_TYPE_TIMESTAMP], 0, NUM_QUERIES_IN_POOL, queryResultsWithAvailabilityBitSize, &queryResultsWithAvailabilityBit[0], sizeof(queryResultsWithAvailabilityBit[0]), vk::VK_QUERY_RESULT_64_BIT | vk::VK_QUERY_RESULT_WITH_AVAILABILITY_BIT);
+
+ if (queryResult != vk::VK_NOT_READY)
+ {
+ TCU_FAIL("We don't have available one query, it should return VK_NOT_READY");
+ }
+
+ log << tcu::TestLog::Section("TimestampQueryResults",
+ "Timestamp query results");
+ for (int ndx = 0; ndx < NUM_QUERIES_IN_POOL; ++ndx)
+ {
+ log << tcu::TestLog::Message << "query[slot == " << ndx
+ << "] result == " << queryResultsWithAvailabilityBit[ndx].first << tcu::TestLog::EndMessage;
+ }
+
+
+ for (deUint32 queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; ++queryNdx)
+ {
+ if (queryNdx == QUERY_INDEX_CAPTURE_EMPTY && (queryResultsWithAvailabilityBit[queryNdx].first != 0u || queryResultsWithAvailabilityBit[queryNdx].second != 0u))
+ {
+ log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
+ "either wrong value of query for index "
+ << queryNdx << " (expected any zero value, got "
+ << queryResultsWithAvailabilityBit[queryNdx].first << ") or the result is available (" << queryResultsWithAvailabilityBit[queryNdx].second << ")"
+ << tcu::TestLog::EndMessage;
+ passed = false;
+ }
+
+ if (queryNdx != QUERY_INDEX_CAPTURE_EMPTY && (queryResultsWithAvailabilityBit[queryNdx].first == 0u || queryResultsWithAvailabilityBit[queryNdx].second == 0u))
+ {
+ log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
+ "either wrong value of query for index "
+ << queryNdx << " (expected any non-zero value, got "
+ << queryResults[0] << ") or result is unavailable." << tcu::TestLog::EndMessage;
+ passed = false;
+ }
+ }
+ log << tcu::TestLog::EndSection;
+ }
+
+ if (passed)
+ {
+ return tcu::TestStatus(QP_TEST_RESULT_PASS, "Query result verification passed");
+ }
+ return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Query result verification failed");
+}
+
+template<class Instance>
+class QueryPoolConcurrentTest : public vkt::TestCase
+{
+public:
+ QueryPoolConcurrentTest (tcu::TestContext &context, const char *name, const char *description)
+ : TestCase (context, name, description)
+ {
+ }
+private:
+ vkt::TestInstance* createInstance (vkt::Context& context) const
+ {
+ return new Instance(context);
+ }
+
+ void initPrograms(vk::SourceCollections& programCollection) const
+ {
+ const std::string fragSrc = std::string(
+ "#version 400\n"
+ "layout(location = 0) out vec4 out_FragColor;\n"
+ "void main()\n"
+ "{\n"
+ " out_FragColor = vec4(0.07, 0.48, 0.75, 1.0);\n"
+ " if ((int(gl_FragCoord.x) % 2) == (int(gl_FragCoord.y) % 2))\n"
+ " discard;\n"
+ "}");
+
+ programCollection.glslSources.add("frag") << glu::FragmentSource(fragSrc.c_str());
+
+ programCollection.glslSources.add("vert") << glu::VertexSource("#version 430\n"
+ "layout(location = 0) in vec4 in_Position;\n"
+ "out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };\n"
+ "void main() {\n"
+ " gl_Position = in_Position;\n"
+ " gl_PointSize = 1.0;\n"
+ "}\n");
+ }
+};
+
+} //anonymous
+
+QueryPoolConcurrentTests::QueryPoolConcurrentTests (tcu::TestContext &testCtx)
+ : TestCaseGroup(testCtx, "concurrent_queries", "Tests for concurrent queries")
+{
+ /* Left blank on purpose */
+}
+
+QueryPoolConcurrentTests::~QueryPoolConcurrentTests (void)
+{
+ /* Left blank on purpose */
+}
+
+void QueryPoolConcurrentTests::init (void)
+{
+ addChild(new QueryPoolConcurrentTest<PrimaryCommandBufferConcurrentTestInstance>(m_testCtx, "primary_command_buffer", ""));
+ addChild(new QueryPoolConcurrentTest<SecondaryCommandBufferConcurrentTestInstance>(m_testCtx, "secondary_command_buffer", ""));
+}
+
+} //QueryPool
+} //vkt