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 #include "vkTypeUtil.hpp"
36 #include "vkCmdUtil.hpp"
37
38 #include "tcuTestLog.hpp"
39 #include "tcuResource.hpp"
40 #include "tcuImageCompare.hpp"
41 #include "tcuCommandLine.hpp"
42
43 namespace vkt
44 {
45
46 namespace QueryPool
47 {
48
49 using namespace Draw;
50
51 namespace
52 {
53
54 struct StateObjects
55 {
56 StateObjects (const vk::DeviceInterface&vk, vkt::Context &context, const int numVertices, vk::VkPrimitiveTopology primitive, const bool noColorAttachments);
57 void setVertices (const vk::DeviceInterface&vk, std::vector<tcu::Vec4> vertices);
58
59 enum
60 {
61 WIDTH = 128,
62 HEIGHT = 128
63 };
64
65 vkt::Context &m_context;
66
67 vk::Move<vk::VkPipeline> m_pipeline;
68 vk::Move<vk::VkPipelineLayout> m_pipelineLayout;
69
70 de::SharedPtr<Image> m_colorAttachmentImage, m_DepthImage;
71 vk::Move<vk::VkImageView> m_attachmentView;
72 vk::Move<vk::VkImageView> m_depthView;
73
74 vk::Move<vk::VkRenderPass> m_renderPass;
75 vk::Move<vk::VkFramebuffer> m_framebuffer;
76
77 de::SharedPtr<Buffer> m_vertexBuffer;
78
79 vk::VkFormat m_colorAttachmentFormat;
80 };
81
StateObjects(const vk::DeviceInterface&vk, vkt::Context &context, const int numVertices, vk::VkPrimitiveTopology primitive, const bool noColorAttachments)82 StateObjects::StateObjects (const vk::DeviceInterface&vk, vkt::Context &context, const int numVertices, vk::VkPrimitiveTopology primitive, const bool noColorAttachments)
83 : m_context(context)
84 , m_colorAttachmentFormat(vk::VK_FORMAT_R8G8B8A8_UNORM)
85
86 {
87 vk::VkFormat depthFormat = vk::VK_FORMAT_D16_UNORM;
88 const vk::VkDevice device = m_context.getDevice();
89
90 vk::VkExtent3D imageExtent =
91 {
92 WIDTH, // width;
93 HEIGHT, // height;
94 1 // depth;
95 };
96
97 ImageCreateInfo depthImageCreateInfo(vk::VK_IMAGE_TYPE_2D, depthFormat, imageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL,
98 vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
99
100 m_DepthImage = Image::createAndAlloc(vk, device, depthImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
101
102 // Construct a depth view from depth image
103 const ImageViewCreateInfo depthViewInfo(m_DepthImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, depthFormat);
104 m_depthView = vk::createImageView(vk, device, &depthViewInfo);
105
106 // Renderpass and Framebuffer
107 if (noColorAttachments)
108 {
109 RenderPassCreateInfo renderPassCreateInfo;
110
111 renderPassCreateInfo.addAttachment(AttachmentDescription(depthFormat, // format
112 vk::VK_SAMPLE_COUNT_1_BIT, // samples
113 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // loadOp
114 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // storeOp
115 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp
116 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilLoadOp
117 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // initialLauout
118 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); // finalLayout
119
120 const vk::VkAttachmentReference depthAttachmentReference =
121 {
122 0, // attachment
123 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // layout
124 };
125
126 renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
127 0, // flags
128 0, // inputCount
129 DE_NULL, // pInputAttachments
130 0, // colorCount
131 DE_NULL, // pColorAttachments
132 DE_NULL, // pResolveAttachments
133 depthAttachmentReference, // depthStencilAttachment
134 0, // preserveCount
135 DE_NULL)); // preserveAttachments
136
137 m_renderPass = vk::createRenderPass(vk, device, &renderPassCreateInfo);
138
139 std::vector<vk::VkImageView> attachments(1);
140 attachments[0] = *m_depthView;
141 FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, attachments, WIDTH, HEIGHT, 1);
142 m_framebuffer = vk::createFramebuffer(vk, device, &framebufferCreateInfo);
143 }
144 else
145 {
146 const ImageCreateInfo colorImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, imageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT, vk::VK_IMAGE_TILING_OPTIMAL,
147 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
148
149 m_colorAttachmentImage = Image::createAndAlloc(vk, device, colorImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
150
151 const ImageViewCreateInfo attachmentViewInfo(m_colorAttachmentImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
152
153 m_attachmentView = vk::createImageView(vk, device, &attachmentViewInfo);
154
155 RenderPassCreateInfo renderPassCreateInfo;
156 renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat, // format
157 vk::VK_SAMPLE_COUNT_1_BIT, // samples
158 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // loadOp
159 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // storeOp
160 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp
161 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilLoadOp
162 vk::VK_IMAGE_LAYOUT_GENERAL, // initialLauout
163 vk::VK_IMAGE_LAYOUT_GENERAL)); // finalLayout
164
165 renderPassCreateInfo.addAttachment(AttachmentDescription(depthFormat, // format
166 vk::VK_SAMPLE_COUNT_1_BIT, // samples
167 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // loadOp
168 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // storeOp
169 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp
170 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilLoadOp
171 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // initialLauout
172 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); // finalLayout
173
174 const vk::VkAttachmentReference colorAttachmentReference =
175 {
176 0, // attachment
177 vk::VK_IMAGE_LAYOUT_GENERAL // layout
178 };
179
180 const vk::VkAttachmentReference depthAttachmentReference =
181 {
182 1, // attachment
183 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // layout
184 };
185
186 renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
187 0, // flags
188 0, // inputCount
189 DE_NULL, // pInputAttachments
190 1, // colorCount
191 &colorAttachmentReference, // pColorAttachments
192 DE_NULL, // pResolveAttachments
193 depthAttachmentReference, // depthStencilAttachment
194 0, // preserveCount
195 DE_NULL)); // preserveAttachments
196
197 m_renderPass = vk::createRenderPass(vk, device, &renderPassCreateInfo);
198
199 std::vector<vk::VkImageView> attachments(2);
200 attachments[0] = *m_attachmentView;
201 attachments[1] = *m_depthView;
202
203 FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, attachments, WIDTH, HEIGHT, 1);
204 m_framebuffer = vk::createFramebuffer(vk, device, &framebufferCreateInfo);
205 }
206
207 {
208 // Pipeline
209
210 vk::Unique<vk::VkShaderModule> vs(vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
211 vk::Unique<vk::VkShaderModule> fs(vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
212
213 const PipelineCreateInfo::ColorBlendState::Attachment attachmentState;
214
215 const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
216 m_pipelineLayout = vk::createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
217
218 const vk::VkVertexInputBindingDescription vf_binding_desc =
219 {
220 0, // binding;
221 4 * (deUint32)sizeof(float), // stride;
222 vk::VK_VERTEX_INPUT_RATE_VERTEX // inputRate
223 };
224
225 const vk::VkVertexInputAttributeDescription vf_attribute_desc =
226 {
227 0, // location;
228 0, // binding;
229 vk::VK_FORMAT_R32G32B32A32_SFLOAT, // format;
230 0 // offset;
231 };
232
233 const vk::VkPipelineVertexInputStateCreateInfo vf_info =
234 { // sType;
235 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // pNext;
236 NULL, // flags;
237 0u, // vertexBindingDescriptionCount;
238 1, // pVertexBindingDescriptions;
239 &vf_binding_desc, // vertexAttributeDescriptionCount;
240 1, // pVertexAttributeDescriptions;
241 &vf_attribute_desc
242 };
243
244 PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
245 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
246 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
247 pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(primitive));
248 pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &attachmentState));
249 const vk::VkViewport viewport = vk::makeViewport(WIDTH, HEIGHT);
250 const vk::VkRect2D scissor = vk::makeRect2D(WIDTH, HEIGHT);
251 pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
252 pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState(true, true, vk::VK_COMPARE_OP_GREATER_OR_EQUAL));
253 pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
254 pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
255 pipelineCreateInfo.addState(vf_info);
256 m_pipeline = vk::createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
257 }
258
259 {
260 // Vertex buffer
261 const size_t kBufferSize = numVertices * sizeof(tcu::Vec4);
262 m_vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(kBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
263 }
264 }
265
setVertices(const vk::DeviceInterface&vk, std::vector<tcu::Vec4> vertices)266 void StateObjects::setVertices (const vk::DeviceInterface&vk, std::vector<tcu::Vec4> vertices)
267 {
268 const vk::VkDevice device = m_context.getDevice();
269
270 tcu::Vec4 *ptr = reinterpret_cast<tcu::Vec4*>(m_vertexBuffer->getBoundMemory().getHostPtr());
271 std::copy(vertices.begin(), vertices.end(), ptr);
272
273 vk::flushAlloc(vk, device, m_vertexBuffer->getBoundMemory());
274 }
275
276 enum OcclusionQueryResultSize
277 {
278 RESULT_SIZE_64_BIT,
279 RESULT_SIZE_32_BIT,
280 };
281
282 enum OcclusionQueryWait
283 {
284 WAIT_QUEUE,
285 WAIT_QUERY,
286 WAIT_NONE
287 };
288
289 enum OcclusionQueryResultsMode
290 {
291 RESULTS_MODE_GET,
292 RESULTS_MODE_GET_RESET,
293 RESULTS_MODE_COPY,
294 RESULTS_MODE_COPY_RESET
295 };
296
297 enum OcculusionQueryClearOp
298 {
299 CLEAR_NOOP,
300 CLEAR_COLOR,
301 CLEAR_DEPTH
302 };
303
304 struct OcclusionQueryTestVector
305 {
306 vk::VkQueryControlFlags queryControlFlags;
307 OcclusionQueryResultSize queryResultSize;
308 OcclusionQueryWait queryWait;
309 OcclusionQueryResultsMode queryResultsMode;
310 vk::VkDeviceSize queryResultsStride;
311 bool queryResultsAvailability;
312 vk::VkPrimitiveTopology primitiveTopology;
313 bool discardHalf;
314 deBool queryResultsDstOffset;
315 OcculusionQueryClearOp clearOp;
316 bool noColorAttachments;
317 };
318
319 class BasicOcclusionQueryTestInstance : public vkt::TestInstance
320 {
321 public:
322 BasicOcclusionQueryTestInstance (vkt::Context &context, const OcclusionQueryTestVector& testVector);
323 ~BasicOcclusionQueryTestInstance (void);
324 private:
325 tcu::TestStatus iterate (void);
326
327 enum
328 {
329 NUM_QUERIES_IN_POOL = 2,
330 QUERY_INDEX_CAPTURE_EMPTY = 0,
331 QUERY_INDEX_CAPTURE_DRAWCALL = 1,
332 NUM_VERTICES_IN_DRAWCALL = 3
333 };
334
335 OcclusionQueryTestVector m_testVector;
336 StateObjects* m_stateObjects;
337 vk::VkQueryPool m_queryPool;
338 };
339
BasicOcclusionQueryTestInstance(vkt::Context &context, const OcclusionQueryTestVector& testVector)340 BasicOcclusionQueryTestInstance::BasicOcclusionQueryTestInstance (vkt::Context &context, const OcclusionQueryTestVector& testVector)
341 : TestInstance (context)
342 , m_testVector (testVector)
343 {
344 DE_ASSERT(testVector.queryResultSize == RESULT_SIZE_64_BIT
345 && testVector.queryWait == WAIT_QUEUE
346 && (testVector.queryResultsMode == RESULTS_MODE_GET || testVector.queryResultsMode == RESULTS_MODE_GET_RESET)
347 && testVector.queryResultsStride == sizeof(deUint64)
348 && testVector.queryResultsAvailability == false
349 && testVector.primitiveTopology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
350
351 if ((m_testVector.queryControlFlags & vk::VK_QUERY_CONTROL_PRECISE_BIT) && !m_context.getDeviceFeatures().occlusionQueryPrecise)
352 throw tcu::NotSupportedError("Precise occlusion queries are not supported");
353
354 m_stateObjects = new StateObjects(m_context.getDeviceInterface(), m_context, NUM_VERTICES_IN_DRAWCALL, m_testVector.primitiveTopology, m_testVector.noColorAttachments);
355
356 const vk::VkDevice device = m_context.getDevice();
357 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
358
359 const vk::VkQueryPoolCreateInfo queryPoolCreateInfo =
360 {
361 vk::VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
362 DE_NULL,
363 0u,
364 vk::VK_QUERY_TYPE_OCCLUSION,
365 NUM_QUERIES_IN_POOL,
366 0
367 };
368 VK_CHECK(vk.createQueryPool(device, &queryPoolCreateInfo, /*pAllocator*/ DE_NULL, &m_queryPool));
369
370 std::vector<tcu::Vec4> vertices(NUM_VERTICES_IN_DRAWCALL);
371 vertices[0] = tcu::Vec4(0.5, 0.5, 0.0, 1.0);
372 vertices[1] = tcu::Vec4(0.5, 0.0, 0.0, 1.0);
373 vertices[2] = tcu::Vec4(0.0, 0.5, 0.0, 1.0);
374 m_stateObjects->setVertices(vk, vertices);
375 }
376
~BasicOcclusionQueryTestInstance(void)377 BasicOcclusionQueryTestInstance::~BasicOcclusionQueryTestInstance (void)
378 {
379 if (m_stateObjects)
380 delete m_stateObjects;
381
382 if (m_queryPool != DE_NULL)
383 {
384 #ifndef CTS_USES_VULKANSC
385 const vk::VkDevice device = m_context.getDevice();
386 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
387 vk.destroyQueryPool(device, m_queryPool, /*pAllocator*/ DE_NULL);
388 #endif
389 }
390 }
391
iterate(void)392 tcu::TestStatus BasicOcclusionQueryTestInstance::iterate (void)
393 {
394 tcu::TestLog &log = m_context.getTestContext().getLog();
395 const vk::VkDevice device = m_context.getDevice();
396 const vk::VkQueue queue = m_context.getUniversalQueue();
397 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
398
399 if (m_testVector.queryResultsMode == RESULTS_MODE_GET_RESET)
400 {
401 // Check VK_EXT_host_query_reset is supported
402 m_context.requireDeviceFunctionality("VK_EXT_host_query_reset");
403 if(m_context.getHostQueryResetFeatures().hostQueryReset == VK_FALSE)
404 throw tcu::NotSupportedError(std::string("Implementation doesn't support resetting queries from the host").c_str());
405 }
406
407 const CmdPoolCreateInfo cmdPoolCreateInfo (m_context.getUniversalQueueFamilyIndex());
408 vk::Move<vk::VkCommandPool> cmdPool = vk::createCommandPool(vk, device, &cmdPoolCreateInfo);
409
410 vk::Unique<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
411
412 beginCommandBuffer(vk, *cmdBuffer);
413
414 if (!m_testVector.noColorAttachments)
415 initialTransitionColor2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
416 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
417 initialTransitionDepth2DImage(vk, *cmdBuffer, m_stateObjects->m_DepthImage->object(), vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
418 vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
419
420 std::vector<vk::VkClearValue> renderPassClearValues(2);
421 deMemset(&renderPassClearValues[0], 0, static_cast<int>(renderPassClearValues.size()) * sizeof(vk::VkClearValue));
422
423 if (m_testVector.queryResultsMode != RESULTS_MODE_GET_RESET)
424 vk.cmdResetQueryPool(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL);
425
426 beginRenderPass(vk, *cmdBuffer, *m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, vk::makeRect2D(0, 0, StateObjects::WIDTH, StateObjects::HEIGHT), (deUint32)renderPassClearValues.size(), &renderPassClearValues[0]);
427
428 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
429
430 vk::VkBuffer vertexBuffer = m_stateObjects->m_vertexBuffer->object();
431 const vk::VkDeviceSize vertexBufferOffset = 0;
432 vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
433
434 vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_EMPTY, m_testVector.queryControlFlags);
435 vk.cmdEndQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_EMPTY);
436
437 vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_DRAWCALL, m_testVector.queryControlFlags);
438 vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, 0, 0);
439 vk.cmdEndQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_DRAWCALL);
440
441 endRenderPass(vk, *cmdBuffer);
442
443 if (!m_testVector.noColorAttachments)
444 transition2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_ASPECT_COLOR_BIT,
445 vk::VK_IMAGE_LAYOUT_GENERAL, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
446 vk::VK_ACCESS_TRANSFER_READ_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
447
448 endCommandBuffer(vk, *cmdBuffer);
449
450 if (m_testVector.queryResultsMode == RESULTS_MODE_GET_RESET)
451 vk.resetQueryPool(device, m_queryPool, 0, NUM_QUERIES_IN_POOL);
452
453 submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
454
455 deUint64 queryResults[NUM_QUERIES_IN_POOL] = { 0 };
456 size_t queryResultsSize = sizeof(queryResults);
457
458 vk::VkResult queryResult = vk.getQueryPoolResults(device, m_queryPool, 0, NUM_QUERIES_IN_POOL, queryResultsSize, queryResults, sizeof(queryResults[0]), vk::VK_QUERY_RESULT_64_BIT);
459
460 if (queryResult == vk::VK_NOT_READY)
461 {
462 TCU_FAIL("Query result not avaliable, but vkWaitIdle() was called.");
463 }
464
465 VK_CHECK(queryResult);
466
467 log << tcu::TestLog::Section("OcclusionQueryResults",
468 "Occlusion query results");
469 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(queryResults); ++ndx)
470 {
471 log << tcu::TestLog::Message << "query[slot == " << ndx
472 << "] result == " << queryResults[ndx] << tcu::TestLog::EndMessage;
473 }
474
475 bool passed = true;
476
477 for (int queryNdx = 0; queryNdx < DE_LENGTH_OF_ARRAY(queryResults); ++queryNdx)
478 {
479
480 deUint64 expectedValue;
481
482 switch (queryNdx)
483 {
484 case QUERY_INDEX_CAPTURE_EMPTY:
485 expectedValue = 0;
486 break;
487 case QUERY_INDEX_CAPTURE_DRAWCALL:
488 expectedValue = NUM_VERTICES_IN_DRAWCALL;
489 break;
490 }
491
492 if ((m_testVector.queryControlFlags & vk::VK_QUERY_CONTROL_PRECISE_BIT) || expectedValue == 0)
493 {
494 // require precise value
495 if (queryResults[queryNdx] != expectedValue)
496 {
497 log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
498 "wrong value of query for index "
499 << queryNdx << ", expected " << expectedValue << ", got "
500 << queryResults[0] << "." << tcu::TestLog::EndMessage;
501 passed = false;
502 }
503 }
504 else
505 {
506 // require imprecize value > 0
507 if (queryResults[queryNdx] == 0)
508 {
509 log << tcu::TestLog::Message << "vkGetQueryPoolResults returned "
510 "wrong value of query for index "
511 << queryNdx << ", expected any non-zero value, got "
512 << queryResults[0] << "." << tcu::TestLog::EndMessage;
513 passed = false;
514 }
515 }
516 }
517 log << tcu::TestLog::EndSection;
518
519 if (passed)
520 {
521 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Query result verification passed");
522 }
523 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Query result verification failed");
524 }
525
526 class OcclusionQueryTestInstance : public vkt::TestInstance
527 {
528 public:
529 OcclusionQueryTestInstance (vkt::Context &context, const OcclusionQueryTestVector& testVector);
530 ~OcclusionQueryTestInstance (void);
531 private:
532 tcu::TestStatus iterate (void);
533
534 bool hasSeparateResetCmdBuf (void) const;
535 bool hasSeparateCopyCmdBuf (void) const;
536 void commandClearAttachment (const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer);
537
538 vk::Move<vk::VkCommandBuffer> recordQueryPoolReset (vk::VkCommandPool commandPool);
539 vk::Move<vk::VkCommandBuffer> recordRender (vk::VkCommandPool commandPool);
540 vk::Move<vk::VkCommandBuffer> recordCopyResults (vk::VkCommandPool commandPool);
541
542 void captureResults (deUint64* retResults, deUint64* retAvailability, bool allowNotReady);
543 void logResults (const deUint64* results, const deUint64* availability);
544 bool validateResults (const deUint64* results, const deUint64* availability, bool allowUnavailable, vk::VkPrimitiveTopology primitiveTopology);
545
546 enum
547 {
548 NUM_QUERIES_IN_POOL = 3,
549 QUERY_INDEX_CAPTURE_ALL = 0,
550 QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED = 1,
551 QUERY_INDEX_CAPTURE_OCCLUDED = 2
552 };
553 enum
554 {
555 NUM_VERTICES_IN_DRAWCALL = 3,
556 NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL = 3,
557 NUM_VERTICES_IN_OCCLUDER_DRAWCALL = 3,
558 NUM_VERTICES = NUM_VERTICES_IN_DRAWCALL + NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL + NUM_VERTICES_IN_OCCLUDER_DRAWCALL
559 };
560 enum
561 {
562 START_VERTEX = 0,
563 START_VERTEX_PARTIALLY_OCCLUDED = START_VERTEX + NUM_VERTICES_IN_DRAWCALL,
564 START_VERTEX_OCCLUDER = START_VERTEX_PARTIALLY_OCCLUDED + NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL
565 };
566
567 OcclusionQueryTestVector m_testVector;
568
569 const vk::VkQueryResultFlags m_queryResultFlags;
570
571 StateObjects* m_stateObjects;
572 vk::VkQueryPool m_queryPool;
573 de::SharedPtr<Buffer> m_queryPoolResultsBuffer;
574
575 vk::Move<vk::VkCommandPool> m_commandPool;
576 vk::Move<vk::VkCommandBuffer> m_queryPoolResetCommandBuffer;
577 vk::Move<vk::VkCommandBuffer> m_renderCommandBuffer;
578 vk::Move<vk::VkCommandBuffer> m_copyResultsCommandBuffer;
579 };
580
OcclusionQueryTestInstance(vkt::Context &context, const OcclusionQueryTestVector& testVector)581 OcclusionQueryTestInstance::OcclusionQueryTestInstance (vkt::Context &context, const OcclusionQueryTestVector& testVector)
582 : vkt::TestInstance (context)
583 , m_testVector (testVector)
584 , m_queryResultFlags (((m_testVector.queryWait == WAIT_QUERY && m_testVector.queryResultsMode != RESULTS_MODE_COPY_RESET)? vk::VK_QUERY_RESULT_WAIT_BIT : 0)
585 | (m_testVector.queryResultSize == RESULT_SIZE_64_BIT ? vk::VK_QUERY_RESULT_64_BIT : 0)
586 | (m_testVector.queryResultsAvailability ? vk::VK_QUERY_RESULT_WITH_AVAILABILITY_BIT : 0))
587 {
588 const vk::VkDevice device = m_context.getDevice();
589 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
590
591 if ((m_testVector.queryControlFlags & vk::VK_QUERY_CONTROL_PRECISE_BIT) && !m_context.getDeviceFeatures().occlusionQueryPrecise)
592 throw tcu::NotSupportedError("Precise occlusion queries are not supported");
593
594 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, m_testVector.noColorAttachments);
595
596 const vk::VkQueryPoolCreateInfo queryPoolCreateInfo =
597 {
598 vk::VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
599 DE_NULL,
600 0u,
601 vk::VK_QUERY_TYPE_OCCLUSION,
602 NUM_QUERIES_IN_POOL,
603 0
604 };
605
606 VK_CHECK(vk.createQueryPool(device, &queryPoolCreateInfo, /*pAllocator*/ DE_NULL, &m_queryPool));
607
608 if (m_testVector.queryResultsMode == RESULTS_MODE_COPY || m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
609 {
610 deUint32 numQueriesinPool = NUM_QUERIES_IN_POOL + (m_testVector.queryResultsDstOffset ? 1 : 0);
611 const vk::VkDeviceSize elementSize = m_testVector.queryResultSize == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64);
612 const vk::VkDeviceSize resultsBufferSize = m_testVector.queryResultsStride == 0
613 ? (elementSize + elementSize * m_testVector.queryResultsAvailability) * numQueriesinPool
614 : m_testVector.queryResultsStride * numQueriesinPool;
615 m_queryPoolResultsBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(resultsBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT), m_context.getDefaultAllocator(), vk::MemoryRequirement::HostVisible);
616 }
617
618 const CmdPoolCreateInfo cmdPoolCreateInfo (m_context.getUniversalQueueFamilyIndex());
619 m_commandPool = vk::createCommandPool(vk, device, &cmdPoolCreateInfo);
620 m_renderCommandBuffer = recordRender(*m_commandPool);
621
622 if (hasSeparateResetCmdBuf())
623 {
624 m_queryPoolResetCommandBuffer = recordQueryPoolReset(*m_commandPool);
625 }
626
627 if (hasSeparateCopyCmdBuf())
628 {
629 m_copyResultsCommandBuffer = recordCopyResults(*m_commandPool);
630 }
631 }
632
~OcclusionQueryTestInstance(void)633 OcclusionQueryTestInstance::~OcclusionQueryTestInstance (void)
634 {
635
636 if (m_stateObjects)
637 delete m_stateObjects;
638
639 if (m_queryPool != DE_NULL)
640 {
641 #ifndef CTS_USES_VULKANSC
642 const vk::VkDevice device = m_context.getDevice();
643 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
644 vk.destroyQueryPool(device, m_queryPool, /*pAllocator*/ DE_NULL);
645 #endif
646 }
647 }
648
iterate(void)649 tcu::TestStatus OcclusionQueryTestInstance::iterate (void)
650 {
651 const vk::VkQueue queue = m_context.getUniversalQueue();
652 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
653 tcu::TestLog& log = m_context.getTestContext().getLog();
654 std::vector<tcu::Vec4> vertices (NUM_VERTICES);
655
656 if (m_testVector.queryResultsMode == RESULTS_MODE_GET_RESET)
657 {
658 // Check VK_EXT_host_query_reset is supported
659 m_context.requireDeviceFunctionality("VK_EXT_host_query_reset");
660 if(m_context.getHostQueryResetFeatures().hostQueryReset == VK_FALSE)
661 throw tcu::NotSupportedError(std::string("Implementation doesn't support resetting queries from the host").c_str());
662 }
663
664 // 1st triangle
665 vertices[START_VERTEX + 0] = tcu::Vec4( 0.5, 0.5, 0.5, 1.0);
666 vertices[START_VERTEX + 1] = tcu::Vec4( 0.5, -0.5, 0.5, 1.0);
667 vertices[START_VERTEX + 2] = tcu::Vec4(-0.5, 0.5, 0.5, 1.0);
668 // 2nd triangle - partially occluding the scene
669 vertices[START_VERTEX_PARTIALLY_OCCLUDED + 0] = tcu::Vec4(-0.5, -0.5, 1.0, 1.0);
670 vertices[START_VERTEX_PARTIALLY_OCCLUDED + 1] = tcu::Vec4( 0.5, -0.5, 1.0, 1.0);
671 vertices[START_VERTEX_PARTIALLY_OCCLUDED + 2] = tcu::Vec4(-0.5, 0.5, 1.0, 1.0);
672 // 3nd triangle - fully occluding the scene
673 vertices[START_VERTEX_OCCLUDER + 0] = tcu::Vec4( 0.5, 0.5, 1.0, 1.0);
674 vertices[START_VERTEX_OCCLUDER + 1] = tcu::Vec4( 0.5, -0.5, 1.0, 1.0);
675 vertices[START_VERTEX_OCCLUDER + 2] = tcu::Vec4(-0.5, 0.5, 1.0, 1.0);
676
677 m_stateObjects->setVertices(vk, vertices);
678
679 if (hasSeparateResetCmdBuf())
680 {
681 const vk::VkSubmitInfo submitInfoReset =
682 {
683 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
684 DE_NULL, // const void* pNext;
685 0u, // deUint32 waitSemaphoreCount;
686 DE_NULL, // const VkSemaphore* pWaitSemaphores;
687 (const vk::VkPipelineStageFlags*)DE_NULL,
688 1u, // deUint32 commandBufferCount;
689 &m_queryPoolResetCommandBuffer.get(), // const VkCommandBuffer* pCommandBuffers;
690 0u, // deUint32 signalSemaphoreCount;
691 DE_NULL // const VkSemaphore* pSignalSemaphores;
692 };
693
694 vk.queueSubmit(queue, 1, &submitInfoReset, DE_NULL);
695
696 // Trivially wait for reset to complete. This is to ensure the query pool is in reset state before
697 // host accesses, so as to not insert any synchronization before capturing the results needed for WAIT_NONE
698 // variant of test.
699 VK_CHECK(vk.queueWaitIdle(queue));
700 }
701
702 {
703 const vk::VkSubmitInfo submitInfoRender =
704 {
705 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
706 DE_NULL, // const void* pNext;
707 0, // deUint32 waitSemaphoreCount;
708 DE_NULL, // const VkSemaphore* pWaitSemaphores;
709 (const vk::VkPipelineStageFlags*)DE_NULL,
710 1, // deUint32 commandBufferCount;
711 &m_renderCommandBuffer.get(), // const VkCommandBuffer* pCommandBuffers;
712 0, // deUint32 signalSemaphoreCount;
713 DE_NULL // const VkSemaphore* pSignalSemaphores;
714 };
715
716 if (!hasSeparateResetCmdBuf() && m_testVector.queryResultsMode == RESULTS_MODE_GET_RESET)
717 vk.resetQueryPool(m_context.getDevice(), m_queryPool, 0, NUM_QUERIES_IN_POOL);
718 vk.queueSubmit(queue, 1, &submitInfoRender, DE_NULL);
719 }
720
721 if (m_testVector.queryWait == WAIT_QUEUE)
722 {
723 VK_CHECK(vk.queueWaitIdle(queue));
724 }
725
726 if (hasSeparateCopyCmdBuf())
727 {
728 // In case of WAIT_QUEUE test variant, the previously submitted m_renderCommandBuffer did not
729 // contain vkCmdCopyQueryResults, so additional cmd buffer is needed.
730
731 // In the case of WAIT_NONE or WAIT_QUERY, vkCmdCopyQueryResults is stored in m_renderCommandBuffer.
732
733 const vk::VkSubmitInfo submitInfo =
734 {
735 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
736 DE_NULL, // const void* pNext;
737 0, // deUint32 waitSemaphoreCount;
738 DE_NULL, // const VkSemaphore* pWaitSemaphores;
739 (const vk::VkPipelineStageFlags*)DE_NULL,
740 1, // deUint32 commandBufferCount;
741 &m_copyResultsCommandBuffer.get(), // const VkCommandBuffer* pCommandBuffers;
742 0, // deUint32 signalSemaphoreCount;
743 DE_NULL // const VkSemaphore* pSignalSemaphores;
744 };
745 vk.queueSubmit(queue, 1, &submitInfo, DE_NULL);
746 }
747
748 if (m_testVector.queryResultsMode == RESULTS_MODE_COPY || m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
749 {
750 // In case of vkCmdCopyQueryResults is used, test must always wait for it
751 // to complete before we can read the result buffer.
752
753 VK_CHECK(vk.queueWaitIdle(queue));
754 }
755
756 deUint64 queryResults [NUM_QUERIES_IN_POOL];
757 deUint64 queryAvailability [NUM_QUERIES_IN_POOL];
758
759 // Allow not ready results only if nobody waited before getting the query results
760 const bool allowNotReady = (m_testVector.queryWait == WAIT_NONE);
761
762 captureResults(queryResults, queryAvailability, allowNotReady);
763
764 log << tcu::TestLog::Section("OcclusionQueryResults", "Occlusion query results");
765
766 logResults(queryResults, queryAvailability);
767 bool passed = validateResults(queryResults, queryAvailability, allowNotReady, m_testVector.primitiveTopology);
768
769 log << tcu::TestLog::EndSection;
770
771 if (m_testVector.queryResultsMode != RESULTS_MODE_COPY && m_testVector.queryResultsMode != RESULTS_MODE_COPY_RESET)
772 {
773 VK_CHECK(vk.queueWaitIdle(queue));
774 }
775
776 if (passed)
777 {
778 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Query result verification passed");
779 }
780 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Query result verification failed");
781 }
782
hasSeparateResetCmdBuf(void) const783 bool OcclusionQueryTestInstance::hasSeparateResetCmdBuf (void) const
784 {
785 // Determine if resetting query pool should be performed in separate command buffer
786 // to avoid race condition between host query access and device query reset.
787
788 if (m_testVector.queryResultsMode == RESULTS_MODE_COPY || m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
789 {
790 // We copy query results on device, so there is no race condition between
791 // host and device
792 return false;
793 }
794 if (m_testVector.queryWait == WAIT_QUEUE)
795 {
796 // We wait for queue to be complete before accessing query results
797 return false;
798 }
799
800 // Separate command buffer with reset must be submitted & completed before
801 // host accesses the query results
802 return true;
803 }
804
hasSeparateCopyCmdBuf(void) const805 bool OcclusionQueryTestInstance::hasSeparateCopyCmdBuf (void) const
806 {
807 // Copy query results must go into separate command buffer, if we want to wait on queue before that
808 return ((m_testVector.queryResultsMode == RESULTS_MODE_COPY || m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
809 && m_testVector.queryWait == WAIT_QUEUE);
810 }
811
recordQueryPoolReset(vk::VkCommandPool cmdPool)812 vk::Move<vk::VkCommandBuffer> OcclusionQueryTestInstance::recordQueryPoolReset (vk::VkCommandPool cmdPool)
813 {
814 const vk::VkDevice device = m_context.getDevice();
815 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
816
817 DE_ASSERT(hasSeparateResetCmdBuf());
818
819 vk::Move<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
820
821 beginCommandBuffer(vk, *cmdBuffer);
822 vk.cmdResetQueryPool(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL);
823 endCommandBuffer(vk, *cmdBuffer);
824
825 return cmdBuffer;
826 }
827
commandClearAttachment(const vk::DeviceInterface& vk, const vk::VkCommandBuffer commandBuffer)828 void OcclusionQueryTestInstance::commandClearAttachment (const vk::DeviceInterface& vk,
829 const vk::VkCommandBuffer commandBuffer)
830 {
831 if (m_testVector.clearOp == CLEAR_NOOP)
832 return;
833
834 const vk::VkOffset2D offset = vk::makeOffset2D(0, 0);
835 const vk::VkExtent2D extent = vk::makeExtent2D(StateObjects::WIDTH, StateObjects::HEIGHT);
836
837 const vk::VkClearAttachment attachment =
838 {
839 m_testVector.clearOp == CLEAR_COLOR ? vk::VK_IMAGE_ASPECT_COLOR_BIT : vk::VK_IMAGE_ASPECT_DEPTH_BIT, // VkImageAspectFlags aspectMask;
840 m_testVector.clearOp == CLEAR_COLOR ? 0u : 1u, // uint32_t colorAttachment;
841 m_testVector.clearOp == CLEAR_COLOR ? vk::makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f)) :
842 vk::makeClearValueDepthStencil(0.0f, 0u) // VkClearValue clearValue;
843 };
844
845 const vk::VkClearRect rect =
846 {
847 { offset, extent }, // VkRect2D rect;
848 0u, // uint32_t baseArrayLayer;
849 1u, // uint32_t layerCount;
850 };
851
852 vk.cmdClearAttachments(commandBuffer, 1u, &attachment, 1u, &rect);
853 }
854
recordRender(vk::VkCommandPool cmdPool)855 vk::Move<vk::VkCommandBuffer> OcclusionQueryTestInstance::recordRender (vk::VkCommandPool cmdPool)
856 {
857 const vk::VkDevice device = m_context.getDevice();
858 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
859
860 vk::Move<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
861
862 beginCommandBuffer(vk, *cmdBuffer);
863
864 if (!m_testVector.noColorAttachments)
865 initialTransitionColor2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL,
866 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
867
868 initialTransitionDepth2DImage(vk, *cmdBuffer, m_stateObjects->m_DepthImage->object(), vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
869 vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
870
871 std::vector<vk::VkClearValue> renderPassClearValues(2);
872 deMemset(&renderPassClearValues[0], 0, static_cast<int>(renderPassClearValues.size()) * sizeof(vk::VkClearValue));
873
874 if (!hasSeparateResetCmdBuf() && m_testVector.queryResultsMode != RESULTS_MODE_GET_RESET)
875 {
876 vk.cmdResetQueryPool(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL);
877 }
878
879 beginRenderPass(vk, *cmdBuffer, *m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, vk::makeRect2D(0, 0, StateObjects::WIDTH, StateObjects::HEIGHT), (deUint32)renderPassClearValues.size(), &renderPassClearValues[0]);
880
881 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
882
883 vk::VkBuffer vertexBuffer = m_stateObjects->m_vertexBuffer->object();
884 const vk::VkDeviceSize vertexBufferOffset = 0;
885 vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
886
887 // Draw un-occluded geometry
888 vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_ALL, m_testVector.queryControlFlags);
889 vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, START_VERTEX, 0);
890 commandClearAttachment(vk, *cmdBuffer);
891 vk.cmdEndQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_ALL);
892
893 endRenderPass(vk, *cmdBuffer);
894
895 beginRenderPass(vk, *cmdBuffer, *m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, vk::makeRect2D(0, 0, StateObjects::WIDTH, StateObjects::HEIGHT), (deUint32)renderPassClearValues.size(), &renderPassClearValues[0]);
896
897 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
898
899 // Draw un-occluded geometry
900 vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, START_VERTEX, 0);
901
902 // Partially occlude geometry
903 vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL, 1, START_VERTEX_PARTIALLY_OCCLUDED, 0);
904
905 // Draw partially-occluded geometry
906 vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED, m_testVector.queryControlFlags);
907 vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, START_VERTEX, 0);
908 commandClearAttachment(vk, *cmdBuffer);
909 vk.cmdEndQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED);
910
911 endRenderPass(vk, *cmdBuffer);
912
913 beginRenderPass(vk, *cmdBuffer, *m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, vk::makeRect2D(0, 0, StateObjects::WIDTH, StateObjects::HEIGHT), (deUint32)renderPassClearValues.size(), &renderPassClearValues[0]);
914
915 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
916
917 // Draw un-occluded geometry
918 vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, START_VERTEX, 0);
919
920 // Partially occlude geometry
921 vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL, 1, START_VERTEX_PARTIALLY_OCCLUDED, 0);
922
923 // Occlude geometry
924 vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_OCCLUDER_DRAWCALL, 1, START_VERTEX_OCCLUDER, 0);
925
926 // Draw occluded geometry
927 vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_OCCLUDED, m_testVector.queryControlFlags);
928 vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_DRAWCALL, 1, START_VERTEX, 0);
929 commandClearAttachment(vk, *cmdBuffer);
930 vk.cmdEndQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_OCCLUDED);
931
932 endRenderPass(vk, *cmdBuffer);
933
934 if (m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
935 {
936 vk.cmdResetQueryPool(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL);
937 }
938
939 if ((m_testVector.queryResultsMode == RESULTS_MODE_COPY || m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
940 && !hasSeparateCopyCmdBuf())
941 {
942 vk::VkDeviceSize dstOffset = m_testVector.queryResultsDstOffset ? m_testVector.queryResultsStride : 0u;
943
944 if (m_testVector.queryResultsStride != 0u)
945 {
946 vk.cmdCopyQueryPoolResults(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL, m_queryPoolResultsBuffer->object(), dstOffset, m_testVector.queryResultsStride, m_queryResultFlags);
947 }
948 else
949 {
950 const vk::VkDeviceSize elementSize = m_testVector.queryResultSize == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64);
951 const vk::VkDeviceSize strideSize = elementSize + elementSize * m_testVector.queryResultsAvailability;
952
953 for (int queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; queryNdx++)
954 {
955 vk.cmdCopyQueryPoolResults(*cmdBuffer, m_queryPool, queryNdx, 1, m_queryPoolResultsBuffer->object(), strideSize * queryNdx, 0, m_queryResultFlags);
956 }
957 }
958
959 bufferBarrier(vk, *cmdBuffer, m_queryPoolResultsBuffer->object(), vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT);
960 }
961
962 if (!m_testVector.noColorAttachments)
963 transition2DImage(vk, *cmdBuffer, m_stateObjects->m_colorAttachmentImage->object(), vk::VK_IMAGE_ASPECT_COLOR_BIT, vk::VK_IMAGE_LAYOUT_GENERAL,
964 vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT,
965 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT);
966
967 endCommandBuffer(vk, *cmdBuffer);
968
969 return cmdBuffer;
970 }
971
recordCopyResults(vk::VkCommandPool cmdPool)972 vk::Move<vk::VkCommandBuffer> OcclusionQueryTestInstance::recordCopyResults (vk::VkCommandPool cmdPool)
973 {
974 const vk::VkDevice device = m_context.getDevice();
975 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
976
977 vk::Move<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
978
979 beginCommandBuffer(vk, *cmdBuffer);
980
981 vk::VkDeviceSize dstOffset = m_testVector.queryResultsDstOffset ? m_testVector.queryResultsStride : 0u;
982
983 if (m_testVector.queryResultsStride != 0u)
984 {
985 vk.cmdCopyQueryPoolResults(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL, m_queryPoolResultsBuffer->object(), dstOffset, m_testVector.queryResultsStride, m_queryResultFlags);
986 }
987 else
988 {
989 const vk::VkDeviceSize elementSize = m_testVector.queryResultSize == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64);
990 const vk::VkDeviceSize strideSize = elementSize + elementSize * m_testVector.queryResultsAvailability;
991
992 for (int queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; queryNdx++)
993 {
994 vk.cmdCopyQueryPoolResults(*cmdBuffer, m_queryPool, queryNdx, 1, m_queryPoolResultsBuffer->object(), strideSize * queryNdx, 0, m_queryResultFlags);
995 }
996 }
997
998 bufferBarrier(vk, *cmdBuffer, m_queryPoolResultsBuffer->object(), vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT);
999
1000 endCommandBuffer(vk, *cmdBuffer);
1001
1002 return cmdBuffer;
1003 }
1004
captureResults(deUint64* retResults, deUint64* retAvailAbility, bool allowNotReady)1005 void OcclusionQueryTestInstance::captureResults (deUint64* retResults, deUint64* retAvailAbility, bool allowNotReady)
1006 {
1007 const vk::VkDevice device = m_context.getDevice();
1008 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
1009 const vk::VkDeviceSize elementSize = m_testVector.queryResultSize == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64);
1010 const vk::VkDeviceSize resultsSize = m_testVector.queryResultsStride == 0
1011 ? elementSize + elementSize * m_testVector.queryResultsAvailability
1012 : m_testVector.queryResultsStride;
1013 std::vector<deUint8> resultsBuffer (static_cast<size_t>(resultsSize * NUM_QUERIES_IN_POOL));
1014
1015 if (m_testVector.queryResultsMode == RESULTS_MODE_GET || m_testVector.queryResultsMode == RESULTS_MODE_GET_RESET)
1016 {
1017 vk::VkResult queryResult = vk.getQueryPoolResults(device, m_queryPool, 0, NUM_QUERIES_IN_POOL, resultsBuffer.size(), &resultsBuffer[0], m_testVector.queryResultsStride, m_queryResultFlags);
1018 if (queryResult == vk::VK_NOT_READY && !allowNotReady)
1019 {
1020 TCU_FAIL("getQueryPoolResults returned VK_NOT_READY, but results should be already available.");
1021 }
1022 else
1023 {
1024 VK_CHECK(queryResult);
1025 }
1026 }
1027 else if (m_testVector.queryResultsMode == RESULTS_MODE_COPY || m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
1028 {
1029 const vk::Allocation& allocation = m_queryPoolResultsBuffer->getBoundMemory();
1030 const deUint8* allocationData = static_cast<deUint8*>(allocation.getHostPtr());
1031 const deInt32 indexData = m_testVector.queryResultsDstOffset ? (deInt32)m_testVector.queryResultsStride : 0u;
1032
1033 vk::invalidateAlloc(vk, device, allocation);
1034
1035 deMemcpy(&resultsBuffer[0], &allocationData[indexData], resultsBuffer.size());
1036 }
1037
1038 for (int queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; queryNdx++)
1039 {
1040 const void* srcPtr = &resultsBuffer[queryNdx * static_cast<size_t>(resultsSize)];
1041
1042 if (m_testVector.queryResultSize == RESULT_SIZE_32_BIT)
1043 {
1044 const deUint32* srcPtrTyped = static_cast<const deUint32*>(srcPtr);
1045 retResults[queryNdx] = *srcPtrTyped;
1046 if (m_testVector.queryResultsAvailability)
1047 {
1048 retAvailAbility[queryNdx] = *(srcPtrTyped + 1);
1049 }
1050 }
1051 else if (m_testVector.queryResultSize == RESULT_SIZE_64_BIT)
1052 {
1053 const deUint64* srcPtrTyped = static_cast<const deUint64*>(srcPtr);
1054 retResults[queryNdx] = *srcPtrTyped;
1055
1056 if (m_testVector.queryResultsAvailability)
1057 {
1058 retAvailAbility[queryNdx] = *(srcPtrTyped + 1);
1059 }
1060 }
1061 else
1062 {
1063 TCU_FAIL("Wrong m_testVector.queryResultSize");
1064 }
1065 }
1066
1067 if (m_testVector.queryResultsMode == RESULTS_MODE_GET_RESET)
1068 {
1069 vk.resetQueryPool(device, m_queryPool, 0, NUM_QUERIES_IN_POOL);
1070
1071 vk::VkResult queryResult = vk.getQueryPoolResults(device, m_queryPool, 0, NUM_QUERIES_IN_POOL, resultsBuffer.size(), &resultsBuffer[0], m_testVector.queryResultsStride, m_queryResultFlags);
1072
1073 if (queryResult != vk::VK_NOT_READY)
1074 {
1075 TCU_FAIL("getQueryPoolResults did not return VK_NOT_READY");
1076 }
1077
1078 /* From Vulkan spec:
1079 *
1080 * If VK_QUERY_RESULT_WAIT_BIT and VK_QUERY_RESULT_PARTIAL_BIT are both not set then no result values are written to pData
1081 * for queries that are in the unavailable state at the time of the call, and vkGetQueryPoolResults returns VK_NOT_READY.
1082 * However, availability state is still written to pData for those queries if VK_QUERY_RESULT_WITH_AVAILABILITY_BIT is set.
1083 */
1084 for (int queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; queryNdx++)
1085 {
1086 const void* srcPtr = &resultsBuffer[queryNdx * static_cast<size_t>(resultsSize)];
1087 if (m_testVector.queryResultSize == RESULT_SIZE_32_BIT)
1088 {
1089 const deUint32* srcPtrTyped = static_cast<const deUint32*>(srcPtr);
1090 if (*srcPtrTyped != retResults[queryNdx])
1091 {
1092 TCU_FAIL("getQueryPoolResults returned modified values");
1093 }
1094
1095 if (m_testVector.queryResultsAvailability && *(srcPtrTyped + 1) != 0)
1096 {
1097 TCU_FAIL("resetQueryPool did not disable availability bit");
1098 }
1099 }
1100 else if (m_testVector.queryResultSize == RESULT_SIZE_64_BIT)
1101 {
1102 const deUint64* srcPtrTyped = static_cast<const deUint64*>(srcPtr);
1103 if (*srcPtrTyped != retResults[queryNdx])
1104 {
1105 TCU_FAIL("getQueryPoolResults returned modified values");
1106 }
1107
1108 if (m_testVector.queryResultsAvailability && *(srcPtrTyped + 1) != 0)
1109 {
1110 TCU_FAIL("resetQueryPool did not disable availability bit");
1111 }
1112 }
1113 else
1114 {
1115 TCU_FAIL("Wrong m_testVector.queryResultSize");
1116 }
1117 }
1118 }
1119 }
1120
logResults(const deUint64* results, const deUint64* availability)1121 void OcclusionQueryTestInstance::logResults (const deUint64* results, const deUint64* availability)
1122 {
1123 tcu::TestLog& log = m_context.getTestContext().getLog();
1124
1125 for (int ndx = 0; ndx < NUM_QUERIES_IN_POOL; ++ndx)
1126 {
1127 if (!m_testVector.queryResultsAvailability)
1128 {
1129 log << tcu::TestLog::Message << "query[slot == " << ndx << "] result == " << results[ndx] << tcu::TestLog::EndMessage;
1130 }
1131 else
1132 {
1133 log << tcu::TestLog::Message << "query[slot == " << ndx << "] result == " << results[ndx] << ", availability == " << availability[ndx] << tcu::TestLog::EndMessage;
1134 }
1135 }
1136 }
1137
validateResults(const deUint64* results , const deUint64* availability, bool allowUnavailable, vk::VkPrimitiveTopology primitiveTopology)1138 bool OcclusionQueryTestInstance::validateResults (const deUint64* results , const deUint64* availability, bool allowUnavailable, vk::VkPrimitiveTopology primitiveTopology)
1139 {
1140 bool passed = true;
1141 tcu::TestLog& log = m_context.getTestContext().getLog();
1142
1143 for (int queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; ++queryNdx)
1144 {
1145 deUint64 expectedValueMin = 0;
1146 deUint64 expectedValueMax = 0;
1147
1148 if (m_testVector.queryResultsMode == RESULTS_MODE_COPY_RESET)
1149 {
1150 DE_ASSERT(m_testVector.queryResultsAvailability);
1151 if (availability[queryNdx] != 0)
1152 {
1153 // In copy-reset mode results should always be unavailable due to the reset command issued before copying results.
1154 log << tcu::TestLog::Message << "query results availability was nonzero for index "
1155 << queryNdx << " when resetting the query before copying results"
1156 << tcu::TestLog::EndMessage;
1157 passed = false;
1158 }
1159
1160 // Not interested in the actual results.
1161 continue;
1162 }
1163 else if (m_testVector.queryResultsAvailability && availability[queryNdx] == 0)
1164 {
1165 // query result was not available
1166 if (!allowUnavailable)
1167 {
1168 log << tcu::TestLog::Message << "query results availability was 0 for index "
1169 << queryNdx << ", expected any value greater than 0." << tcu::TestLog::EndMessage;
1170 passed = false;
1171 continue;
1172 }
1173 }
1174 else
1175 {
1176 // query is available, so expect proper result values
1177 if (primitiveTopology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
1178 {
1179 switch (queryNdx)
1180 {
1181 case QUERY_INDEX_CAPTURE_OCCLUDED:
1182 expectedValueMin = 0;
1183 expectedValueMax = 0;
1184 break;
1185 case QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED:
1186 expectedValueMin = 1;
1187 expectedValueMax = 1;
1188 break;
1189 case QUERY_INDEX_CAPTURE_ALL:
1190 expectedValueMin = NUM_VERTICES_IN_DRAWCALL;
1191 expectedValueMax = NUM_VERTICES_IN_DRAWCALL;
1192 break;
1193 }
1194 }
1195 else if (primitiveTopology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
1196 {
1197 switch (queryNdx)
1198 {
1199 case QUERY_INDEX_CAPTURE_OCCLUDED:
1200 expectedValueMin = 0;
1201 expectedValueMax = 0;
1202 break;
1203 case QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED:
1204 case QUERY_INDEX_CAPTURE_ALL:
1205 {
1206 const int primWidth = StateObjects::WIDTH / 2;
1207 const int primHeight = StateObjects::HEIGHT / 2;
1208 const int primArea = primWidth * primHeight / 2;
1209
1210 if (m_testVector.discardHalf)
1211 {
1212 expectedValueMin = (int)(0.95f * primArea * 0.5f);
1213 expectedValueMax = (int)(1.05f * primArea * 0.5f);
1214 }
1215 else
1216 {
1217 expectedValueMin = (int)(0.97f * primArea);
1218 expectedValueMax = (int)(1.03f * primArea);
1219 }
1220 }
1221 }
1222 }
1223 else
1224 {
1225 TCU_FAIL("Unsupported primitive topology");
1226 }
1227 }
1228
1229 if ((m_testVector.queryControlFlags & vk::VK_QUERY_CONTROL_PRECISE_BIT) || (expectedValueMin == 0 && expectedValueMax == 0))
1230 {
1231 // require precise value
1232 if (results[queryNdx] < expectedValueMin || results[queryNdx] > expectedValueMax)
1233 {
1234 log << tcu::TestLog::Message << "wrong value of query for index "
1235 << queryNdx << ", expected the value minimum of " << expectedValueMin << ", maximum of " << expectedValueMax << " got "
1236 << results[queryNdx] << "." << tcu::TestLog::EndMessage;
1237 passed = false;
1238 }
1239 }
1240 else
1241 {
1242 // require imprecise value greater than 0
1243 if (results[queryNdx] == 0)
1244 {
1245 log << tcu::TestLog::Message << "wrong value of query for index "
1246 << queryNdx << ", expected any non-zero value, got "
1247 << results[queryNdx] << "." << tcu::TestLog::EndMessage;
1248 passed = false;
1249 }
1250 }
1251 }
1252 return passed;
1253 }
1254
1255 template<class Instance>
1256 class QueryPoolOcclusionTest : public vkt::TestCase
1257 {
1258 public:
QueryPoolOcclusionTest(tcu::TestContext &context, const char *name, const char *description, const OcclusionQueryTestVector& testVector)1259 QueryPoolOcclusionTest (tcu::TestContext &context, const char *name, const char *description, const OcclusionQueryTestVector& testVector)
1260 : TestCase (context, name, description)
1261 , m_testVector (testVector)
1262 {
1263 }
1264 private:
createInstance(vkt::Context& context) const1265 vkt::TestInstance* createInstance (vkt::Context& context) const
1266 {
1267 return new Instance(context, m_testVector);
1268 }
1269
initPrograms(vk::SourceCollections& programCollection) const1270 void initPrograms(vk::SourceCollections& programCollection) const
1271 {
1272 const char* const discard =
1273 " if ((int(gl_FragCoord.x) % 2) == (int(gl_FragCoord.y) % 2))\n"
1274 " discard;\n";
1275
1276 const std::string fragSrc = std::string(
1277 "#version 400\n"
1278 "layout(location = 0) out vec4 out_FragColor;\n"
1279 "void main()\n"
1280 "{\n"
1281 " out_FragColor = vec4(0.07, 0.48, 0.75, 1.0);\n")
1282 + std::string(m_testVector.discardHalf ? discard : "")
1283 + "}\n";
1284
1285 programCollection.glslSources.add("frag") << glu::FragmentSource(fragSrc.c_str());
1286
1287 programCollection.glslSources.add("vert") << glu::VertexSource("#version 430\n"
1288 "layout(location = 0) in vec4 in_Position;\n"
1289 "out gl_PerVertex { vec4 gl_Position; float gl_PointSize; };\n"
1290 "void main() {\n"
1291 " gl_Position = in_Position;\n"
1292 " gl_PointSize = 1.0;\n"
1293 "}\n");
1294 }
1295
1296 OcclusionQueryTestVector m_testVector;
1297 };
1298
1299 } //anonymous
1300
QueryPoolOcclusionTests(tcu::TestContext &testCtx)1301 QueryPoolOcclusionTests::QueryPoolOcclusionTests (tcu::TestContext &testCtx)
1302 : TestCaseGroup(testCtx, "occlusion_query", "Tests for occlusion queries")
1303 {
1304 /* Left blank on purpose */
1305 }
1306
~QueryPoolOcclusionTests(void)1307 QueryPoolOcclusionTests::~QueryPoolOcclusionTests (void)
1308 {
1309 /* Left blank on purpose */
1310 }
1311
init(void)1312 void QueryPoolOcclusionTests::init (void)
1313 {
1314 OcclusionQueryTestVector baseTestVector;
1315 baseTestVector.queryControlFlags = 0;
1316 baseTestVector.queryResultSize = RESULT_SIZE_64_BIT;
1317 baseTestVector.queryWait = WAIT_QUEUE;
1318 baseTestVector.queryResultsMode = RESULTS_MODE_GET;
1319 baseTestVector.queryResultsStride = sizeof(deUint64);
1320 baseTestVector.queryResultsAvailability = false;
1321 baseTestVector.primitiveTopology = vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
1322 baseTestVector.discardHalf = false;
1323 baseTestVector.clearOp = CLEAR_NOOP;
1324 baseTestVector.noColorAttachments = false;
1325
1326 //Basic tests
1327 {
1328 OcclusionQueryTestVector testVector = baseTestVector;
1329 testVector.queryControlFlags = 0;
1330 addChild(new QueryPoolOcclusionTest<BasicOcclusionQueryTestInstance>(m_testCtx, "basic_conservative", "draw with conservative occlusion query", testVector));
1331 testVector.queryControlFlags = vk::VK_QUERY_CONTROL_PRECISE_BIT;
1332 addChild(new QueryPoolOcclusionTest<BasicOcclusionQueryTestInstance>(m_testCtx, "basic_precise", "draw with precise occlusion query", testVector));
1333 }
1334
1335 // Functional test
1336 {
1337 const vk::VkQueryControlFlags controlFlags[] = { 0, vk::VK_QUERY_CONTROL_PRECISE_BIT };
1338 const char* const controlFlagsStr[] = { "conservative", "precise" };
1339
1340 for (int controlFlagIdx = 0; controlFlagIdx < DE_LENGTH_OF_ARRAY(controlFlags); ++controlFlagIdx)
1341 {
1342
1343 const vk::VkPrimitiveTopology primitiveTopology[] = { vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST };
1344 const char* const primitiveTopologyStr[] = { "points", "triangles" };
1345 for (int primitiveTopologyIdx = 0; primitiveTopologyIdx < DE_LENGTH_OF_ARRAY(primitiveTopology); ++primitiveTopologyIdx)
1346 {
1347
1348 const OcclusionQueryResultSize resultSize[] = { RESULT_SIZE_32_BIT, RESULT_SIZE_64_BIT };
1349 const char* const resultSizeStr[] = { "32", "64" };
1350
1351 for (int resultSizeIdx = 0; resultSizeIdx < DE_LENGTH_OF_ARRAY(resultSize); ++resultSizeIdx)
1352 {
1353
1354 const OcclusionQueryWait wait[] = { WAIT_QUEUE, WAIT_QUERY };
1355 const char* const waitStr[] = { "queue", "query" };
1356
1357 for (int waitIdx = 0; waitIdx < DE_LENGTH_OF_ARRAY(wait); ++waitIdx)
1358 {
1359 const OcclusionQueryResultsMode resultsMode[] = { RESULTS_MODE_GET, RESULTS_MODE_GET_RESET, RESULTS_MODE_COPY, RESULTS_MODE_COPY_RESET };
1360 const char* const resultsModeStr[] = { "get", "get_reset", "copy", "copy_reset" };
1361
1362 for (int resultsModeIdx = 0; resultsModeIdx < DE_LENGTH_OF_ARRAY(resultsMode); ++resultsModeIdx)
1363 {
1364 if (wait[waitIdx] == WAIT_QUERY && resultsMode[resultsModeIdx] == RESULTS_MODE_GET_RESET)
1365 {
1366 /* In RESULTS_MODE_GET_RESET we are going to reset the queries and get the query pool results again
1367 * without issueing them, in order to check the availability field. In Vulkan spec it mentions that
1368 * vkGetQueryPoolResults may not return in finite time. Because of that, we skip those tests.
1369 */
1370 continue;
1371 }
1372
1373 const bool testAvailability[] = { false, true };
1374 const char* const testAvailabilityStr[] = { "without", "with"};
1375
1376 for (int testAvailabilityIdx = 0; testAvailabilityIdx < DE_LENGTH_OF_ARRAY(testAvailability); ++testAvailabilityIdx)
1377 {
1378 if (resultsMode[resultsModeIdx] == RESULTS_MODE_COPY_RESET && (! testAvailability[testAvailabilityIdx]))
1379 {
1380 /* In RESULTS_MODE_COPY_RESET mode we will reset queries and make sure the availability flag is
1381 * set to zero. It does not make sense to run in this mode without obtaining the availability
1382 * flag.
1383 */
1384 continue;
1385 }
1386
1387 const bool discardHalf[] = { false, true };
1388 const char* const discardHalfStr[] = { "", "_discard" };
1389
1390 for (int discardHalfIdx = 0; discardHalfIdx < DE_LENGTH_OF_ARRAY(discardHalf); ++discardHalfIdx)
1391 {
1392 OcclusionQueryTestVector testVector = baseTestVector;
1393 testVector.queryControlFlags = controlFlags[controlFlagIdx];
1394 testVector.queryResultSize = resultSize[resultSizeIdx];
1395 testVector.queryWait = wait[waitIdx];
1396 testVector.queryResultsMode = resultsMode[resultsModeIdx];
1397 testVector.queryResultsStride = testVector.queryResultSize == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64);
1398 testVector.queryResultsAvailability = testAvailability[testAvailabilityIdx];
1399 testVector.primitiveTopology = primitiveTopology[primitiveTopologyIdx];
1400 testVector.discardHalf = discardHalf[discardHalfIdx];
1401
1402 if (testVector.discardHalf && testVector.primitiveTopology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
1403 continue; // Discarding half of the pixels in fragment shader doesn't make sense with one-pixel-sized points.
1404
1405 if (testVector.queryResultsAvailability)
1406 {
1407 testVector.queryResultsStride *= 2;
1408 }
1409
1410 std::ostringstream testName;
1411 std::ostringstream testDescr;
1412
1413 testName << resultsModeStr[resultsModeIdx] << "_results"
1414 << "_" << controlFlagsStr[controlFlagIdx]
1415 << "_size_" << resultSizeStr[resultSizeIdx]
1416 << "_wait_" << waitStr[waitIdx]
1417 << "_" << testAvailabilityStr[testAvailabilityIdx] << "_availability"
1418 << "_draw_" << primitiveTopologyStr[primitiveTopologyIdx]
1419 << discardHalfStr[discardHalfIdx];
1420
1421 testDescr << "draw occluded " << primitiveTopologyStr[primitiveTopologyIdx]
1422 << "with " << controlFlagsStr[controlFlagIdx] << ", "
1423 << resultsModeStr[resultsModeIdx] << " results "
1424 << testAvailabilityStr[testAvailabilityIdx] << " availability bit as "
1425 << resultSizeStr[resultSizeIdx] << "bit variables,"
1426 << (testVector.discardHalf ? " discarding half of the fragments," : "")
1427 << "wait for results on" << waitStr[waitIdx];
1428
1429 addChild(new QueryPoolOcclusionTest<OcclusionQueryTestInstance>(m_testCtx, testName.str().c_str(), testDescr.str().c_str(), testVector));
1430 }
1431 }
1432 }
1433
1434 /* Tests for clear operation within a occulusion query activated.
1435 * The query shouldn't count internal driver operations relevant to the clear operations.
1436 */
1437 const OcculusionQueryClearOp clearOp[] = { CLEAR_COLOR, CLEAR_DEPTH };
1438 const char* const clearOpStr[] = { "clear_color", "clear_depth" };
1439
1440 for (int clearOpIdx = 0; clearOpIdx < DE_LENGTH_OF_ARRAY(clearOp); ++clearOpIdx)
1441 {
1442 OcclusionQueryTestVector testVector = baseTestVector;
1443 testVector.queryControlFlags = controlFlags[controlFlagIdx];
1444 testVector.queryResultSize = resultSize[resultSizeIdx];
1445 testVector.queryWait = wait[waitIdx];
1446 testVector.queryResultsMode = RESULTS_MODE_GET;
1447 testVector.queryResultsStride = testVector.queryResultSize == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64);
1448 testVector.primitiveTopology = primitiveTopology[primitiveTopologyIdx];
1449 testVector.clearOp = clearOp[clearOpIdx];
1450
1451 std::ostringstream testName;
1452 std::ostringstream testDescr;
1453
1454 testName << "get_results"
1455 << "_" << controlFlagsStr[controlFlagIdx]
1456 << "_size_" << resultSizeStr[resultSizeIdx]
1457 << "_wait_" << waitStr[waitIdx]
1458 << "_without_availability"
1459 << "_draw_" << primitiveTopologyStr[primitiveTopologyIdx]
1460 << "_" << clearOpStr[clearOpIdx];
1461
1462 testDescr << "draw occluded " << primitiveTopologyStr[primitiveTopologyIdx]
1463 << "with " << controlFlagsStr[controlFlagIdx] << ", "
1464 << "get results without availability bit "
1465 << "with " << clearOpStr[clearOpIdx] << " as "
1466 << resultSizeStr[resultSizeIdx] << "bit variables,"
1467 << "wait for results on" << waitStr[waitIdx];
1468
1469 addChild(new QueryPoolOcclusionTest<OcclusionQueryTestInstance>(m_testCtx, testName.str().c_str(), testDescr.str().c_str(), testVector));
1470 }
1471
1472 // Tests with no color attachments.
1473 {
1474 OcclusionQueryTestVector testVector = baseTestVector;
1475 testVector.queryControlFlags = controlFlags[controlFlagIdx];
1476 testVector.queryResultSize = resultSize[resultSizeIdx];
1477 testVector.queryWait = wait[waitIdx];
1478 testVector.queryResultsMode = RESULTS_MODE_GET;
1479 testVector.queryResultsStride = testVector.queryResultSize == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64);
1480 testVector.primitiveTopology = primitiveTopology[primitiveTopologyIdx];
1481 testVector.noColorAttachments = true;
1482
1483 std::ostringstream testName;
1484 std::ostringstream testDescr;
1485
1486 testName << "get_results"
1487 << "_" << controlFlagsStr[controlFlagIdx]
1488 << "_size_" << resultSizeStr[resultSizeIdx]
1489 << "_wait_" << waitStr[waitIdx]
1490 << "_without_availability"
1491 << "_draw_" << primitiveTopologyStr[primitiveTopologyIdx]
1492 << "_no_color_attachments";
1493
1494 testDescr << "draw occluded " << primitiveTopologyStr[primitiveTopologyIdx]
1495 << "with " << controlFlagsStr[controlFlagIdx] << ", "
1496 << "get results without availability bit and attachments as "
1497 << resultSizeStr[resultSizeIdx] << "bit variables,"
1498 << "wait for results on" << waitStr[waitIdx];
1499
1500 addChild(new QueryPoolOcclusionTest<OcclusionQueryTestInstance>(m_testCtx, testName.str().c_str(), testDescr.str().c_str(), testVector));
1501 }
1502 }
1503 }
1504 }
1505 }
1506 }
1507 // Test different strides
1508 {
1509 const OcclusionQueryResultsMode resultsMode[] = { RESULTS_MODE_GET, RESULTS_MODE_GET_RESET, RESULTS_MODE_COPY, RESULTS_MODE_COPY_RESET };
1510 const char* const resultsModeStr[] = { "get", "get_reset", "copy", "copy_reset" };
1511
1512 for (int resultsModeIdx = 0; resultsModeIdx < DE_LENGTH_OF_ARRAY(resultsMode); ++resultsModeIdx)
1513 {
1514 const OcclusionQueryResultSize resultSizes[] = { RESULT_SIZE_32_BIT, RESULT_SIZE_64_BIT };
1515 const char* const resultSizeStr[] = { "32", "64" };
1516
1517 const deBool copyQueryDstOffset[] = { DE_TRUE, DE_FALSE };
1518 const char *const copyQueryDstOffsetStr[] = { "_dstoffset", ""};
1519
1520 const bool testAvailability[] = { false, true };
1521 const char* const testAvailabilityStr[] = { "without", "with" };
1522
1523 for (int testAvailabilityIdx = 0; testAvailabilityIdx < DE_LENGTH_OF_ARRAY(testAvailability); ++testAvailabilityIdx)
1524 {
1525 if (resultsMode[resultsModeIdx] == RESULTS_MODE_COPY_RESET && (! testAvailability[testAvailabilityIdx]))
1526 {
1527 /* In RESULTS_MODE_COPY_RESET mode we will reset queries and make sure the availability flag is set to zero. It
1528 * does not make sense to run in this mode without obtaining the availability flag.
1529 */
1530 continue;
1531 }
1532
1533 for (int resultSizeIdx = 0; resultSizeIdx < DE_LENGTH_OF_ARRAY(resultSizes); ++resultSizeIdx)
1534 {
1535 const vk::VkDeviceSize resultSize = (resultSizes[resultSizeIdx] == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64));
1536
1537 // \todo [2015-12-18 scygan] Ensure only stride values aligned to resultSize are allowed. Otherwise test should be extended.
1538 const vk::VkDeviceSize strides[] =
1539 {
1540 0u,
1541 1 * resultSize,
1542 2 * resultSize,
1543 3 * resultSize,
1544 4 * resultSize,
1545 5 * resultSize,
1546 13 * resultSize,
1547 1024 * resultSize
1548 };
1549
1550 for (int dstOffsetIdx = 0; dstOffsetIdx < DE_LENGTH_OF_ARRAY(copyQueryDstOffset); dstOffsetIdx++)
1551 {
1552 for (int strideIdx = 0; strideIdx < DE_LENGTH_OF_ARRAY(strides); strideIdx++)
1553 {
1554 OcclusionQueryTestVector testVector = baseTestVector;
1555 testVector.queryResultsMode = resultsMode[resultsModeIdx];
1556 testVector.queryResultSize = resultSizes[resultSizeIdx];
1557 testVector.queryResultsAvailability = testAvailability[testAvailabilityIdx];
1558 testVector.queryResultsStride = strides[strideIdx];
1559 testVector.queryResultsDstOffset = copyQueryDstOffset[dstOffsetIdx];
1560
1561 const vk::VkDeviceSize elementSize = (testVector.queryResultsAvailability ? resultSize * 2 : resultSize);
1562
1563 if (elementSize > testVector.queryResultsStride && strides[strideIdx] != 0)
1564 {
1565 continue;
1566 }
1567
1568 if (strides[strideIdx] == 0)
1569 {
1570 // Due to the nature of the test, the dstOffset is tested automatically when stride size is 0.
1571 if (testVector.queryResultsDstOffset)
1572 {
1573 continue;
1574 }
1575
1576 // We are testing only VkCmdCopyQueryPoolResults with stride 0.
1577 if (testVector.queryResultsMode != RESULTS_MODE_COPY)
1578 {
1579 continue;
1580 }
1581 }
1582
1583 std::ostringstream testName;
1584 std::ostringstream testDescr;
1585
1586 testName << resultsModeStr[resultsModeIdx]
1587 << "_results_size_" << resultSizeStr[resultSizeIdx]
1588 << "_stride_" << strides[strideIdx]
1589 << "_" << testAvailabilityStr[testAvailabilityIdx] << "_availability"
1590 << copyQueryDstOffsetStr[dstOffsetIdx];
1591
1592 testDescr << resultsModeStr[resultsModeIdx] << " results "
1593 << testAvailabilityStr[testAvailabilityIdx] << " availability bit as "
1594 << resultSizeStr[resultSizeIdx] << "bit variables, with stride" << strides[strideIdx];
1595
1596 addChild(new QueryPoolOcclusionTest<OcclusionQueryTestInstance>(m_testCtx, testName.str().c_str(), testDescr.str().c_str(), testVector));
1597 }
1598 }
1599 }
1600 }
1601 }
1602
1603 }
1604 }
1605
1606 } //QueryPool
1607 } //vkt
1608