1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2020 The Khronos Group Inc.
6  * Copyright (c) 2020 Valve Corporation
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Vulkan Concurrent Query Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktQueryPoolConcurrentTests.hpp"
26 
27 #include "vktTestCase.hpp"
28 
29 #include "vktDrawImageObjectUtil.hpp"
30 #include "vktDrawBufferObjectUtil.hpp"
31 #include "vktDrawCreateInfoUtil.hpp"
32 #include "vkBuilderUtil.hpp"
33 #include "vkRef.hpp"
34 #include "vkRefUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkQueryUtil.hpp"
38 
39 #include "tcuTestLog.hpp"
40 #include "tcuImageCompare.hpp"
41 
42 #include <memory>
43 
44 namespace vkt
45 {
46 
47 namespace QueryPool
48 {
49 
50 using namespace Draw;
51 
52 namespace
53 {
54 
55 enum QueryType
56 {
57     QUERY_TYPE_OCCLUSION           = vk::VK_QUERY_TYPE_OCCLUSION,
58     QUERY_TYPE_PIPELINE_STATISTICS = vk::VK_QUERY_TYPE_PIPELINE_STATISTICS,
59     QUERY_TYPE_TIMESTAMP           = vk::VK_QUERY_TYPE_TIMESTAMP,
60     NUM_QUERY_POOLS                = 3
61 };
62 
63 struct StateObjects
64 {
65     StateObjects(const vk::DeviceInterface &vk, vkt::Context &context, const int numVertices,
66                  vk::VkPrimitiveTopology primitive);
67     void setVertices(const vk::DeviceInterface &vk, std::vector<tcu::Vec4> vertices);
68 
69     enum
70     {
71         WIDTH  = 128,
72         HEIGHT = 128
73     };
74 
75     vkt::Context &m_context;
76 
77     vk::Move<vk::VkPipeline> m_pipeline;
78     vk::Move<vk::VkPipelineLayout> m_pipelineLayout;
79 
80     de::SharedPtr<Image> m_colorAttachmentImage, m_DepthImage;
81     vk::Move<vk::VkImageView> m_attachmentView;
82     vk::Move<vk::VkImageView> m_depthiew;
83 
84     vk::Move<vk::VkRenderPass> m_renderPass;
85     vk::Move<vk::VkFramebuffer> m_framebuffer;
86 
87     de::SharedPtr<Buffer> m_vertexBuffer;
88 
89     vk::VkFormat m_colorAttachmentFormat;
90 };
91 
StateObjects(const vk::DeviceInterface & vk,vkt::Context & context,const int numVertices,vk::VkPrimitiveTopology primitive)92 StateObjects::StateObjects(const vk::DeviceInterface &vk, vkt::Context &context, const int numVertices,
93                            vk::VkPrimitiveTopology primitive)
94     : m_context(context)
95     , m_colorAttachmentFormat(vk::VK_FORMAT_R8G8B8A8_UNORM)
96 
97 {
98     vk::VkFormat depthFormat  = vk::VK_FORMAT_D16_UNORM;
99     const vk::VkDevice device = m_context.getDevice();
100 
101     //attachment images and views
102     {
103         vk::VkExtent3D imageExtent = {
104             WIDTH,  // width;
105             HEIGHT, // height;
106             1       // depth;
107         };
108 
109         const ImageCreateInfo colorImageCreateInfo(
110             vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, imageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT,
111             vk::VK_IMAGE_TILING_OPTIMAL, vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
112 
113         m_colorAttachmentImage =
114             Image::createAndAlloc(vk, device, colorImageCreateInfo, m_context.getDefaultAllocator(),
115                                   m_context.getUniversalQueueFamilyIndex());
116 
117         const ImageViewCreateInfo attachmentViewInfo(m_colorAttachmentImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D,
118                                                      m_colorAttachmentFormat);
119         m_attachmentView = vk::createImageView(vk, device, &attachmentViewInfo);
120 
121         ImageCreateInfo depthImageCreateInfo(vk::VK_IMAGE_TYPE_2D, depthFormat, imageExtent, 1, 1,
122                                              vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL,
123                                              vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
124 
125         m_DepthImage = Image::createAndAlloc(vk, device, depthImageCreateInfo, m_context.getDefaultAllocator(),
126                                              m_context.getUniversalQueueFamilyIndex());
127 
128         // Construct a depth  view from depth image
129         const ImageViewCreateInfo depthViewInfo(m_DepthImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, depthFormat);
130         m_depthiew = vk::createImageView(vk, device, &depthViewInfo);
131     }
132 
133     {
134         // Renderpass and Framebuffer
135 
136         RenderPassCreateInfo renderPassCreateInfo;
137         renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat,              // format
138                                                                  vk::VK_SAMPLE_COUNT_1_BIT,            // samples
139                                                                  vk::VK_ATTACHMENT_LOAD_OP_CLEAR,      // loadOp
140                                                                  vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // storeOp
141                                                                  vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,  // stencilLoadOp
142                                                                  vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilLoadOp
143                                                                  vk::VK_IMAGE_LAYOUT_GENERAL,          // initialLauout
144                                                                  vk::VK_IMAGE_LAYOUT_GENERAL));        // finalLayout
145 
146         renderPassCreateInfo.addAttachment(
147             AttachmentDescription(depthFormat,                                            // format
148                                   vk::VK_SAMPLE_COUNT_1_BIT,                              // samples
149                                   vk::VK_ATTACHMENT_LOAD_OP_CLEAR,                        // loadOp
150                                   vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,                   // storeOp
151                                   vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,                    // stencilLoadOp
152                                   vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,                   // stencilLoadOp
153                                   vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,   // initialLauout
154                                   vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); // finalLayout
155 
156         const vk::VkAttachmentReference colorAttachmentReference = {
157             0,                          // attachment
158             vk::VK_IMAGE_LAYOUT_GENERAL // layout
159         };
160 
161         const vk::VkAttachmentReference depthAttachmentReference = {
162             1,                                                   // attachment
163             vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // layout
164         };
165 
166         renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
167                                                            0,                                   // flags
168                                                            0,                                   // inputCount
169                                                            DE_NULL,                             // pInputAttachments
170                                                            1,                                   // colorCount
171                                                            &colorAttachmentReference,           // pColorAttachments
172                                                            DE_NULL,                             // pResolveAttachments
173                                                            depthAttachmentReference, // depthStencilAttachment
174                                                            0,                        // preserveCount
175                                                            DE_NULL));                // preserveAttachments
176 
177         m_renderPass = vk::createRenderPass(vk, device, &renderPassCreateInfo);
178 
179         std::vector<vk::VkImageView> attachments(2);
180         attachments[0] = *m_attachmentView;
181         attachments[1] = *m_depthiew;
182 
183         FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, attachments, WIDTH, HEIGHT, 1);
184         m_framebuffer = vk::createFramebuffer(vk, device, &framebufferCreateInfo);
185     }
186 
187     {
188         // Pipeline
189 
190         vk::Unique<vk::VkShaderModule> vs(
191             vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
192         vk::Unique<vk::VkShaderModule> fs(
193             vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
194 
195         const PipelineCreateInfo::ColorBlendState::Attachment attachmentState;
196 
197         const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
198         m_pipelineLayout = vk::createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
199 
200         const vk::VkVertexInputBindingDescription vf_binding_desc = {
201             0,                              // binding;
202             4 * (uint32_t)sizeof(float),    // stride;
203             vk::VK_VERTEX_INPUT_RATE_VERTEX // inputRate
204         };
205 
206         const vk::VkVertexInputAttributeDescription vf_attribute_desc = {
207             0,                                 // location;
208             0,                                 // binding;
209             vk::VK_FORMAT_R32G32B32A32_SFLOAT, // format;
210             0                                  // offset;
211         };
212 
213         const vk::VkPipelineVertexInputStateCreateInfo vf_info = {
214             // sType;
215             vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // pNext;
216             NULL,                                                          // flags;
217             0u,                                                            // vertexBindingDescriptionCount;
218             1,                                                             // pVertexBindingDescriptions;
219             &vf_binding_desc,                                              // vertexAttributeDescriptionCount;
220             1,                                                             // pVertexAttributeDescriptions;
221             &vf_attribute_desc};
222 
223         PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
224         pipelineCreateInfo.addShader(
225             PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
226         pipelineCreateInfo.addShader(
227             PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
228         pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(primitive));
229         pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &attachmentState));
230         const vk::VkViewport viewport = vk::makeViewport(WIDTH, HEIGHT);
231         const vk::VkRect2D scissor    = vk::makeRect2D(WIDTH, HEIGHT);
232         pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport),
233                                                                       std::vector<vk::VkRect2D>(1, scissor)));
234         pipelineCreateInfo.addState(
235             PipelineCreateInfo::DepthStencilState(true, true, vk::VK_COMPARE_OP_GREATER_OR_EQUAL));
236         pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
237         pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
238         pipelineCreateInfo.addState(vf_info);
239         m_pipeline = vk::createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
240     }
241 
242     {
243         // Vertex buffer
244         const size_t kBufferSize = numVertices * sizeof(tcu::Vec4);
245         m_vertexBuffer =
246             Buffer::createAndAlloc(vk, device, BufferCreateInfo(kBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
247                                    m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
248     }
249 }
250 
setVertices(const vk::DeviceInterface & vk,std::vector<tcu::Vec4> vertices)251 void StateObjects::setVertices(const vk::DeviceInterface &vk, std::vector<tcu::Vec4> vertices)
252 {
253     const vk::VkDevice device = m_context.getDevice();
254 
255     tcu::Vec4 *ptr = reinterpret_cast<tcu::Vec4 *>(m_vertexBuffer->getBoundMemory().getHostPtr());
256     std::copy(vertices.begin(), vertices.end(), ptr);
257 
258     vk::flushAlloc(vk, device, m_vertexBuffer->getBoundMemory());
259 }
260 
261 class PrimaryCommandBufferConcurrentTestInstance : public vkt::TestInstance
262 {
263 public:
264     PrimaryCommandBufferConcurrentTestInstance(vkt::Context &context);
265     ~PrimaryCommandBufferConcurrentTestInstance(void);
266 
267 private:
268     tcu::TestStatus iterate(void);
269 
270     enum
271     {
272         NUM_QUERIES_IN_POOL          = 2,
273         QUERY_INDEX_CAPTURE_EMPTY    = 0,
274         QUERY_INDEX_CAPTURE_DRAWCALL = 1,
275         NUM_VERTICES_IN_DRAWCALL     = 3
276     };
277 
278     std::unique_ptr<StateObjects> m_stateObjects;
279     vk::Move<vk::VkQueryPool> m_queryPools[NUM_QUERY_POOLS];
280     bool m_supportedQueryType[NUM_QUERY_POOLS];
281 };
282 
PrimaryCommandBufferConcurrentTestInstance(vkt::Context & context)283 PrimaryCommandBufferConcurrentTestInstance::PrimaryCommandBufferConcurrentTestInstance(vkt::Context &context)
284     : TestInstance(context)
285 {
286     // Check support for multiple query types
287     {
288         for (uint32_t poolNdx = 0; poolNdx < NUM_QUERY_POOLS; poolNdx++)
289             m_supportedQueryType[poolNdx] = false;
290 
291         uint32_t numSupportedQueryTypes            = 0;
292         m_supportedQueryType[QUERY_TYPE_OCCLUSION] = true;
293         numSupportedQueryTypes++;
294 
295         if (context.getDeviceFeatures().pipelineStatisticsQuery)
296         {
297             m_supportedQueryType[QUERY_TYPE_PIPELINE_STATISTICS] = true;
298             numSupportedQueryTypes++;
299         }
300 
301         // Check support for timestamp queries
302         {
303             const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
304             const std::vector<vk::VkQueueFamilyProperties> queueProperties =
305                 vk::getPhysicalDeviceQueueFamilyProperties(context.getInstanceInterface(), context.getPhysicalDevice());
306 
307             DE_ASSERT(queueFamilyIndex < (uint32_t)queueProperties.size());
308 
309             if (queueProperties[queueFamilyIndex].timestampValidBits)
310             {
311                 m_supportedQueryType[QUERY_TYPE_TIMESTAMP] = true;
312                 numSupportedQueryTypes++;
313             }
314         }
315         if (numSupportedQueryTypes < 2)
316             throw tcu::NotSupportedError("Device does not support multiple query types");
317     }
318 
319     m_stateObjects = std::unique_ptr<StateObjects>(new StateObjects(
320         m_context.getDeviceInterface(), m_context, NUM_VERTICES_IN_DRAWCALL, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
321 
322     const vk::VkDevice device     = m_context.getDevice();
323     const vk::DeviceInterface &vk = m_context.getDeviceInterface();
324 
325     for (uint32_t poolNdx = 0; poolNdx < NUM_QUERY_POOLS; poolNdx++)
326     {
327         if (!m_supportedQueryType[poolNdx])
328             continue;
329 
330         vk::VkQueryPoolCreateInfo queryPoolCreateInfo = {
331             vk::VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
332             DE_NULL,
333             0u,
334             static_cast<vk::VkQueryType>(poolNdx),
335             NUM_QUERIES_IN_POOL,
336             0u,
337         };
338         if (poolNdx == QUERY_TYPE_PIPELINE_STATISTICS)
339             queryPoolCreateInfo.pipelineStatistics = vk::VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT;
340 
341         m_queryPools[poolNdx] = createQueryPool(vk, device, &queryPoolCreateInfo, /*pAllocator*/ DE_NULL);
342     }
343 
344     std::vector<tcu::Vec4> vertices(NUM_VERTICES_IN_DRAWCALL);
345     vertices[0] = tcu::Vec4(0.5, 0.5, 0.0, 1.0);
346     vertices[1] = tcu::Vec4(0.5, 0.0, 0.0, 1.0);
347     vertices[2] = tcu::Vec4(0.0, 0.5, 0.0, 1.0);
348     m_stateObjects->setVertices(vk, vertices);
349 }
350 
~PrimaryCommandBufferConcurrentTestInstance(void)351 PrimaryCommandBufferConcurrentTestInstance::~PrimaryCommandBufferConcurrentTestInstance(void)
352 {
353 }
354 
iterate(void)355 tcu::TestStatus PrimaryCommandBufferConcurrentTestInstance::iterate(void)
356 {
357     tcu::TestLog &log             = m_context.getTestContext().getLog();
358     const vk::VkDevice device     = m_context.getDevice();
359     const vk::VkQueue queue       = m_context.getUniversalQueue();
360     const vk::DeviceInterface &vk = m_context.getDeviceInterface();
361 
362     const CmdPoolCreateInfo cmdPoolCreateInfo(m_context.getUniversalQueueFamilyIndex());
363     vk::Move<vk::VkCommandPool> cmdPool = vk::createCommandPool(vk, device, &cmdPoolCreateInfo);
364 
365     vk::Unique<vk::VkCommandBuffer> cmdBuffer(
366         vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
367 
368     beginCommandBuffer(vk, *cmdBuffer);
369 
370     initialTransitionColor2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(),
371                                   vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
372                                   vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
373     initialTransitionDepth2DImage(
374         vk, *cmdBuffer, m_stateObjects->m_DepthImage->object(), vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
375         vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
376         vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
377 
378     std::vector<vk::VkClearValue> renderPassClearValues(2);
379     deMemset(&renderPassClearValues[0], 0, static_cast<int>(renderPassClearValues.size()) * sizeof(vk::VkClearValue));
380 
381     for (uint32_t poolNdx = 0u; poolNdx < NUM_QUERY_POOLS; poolNdx++)
382     {
383         if (m_supportedQueryType[poolNdx])
384             vk.cmdResetQueryPool(*cmdBuffer, *m_queryPools[poolNdx], 0u, NUM_QUERIES_IN_POOL);
385     }
386 
387     beginRenderPass(vk, *cmdBuffer, *m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer,
388                     vk::makeRect2D(0, 0, StateObjects::WIDTH, StateObjects::HEIGHT),
389                     (uint32_t)renderPassClearValues.size(), &renderPassClearValues[0]);
390 
391     vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
392 
393     vk::VkBuffer vertexBuffer                 = m_stateObjects->m_vertexBuffer->object();
394     const vk::VkDeviceSize vertexBufferOffset = 0;
395     vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
396 
397     // Begin all queries
398     for (uint32_t poolNdx = 0u; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
399     {
400         if (m_supportedQueryType[poolNdx])
401             vk.cmdBeginQuery(*cmdBuffer, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_EMPTY, 0u);
402     }
403 
404     // End first capture (should not have any result). Start the second one.
405     for (uint32_t poolNdx = 0u; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
406     {
407         if (m_supportedQueryType[poolNdx])
408         {
409             vk.cmdEndQuery(*cmdBuffer, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_EMPTY);
410             vk.cmdBeginQuery(*cmdBuffer, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_DRAWCALL, 0u);
411         }
412     }
413 
414     vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, 0, 0);
415 
416     if (m_supportedQueryType[QUERY_TYPE_TIMESTAMP])
417         vk.cmdWriteTimestamp(*cmdBuffer, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
418                              *m_queryPools[QUERY_TYPE_TIMESTAMP], QUERY_INDEX_CAPTURE_DRAWCALL);
419 
420     for (uint32_t poolNdx = 0u; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
421     {
422         if (m_supportedQueryType[poolNdx])
423             vk.cmdEndQuery(*cmdBuffer, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_DRAWCALL);
424     }
425 
426     endRenderPass(vk, *cmdBuffer);
427 
428     transition2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_ASPECT_COLOR_BIT,
429                       vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
430                       vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT,
431                       vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
432 
433     endCommandBuffer(vk, *cmdBuffer);
434 
435     submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
436 
437     uint64_t queryResults[NUM_QUERIES_IN_POOL] = {0};
438     size_t queryResultsSize                    = sizeof(queryResults);
439     bool passed                                = true;
440 
441     // Occlusion and pipeline statistics queries verification
442     for (uint32_t poolNdx = 0; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
443     {
444         if (m_supportedQueryType[poolNdx] == false)
445             continue;
446         vk::VkResult queryResult =
447             vk.getQueryPoolResults(device, *m_queryPools[poolNdx], 0, NUM_QUERIES_IN_POOL, queryResultsSize,
448                                    queryResults, sizeof(queryResults[0]), vk::VK_QUERY_RESULT_64_BIT);
449 
450         if (queryResult == vk::VK_NOT_READY)
451         {
452             TCU_FAIL("Query result not available, but vkWaitIdle() was called.");
453         }
454 
455         VK_CHECK(queryResult);
456         std::string name =
457             (poolNdx == QUERY_TYPE_OCCLUSION) ? "OcclusionQueryResults" : "PipelineStatisticsQueryResults";
458         std::string desc =
459             (poolNdx == QUERY_TYPE_OCCLUSION) ? "Occlusion query results" : "PipelineStatistics query results";
460         log << tcu::TestLog::Section(name, desc);
461         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(queryResults); ++ndx)
462         {
463             log << tcu::TestLog::Message << "query[slot == " << ndx << "] result == " << queryResults[ndx]
464                 << tcu::TestLog::EndMessage;
465         }
466 
467         for (uint32_t queryNdx = 0; queryNdx < DE_LENGTH_OF_ARRAY(queryResults); ++queryNdx)
468         {
469             if (queryNdx == QUERY_INDEX_CAPTURE_EMPTY && queryResults[queryNdx] != 0u)
470             {
471                 log << tcu::TestLog::Message
472                     << "vkGetQueryPoolResults returned "
473                        "wrong value of query for index "
474                     << queryNdx << ", expected any zero value, got " << queryResults[0] << "."
475                     << tcu::TestLog::EndMessage;
476                 passed = false;
477             }
478 
479             if (queryNdx != QUERY_INDEX_CAPTURE_EMPTY && queryResults[queryNdx] == 0)
480             {
481                 log << tcu::TestLog::Message
482                     << "vkGetQueryPoolResults returned "
483                        "wrong value of query for index "
484                     << queryNdx << ", expected any non-zero value, got " << queryResults[0] << "."
485                     << tcu::TestLog::EndMessage;
486                 passed = false;
487             }
488         }
489         log << tcu::TestLog::EndSection;
490     }
491 
492     // Timestamp query verification
493     if (m_supportedQueryType[QUERY_TYPE_TIMESTAMP])
494     {
495         std::pair<uint64_t, uint64_t> queryResultsWithAvailabilityBit[NUM_QUERIES_IN_POOL];
496         size_t queryResultsWithAvailabilityBitSize = sizeof(queryResultsWithAvailabilityBit);
497         vk::VkResult queryResult                   = vk.getQueryPoolResults(
498             device, *m_queryPools[QUERY_TYPE_TIMESTAMP], 0, NUM_QUERIES_IN_POOL, queryResultsWithAvailabilityBitSize,
499             &queryResultsWithAvailabilityBit[0], sizeof(queryResultsWithAvailabilityBit[0]),
500             vk::VK_QUERY_RESULT_64_BIT | vk::VK_QUERY_RESULT_WITH_AVAILABILITY_BIT);
501 
502         if (queryResult != vk::VK_NOT_READY)
503         {
504             TCU_FAIL("We don't have available one query, it should return VK_NOT_READY");
505         }
506 
507         log << tcu::TestLog::Section("TimestampQueryResults", "Timestamp query results");
508         for (int ndx = 0; ndx < NUM_QUERIES_IN_POOL; ++ndx)
509         {
510             log << tcu::TestLog::Message << "query[slot == " << ndx
511                 << "] result == " << queryResultsWithAvailabilityBit[ndx].first << tcu::TestLog::EndMessage;
512         }
513 
514         for (uint32_t queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; ++queryNdx)
515         {
516             if (queryNdx == QUERY_INDEX_CAPTURE_EMPTY && (queryResultsWithAvailabilityBit[queryNdx].first != 0u ||
517                                                           queryResultsWithAvailabilityBit[queryNdx].second != 0u))
518             {
519                 log << tcu::TestLog::Message
520                     << "vkGetQueryPoolResults returned "
521                        "either wrong value of query for index "
522                     << queryNdx << " (expected any zero value, got " << queryResultsWithAvailabilityBit[queryNdx].first
523                     << ") or the result is available (" << queryResultsWithAvailabilityBit[queryNdx].second << ")"
524                     << tcu::TestLog::EndMessage;
525                 passed = false;
526             }
527 
528             if (queryNdx != QUERY_INDEX_CAPTURE_EMPTY && (queryResultsWithAvailabilityBit[queryNdx].first == 0u ||
529                                                           queryResultsWithAvailabilityBit[queryNdx].second == 0u))
530             {
531                 log << tcu::TestLog::Message
532                     << "vkGetQueryPoolResults returned "
533                        "either wrong value of query for index "
534                     << queryNdx << " (expected any non-zero value, got " << queryResults[0]
535                     << ") or result is unavailable." << tcu::TestLog::EndMessage;
536                 passed = false;
537             }
538         }
539         log << tcu::TestLog::EndSection;
540     }
541 
542     if (passed)
543     {
544         return tcu::TestStatus(QP_TEST_RESULT_PASS, "Query result verification passed");
545     }
546     return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Query result verification failed");
547 }
548 
549 class SecondaryCommandBufferConcurrentTestInstance : public vkt::TestInstance
550 {
551 public:
552     SecondaryCommandBufferConcurrentTestInstance(vkt::Context &context);
553     ~SecondaryCommandBufferConcurrentTestInstance(void);
554 
555 private:
556     tcu::TestStatus iterate(void);
557 
558     enum
559     {
560         NUM_QUERIES_IN_POOL          = 2,
561         QUERY_INDEX_CAPTURE_EMPTY    = 0,
562         QUERY_INDEX_CAPTURE_DRAWCALL = 1,
563         NUM_VERTICES_IN_DRAWCALL     = 3
564     };
565 
566     std::unique_ptr<StateObjects> m_stateObjects;
567     vk::Move<vk::VkQueryPool> m_queryPools[NUM_QUERY_POOLS];
568     bool m_supportedQueryType[NUM_QUERY_POOLS];
569 };
570 
SecondaryCommandBufferConcurrentTestInstance(vkt::Context & context)571 SecondaryCommandBufferConcurrentTestInstance::SecondaryCommandBufferConcurrentTestInstance(vkt::Context &context)
572     : TestInstance(context)
573 {
574     // Check support for multiple query types
575     {
576         for (uint32_t poolNdx = 0; poolNdx < NUM_QUERY_POOLS; poolNdx++)
577             m_supportedQueryType[poolNdx] = false;
578 
579         uint32_t numSupportedQueryTypes            = 0;
580         m_supportedQueryType[QUERY_TYPE_OCCLUSION] = true;
581         numSupportedQueryTypes++;
582 
583         if (context.getDeviceFeatures().pipelineStatisticsQuery)
584         {
585             m_supportedQueryType[QUERY_TYPE_PIPELINE_STATISTICS] = true;
586             numSupportedQueryTypes++;
587         }
588 
589         // Check support for timestamp queries
590         {
591             const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
592             const std::vector<vk::VkQueueFamilyProperties> queueProperties =
593                 vk::getPhysicalDeviceQueueFamilyProperties(context.getInstanceInterface(), context.getPhysicalDevice());
594 
595             DE_ASSERT(queueFamilyIndex < (uint32_t)queueProperties.size());
596 
597             if (queueProperties[queueFamilyIndex].timestampValidBits)
598             {
599                 m_supportedQueryType[QUERY_TYPE_TIMESTAMP] = true;
600                 numSupportedQueryTypes++;
601             }
602         }
603         if (numSupportedQueryTypes < 2)
604             throw tcu::NotSupportedError("Device does not support multiple query types");
605     }
606 
607     m_stateObjects = std::unique_ptr<StateObjects>(new StateObjects(
608         m_context.getDeviceInterface(), m_context, NUM_VERTICES_IN_DRAWCALL, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
609 
610     const vk::VkDevice device     = m_context.getDevice();
611     const vk::DeviceInterface &vk = m_context.getDeviceInterface();
612 
613     for (uint32_t poolNdx = 0; poolNdx < NUM_QUERY_POOLS; poolNdx++)
614     {
615         if (!m_supportedQueryType[poolNdx])
616             continue;
617 
618         vk::VkQueryPoolCreateInfo queryPoolCreateInfo = {
619             vk::VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
620             DE_NULL,
621             0u,
622             static_cast<vk::VkQueryType>(poolNdx),
623             NUM_QUERIES_IN_POOL,
624             0u,
625         };
626         if (poolNdx == QUERY_TYPE_PIPELINE_STATISTICS)
627             queryPoolCreateInfo.pipelineStatistics = vk::VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT;
628 
629         m_queryPools[poolNdx] = createQueryPool(vk, device, &queryPoolCreateInfo, /*pAllocator*/ DE_NULL);
630     }
631 
632     std::vector<tcu::Vec4> vertices(NUM_VERTICES_IN_DRAWCALL);
633     vertices[0] = tcu::Vec4(0.5, 0.5, 0.0, 1.0);
634     vertices[1] = tcu::Vec4(0.5, 0.0, 0.0, 1.0);
635     vertices[2] = tcu::Vec4(0.0, 0.5, 0.0, 1.0);
636     m_stateObjects->setVertices(vk, vertices);
637 }
638 
~SecondaryCommandBufferConcurrentTestInstance(void)639 SecondaryCommandBufferConcurrentTestInstance::~SecondaryCommandBufferConcurrentTestInstance(void)
640 {
641 }
642 
beginSecondaryCommandBuffer(const vk::DeviceInterface & vk,const vk::VkCommandBuffer secondaryCmdBuffer,const vk::VkCommandBufferInheritanceInfo bufferInheritanceInfo)643 void beginSecondaryCommandBuffer(const vk::DeviceInterface &vk, const vk::VkCommandBuffer secondaryCmdBuffer,
644                                  const vk::VkCommandBufferInheritanceInfo bufferInheritanceInfo)
645 {
646     const vk::VkCommandBufferUsageFlags flags =
647         bufferInheritanceInfo.renderPass != DE_NULL ?
648             (vk::VkCommandBufferUsageFlags)vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT :
649             (vk::VkCommandBufferUsageFlags)0u;
650     const vk::VkCommandBufferBeginInfo beginInfo = {
651         vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // sType
652         DE_NULL,                                         // pNext
653         flags,                                           // flags
654         &bufferInheritanceInfo,                          // pInheritanceInfo
655     };
656     VK_CHECK(vk.beginCommandBuffer(secondaryCmdBuffer, &beginInfo));
657 }
658 
iterate(void)659 tcu::TestStatus SecondaryCommandBufferConcurrentTestInstance::iterate(void)
660 {
661     tcu::TestLog &log             = m_context.getTestContext().getLog();
662     const vk::VkDevice device     = m_context.getDevice();
663     const vk::VkQueue queue       = m_context.getUniversalQueue();
664     const vk::DeviceInterface &vk = m_context.getDeviceInterface();
665     const bool inheritedQueries   = m_context.getDeviceFeatures().inheritedQueries;
666 
667     const CmdPoolCreateInfo cmdPoolCreateInfo(m_context.getUniversalQueueFamilyIndex());
668     vk::Move<vk::VkCommandPool> cmdPool = vk::createCommandPool(vk, device, &cmdPoolCreateInfo);
669 
670     vk::Unique<vk::VkCommandBuffer> cmdBufferPrimary(
671         vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
672     vk::Unique<vk::VkCommandBuffer> cmdBufferSecondary(
673         vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY));
674 
675     // Secondary command buffer recording.
676     {
677         // Begin secondary command buffer
678         const vk::VkCommandBufferInheritanceInfo secCmdBufInheritInfo = {
679             vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
680             DE_NULL,
681             *m_stateObjects->m_renderPass,         // renderPass
682             0u,                                    // subpass
683             *m_stateObjects->m_framebuffer,        // framebuffer
684             inheritedQueries ? VK_TRUE : VK_FALSE, // occlusionQueryEnable
685             (vk::VkQueryControlFlags)0u,           // queryFlags
686             (vk::VkQueryPipelineStatisticFlags)0u, // pipelineStatistics
687         };
688         beginSecondaryCommandBuffer(vk, *cmdBufferSecondary, secCmdBufInheritInfo);
689 
690         vk.cmdBindPipeline(*cmdBufferSecondary, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
691         vk::VkBuffer vertexBuffer                 = m_stateObjects->m_vertexBuffer->object();
692         const vk::VkDeviceSize vertexBufferOffset = 0;
693         vk.cmdBindVertexBuffers(*cmdBufferSecondary, 0, 1, &vertexBuffer, &vertexBufferOffset);
694 
695         if (!inheritedQueries && m_supportedQueryType[QUERY_TYPE_OCCLUSION])
696             vk.cmdBeginQuery(*cmdBufferSecondary, *m_queryPools[QUERY_TYPE_OCCLUSION], QUERY_INDEX_CAPTURE_DRAWCALL,
697                              0u);
698 
699         // Run pipeline statistics queries capture in the second command buffer
700         if (m_supportedQueryType[QUERY_TYPE_PIPELINE_STATISTICS])
701             vk.cmdBeginQuery(*cmdBufferSecondary, *m_queryPools[QUERY_TYPE_PIPELINE_STATISTICS],
702                              QUERY_INDEX_CAPTURE_DRAWCALL, 0u);
703 
704         // Timestamp query happening in the secondary command buffer
705         if (m_supportedQueryType[QUERY_TYPE_TIMESTAMP])
706             vk.cmdWriteTimestamp(*cmdBufferSecondary, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
707                                  *m_queryPools[QUERY_TYPE_TIMESTAMP], QUERY_INDEX_CAPTURE_DRAWCALL);
708 
709         vk.cmdDraw(*cmdBufferSecondary, NUM_VERTICES_IN_DRAWCALL, 1, 0, 0);
710 
711         if (m_supportedQueryType[QUERY_TYPE_PIPELINE_STATISTICS])
712             vk.cmdEndQuery(*cmdBufferSecondary, *m_queryPools[QUERY_TYPE_PIPELINE_STATISTICS],
713                            QUERY_INDEX_CAPTURE_DRAWCALL);
714 
715         if (!inheritedQueries && m_supportedQueryType[QUERY_TYPE_OCCLUSION])
716             vk.cmdEndQuery(*cmdBufferSecondary, *m_queryPools[QUERY_TYPE_OCCLUSION], QUERY_INDEX_CAPTURE_DRAWCALL);
717 
718         endCommandBuffer(vk, *cmdBufferSecondary);
719     }
720 
721     // Primary command buffer recording
722     {
723         beginCommandBuffer(vk, *cmdBufferPrimary);
724 
725         initialTransitionColor2DImage(vk, *cmdBufferPrimary, m_stateObjects->m_colorAttachmentImage->object(),
726                                       vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
727                                       vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
728         initialTransitionDepth2DImage(
729             vk, *cmdBufferPrimary, m_stateObjects->m_DepthImage->object(),
730             vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
731             vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
732 
733         std::vector<vk::VkClearValue> renderPassClearValues(2);
734         deMemset(&renderPassClearValues[0], 0,
735                  static_cast<int>(renderPassClearValues.size()) * sizeof(vk::VkClearValue));
736 
737         for (uint32_t poolNdx = 0u; poolNdx < NUM_QUERY_POOLS; poolNdx++)
738         {
739             if (m_supportedQueryType[poolNdx])
740                 vk.cmdResetQueryPool(*cmdBufferPrimary, *m_queryPools[poolNdx], 0u, NUM_QUERIES_IN_POOL);
741         }
742 
743         for (uint32_t poolNdx = 0u; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
744         {
745             if (m_supportedQueryType[poolNdx])
746                 vk.cmdBeginQuery(*cmdBufferPrimary, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_EMPTY, 0u);
747         }
748 
749         for (uint32_t poolNdx = 0u; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
750         {
751             if (m_supportedQueryType[poolNdx])
752                 vk.cmdEndQuery(*cmdBufferPrimary, *m_queryPools[poolNdx], QUERY_INDEX_CAPTURE_EMPTY);
753         }
754 
755         // Run oclussion queries capture in the primary command buffer, inherit the counters for the secondary command buffer
756         if (inheritedQueries && m_supportedQueryType[QUERY_TYPE_OCCLUSION])
757             vk.cmdBeginQuery(*cmdBufferPrimary, *m_queryPools[QUERY_TYPE_OCCLUSION], QUERY_INDEX_CAPTURE_DRAWCALL, 0u);
758 
759         beginRenderPass(vk, *cmdBufferPrimary, *m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer,
760                         vk::makeRect2D(0, 0, StateObjects::WIDTH, StateObjects::HEIGHT),
761                         (uint32_t)renderPassClearValues.size(), &renderPassClearValues[0],
762                         vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
763 
764         vk.cmdExecuteCommands(*cmdBufferPrimary, 1u, &cmdBufferSecondary.get());
765 
766         endRenderPass(vk, *cmdBufferPrimary);
767 
768         if (inheritedQueries && m_supportedQueryType[QUERY_TYPE_OCCLUSION])
769             vk.cmdEndQuery(*cmdBufferPrimary, *m_queryPools[QUERY_TYPE_OCCLUSION], QUERY_INDEX_CAPTURE_DRAWCALL);
770 
771         transition2DImage(vk, *cmdBufferPrimary, m_stateObjects->m_colorAttachmentImage->object(),
772                           vk::VK_IMAGE_ASPECT_COLOR_BIT, vk::VK_IMAGE_LAYOUT_GENERAL,
773                           vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
774                           vk::VK_ACCESS_TRANSFER_READ_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
775                           vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
776 
777         endCommandBuffer(vk, *cmdBufferPrimary);
778     }
779 
780     submitCommandsAndWait(vk, device, queue, cmdBufferPrimary.get());
781 
782     uint64_t queryResults[NUM_QUERIES_IN_POOL] = {0};
783     size_t queryResultsSize                    = sizeof(queryResults);
784     bool passed                                = true;
785 
786     // Occlusion and pipeline statistics queries verification
787     for (uint32_t poolNdx = 0; poolNdx < QUERY_TYPE_TIMESTAMP; poolNdx++)
788     {
789         if (!m_supportedQueryType[poolNdx])
790             continue;
791         vk::VkResult queryResult =
792             vk.getQueryPoolResults(device, *m_queryPools[poolNdx], 0, NUM_QUERIES_IN_POOL, queryResultsSize,
793                                    queryResults, sizeof(queryResults[0]), vk::VK_QUERY_RESULT_64_BIT);
794 
795         if (queryResult == vk::VK_NOT_READY)
796         {
797             TCU_FAIL("Query result not available, but vkWaitIdle() was called.");
798         }
799 
800         VK_CHECK(queryResult);
801         std::string name =
802             (poolNdx == QUERY_TYPE_OCCLUSION) ? "OcclusionQueryResults" : "PipelineStatisticsQueryResults";
803         std::string desc =
804             (poolNdx == QUERY_TYPE_OCCLUSION) ? "Occlusion query results" : "PipelineStatistics query results";
805         log << tcu::TestLog::Section(name, desc);
806         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(queryResults); ++ndx)
807         {
808             log << tcu::TestLog::Message << "query[slot == " << ndx << "] result == " << queryResults[ndx]
809                 << tcu::TestLog::EndMessage;
810         }
811 
812         for (uint32_t queryNdx = 0; queryNdx < DE_LENGTH_OF_ARRAY(queryResults); ++queryNdx)
813         {
814             if (queryNdx == QUERY_INDEX_CAPTURE_EMPTY && queryResults[queryNdx] != 0u)
815             {
816                 log << tcu::TestLog::Message
817                     << "vkGetQueryPoolResults returned "
818                        "wrong value of query for index "
819                     << queryNdx << ", expected any zero value, got " << queryResults[0] << "."
820                     << tcu::TestLog::EndMessage;
821                 passed = false;
822             }
823 
824             if (queryNdx != QUERY_INDEX_CAPTURE_EMPTY && queryResults[queryNdx] == 0)
825             {
826                 log << tcu::TestLog::Message
827                     << "vkGetQueryPoolResults returned "
828                        "wrong value of query for index "
829                     << queryNdx << ", expected any non-zero value, got " << queryResults[0] << "."
830                     << tcu::TestLog::EndMessage;
831                 passed = false;
832             }
833         }
834         log << tcu::TestLog::EndSection;
835     }
836 
837     // Timestamp query verification
838     if (m_supportedQueryType[QUERY_TYPE_TIMESTAMP])
839     {
840         std::pair<uint64_t, uint64_t> queryResultsWithAvailabilityBit[NUM_QUERIES_IN_POOL];
841         size_t queryResultsWithAvailabilityBitSize = sizeof(queryResultsWithAvailabilityBit);
842         vk::VkResult queryResult                   = vk.getQueryPoolResults(
843             device, *m_queryPools[QUERY_TYPE_TIMESTAMP], 0, NUM_QUERIES_IN_POOL, queryResultsWithAvailabilityBitSize,
844             &queryResultsWithAvailabilityBit[0], sizeof(queryResultsWithAvailabilityBit[0]),
845             vk::VK_QUERY_RESULT_64_BIT | vk::VK_QUERY_RESULT_WITH_AVAILABILITY_BIT);
846 
847         if (queryResult != vk::VK_NOT_READY)
848         {
849             TCU_FAIL("We don't have available one query, it should return VK_NOT_READY");
850         }
851 
852         log << tcu::TestLog::Section("TimestampQueryResults", "Timestamp query results");
853         for (int ndx = 0; ndx < NUM_QUERIES_IN_POOL; ++ndx)
854         {
855             log << tcu::TestLog::Message << "query[slot == " << ndx
856                 << "] result == " << queryResultsWithAvailabilityBit[ndx].first << tcu::TestLog::EndMessage;
857         }
858 
859         for (uint32_t queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; ++queryNdx)
860         {
861             if (queryNdx == QUERY_INDEX_CAPTURE_EMPTY && (queryResultsWithAvailabilityBit[queryNdx].first != 0u ||
862                                                           queryResultsWithAvailabilityBit[queryNdx].second != 0u))
863             {
864                 log << tcu::TestLog::Message
865                     << "vkGetQueryPoolResults returned "
866                        "either wrong value of query for index "
867                     << queryNdx << " (expected any zero value, got " << queryResultsWithAvailabilityBit[queryNdx].first
868                     << ") or the result is available (" << queryResultsWithAvailabilityBit[queryNdx].second << ")"
869                     << tcu::TestLog::EndMessage;
870                 passed = false;
871             }
872 
873             if (queryNdx != QUERY_INDEX_CAPTURE_EMPTY && (queryResultsWithAvailabilityBit[queryNdx].first == 0u ||
874                                                           queryResultsWithAvailabilityBit[queryNdx].second == 0u))
875             {
876                 log << tcu::TestLog::Message
877                     << "vkGetQueryPoolResults returned "
878                        "either wrong value of query for index "
879                     << queryNdx << " (expected any non-zero value, got " << queryResults[0]
880                     << ") or result is unavailable." << tcu::TestLog::EndMessage;
881                 passed = false;
882             }
883         }
884         log << tcu::TestLog::EndSection;
885     }
886 
887     if (passed)
888     {
889         return tcu::TestStatus(QP_TEST_RESULT_PASS, "Query result verification passed");
890     }
891     return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Query result verification failed");
892 }
893 
894 template <class Instance>
895 class QueryPoolConcurrentTest : public vkt::TestCase
896 {
897 public:
QueryPoolConcurrentTest(tcu::TestContext & context,const char * name)898     QueryPoolConcurrentTest(tcu::TestContext &context, const char *name) : TestCase(context, name)
899     {
900     }
901 
902 private:
createInstance(vkt::Context & context) const903     vkt::TestInstance *createInstance(vkt::Context &context) const
904     {
905         return new Instance(context);
906     }
907 
initPrograms(vk::SourceCollections & programCollection) const908     void initPrograms(vk::SourceCollections &programCollection) const
909     {
910         const std::string fragSrc = std::string("#version 400\n"
911                                                 "layout(location = 0) out vec4 out_FragColor;\n"
912                                                 "void main()\n"
913                                                 "{\n"
914                                                 "    out_FragColor = vec4(0.07, 0.48, 0.75, 1.0);\n"
915                                                 "    if ((int(gl_FragCoord.x) % 2) == (int(gl_FragCoord.y) % 2))\n"
916                                                 "        discard;\n"
917                                                 "}");
918 
919         programCollection.glslSources.add("frag") << glu::FragmentSource(fragSrc.c_str());
920 
921         programCollection.glslSources.add("vert")
922             << glu::VertexSource("#version 430\n"
923                                  "layout(location = 0) in vec4 in_Position;\n"
924                                  "out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };\n"
925                                  "void main() {\n"
926                                  "    gl_Position  = in_Position;\n"
927                                  "    gl_PointSize = 1.0;\n"
928                                  "}\n");
929     }
930 };
931 
932 } // namespace
933 
QueryPoolConcurrentTests(tcu::TestContext & testCtx)934 QueryPoolConcurrentTests::QueryPoolConcurrentTests(tcu::TestContext &testCtx)
935     : TestCaseGroup(testCtx, "concurrent_queries")
936 {
937     /* Left blank on purpose */
938 }
939 
~QueryPoolConcurrentTests(void)940 QueryPoolConcurrentTests::~QueryPoolConcurrentTests(void)
941 {
942     /* Left blank on purpose */
943 }
944 
init(void)945 void QueryPoolConcurrentTests::init(void)
946 {
947     addChild(
948         new QueryPoolConcurrentTest<PrimaryCommandBufferConcurrentTestInstance>(m_testCtx, "primary_command_buffer"));
949     addChild(new QueryPoolConcurrentTest<SecondaryCommandBufferConcurrentTestInstance>(m_testCtx,
950                                                                                        "secondary_command_buffer"));
951 }
952 
953 } // namespace QueryPool
954 } // namespace vkt
955