Modify spirv_assembly tests adding dependency on 16bit_storage extension
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / query_pool / vktQueryPoolOcclusionTests.cpp
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2015 The Khronos Group Inc.
6  * Copyright (c) 2015 Intel 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 Occlusion Query Tests
23  *//*--------------------------------------------------------------------*/
24
25 #include "vktQueryPoolOcclusionTests.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 "vkRefUtil.hpp"
34 #include "vkPrograms.hpp"
35
36 #include "tcuTestLog.hpp"
37 #include "tcuResource.hpp"
38 #include "tcuImageCompare.hpp"
39 #include "tcuCommandLine.hpp"
40
41 namespace vkt
42 {
43
44 namespace QueryPool
45 {
46
47 using namespace Draw;
48
49 namespace
50 {
51
52 struct StateObjects
53 {
54                         StateObjects    (const vk::DeviceInterface&vk, vkt::Context &context, const int numVertices, vk::VkPrimitiveTopology primitive);
55         void    setVertices             (const vk::DeviceInterface&vk, std::vector<tcu::Vec4> vertices);
56
57         enum
58         {
59                 WIDTH   = 128,
60                 HEIGHT  = 128
61         };
62
63         vkt::Context &m_context;
64
65         vk::Move<vk::VkPipeline>                m_pipeline;
66         vk::Move<vk::VkPipelineLayout>  m_pipelineLayout;
67
68         de::SharedPtr<Image>                    m_colorAttachmentImage, m_DepthImage;
69         vk::Move<vk::VkImageView>               m_attachmentView;
70         vk::Move<vk::VkImageView>               m_depthiew;
71
72         vk::Move<vk::VkRenderPass>              m_renderPass;
73         vk::Move<vk::VkFramebuffer>             m_framebuffer;
74
75         de::SharedPtr<Buffer>                   m_vertexBuffer;
76
77         vk::VkFormat                                    m_colorAttachmentFormat;
78 };
79
80 StateObjects::StateObjects (const vk::DeviceInterface&vk, vkt::Context &context, const int numVertices, vk::VkPrimitiveTopology primitive)
81         : m_context(context)
82         , m_colorAttachmentFormat(vk::VK_FORMAT_R8G8B8A8_UNORM)
83
84 {
85         vk::VkFormat            depthFormat = vk::VK_FORMAT_D16_UNORM;
86         const vk::VkDevice      device          = m_context.getDevice();
87
88         //attachment images and views
89         {
90                 vk::VkExtent3D imageExtent =
91                 {
92                         WIDTH,  // width;
93                         HEIGHT, // height;
94                         1               // depth;
95                 };
96
97                 const ImageCreateInfo colorImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, imageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL,
98                                                                                                    vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
99
100                 m_colorAttachmentImage  = Image::createAndAlloc(vk, device, colorImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
101
102                 const ImageViewCreateInfo attachmentViewInfo(m_colorAttachmentImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
103                 m_attachmentView                = vk::createImageView(vk, device, &attachmentViewInfo);
104
105                 ImageCreateInfo depthImageCreateInfo(vk::VK_IMAGE_TYPE_2D, depthFormat, imageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL,
106                         vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
107
108                 m_DepthImage                    = Image::createAndAlloc(vk, device, depthImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
109
110                 // Construct a depth  view from depth image
111                 const ImageViewCreateInfo depthViewInfo(m_DepthImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, depthFormat);
112                 m_depthiew                              = vk::createImageView(vk, device, &depthViewInfo);
113         }
114
115         {
116                 // Renderpass and Framebuffer
117
118                 RenderPassCreateInfo renderPassCreateInfo;
119                 renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat,                                                                       // format
120                                                                                                                                         vk::VK_SAMPLE_COUNT_1_BIT,                                                              // samples
121                                                                                                                                         vk::VK_ATTACHMENT_LOAD_OP_CLEAR,                                                // loadOp
122                                                                                                                                         vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,                                   // storeOp
123                                                                                                                                         vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,                                    // stencilLoadOp
124                                                                                                                                         vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,                                   // stencilLoadOp
125                                                                                                                                         vk::VK_IMAGE_LAYOUT_GENERAL,                                                    // initialLauout
126                                                                                                                                         vk::VK_IMAGE_LAYOUT_GENERAL));                                                  // finalLayout
127
128                 renderPassCreateInfo.addAttachment(AttachmentDescription(depthFormat,                                                                                           // format
129                                                                                                                                  vk::VK_SAMPLE_COUNT_1_BIT,                                                                     // samples
130                                                                                                                                  vk::VK_ATTACHMENT_LOAD_OP_CLEAR,                                                       // loadOp
131                                                                                                                                  vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,                                          // storeOp
132                                                                                                                                  vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,                                           // stencilLoadOp
133                                                                                                                                  vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,                                          // stencilLoadOp
134                                                                                                                                  vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,          // initialLauout
135                                                                                                                                  vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL));        // finalLayout
136
137                 const vk::VkAttachmentReference colorAttachmentReference =
138                 {
139                         0,                                                                                                                      // attachment
140                         vk::VK_IMAGE_LAYOUT_GENERAL                                                                     // layout
141                 };
142
143                 const vk::VkAttachmentReference depthAttachmentReference =
144                 {
145                         1,                                                                                                                      // attachment
146                         vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL            // layout
147                 };
148
149                 renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS,                                 // pipelineBindPoint
150                                                                                                                    0,                                                                                                   // flags
151                                                                                                                    0,                                                                                                   // inputCount
152                                                                                                                    DE_NULL,                                                                                             // pInputAttachments
153                                                                                                                    1,                                                                                                   // colorCount
154                                                                                                                    &colorAttachmentReference,                                                   // pColorAttachments
155                                                                                                                    DE_NULL,                                                                                             // pResolveAttachments
156                                                                                                                    depthAttachmentReference,                                                    // depthStencilAttachment
157                                                                                                                    0,                                                                                                   // preserveCount
158                                                                                                                    DE_NULL));                                                                                   // preserveAttachments
159
160                 m_renderPass = vk::createRenderPass(vk, device, &renderPassCreateInfo);
161
162                 std::vector<vk::VkImageView> attachments(2);
163                 attachments[0] = *m_attachmentView;
164                 attachments[1] = *m_depthiew;
165
166                 FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, attachments, WIDTH, HEIGHT, 1);
167                 m_framebuffer = vk::createFramebuffer(vk, device, &framebufferCreateInfo);
168         }
169
170         {
171                 // Pipeline
172
173                 vk::Unique<vk::VkShaderModule> vs(vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
174                 vk::Unique<vk::VkShaderModule> fs(vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
175
176                 const PipelineCreateInfo::ColorBlendState::Attachment attachmentState;
177
178                 const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
179                 m_pipelineLayout = vk::createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
180
181                 const vk::VkVertexInputBindingDescription vf_binding_desc               =
182                 {
183                         0,                                                                                                                              // binding;
184                         4 * (deUint32)sizeof(float),                                                                    // stride;
185                         vk::VK_VERTEX_INPUT_RATE_VERTEX                                                                 // inputRate
186                 };
187
188                 const vk::VkVertexInputAttributeDescription vf_attribute_desc   =
189                 {
190                         0,                                                                                                                              // location;
191                         0,                                                                                                                              // binding;
192                         vk::VK_FORMAT_R32G32B32A32_SFLOAT,                                                              // format;
193                         0                                                                                                                               // offset;
194                 };
195
196                 const vk::VkPipelineVertexInputStateCreateInfo vf_info                  =
197                 {                                                                                                                                       // sType;
198                         vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,  // pNext;
199                         NULL,                                                                                                                   // flags;
200                         0u,                                                                                                                             // vertexBindingDescriptionCount;
201                         1,                                                                                                                              // pVertexBindingDescriptions;
202                         &vf_binding_desc,                                                                                               // vertexAttributeDescriptionCount;
203                         1,                                                                                                                              // pVertexAttributeDescriptions;
204                         &vf_attribute_desc
205                 };
206
207                 PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
208                 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
209                 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
210                 pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(primitive));
211                 pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &attachmentState));
212                 const vk::VkViewport viewport   =
213                 {
214                         0,              // float x;
215                         0,              // float y;
216                         WIDTH,  // float width;
217                         HEIGHT, // float height;
218                         0.0f,   // float minDepth;
219                         1.0f    // float maxDepth;
220                 };
221
222                 const vk::VkRect2D scissor              =
223                 {
224                         {
225                                 0,              // deInt32 x
226                                 0,              // deInt32 y
227                         },              // VkOffset2D   offset;
228                         {
229                                 WIDTH,  // deInt32 width;
230                                 HEIGHT, // deInt32 height
231                         },              // VkExtent2D   extent;
232                 };
233                 pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
234                 pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState(true, true, vk::VK_COMPARE_OP_GREATER_OR_EQUAL));
235                 pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
236                 pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
237                 pipelineCreateInfo.addState(vf_info);
238                 m_pipeline = vk::createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
239         }
240
241         {
242                 // Vertex buffer
243                 const size_t kBufferSize = numVertices * sizeof(tcu::Vec4);
244                 m_vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(kBufferSize, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
245         }
246 }
247
248 void StateObjects::setVertices (const vk::DeviceInterface&vk, std::vector<tcu::Vec4> vertices)
249 {
250         const vk::VkDevice device                       = m_context.getDevice();
251
252         tcu::Vec4 *ptr = reinterpret_cast<tcu::Vec4*>(m_vertexBuffer->getBoundMemory().getHostPtr());
253         std::copy(vertices.begin(), vertices.end(), ptr);
254
255         vk::flushMappedMemoryRange(vk, device,  m_vertexBuffer->getBoundMemory().getMemory(), m_vertexBuffer->getBoundMemory().getOffset(),     vertices.size() * sizeof(vertices[0]));
256 }
257
258 enum OcclusionQueryResultSize
259 {
260         RESULT_SIZE_64_BIT,
261         RESULT_SIZE_32_BIT,
262 };
263
264 enum OcclusionQueryWait
265 {
266         WAIT_QUEUE,
267         WAIT_QUERY,
268         WAIT_NONE
269 };
270
271 enum OcclusionQueryResultsMode
272 {
273         RESULTS_MODE_GET,
274         RESULTS_MODE_COPY
275 };
276
277 struct OcclusionQueryTestVector
278 {
279         vk::VkQueryControlFlags         queryControlFlags;
280         OcclusionQueryResultSize        queryResultSize;
281         OcclusionQueryWait                      queryWait;
282         OcclusionQueryResultsMode       queryResultsMode;
283         vk::VkDeviceSize                        queryResultsStride;
284         bool                                            queryResultsAvailability;
285         vk::VkPrimitiveTopology         primitiveTopology;
286         bool                                            discardHalf;
287 };
288
289 class BasicOcclusionQueryTestInstance : public vkt::TestInstance
290 {
291 public:
292                                         BasicOcclusionQueryTestInstance         (vkt::Context &context, const OcclusionQueryTestVector&  testVector);
293                                         ~BasicOcclusionQueryTestInstance        (void);
294 private:
295         tcu::TestStatus iterate                                                         (void);
296
297         enum
298         {
299                 NUM_QUERIES_IN_POOL                             = 2,
300                 QUERY_INDEX_CAPTURE_EMPTY               = 0,
301                 QUERY_INDEX_CAPTURE_DRAWCALL    = 1,
302                 NUM_VERTICES_IN_DRAWCALL                = 3
303         };
304
305         OcclusionQueryTestVector        m_testVector;
306         StateObjects*                           m_stateObjects;
307         vk::VkQueryPool                         m_queryPool;
308 };
309
310 BasicOcclusionQueryTestInstance::BasicOcclusionQueryTestInstance (vkt::Context &context, const OcclusionQueryTestVector&  testVector)
311         : TestInstance          (context)
312         , m_testVector          (testVector)
313 {
314         DE_ASSERT(testVector.queryResultSize                    == RESULT_SIZE_64_BIT
315                         && testVector.queryWait                                 == WAIT_QUEUE
316                         && testVector.queryResultsMode                  == RESULTS_MODE_GET
317                         && testVector.queryResultsStride                == sizeof(deUint64)
318                         && testVector.queryResultsAvailability  == false
319                         && testVector.primitiveTopology                 == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
320
321         if ((m_testVector.queryControlFlags & vk::VK_QUERY_CONTROL_PRECISE_BIT) && !m_context.getDeviceFeatures().occlusionQueryPrecise)
322                 throw tcu::NotSupportedError("Precise occlusion queries are not supported");
323
324         m_stateObjects = new StateObjects(m_context.getDeviceInterface(), m_context, NUM_VERTICES_IN_DRAWCALL, m_testVector.primitiveTopology);
325
326         const vk::VkDevice                      device  = m_context.getDevice();
327         const vk::DeviceInterface&      vk              = m_context.getDeviceInterface();
328
329         const vk::VkQueryPoolCreateInfo queryPoolCreateInfo =
330         {
331                 vk::VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
332                 DE_NULL,
333                 0u,
334                 vk::VK_QUERY_TYPE_OCCLUSION,
335                 NUM_QUERIES_IN_POOL,
336                 0
337         };
338         VK_CHECK(vk.createQueryPool(device, &queryPoolCreateInfo, /*pAllocator*/ DE_NULL, &m_queryPool));
339
340         std::vector<tcu::Vec4> vertices(NUM_VERTICES_IN_DRAWCALL);
341         vertices[0] = tcu::Vec4(0.5, 0.5, 0.0, 1.0);
342         vertices[1] = tcu::Vec4(0.5, 0.0, 0.0, 1.0);
343         vertices[2] = tcu::Vec4(0.0, 0.5, 0.0, 1.0);
344         m_stateObjects->setVertices(vk, vertices);
345 }
346
347 BasicOcclusionQueryTestInstance::~BasicOcclusionQueryTestInstance (void)
348 {
349         if (m_stateObjects)
350                 delete m_stateObjects;
351
352         if (m_queryPool != DE_NULL)
353         {
354                 const vk::VkDevice device               = m_context.getDevice();
355                 const vk::DeviceInterface& vk   = m_context.getDeviceInterface();
356
357                 vk.destroyQueryPool(device, m_queryPool, /*pAllocator*/ DE_NULL);
358         }
359 }
360
361 tcu::TestStatus BasicOcclusionQueryTestInstance::iterate (void)
362 {
363         tcu::TestLog &log                               = m_context.getTestContext().getLog();
364         const vk::VkDevice device               = m_context.getDevice();
365         const vk::VkQueue queue                 = m_context.getUniversalQueue();
366         const vk::DeviceInterface& vk   = m_context.getDeviceInterface();
367
368         const CmdPoolCreateInfo                 cmdPoolCreateInfo       (m_context.getUniversalQueueFamilyIndex());
369         vk::Move<vk::VkCommandPool>             cmdPool                         = vk::createCommandPool(vk, device, &cmdPoolCreateInfo);
370
371         vk::Unique<vk::VkCommandBuffer> cmdBuffer                       (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
372         const CmdBufferBeginInfo                beginInfo                       (0u);
373
374         vk.beginCommandBuffer(*cmdBuffer, &beginInfo);
375
376         initialTransitionColor2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
377                                                                   vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
378         initialTransitionDepth2DImage(vk, *cmdBuffer, m_stateObjects->m_DepthImage->object(), vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
379                                                                   vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
380
381         std::vector<vk::VkClearValue> renderPassClearValues(2);
382         deMemset(&renderPassClearValues[0], 0, static_cast<int>(renderPassClearValues.size()) * sizeof(vk::VkClearValue));
383
384         const vk::VkRect2D renderArea =
385         {
386                 { 0,                                    0 },
387                 { StateObjects::WIDTH,  StateObjects::HEIGHT }
388         };
389
390         RenderPassBeginInfo renderPassBegin(*m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, renderArea, renderPassClearValues);
391
392         vk.cmdResetQueryPool(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL);
393
394         vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBegin, vk::VK_SUBPASS_CONTENTS_INLINE);
395
396         vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
397
398         vk::VkBuffer vertexBuffer = m_stateObjects->m_vertexBuffer->object();
399         const vk::VkDeviceSize vertexBufferOffset = 0;
400         vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
401
402         vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_EMPTY, m_testVector.queryControlFlags);
403         vk.cmdEndQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_EMPTY);
404
405         vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_DRAWCALL, m_testVector.queryControlFlags);
406         vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, 0, 0);
407         vk.cmdEndQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_DRAWCALL);
408
409         vk.cmdEndRenderPass(*cmdBuffer);
410
411         transition2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_ASPECT_COLOR_BIT,
412                                           vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
413                                           vk::VK_ACCESS_TRANSFER_READ_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
414
415         vk.endCommandBuffer(*cmdBuffer);
416
417         // Submit command buffer
418         const vk::VkSubmitInfo submitInfo =
419         {
420                 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,      // VkStructureType                      sType;
421                 DE_NULL,                                                        // const void*                          pNext;
422                 0,                                                                      // deUint32                                     waitSemaphoreCount;
423                 DE_NULL,                                                        // const VkSemaphore*           pWaitSemaphores;
424                 (const vk::VkPipelineStageFlags*)DE_NULL,
425                 1,                                                                      // deUint32                                     commandBufferCount;
426                 &cmdBuffer.get(),                                       // const VkCommandBuffer*       pCommandBuffers;
427                 0,                                                                      // deUint32                                     signalSemaphoreCount;
428                 DE_NULL                                                         // const VkSemaphore*           pSignalSemaphores;
429         };
430         vk.queueSubmit(queue, 1, &submitInfo, DE_NULL);
431
432         VK_CHECK(vk.queueWaitIdle(queue));
433
434         deUint64 queryResults[NUM_QUERIES_IN_POOL] = { 0 };
435         size_t queryResultsSize         = sizeof(queryResults);
436
437         vk::VkResult queryResult        = vk.getQueryPoolResults(device, m_queryPool, 0, NUM_QUERIES_IN_POOL, queryResultsSize, queryResults, sizeof(queryResults[0]), vk::VK_QUERY_RESULT_64_BIT);
438
439         if (queryResult == vk::VK_NOT_READY)
440         {
441                 TCU_FAIL("Query result not avaliable, but vkWaitIdle() was called.");
442         }
443
444         VK_CHECK(queryResult);
445
446         log << tcu::TestLog::Section("OcclusionQueryResults",
447                 "Occlusion query results");
448         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(queryResults); ++ndx)
449         {
450                 log << tcu::TestLog::Message << "query[ slot == " << ndx
451                         << "] result == " << queryResults[ndx] << tcu::TestLog::EndMessage;
452         }
453
454         bool passed = true;
455
456         for (int queryNdx = 0; queryNdx < DE_LENGTH_OF_ARRAY(queryResults); ++queryNdx)
457         {
458
459                 deUint64 expectedValue;
460
461                 switch (queryNdx)
462                 {
463                         case QUERY_INDEX_CAPTURE_EMPTY:
464                                 expectedValue = 0;
465                                 break;
466                         case QUERY_INDEX_CAPTURE_DRAWCALL:
467                                 expectedValue = NUM_VERTICES_IN_DRAWCALL;
468                                 break;
469                 }
470
471                 if ((m_testVector.queryControlFlags & vk::VK_QUERY_CONTROL_PRECISE_BIT) || expectedValue == 0)
472                 {
473                         // require precise value
474                         if (queryResults[queryNdx] != expectedValue)
475                         {
476                                 log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
477                                         "wrong value of query for index "
478                                         << queryNdx << ", expected " << expectedValue << ", got "
479                                         << queryResults[0] << "." << tcu::TestLog::EndMessage;
480                                 passed = false;
481                         }
482                 }
483                 else
484                 {
485                         // require imprecize value > 0
486                         if (queryResults[queryNdx] == 0)
487                         {
488                                 log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
489                                         "wrong value of query for index "
490                                         << queryNdx << ", expected any non-zero value, got "
491                                         << queryResults[0] << "." << tcu::TestLog::EndMessage;
492                                 passed = false;
493                         }
494                 }
495         }
496         log << tcu::TestLog::EndSection;
497
498         if (passed)
499         {
500                 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Query result verification passed");
501         }
502         return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Query result verification failed");
503 }
504
505 class OcclusionQueryTestInstance : public vkt::TestInstance
506 {
507 public:
508         OcclusionQueryTestInstance              (vkt::Context &context, const OcclusionQueryTestVector& testVector);
509         ~OcclusionQueryTestInstance             (void);
510 private:
511         tcu::TestStatus                                 iterate                                                 (void);
512
513         bool                                                    hasSeparateResetCmdBuf                  (void) const;
514         bool                                                    hasSeparateCopyCmdBuf                   (void) const;
515
516         vk::Move<vk::VkCommandBuffer>   recordQueryPoolReset                    (vk::VkCommandPool commandPool);
517         vk::Move<vk::VkCommandBuffer>   recordRender                                    (vk::VkCommandPool commandPool);
518         vk::Move<vk::VkCommandBuffer>   recordCopyResults                               (vk::VkCommandPool commandPool);
519
520         void                                                    captureResults                                  (deUint64*                      retResults,     deUint64*               retAvailability,        bool    allowNotReady);
521         void                                                    logResults                                              (const deUint64*        results,        const deUint64* availability);
522         bool                                                    validateResults                                 (const deUint64*        results,        const deUint64* availability,           bool    allowUnavailable,       vk::VkPrimitiveTopology primitiveTopology);
523
524         enum
525         {
526                 NUM_QUERIES_IN_POOL                                                     = 3,
527                 QUERY_INDEX_CAPTURE_ALL                                         = 0,
528                 QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED          = 1,
529                 QUERY_INDEX_CAPTURE_OCCLUDED                            = 2
530         };
531         enum
532         {
533                 NUM_VERTICES_IN_DRAWCALL                                        = 3,
534                 NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL     = 3,
535                 NUM_VERTICES_IN_OCCLUDER_DRAWCALL                       = 3,
536                 NUM_VERTICES                                                            = NUM_VERTICES_IN_DRAWCALL + NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL + NUM_VERTICES_IN_OCCLUDER_DRAWCALL
537         };
538         enum
539         {
540                 START_VERTEX                                                            = 0,
541                 START_VERTEX_PARTIALLY_OCCLUDED                         = START_VERTEX + NUM_VERTICES_IN_DRAWCALL,
542                 START_VERTEX_OCCLUDER                                           = START_VERTEX_PARTIALLY_OCCLUDED + NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL
543         };
544
545         OcclusionQueryTestVector                m_testVector;
546
547         const vk::VkQueryResultFlags    m_queryResultFlags;
548
549         StateObjects*                                   m_stateObjects;
550         vk::VkQueryPool                                 m_queryPool;
551         de::SharedPtr<Buffer>                   m_queryPoolResultsBuffer;
552
553         vk::Move<vk::VkCommandPool>             m_commandPool;
554         vk::Move<vk::VkCommandBuffer>   m_queryPoolResetCommandBuffer;
555         vk::Move<vk::VkCommandBuffer>   m_renderCommandBuffer;
556         vk::Move<vk::VkCommandBuffer>   m_copyResultsCommandBuffer;
557 };
558
559 OcclusionQueryTestInstance::OcclusionQueryTestInstance (vkt::Context &context, const OcclusionQueryTestVector& testVector)
560         : vkt::TestInstance             (context)
561         , m_testVector                  (testVector)
562         , m_queryResultFlags    ((m_testVector.queryWait == WAIT_QUERY                                  ? vk::VK_QUERY_RESULT_WAIT_BIT                          : 0)
563                                                         | (m_testVector.queryResultSize == RESULT_SIZE_64_BIT   ? vk::VK_QUERY_RESULT_64_BIT                            : 0)
564                                                         | (m_testVector.queryResultsAvailability                                ? vk::VK_QUERY_RESULT_WITH_AVAILABILITY_BIT     : 0))
565 {
566         const vk::VkDevice                      device                          = m_context.getDevice();
567         const vk::DeviceInterface&      vk                                      = m_context.getDeviceInterface();
568
569         if ((m_testVector.queryControlFlags & vk::VK_QUERY_CONTROL_PRECISE_BIT) && !m_context.getDeviceFeatures().occlusionQueryPrecise)
570                 throw tcu::NotSupportedError("Precise occlusion queries are not supported");
571
572         m_stateObjects  = new StateObjects(m_context.getDeviceInterface(), m_context, NUM_VERTICES_IN_DRAWCALL + NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL + NUM_VERTICES_IN_OCCLUDER_DRAWCALL, m_testVector.primitiveTopology);
573
574         const vk::VkQueryPoolCreateInfo queryPoolCreateInfo     =
575         {
576                 vk::VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
577                 DE_NULL,
578                 0u,
579                 vk::VK_QUERY_TYPE_OCCLUSION,
580                 NUM_QUERIES_IN_POOL,
581                 0
582         };
583
584         VK_CHECK(vk.createQueryPool(device, &queryPoolCreateInfo, /*pAllocator*/ DE_NULL, &m_queryPool));
585
586         if (m_testVector.queryResultsMode == RESULTS_MODE_COPY)
587         {
588                 const vk::VkDeviceSize  resultsBufferSize                       = m_testVector.queryResultsStride * NUM_QUERIES_IN_POOL;
589                                                                 m_queryPoolResultsBuffer        = Buffer::createAndAlloc(vk, device, BufferCreateInfo(resultsBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
590         }
591
592         const CmdPoolCreateInfo cmdPoolCreateInfo               (m_context.getUniversalQueueFamilyIndex());
593                                                         m_commandPool                   = vk::createCommandPool(vk, device, &cmdPoolCreateInfo);
594                                                         m_renderCommandBuffer   = recordRender(*m_commandPool);
595
596         if (hasSeparateResetCmdBuf())
597         {
598                 m_queryPoolResetCommandBuffer   = recordQueryPoolReset(*m_commandPool);
599         }
600
601         if (hasSeparateCopyCmdBuf())
602         {
603                 m_copyResultsCommandBuffer = recordCopyResults(*m_commandPool);
604         }
605 }
606
607 OcclusionQueryTestInstance::~OcclusionQueryTestInstance (void)
608 {
609         const vk::VkDevice device = m_context.getDevice();
610
611         if (m_stateObjects)
612                 delete m_stateObjects;
613
614         if (m_queryPool != DE_NULL)
615         {
616                 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
617                 vk.destroyQueryPool(device, m_queryPool, /*pAllocator*/ DE_NULL);
618         }
619 }
620
621 tcu::TestStatus OcclusionQueryTestInstance::iterate (void)
622 {
623         const vk::VkQueue                       queue           = m_context.getUniversalQueue();
624         const vk::DeviceInterface&      vk                      = m_context.getDeviceInterface();
625         tcu::TestLog&                           log                     = m_context.getTestContext().getLog();
626         std::vector<tcu::Vec4>          vertices        (NUM_VERTICES);
627
628         // 1st triangle
629         vertices[START_VERTEX + 0] = tcu::Vec4( 0.5,  0.5, 0.5, 1.0);
630         vertices[START_VERTEX + 1] = tcu::Vec4( 0.5, -0.5, 0.5, 1.0);
631         vertices[START_VERTEX + 2] = tcu::Vec4(-0.5,  0.5, 0.5, 1.0);
632         // 2nd triangle - partially occluding the scene
633         vertices[START_VERTEX_PARTIALLY_OCCLUDED + 0] = tcu::Vec4(-0.5, -0.5, 1.0, 1.0);
634         vertices[START_VERTEX_PARTIALLY_OCCLUDED + 1] = tcu::Vec4( 0.5, -0.5, 1.0, 1.0);
635         vertices[START_VERTEX_PARTIALLY_OCCLUDED + 2] = tcu::Vec4(-0.5,  0.5, 1.0, 1.0);
636         // 3nd triangle - fully occluding the scene
637         vertices[START_VERTEX_OCCLUDER + 0] = tcu::Vec4( 0.5,  0.5, 1.0, 1.0);
638         vertices[START_VERTEX_OCCLUDER + 1] = tcu::Vec4( 0.5, -0.5, 1.0, 1.0);
639         vertices[START_VERTEX_OCCLUDER + 2] = tcu::Vec4(-0.5,  0.5, 1.0, 1.0);
640
641         m_stateObjects->setVertices(vk, vertices);
642
643         if (hasSeparateResetCmdBuf())
644         {
645                 const vk::VkSubmitInfo          submitInfoReset =
646                 {
647                         vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,                      // VkStructureType                      sType;
648                         DE_NULL,                                                                        // const void*                          pNext;
649                         0u,                                                                                     // deUint32                                     waitSemaphoreCount;
650                         DE_NULL,                                                                        // const VkSemaphore*           pWaitSemaphores;
651                         (const vk::VkPipelineStageFlags*)DE_NULL,
652                         1u,                                                                                     // deUint32                                     commandBufferCount;
653                         &m_queryPoolResetCommandBuffer.get(),           // const VkCommandBuffer*       pCommandBuffers;
654                         0u,                                                                                     // deUint32                                     signalSemaphoreCount;
655                         DE_NULL                                                                         // const VkSemaphore*           pSignalSemaphores;
656                 };
657
658                 vk.queueSubmit(queue, 1, &submitInfoReset, DE_NULL);
659
660                 // Trivially wait for reset to complete. This is to ensure the query pool is in reset state before
661                 // host accesses, so as to not insert any synchronization before capturing the results needed for WAIT_NONE
662                 // variant of test.
663                 VK_CHECK(vk.queueWaitIdle(queue));
664         }
665
666         {
667                 const vk::VkSubmitInfo submitInfoRender =
668                 {
669                         vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,      // VkStructureType                      sType;
670                         DE_NULL,                                                        // const void*                          pNext;
671                         0,                                                                      // deUint32                                     waitSemaphoreCount;
672                         DE_NULL,                                                        // const VkSemaphore*           pWaitSemaphores;
673                         (const vk::VkPipelineStageFlags*)DE_NULL,
674                         1,                                                                      // deUint32                                     commandBufferCount;
675                         &m_renderCommandBuffer.get(),           // const VkCommandBuffer*       pCommandBuffers;
676                         0,                                                                      // deUint32                                     signalSemaphoreCount;
677                         DE_NULL                                                         // const VkSemaphore*           pSignalSemaphores;
678                 };
679                 vk.queueSubmit(queue, 1, &submitInfoRender, DE_NULL);
680         }
681
682         if (m_testVector.queryWait == WAIT_QUEUE)
683         {
684                 VK_CHECK(vk.queueWaitIdle(queue));
685         }
686
687         if (hasSeparateCopyCmdBuf())
688         {
689                 // In case of WAIT_QUEUE test variant, the previously submitted m_renderCommandBuffer did not
690                 // contain vkCmdCopyQueryResults, so additional cmd buffer is needed.
691
692                 // In the case of WAIT_NONE or WAIT_QUERY, vkCmdCopyQueryResults is stored in m_renderCommandBuffer.
693
694                 const vk::VkSubmitInfo submitInfo =
695                 {
696                         vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,      // VkStructureType                      sType;
697                         DE_NULL,                                                        // const void*                          pNext;
698                         0,                                                                      // deUint32                                     waitSemaphoreCount;
699                         DE_NULL,                                                        // const VkSemaphore*           pWaitSemaphores;
700                         (const vk::VkPipelineStageFlags*)DE_NULL,
701                         1,                                                                      // deUint32                                     commandBufferCount;
702                         &m_copyResultsCommandBuffer.get(),      // const VkCommandBuffer*       pCommandBuffers;
703                         0,                                                                      // deUint32                                     signalSemaphoreCount;
704                         DE_NULL                                                         // const VkSemaphore*           pSignalSemaphores;
705                 };
706                 vk.queueSubmit(queue, 1, &submitInfo, DE_NULL);
707         }
708
709         if (m_testVector.queryResultsMode == RESULTS_MODE_COPY)
710         {
711                 // In case of vkCmdCopyQueryResults is used, test must always wait for it
712                 // to complete before we can read the result buffer.
713
714                 VK_CHECK(vk.queueWaitIdle(queue));
715         }
716
717         deUint64        queryResults            [NUM_QUERIES_IN_POOL];
718         deUint64        queryAvailability       [NUM_QUERIES_IN_POOL];
719
720         // Allow not ready results only if nobody waited before getting the query results
721         const bool      allowNotReady           = (m_testVector.queryWait == WAIT_NONE);
722
723         captureResults(queryResults, queryAvailability, allowNotReady);
724
725         log << tcu::TestLog::Section("OcclusionQueryResults", "Occlusion query results");
726
727         logResults(queryResults, queryAvailability);
728         bool passed = validateResults(queryResults, queryAvailability, allowNotReady, m_testVector.primitiveTopology);
729
730         log << tcu::TestLog::EndSection;
731
732         if (m_testVector.queryResultsMode != RESULTS_MODE_COPY)
733         {
734                 VK_CHECK(vk.queueWaitIdle(queue));
735         }
736
737                 if (passed)
738         {
739                 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Query result verification passed");
740         }
741         return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Query result verification failed");
742 }
743
744 bool OcclusionQueryTestInstance::hasSeparateResetCmdBuf (void) const
745 {
746         // Determine if resetting query pool should be performed in separate command buffer
747         // to avoid race condition between host query access and device query reset.
748
749         if (m_testVector.queryResultsMode == RESULTS_MODE_COPY)
750         {
751                 // We copy query results on device, so there is no race condition between
752                 // host and device
753                 return false;
754         }
755         if (m_testVector.queryWait == WAIT_QUEUE)
756         {
757                 // We wait for queue to be complete before accessing query results
758                 return false;
759         }
760
761         // Separate command buffer with reset must be submitted & completed before
762         // host accesses the query results
763         return true;
764 }
765
766 bool OcclusionQueryTestInstance::hasSeparateCopyCmdBuf (void) const
767 {
768         // Copy query results must go into separate command buffer, if we want to wait on queue before that
769         return (m_testVector.queryResultsMode == RESULTS_MODE_COPY && m_testVector.queryWait == WAIT_QUEUE);
770 }
771
772 vk::Move<vk::VkCommandBuffer> OcclusionQueryTestInstance::recordQueryPoolReset (vk::VkCommandPool cmdPool)
773 {
774         const vk::VkDevice                              device          = m_context.getDevice();
775         const vk::DeviceInterface&              vk                      = m_context.getDeviceInterface();
776
777         DE_ASSERT(hasSeparateResetCmdBuf());
778
779         vk::Move<vk::VkCommandBuffer>   cmdBuffer       (vk::allocateCommandBuffer(vk, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
780         CmdBufferBeginInfo                              beginInfo       (0u);
781
782         vk.beginCommandBuffer(*cmdBuffer, &beginInfo);
783         vk.cmdResetQueryPool(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL);
784         vk.endCommandBuffer(*cmdBuffer);
785
786         return cmdBuffer;
787 }
788
789 vk::Move<vk::VkCommandBuffer> OcclusionQueryTestInstance::recordRender (vk::VkCommandPool cmdPool)
790 {
791         const vk::VkDevice                              device          = m_context.getDevice();
792         const vk::DeviceInterface&              vk                      = m_context.getDeviceInterface();
793
794         vk::Move<vk::VkCommandBuffer>   cmdBuffer       (vk::allocateCommandBuffer(vk, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
795         CmdBufferBeginInfo                              beginInfo       (0u);
796
797         vk.beginCommandBuffer(*cmdBuffer, &beginInfo);
798
799         initialTransitionColor2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
800                                                                   vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
801         initialTransitionDepth2DImage(vk, *cmdBuffer, m_stateObjects->m_DepthImage->object(), vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
802                                                                   vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
803
804         std::vector<vk::VkClearValue>   renderPassClearValues(2);
805         deMemset(&renderPassClearValues[0], 0, static_cast<int>(renderPassClearValues.size()) * sizeof(vk::VkClearValue));
806
807         const vk::VkRect2D renderArea =
808         {
809                 { 0,                                    0 },
810                 { StateObjects::WIDTH,  StateObjects::HEIGHT }
811         };
812
813         RenderPassBeginInfo renderPassBegin(*m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, renderArea, renderPassClearValues);
814
815         if (!hasSeparateResetCmdBuf())
816         {
817                 vk.cmdResetQueryPool(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL);
818         }
819
820         vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBegin, vk::VK_SUBPASS_CONTENTS_INLINE);
821
822         vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS,     *m_stateObjects->m_pipeline);
823
824         vk::VkBuffer vertexBuffer = m_stateObjects->m_vertexBuffer->object();
825         const vk::VkDeviceSize vertexBufferOffset = 0;
826         vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
827
828         // Draw un-occluded geometry
829         vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_ALL, m_testVector.queryControlFlags);
830         vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, START_VERTEX, 0);
831         vk.cmdEndQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_ALL);
832
833         // Partially occlude geometry
834         vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL, 1, START_VERTEX_PARTIALLY_OCCLUDED, 0);
835
836         // Draw partially-occluded geometry
837         vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED, m_testVector.queryControlFlags);
838         vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, START_VERTEX, 0);
839         vk.cmdEndQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED);
840
841         // Occlude geometry
842         vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_OCCLUDER_DRAWCALL, 1, START_VERTEX_OCCLUDER, 0);
843
844         // Draw occluded geometry
845         vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_OCCLUDED, m_testVector.queryControlFlags);
846         vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, START_VERTEX, 0);
847         vk.cmdEndQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_OCCLUDED);
848
849         vk.cmdEndRenderPass(*cmdBuffer);
850
851         if (m_testVector.queryResultsMode == RESULTS_MODE_COPY && !hasSeparateCopyCmdBuf())
852         {
853                 vk.cmdCopyQueryPoolResults(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL, m_queryPoolResultsBuffer->object(), /*dstOffset*/ 0, m_testVector.queryResultsStride, m_queryResultFlags);
854         }
855
856         transition2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_ASPECT_COLOR_BIT, vk::VK_IMAGE_LAYOUT_GENERAL,
857                                           vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT,
858                                           vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
859
860         vk.endCommandBuffer(*cmdBuffer);
861
862         return cmdBuffer;
863 }
864
865 vk::Move<vk::VkCommandBuffer> OcclusionQueryTestInstance::recordCopyResults (vk::VkCommandPool cmdPool)
866 {
867         const vk::VkDevice                              device          = m_context.getDevice();
868         const vk::DeviceInterface&              vk                      = m_context.getDeviceInterface();
869
870         vk::Move<vk::VkCommandBuffer>   cmdBuffer       (vk::allocateCommandBuffer(vk, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
871         const CmdBufferBeginInfo                beginInfo       (0u);
872
873         vk.beginCommandBuffer(*cmdBuffer, &beginInfo);
874         vk.cmdCopyQueryPoolResults(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL, m_queryPoolResultsBuffer->object(), /*dstOffset*/ 0, m_testVector.queryResultsStride, m_queryResultFlags);
875         vk.endCommandBuffer(*cmdBuffer);
876
877         return cmdBuffer;
878 }
879
880 void OcclusionQueryTestInstance::captureResults (deUint64* retResults, deUint64* retAvailAbility, bool allowNotReady)
881 {
882
883         const vk::VkDevice                      device                  = m_context.getDevice();
884         const vk::DeviceInterface&      vk                              = m_context.getDeviceInterface();
885         std::vector<deUint8>            resultsBuffer   (static_cast<size_t>(m_testVector.queryResultsStride) * NUM_QUERIES_IN_POOL);
886
887         if (m_testVector.queryResultsMode == RESULTS_MODE_GET)
888         {
889                 const vk::VkResult queryResult = vk.getQueryPoolResults(device, m_queryPool, 0, NUM_QUERIES_IN_POOL, resultsBuffer.size(), &resultsBuffer[0], m_testVector.queryResultsStride, m_queryResultFlags);
890                 if (queryResult == vk::VK_NOT_READY && !allowNotReady)
891                 {
892                         TCU_FAIL("getQueryPoolResults returned VK_NOT_READY, but results should be already available.");
893                 }
894                 else
895                 {
896                         VK_CHECK(queryResult);
897                 }
898         }
899         else if (m_testVector.queryResultsMode == RESULTS_MODE_COPY)
900         {
901                 const vk::Allocation& allocation = m_queryPoolResultsBuffer->getBoundMemory();
902                 const void* allocationData = allocation.getHostPtr();
903
904                 vk::invalidateMappedMemoryRange(vk, device, allocation.getMemory(), allocation.getOffset(), resultsBuffer.size());
905
906                 deMemcpy(&resultsBuffer[0], allocationData, resultsBuffer.size());
907         }
908
909         for (int queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; queryNdx++)
910         {
911                 const void* srcPtr = &resultsBuffer[queryNdx * static_cast<size_t>(m_testVector.queryResultsStride)];
912                 if (m_testVector.queryResultSize == RESULT_SIZE_32_BIT)
913                 {
914                         const deUint32* srcPtrTyped = static_cast<const deUint32*>(srcPtr);
915                         retResults[queryNdx]            = *srcPtrTyped;
916                         if (m_testVector.queryResultsAvailability)
917                         {
918                                 retAvailAbility[queryNdx] = *(srcPtrTyped + 1);
919                         }
920                 }
921                 else if (m_testVector.queryResultSize == RESULT_SIZE_64_BIT)
922                 {
923                         const deUint64* srcPtrTyped = static_cast<const deUint64*>(srcPtr);
924                         retResults[queryNdx]            = *srcPtrTyped;
925
926                         if (m_testVector.queryResultsAvailability)
927                         {
928                                 if (m_testVector.queryResultsAvailability)
929                                 {
930                                         retAvailAbility[queryNdx] = *(srcPtrTyped + 1);
931                                 }
932                         }
933                 }
934                 else
935                 {
936                         TCU_FAIL("Wrong m_testVector.queryResultSize");
937                 }
938         }
939 }
940
941 void OcclusionQueryTestInstance::logResults (const deUint64* results, const deUint64* availability)
942 {
943         tcu::TestLog& log = m_context.getTestContext().getLog();
944
945         for (int ndx = 0; ndx < NUM_QUERIES_IN_POOL; ++ndx)
946         {
947                 if (!m_testVector.queryResultsAvailability)
948                 {
949                         log << tcu::TestLog::Message << "query[ slot == " << ndx << "] result == " << results[ndx] << tcu::TestLog::EndMessage;
950                 }
951                 else
952                 {
953                         log << tcu::TestLog::Message << "query[ slot == " << ndx << "] result == " << results[ndx] << ", availability   == " << availability[ndx] << tcu::TestLog::EndMessage;
954                 }
955         }
956 }
957
958 bool OcclusionQueryTestInstance::validateResults (const deUint64* results , const deUint64* availability, bool allowUnavailable, vk::VkPrimitiveTopology primitiveTopology)
959 {
960         bool passed                     = true;
961         tcu::TestLog& log       = m_context.getTestContext().getLog();
962
963         for (int queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; ++queryNdx)
964         {
965                 deUint64 expectedValueMin = 0;
966                 deUint64 expectedValueMax = 0;
967
968                 if (m_testVector.queryResultsAvailability && availability[queryNdx] == 0)
969                 {
970                         // query result was not available
971                         if (!allowUnavailable)
972                         {
973                                 log << tcu::TestLog::Message << "query results availability was 0 for index "
974                                         << queryNdx << ", expected any value greater than 0." << tcu::TestLog::EndMessage;
975                                 passed = false;
976                                 continue;
977                         }
978                 }
979                 else
980                 {
981                         // query is available, so expect proper result values
982                         if (primitiveTopology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
983                         {
984                                 switch (queryNdx)
985                                 {
986                                         case QUERY_INDEX_CAPTURE_OCCLUDED:
987                                                 expectedValueMin = 0;
988                                                 expectedValueMax = 0;
989                                                 break;
990                                         case QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED:
991                                                 expectedValueMin = 1;
992                                                 expectedValueMax = 1;
993                                                 break;
994                                         case QUERY_INDEX_CAPTURE_ALL:
995                                                 expectedValueMin = NUM_VERTICES_IN_DRAWCALL;
996                                                 expectedValueMax = NUM_VERTICES_IN_DRAWCALL;
997                                                 break;
998                                 }
999                         }
1000                         else if (primitiveTopology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
1001                         {
1002                                 switch (queryNdx)
1003                                 {
1004                                         case QUERY_INDEX_CAPTURE_OCCLUDED:
1005                                                 expectedValueMin = 0;
1006                                                 expectedValueMax = 0;
1007                                                 break;
1008                                         case QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED:
1009                                         case QUERY_INDEX_CAPTURE_ALL:
1010                                                 {
1011                                                         const int primWidth             = StateObjects::WIDTH  / 2;
1012                                                         const int primHeight    = StateObjects::HEIGHT / 2;
1013                                                         const int primArea              = primWidth * primHeight / 2;
1014
1015                                                         if (m_testVector.discardHalf)
1016                                                         {
1017                                                                 expectedValueMin        = (int)(0.95f * primArea * 0.5f);
1018                                                                 expectedValueMax        = (int)(1.05f * primArea * 0.5f);
1019                                                         }
1020                                                         else
1021                                                         {
1022                                                                 expectedValueMin        = (int)(0.97f * primArea);
1023                                                                 expectedValueMax        = (int)(1.03f * primArea);
1024                                                         }
1025                                                 }
1026                                 }
1027                         }
1028                         else
1029                         {
1030                                 TCU_FAIL("Unsupported primitive topology");
1031                         }
1032                 }
1033
1034                 if ((m_testVector.queryControlFlags & vk::VK_QUERY_CONTROL_PRECISE_BIT) || (expectedValueMin == 0 && expectedValueMax == 0))
1035                 {
1036                         // require precise value
1037                         if (results[queryNdx] < expectedValueMin || results[queryNdx] > expectedValueMax)
1038                         {
1039                                 log << tcu::TestLog::Message << "wrong value of query for index "
1040                                         << queryNdx << ", expected the value minimum of " << expectedValueMin << ", maximum of " << expectedValueMax << " got "
1041                                         << results[queryNdx] << "." << tcu::TestLog::EndMessage;
1042                                 passed = false;
1043                         }
1044                 }
1045                 else
1046                 {
1047                         // require imprecise value greater than 0
1048                         if (results[queryNdx] == 0)
1049                         {
1050                                 log << tcu::TestLog::Message << "wrong value of query for index "
1051                                         << queryNdx << ", expected any non-zero value, got "
1052                                         << results[queryNdx] << "." << tcu::TestLog::EndMessage;
1053                                 passed = false;
1054                         }
1055                 }
1056         }
1057         return passed;
1058 }
1059
1060 template<class Instance>
1061 class QueryPoolOcclusionTest : public vkt::TestCase
1062 {
1063 public:
1064         QueryPoolOcclusionTest (tcu::TestContext &context, const char *name, const char *description, const OcclusionQueryTestVector& testVector)
1065                 : TestCase                      (context, name, description)
1066                 , m_testVector          (testVector)
1067         {
1068         }
1069 private:
1070         vkt::TestInstance* createInstance (vkt::Context& context) const
1071         {
1072                 return new Instance(context, m_testVector);
1073         }
1074
1075         void initPrograms(vk::SourceCollections& programCollection) const
1076         {
1077                 const char* const discard =
1078                         "       if ((int(gl_FragCoord.x) % 2) == (int(gl_FragCoord.y) % 2))\n"
1079                         "               discard;\n";
1080
1081                 const std::string fragSrc = std::string(
1082                         "#version 400\n"
1083                         "layout(location = 0) out vec4 out_FragColor;\n"
1084                         "void main()\n"
1085                         "{\n"
1086                         "       out_FragColor = vec4(0.07, 0.48, 0.75, 1.0);\n")
1087                         + std::string(m_testVector.discardHalf ? discard : "")
1088                         + "}\n";
1089
1090                 programCollection.glslSources.add("frag") << glu::FragmentSource(fragSrc.c_str());
1091
1092                 programCollection.glslSources.add("vert") << glu::VertexSource("#version 430\n"
1093                                                                                                                                                  "layout(location = 0) in vec4 in_Position;\n"
1094                                                                                                                                                  "out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };\n"
1095                                                                                                                                                  "void main() {\n"
1096                                                                                                                                                  "      gl_Position  = in_Position;\n"
1097                                                                                                                                                  "      gl_PointSize = 1.0;\n"
1098                                                                                                                                                  "}\n");
1099         }
1100
1101         OcclusionQueryTestVector m_testVector;
1102 };
1103
1104 } //anonymous
1105
1106 QueryPoolOcclusionTests::QueryPoolOcclusionTests (tcu::TestContext &testCtx)
1107         : TestCaseGroup(testCtx, "occlusion_query", "Tests for occlusion queries")
1108 {
1109         /* Left blank on purpose */
1110 }
1111
1112 QueryPoolOcclusionTests::~QueryPoolOcclusionTests (void)
1113 {
1114         /* Left blank on purpose */
1115 }
1116
1117 void QueryPoolOcclusionTests::init (void)
1118 {
1119         OcclusionQueryTestVector baseTestVector;
1120         baseTestVector.queryControlFlags                = 0;
1121         baseTestVector.queryResultSize                  = RESULT_SIZE_64_BIT;
1122         baseTestVector.queryWait                                = WAIT_QUEUE;
1123         baseTestVector.queryResultsMode                 = RESULTS_MODE_GET;
1124         baseTestVector.queryResultsStride               = sizeof(deUint64);
1125         baseTestVector.queryResultsAvailability = false;
1126         baseTestVector.primitiveTopology                = vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
1127         baseTestVector.discardHalf                              = false;
1128
1129         //Basic tests
1130         {
1131                 OcclusionQueryTestVector testVector = baseTestVector;
1132                 testVector.queryControlFlags = 0;
1133                 addChild(new QueryPoolOcclusionTest<BasicOcclusionQueryTestInstance>(m_testCtx, "basic_conservative",   "draw with conservative occlusion query",       testVector));
1134                 testVector.queryControlFlags = vk::VK_QUERY_CONTROL_PRECISE_BIT;
1135                 addChild(new QueryPoolOcclusionTest<BasicOcclusionQueryTestInstance>(m_testCtx, "basic_precise",                "draw with precise occlusion query",            testVector));
1136         }
1137
1138         // Functional test
1139         {
1140                 const vk::VkQueryControlFlags   controlFlags[]          = { 0,                                  vk::VK_QUERY_CONTROL_PRECISE_BIT        };
1141                 const char* const                               controlFlagsStr[]       = { "conservative",             "precise"                                                       };
1142
1143                 for (int controlFlagIdx = 0; controlFlagIdx < DE_LENGTH_OF_ARRAY(controlFlags); ++controlFlagIdx)
1144                 {
1145
1146                         const vk::VkPrimitiveTopology   primitiveTopology[]             = { vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST };
1147                         const char* const                               primitiveTopologyStr[]  = { "points", "triangles" };
1148                         for (int primitiveTopologyIdx = 0; primitiveTopologyIdx < DE_LENGTH_OF_ARRAY(primitiveTopology); ++primitiveTopologyIdx)
1149                         {
1150
1151                                 const OcclusionQueryResultSize  resultSize[]    = { RESULT_SIZE_32_BIT, RESULT_SIZE_64_BIT };
1152                                 const char* const                               resultSizeStr[] = { "32",                               "64" };
1153
1154                                 for (int resultSizeIdx = 0; resultSizeIdx < DE_LENGTH_OF_ARRAY(resultSize); ++resultSizeIdx)
1155                                 {
1156
1157                                         const OcclusionQueryWait        wait[]          = { WAIT_QUEUE, WAIT_QUERY };
1158                                         const char* const                       waitStr[]       = { "queue",    "query" };
1159
1160                                         for (int waitIdx = 0; waitIdx < DE_LENGTH_OF_ARRAY(wait); ++waitIdx)
1161                                         {
1162                                                 const OcclusionQueryResultsMode resultsMode[]           = { RESULTS_MODE_GET,   RESULTS_MODE_COPY };
1163                                                 const char* const                               resultsModeStr[]        = { "get",                              "copy" };
1164
1165                                                 for (int resultsModeIdx = 0; resultsModeIdx < DE_LENGTH_OF_ARRAY(resultsMode); ++resultsModeIdx)
1166                                                 {
1167
1168                                                         const bool                      testAvailability[]              = { false, true };
1169                                                         const char* const       testAvailabilityStr[]   = { "without", "with"};
1170
1171                                                         for (int testAvailabilityIdx = 0; testAvailabilityIdx < DE_LENGTH_OF_ARRAY(testAvailability); ++testAvailabilityIdx)
1172                                                         {
1173                                                                 const bool                      discardHalf[]           = { false, true };
1174                                                                 const char* const       discardHalfStr[]        = { "", "_discard" };
1175
1176                                                                 for (int discardHalfIdx = 0; discardHalfIdx < DE_LENGTH_OF_ARRAY(discardHalf); ++discardHalfIdx)
1177                                                                 {
1178                                                                         OcclusionQueryTestVector testVector                     = baseTestVector;
1179                                                                         testVector.queryControlFlags                            = controlFlags[controlFlagIdx];
1180                                                                         testVector.queryResultSize                                      = resultSize[resultSizeIdx];
1181                                                                         testVector.queryWait                                            = wait[waitIdx];
1182                                                                         testVector.queryResultsMode                                     = resultsMode[resultsModeIdx];
1183                                                                         testVector.queryResultsStride                           = (testVector.queryResultSize == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64));
1184                                                                         testVector.queryResultsAvailability                     = testAvailability[testAvailabilityIdx];
1185                                                                         testVector.primitiveTopology                            = primitiveTopology[primitiveTopologyIdx];
1186                                                                         testVector.discardHalf                                          = discardHalf[discardHalfIdx];
1187
1188                                                                         if (testVector.discardHalf && testVector.primitiveTopology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
1189                                                                                 continue; // Discarding half of the pixels in fragment shader doesn't make sense with one-pixel-sized points.
1190
1191                                                                         if (testVector.queryResultsAvailability)
1192                                                                         {
1193                                                                                 testVector.queryResultsStride *= 2;
1194                                                                         }
1195
1196                                                                         std::ostringstream testName;
1197                                                                         std::ostringstream testDescr;
1198
1199                                                                         testName << resultsModeStr[resultsModeIdx] << "_results"
1200                                                                                          << "_" << controlFlagsStr[controlFlagIdx]
1201                                                                                          << "_size_" << resultSizeStr[resultSizeIdx]
1202                                                                                          << "_wait_" << waitStr[waitIdx]
1203                                                                                          << "_" << testAvailabilityStr[testAvailabilityIdx] << "_availability"
1204                                                                                          << "_draw_" <<  primitiveTopologyStr[primitiveTopologyIdx]
1205                                                                                          << discardHalfStr[discardHalfIdx];
1206
1207                                                                         testDescr << "draw occluded " << primitiveTopologyStr[primitiveTopologyIdx]
1208                                                                                           << "with " << controlFlagsStr[controlFlagIdx] << ", "
1209                                                                                           << resultsModeStr[resultsModeIdx] << " results "
1210                                                                                           << testAvailabilityStr[testAvailabilityIdx] << " availability bit as "
1211                                                                                           << resultSizeStr[resultSizeIdx] << "bit variables,"
1212                                                                                           << (testVector.discardHalf ? " discarding half of the fragments," : "")
1213                                                                                           << "wait for results on" << waitStr[waitIdx];
1214
1215                                                                         addChild(new QueryPoolOcclusionTest<OcclusionQueryTestInstance>(m_testCtx, testName.str().c_str(), testDescr.str().c_str(), testVector));
1216                                                                 }
1217                                                         }
1218                                                 }
1219                                         }
1220                                 }
1221                         }
1222                 }
1223         }
1224         // Test different strides
1225         {
1226                 const OcclusionQueryResultsMode resultsMode[]           = { RESULTS_MODE_GET,   RESULTS_MODE_COPY       };
1227                 const char* const                               resultsModeStr[]        = { "get",                              "copy"                          };
1228
1229                 for (int resultsModeIdx = 0; resultsModeIdx < DE_LENGTH_OF_ARRAY(resultsMode); ++resultsModeIdx)
1230                 {
1231                         const OcclusionQueryResultSize  resultSizes[]   = { RESULT_SIZE_32_BIT, RESULT_SIZE_64_BIT };
1232                         const char* const                               resultSizeStr[] = { "32", "64" };
1233
1234                         const bool                      testAvailability[]              = { false,              true    };
1235                         const char* const       testAvailabilityStr[]   = { "without",  "with"  };
1236
1237                         for (int testAvailabilityIdx = 0; testAvailabilityIdx < DE_LENGTH_OF_ARRAY(testAvailability); ++testAvailabilityIdx)
1238                         {
1239                                 for (int resultSizeIdx = 0; resultSizeIdx < DE_LENGTH_OF_ARRAY(resultSizes); ++resultSizeIdx)
1240                                 {
1241                                         const vk::VkDeviceSize resultSize       = (resultSizes[resultSizeIdx] == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64));
1242
1243                                         // \todo [2015-12-18 scygan] Ensure only stride values aligned to resultSize are allowed. Otherwise test should be extended.
1244                                         const vk::VkDeviceSize strides[]        =
1245                                         {
1246                                                 1 * resultSize,
1247                                                 2 * resultSize,
1248                                                 3 * resultSize,
1249                                                 4 * resultSize,
1250                                                 5 * resultSize,
1251                                                 13 * resultSize,
1252                                                 1024 * resultSize
1253                                         };
1254
1255                                         for (int strideIdx = 0; strideIdx < DE_LENGTH_OF_ARRAY(strides); strideIdx++)
1256                                         {
1257                                                 OcclusionQueryTestVector testVector             = baseTestVector;
1258                                                 testVector.queryResultsMode                             = resultsMode[resultsModeIdx];
1259                                                 testVector.queryResultSize                              = resultSizes[resultSizeIdx];
1260                                                 testVector.queryResultsAvailability             = testAvailability[testAvailabilityIdx];
1261                                                 testVector.queryResultsStride                   = strides[strideIdx];
1262
1263                                                 const vk::VkDeviceSize elementSize              = (testVector.queryResultsAvailability ? resultSize * 2 : resultSize);
1264
1265                                                 if (elementSize > testVector.queryResultsStride)
1266                                                 {
1267                                                         continue;
1268                                                 }
1269
1270                                                 std::ostringstream testName;
1271                                                 std::ostringstream testDescr;
1272
1273                                                 testName << resultsModeStr[resultsModeIdx]
1274                                                                  << "_results_size_" << resultSizeStr[resultSizeIdx]
1275                                                                  << "_stride_" << strides[strideIdx]
1276                                                                  << "_" << testAvailabilityStr[testAvailabilityIdx] << "_availability";
1277
1278                                                 testDescr << resultsModeStr[resultsModeIdx] << " results "
1279                                                                   << testAvailabilityStr[testAvailabilityIdx] << " availability bit as "
1280                                                                   << resultSizeStr[resultSizeIdx] << "bit variables, with stride" << strides[strideIdx];
1281
1282                                                 addChild(new QueryPoolOcclusionTest<OcclusionQueryTestInstance>(m_testCtx, testName.str().c_str(), testDescr.str().c_str(), testVector));
1283                                         }
1284                                 }
1285                         }
1286                 }
1287
1288         }
1289 }
1290
1291 } //QueryPool
1292 } //vkt
1293