1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Intel Corporation
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * \brief Vulkan Occlusion Query Tests
23 *//*--------------------------------------------------------------------*/
25 #include "vktQueryPoolOcclusionTests.hpp"
27 #include "vktTestCase.hpp"
29 #include "vktDrawImageObjectUtil.hpp"
30 #include "vktDrawBufferObjectUtil.hpp"
31 #include "vktDrawCreateInfoUtil.hpp"
32 #include "vkBuilderUtil.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkPrograms.hpp"
36 #include "tcuTestLog.hpp"
37 #include "tcuResource.hpp"
38 #include "tcuImageCompare.hpp"
39 #include "tcuCommandLine.hpp"
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);
63 vkt::Context &m_context;
65 vk::Move<vk::VkPipeline> m_pipeline;
66 vk::Move<vk::VkPipelineLayout> m_pipelineLayout;
68 de::SharedPtr<Image> m_colorAttachmentImage, m_DepthImage;
69 vk::Move<vk::VkImageView> m_attachmentView;
70 vk::Move<vk::VkImageView> m_depthiew;
72 vk::Move<vk::VkRenderPass> m_renderPass;
73 vk::Move<vk::VkFramebuffer> m_framebuffer;
75 de::SharedPtr<Buffer> m_vertexBuffer;
77 vk::VkFormat m_colorAttachmentFormat;
80 StateObjects::StateObjects (const vk::DeviceInterface&vk, vkt::Context &context, const int numVertices, vk::VkPrimitiveTopology primitive)
82 , m_colorAttachmentFormat(vk::VK_FORMAT_R8G8B8A8_UNORM)
85 vk::VkFormat depthFormat = vk::VK_FORMAT_D16_UNORM;
86 const vk::VkDevice device = m_context.getDevice();
88 //attachment images and views
90 vk::VkExtent3D imageExtent =
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);
100 m_colorAttachmentImage = Image::createAndAlloc(vk, device, colorImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
102 const ImageViewCreateInfo attachmentViewInfo(m_colorAttachmentImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
103 m_attachmentView = vk::createImageView(vk, device, &attachmentViewInfo);
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);
108 m_DepthImage = Image::createAndAlloc(vk, device, depthImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
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);
116 // Renderpass and Framebuffer
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
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
137 const vk::VkAttachmentReference colorAttachmentReference =
140 vk::VK_IMAGE_LAYOUT_GENERAL // layout
143 const vk::VkAttachmentReference depthAttachmentReference =
146 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // layout
149 renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
152 DE_NULL, // pInputAttachments
154 &colorAttachmentReference, // pColorAttachments
155 DE_NULL, // pResolveAttachments
156 depthAttachmentReference, // depthStencilAttachment
158 DE_NULL)); // preserveAttachments
160 m_renderPass = vk::createRenderPass(vk, device, &renderPassCreateInfo);
162 std::vector<vk::VkImageView> attachments(2);
163 attachments[0] = *m_attachmentView;
164 attachments[1] = *m_depthiew;
166 FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, attachments, WIDTH, HEIGHT, 1);
167 m_framebuffer = vk::createFramebuffer(vk, device, &framebufferCreateInfo);
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));
176 const PipelineCreateInfo::ColorBlendState::Attachment attachmentState;
178 const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
179 m_pipelineLayout = vk::createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
181 const vk::VkVertexInputBindingDescription vf_binding_desc =
184 4 * (deUint32)sizeof(float), // stride;
185 vk::VK_VERTEX_INPUT_RATE_VERTEX // inputRate
188 const vk::VkVertexInputAttributeDescription vf_attribute_desc =
192 vk::VK_FORMAT_R32G32B32A32_SFLOAT, // format;
196 const vk::VkPipelineVertexInputStateCreateInfo vf_info =
198 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // pNext;
200 0u, // vertexBindingDescriptionCount;
201 1, // pVertexBindingDescriptions;
202 &vf_binding_desc, // vertexAttributeDescriptionCount;
203 1, // pVertexAttributeDescriptions;
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 =
216 WIDTH, // float width;
217 HEIGHT, // float height;
218 0.0f, // float minDepth;
219 1.0f // float maxDepth;
222 const vk::VkRect2D scissor =
227 }, // VkOffset2D offset;
229 WIDTH, // deInt32 width;
230 HEIGHT, // deInt32 height
231 }, // VkExtent2D extent;
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);
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);
248 void StateObjects::setVertices (const vk::DeviceInterface&vk, std::vector<tcu::Vec4> vertices)
250 const vk::VkDevice device = m_context.getDevice();
252 tcu::Vec4 *ptr = reinterpret_cast<tcu::Vec4*>(m_vertexBuffer->getBoundMemory().getHostPtr());
253 std::copy(vertices.begin(), vertices.end(), ptr);
255 vk::flushMappedMemoryRange(vk, device, m_vertexBuffer->getBoundMemory().getMemory(), m_vertexBuffer->getBoundMemory().getOffset(), vertices.size() * sizeof(vertices[0]));
258 enum OcclusionQueryResultSize
264 enum OcclusionQueryWait
271 enum OcclusionQueryResultsMode
277 struct OcclusionQueryTestVector
279 vk::VkQueryControlFlags queryControlFlags;
280 OcclusionQueryResultSize queryResultSize;
281 OcclusionQueryWait queryWait;
282 OcclusionQueryResultsMode queryResultsMode;
283 vk::VkDeviceSize queryResultsStride;
284 bool queryResultsAvailability;
285 vk::VkPrimitiveTopology primitiveTopology;
289 class BasicOcclusionQueryTestInstance : public vkt::TestInstance
292 BasicOcclusionQueryTestInstance (vkt::Context &context, const OcclusionQueryTestVector& testVector);
293 ~BasicOcclusionQueryTestInstance (void);
295 tcu::TestStatus iterate (void);
299 NUM_QUERIES_IN_POOL = 2,
300 QUERY_INDEX_CAPTURE_EMPTY = 0,
301 QUERY_INDEX_CAPTURE_DRAWCALL = 1,
302 NUM_VERTICES_IN_DRAWCALL = 3
305 OcclusionQueryTestVector m_testVector;
306 StateObjects* m_stateObjects;
307 vk::VkQueryPool m_queryPool;
310 BasicOcclusionQueryTestInstance::BasicOcclusionQueryTestInstance (vkt::Context &context, const OcclusionQueryTestVector& testVector)
311 : TestInstance (context)
312 , m_testVector (testVector)
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);
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");
324 m_stateObjects = new StateObjects(m_context.getDeviceInterface(), m_context, NUM_VERTICES_IN_DRAWCALL, m_testVector.primitiveTopology);
326 const vk::VkDevice device = m_context.getDevice();
327 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
329 const vk::VkQueryPoolCreateInfo queryPoolCreateInfo =
331 vk::VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
334 vk::VK_QUERY_TYPE_OCCLUSION,
338 VK_CHECK(vk.createQueryPool(device, &queryPoolCreateInfo, /*pAllocator*/ DE_NULL, &m_queryPool));
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);
347 BasicOcclusionQueryTestInstance::~BasicOcclusionQueryTestInstance (void)
350 delete m_stateObjects;
352 if (m_queryPool != DE_NULL)
354 const vk::VkDevice device = m_context.getDevice();
355 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
357 vk.destroyQueryPool(device, m_queryPool, /*pAllocator*/ DE_NULL);
361 tcu::TestStatus BasicOcclusionQueryTestInstance::iterate (void)
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();
368 const CmdPoolCreateInfo cmdPoolCreateInfo (m_context.getUniversalQueueFamilyIndex());
369 vk::Move<vk::VkCommandPool> cmdPool = vk::createCommandPool(vk, device, &cmdPoolCreateInfo);
371 vk::Unique<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
372 const CmdBufferBeginInfo beginInfo (0u);
374 vk.beginCommandBuffer(*cmdBuffer, &beginInfo);
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);
381 std::vector<vk::VkClearValue> renderPassClearValues(2);
382 deMemset(&renderPassClearValues[0], 0, static_cast<int>(renderPassClearValues.size()) * sizeof(vk::VkClearValue));
384 const vk::VkRect2D renderArea =
387 { StateObjects::WIDTH, StateObjects::HEIGHT }
390 RenderPassBeginInfo renderPassBegin(*m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, renderArea, renderPassClearValues);
392 vk.cmdResetQueryPool(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL);
394 vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBegin, vk::VK_SUBPASS_CONTENTS_INLINE);
396 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
398 vk::VkBuffer vertexBuffer = m_stateObjects->m_vertexBuffer->object();
399 const vk::VkDeviceSize vertexBufferOffset = 0;
400 vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
402 vk.cmdBeginQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_EMPTY, m_testVector.queryControlFlags);
403 vk.cmdEndQuery(*cmdBuffer, m_queryPool, QUERY_INDEX_CAPTURE_EMPTY);
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);
409 vk.cmdEndRenderPass(*cmdBuffer);
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);
415 vk.endCommandBuffer(*cmdBuffer);
417 // Submit command buffer
418 const vk::VkSubmitInfo submitInfo =
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;
430 vk.queueSubmit(queue, 1, &submitInfo, DE_NULL);
432 VK_CHECK(vk.queueWaitIdle(queue));
434 deUint64 queryResults[NUM_QUERIES_IN_POOL] = { 0 };
435 size_t queryResultsSize = sizeof(queryResults);
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);
439 if (queryResult == vk::VK_NOT_READY)
441 TCU_FAIL("Query result not avaliable, but vkWaitIdle() was called.");
444 VK_CHECK(queryResult);
446 log << tcu::TestLog::Section("OcclusionQueryResults",
447 "Occlusion query results");
448 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(queryResults); ++ndx)
450 log << tcu::TestLog::Message << "query[ slot == " << ndx
451 << "] result == " << queryResults[ndx] << tcu::TestLog::EndMessage;
456 for (int queryNdx = 0; queryNdx < DE_LENGTH_OF_ARRAY(queryResults); ++queryNdx)
459 deUint64 expectedValue;
463 case QUERY_INDEX_CAPTURE_EMPTY:
466 case QUERY_INDEX_CAPTURE_DRAWCALL:
467 expectedValue = NUM_VERTICES_IN_DRAWCALL;
471 if ((m_testVector.queryControlFlags & vk::VK_QUERY_CONTROL_PRECISE_BIT) || expectedValue == 0)
473 // require precise value
474 if (queryResults[queryNdx] != expectedValue)
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;
485 // require imprecize value > 0
486 if (queryResults[queryNdx] == 0)
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;
496 log << tcu::TestLog::EndSection;
500 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Query result verification passed");
502 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Query result verification failed");
505 class OcclusionQueryTestInstance : public vkt::TestInstance
508 OcclusionQueryTestInstance (vkt::Context &context, const OcclusionQueryTestVector& testVector);
509 ~OcclusionQueryTestInstance (void);
511 tcu::TestStatus iterate (void);
513 bool hasSeparateResetCmdBuf (void) const;
514 bool hasSeparateCopyCmdBuf (void) const;
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);
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);
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
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
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
545 OcclusionQueryTestVector m_testVector;
547 const vk::VkQueryResultFlags m_queryResultFlags;
549 StateObjects* m_stateObjects;
550 vk::VkQueryPool m_queryPool;
551 de::SharedPtr<Buffer> m_queryPoolResultsBuffer;
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;
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))
566 const vk::VkDevice device = m_context.getDevice();
567 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
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");
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);
574 const vk::VkQueryPoolCreateInfo queryPoolCreateInfo =
576 vk::VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,
579 vk::VK_QUERY_TYPE_OCCLUSION,
584 VK_CHECK(vk.createQueryPool(device, &queryPoolCreateInfo, /*pAllocator*/ DE_NULL, &m_queryPool));
586 if (m_testVector.queryResultsMode == RESULTS_MODE_COPY)
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);
592 const CmdPoolCreateInfo cmdPoolCreateInfo (m_context.getUniversalQueueFamilyIndex());
593 m_commandPool = vk::createCommandPool(vk, device, &cmdPoolCreateInfo);
594 m_renderCommandBuffer = recordRender(*m_commandPool);
596 if (hasSeparateResetCmdBuf())
598 m_queryPoolResetCommandBuffer = recordQueryPoolReset(*m_commandPool);
601 if (hasSeparateCopyCmdBuf())
603 m_copyResultsCommandBuffer = recordCopyResults(*m_commandPool);
607 OcclusionQueryTestInstance::~OcclusionQueryTestInstance (void)
609 const vk::VkDevice device = m_context.getDevice();
612 delete m_stateObjects;
614 if (m_queryPool != DE_NULL)
616 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
617 vk.destroyQueryPool(device, m_queryPool, /*pAllocator*/ DE_NULL);
621 tcu::TestStatus OcclusionQueryTestInstance::iterate (void)
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);
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);
641 m_stateObjects->setVertices(vk, vertices);
643 if (hasSeparateResetCmdBuf())
645 const vk::VkSubmitInfo submitInfoReset =
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;
658 vk.queueSubmit(queue, 1, &submitInfoReset, DE_NULL);
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
663 VK_CHECK(vk.queueWaitIdle(queue));
667 const vk::VkSubmitInfo submitInfoRender =
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;
679 vk.queueSubmit(queue, 1, &submitInfoRender, DE_NULL);
682 if (m_testVector.queryWait == WAIT_QUEUE)
684 VK_CHECK(vk.queueWaitIdle(queue));
687 if (hasSeparateCopyCmdBuf())
689 // In case of WAIT_QUEUE test variant, the previously submitted m_renderCommandBuffer did not
690 // contain vkCmdCopyQueryResults, so additional cmd buffer is needed.
692 // In the case of WAIT_NONE or WAIT_QUERY, vkCmdCopyQueryResults is stored in m_renderCommandBuffer.
694 const vk::VkSubmitInfo submitInfo =
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;
706 vk.queueSubmit(queue, 1, &submitInfo, DE_NULL);
709 if (m_testVector.queryResultsMode == RESULTS_MODE_COPY)
711 // In case of vkCmdCopyQueryResults is used, test must always wait for it
712 // to complete before we can read the result buffer.
714 VK_CHECK(vk.queueWaitIdle(queue));
717 deUint64 queryResults [NUM_QUERIES_IN_POOL];
718 deUint64 queryAvailability [NUM_QUERIES_IN_POOL];
720 // Allow not ready results only if nobody waited before getting the query results
721 const bool allowNotReady = (m_testVector.queryWait == WAIT_NONE);
723 captureResults(queryResults, queryAvailability, allowNotReady);
725 log << tcu::TestLog::Section("OcclusionQueryResults", "Occlusion query results");
727 logResults(queryResults, queryAvailability);
728 bool passed = validateResults(queryResults, queryAvailability, allowNotReady, m_testVector.primitiveTopology);
730 log << tcu::TestLog::EndSection;
732 if (m_testVector.queryResultsMode != RESULTS_MODE_COPY)
734 VK_CHECK(vk.queueWaitIdle(queue));
739 return tcu::TestStatus(QP_TEST_RESULT_PASS, "Query result verification passed");
741 return tcu::TestStatus(QP_TEST_RESULT_FAIL, "Query result verification failed");
744 bool OcclusionQueryTestInstance::hasSeparateResetCmdBuf (void) const
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.
749 if (m_testVector.queryResultsMode == RESULTS_MODE_COPY)
751 // We copy query results on device, so there is no race condition between
755 if (m_testVector.queryWait == WAIT_QUEUE)
757 // We wait for queue to be complete before accessing query results
761 // Separate command buffer with reset must be submitted & completed before
762 // host accesses the query results
766 bool OcclusionQueryTestInstance::hasSeparateCopyCmdBuf (void) const
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);
772 vk::Move<vk::VkCommandBuffer> OcclusionQueryTestInstance::recordQueryPoolReset (vk::VkCommandPool cmdPool)
774 const vk::VkDevice device = m_context.getDevice();
775 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
777 DE_ASSERT(hasSeparateResetCmdBuf());
779 vk::Move<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
780 CmdBufferBeginInfo beginInfo (0u);
782 vk.beginCommandBuffer(*cmdBuffer, &beginInfo);
783 vk.cmdResetQueryPool(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL);
784 vk.endCommandBuffer(*cmdBuffer);
789 vk::Move<vk::VkCommandBuffer> OcclusionQueryTestInstance::recordRender (vk::VkCommandPool cmdPool)
791 const vk::VkDevice device = m_context.getDevice();
792 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
794 vk::Move<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
795 CmdBufferBeginInfo beginInfo (0u);
797 vk.beginCommandBuffer(*cmdBuffer, &beginInfo);
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);
804 std::vector<vk::VkClearValue> renderPassClearValues(2);
805 deMemset(&renderPassClearValues[0], 0, static_cast<int>(renderPassClearValues.size()) * sizeof(vk::VkClearValue));
807 const vk::VkRect2D renderArea =
810 { StateObjects::WIDTH, StateObjects::HEIGHT }
813 RenderPassBeginInfo renderPassBegin(*m_stateObjects->m_renderPass, *m_stateObjects->m_framebuffer, renderArea, renderPassClearValues);
815 if (!hasSeparateResetCmdBuf())
817 vk.cmdResetQueryPool(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL);
820 vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBegin, vk::VK_SUBPASS_CONTENTS_INLINE);
822 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_stateObjects->m_pipeline);
824 vk::VkBuffer vertexBuffer = m_stateObjects->m_vertexBuffer->object();
825 const vk::VkDeviceSize vertexBufferOffset = 0;
826 vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertexBuffer, &vertexBufferOffset);
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);
833 // Partially occlude geometry
834 vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_PARTIALLY_OCCLUDED_DRAWCALL, 1, START_VERTEX_PARTIALLY_OCCLUDED, 0);
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);
842 vk.cmdDraw(*cmdBuffer, NUM_VERTICES_IN_OCCLUDER_DRAWCALL, 1, START_VERTEX_OCCLUDER, 0);
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);
849 vk.cmdEndRenderPass(*cmdBuffer);
851 if (m_testVector.queryResultsMode == RESULTS_MODE_COPY && !hasSeparateCopyCmdBuf())
853 vk.cmdCopyQueryPoolResults(*cmdBuffer, m_queryPool, 0, NUM_QUERIES_IN_POOL, m_queryPoolResultsBuffer->object(), /*dstOffset*/ 0, m_testVector.queryResultsStride, m_queryResultFlags);
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);
860 vk.endCommandBuffer(*cmdBuffer);
865 vk::Move<vk::VkCommandBuffer> OcclusionQueryTestInstance::recordCopyResults (vk::VkCommandPool cmdPool)
867 const vk::VkDevice device = m_context.getDevice();
868 const vk::DeviceInterface& vk = m_context.getDeviceInterface();
870 vk::Move<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
871 const CmdBufferBeginInfo beginInfo (0u);
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);
880 void OcclusionQueryTestInstance::captureResults (deUint64* retResults, deUint64* retAvailAbility, bool allowNotReady)
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);
887 if (m_testVector.queryResultsMode == RESULTS_MODE_GET)
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)
892 TCU_FAIL("getQueryPoolResults returned VK_NOT_READY, but results should be already available.");
896 VK_CHECK(queryResult);
899 else if (m_testVector.queryResultsMode == RESULTS_MODE_COPY)
901 const vk::Allocation& allocation = m_queryPoolResultsBuffer->getBoundMemory();
902 const void* allocationData = allocation.getHostPtr();
904 vk::invalidateMappedMemoryRange(vk, device, allocation.getMemory(), allocation.getOffset(), resultsBuffer.size());
906 deMemcpy(&resultsBuffer[0], allocationData, resultsBuffer.size());
909 for (int queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; queryNdx++)
911 const void* srcPtr = &resultsBuffer[queryNdx * static_cast<size_t>(m_testVector.queryResultsStride)];
912 if (m_testVector.queryResultSize == RESULT_SIZE_32_BIT)
914 const deUint32* srcPtrTyped = static_cast<const deUint32*>(srcPtr);
915 retResults[queryNdx] = *srcPtrTyped;
916 if (m_testVector.queryResultsAvailability)
918 retAvailAbility[queryNdx] = *(srcPtrTyped + 1);
921 else if (m_testVector.queryResultSize == RESULT_SIZE_64_BIT)
923 const deUint64* srcPtrTyped = static_cast<const deUint64*>(srcPtr);
924 retResults[queryNdx] = *srcPtrTyped;
926 if (m_testVector.queryResultsAvailability)
928 if (m_testVector.queryResultsAvailability)
930 retAvailAbility[queryNdx] = *(srcPtrTyped + 1);
936 TCU_FAIL("Wrong m_testVector.queryResultSize");
941 void OcclusionQueryTestInstance::logResults (const deUint64* results, const deUint64* availability)
943 tcu::TestLog& log = m_context.getTestContext().getLog();
945 for (int ndx = 0; ndx < NUM_QUERIES_IN_POOL; ++ndx)
947 if (!m_testVector.queryResultsAvailability)
949 log << tcu::TestLog::Message << "query[ slot == " << ndx << "] result == " << results[ndx] << tcu::TestLog::EndMessage;
953 log << tcu::TestLog::Message << "query[ slot == " << ndx << "] result == " << results[ndx] << ", availability == " << availability[ndx] << tcu::TestLog::EndMessage;
958 bool OcclusionQueryTestInstance::validateResults (const deUint64* results , const deUint64* availability, bool allowUnavailable, vk::VkPrimitiveTopology primitiveTopology)
961 tcu::TestLog& log = m_context.getTestContext().getLog();
963 for (int queryNdx = 0; queryNdx < NUM_QUERIES_IN_POOL; ++queryNdx)
965 deUint64 expectedValueMin = 0;
966 deUint64 expectedValueMax = 0;
968 if (m_testVector.queryResultsAvailability && availability[queryNdx] == 0)
970 // query result was not available
971 if (!allowUnavailable)
973 log << tcu::TestLog::Message << "query results availability was 0 for index "
974 << queryNdx << ", expected any value greater than 0." << tcu::TestLog::EndMessage;
981 // query is available, so expect proper result values
982 if (primitiveTopology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
986 case QUERY_INDEX_CAPTURE_OCCLUDED:
987 expectedValueMin = 0;
988 expectedValueMax = 0;
990 case QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED:
991 expectedValueMin = 1;
992 expectedValueMax = 1;
994 case QUERY_INDEX_CAPTURE_ALL:
995 expectedValueMin = NUM_VERTICES_IN_DRAWCALL;
996 expectedValueMax = NUM_VERTICES_IN_DRAWCALL;
1000 else if (primitiveTopology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
1004 case QUERY_INDEX_CAPTURE_OCCLUDED:
1005 expectedValueMin = 0;
1006 expectedValueMax = 0;
1008 case QUERY_INDEX_CAPTURE_PARTIALLY_OCCLUDED:
1009 case QUERY_INDEX_CAPTURE_ALL:
1011 const int primWidth = StateObjects::WIDTH / 2;
1012 const int primHeight = StateObjects::HEIGHT / 2;
1013 const int primArea = primWidth * primHeight / 2;
1015 if (m_testVector.discardHalf)
1017 expectedValueMin = (int)(0.95f * primArea * 0.5f);
1018 expectedValueMax = (int)(1.05f * primArea * 0.5f);
1022 expectedValueMin = (int)(0.97f * primArea);
1023 expectedValueMax = (int)(1.03f * primArea);
1030 TCU_FAIL("Unsupported primitive topology");
1034 if ((m_testVector.queryControlFlags & vk::VK_QUERY_CONTROL_PRECISE_BIT) || (expectedValueMin == 0 && expectedValueMax == 0))
1036 // require precise value
1037 if (results[queryNdx] < expectedValueMin || results[queryNdx] > expectedValueMax)
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;
1047 // require imprecise value greater than 0
1048 if (results[queryNdx] == 0)
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;
1060 template<class Instance>
1061 class QueryPoolOcclusionTest : public vkt::TestCase
1064 QueryPoolOcclusionTest (tcu::TestContext &context, const char *name, const char *description, const OcclusionQueryTestVector& testVector)
1065 : TestCase (context, name, description)
1066 , m_testVector (testVector)
1070 vkt::TestInstance* createInstance (vkt::Context& context) const
1072 return new Instance(context, m_testVector);
1075 void initPrograms(vk::SourceCollections& programCollection) const
1077 const char* const discard =
1078 " if ((int(gl_FragCoord.x) % 2) == (int(gl_FragCoord.y) % 2))\n"
1081 const std::string fragSrc = std::string(
1083 "layout(location = 0) out vec4 out_FragColor;\n"
1086 " out_FragColor = vec4(0.07, 0.48, 0.75, 1.0);\n")
1087 + std::string(m_testVector.discardHalf ? discard : "")
1090 programCollection.glslSources.add("frag") << glu::FragmentSource(fragSrc.c_str());
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"
1096 " gl_Position = in_Position;\n"
1097 " gl_PointSize = 1.0;\n"
1101 OcclusionQueryTestVector m_testVector;
1106 QueryPoolOcclusionTests::QueryPoolOcclusionTests (tcu::TestContext &testCtx)
1107 : TestCaseGroup(testCtx, "occlusion_query", "Tests for occlusion queries")
1109 /* Left blank on purpose */
1112 QueryPoolOcclusionTests::~QueryPoolOcclusionTests (void)
1114 /* Left blank on purpose */
1117 void QueryPoolOcclusionTests::init (void)
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;
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));
1140 const vk::VkQueryControlFlags controlFlags[] = { 0, vk::VK_QUERY_CONTROL_PRECISE_BIT };
1141 const char* const controlFlagsStr[] = { "conservative", "precise" };
1143 for (int controlFlagIdx = 0; controlFlagIdx < DE_LENGTH_OF_ARRAY(controlFlags); ++controlFlagIdx)
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)
1151 const OcclusionQueryResultSize resultSize[] = { RESULT_SIZE_32_BIT, RESULT_SIZE_64_BIT };
1152 const char* const resultSizeStr[] = { "32", "64" };
1154 for (int resultSizeIdx = 0; resultSizeIdx < DE_LENGTH_OF_ARRAY(resultSize); ++resultSizeIdx)
1157 const OcclusionQueryWait wait[] = { WAIT_QUEUE, WAIT_QUERY };
1158 const char* const waitStr[] = { "queue", "query" };
1160 for (int waitIdx = 0; waitIdx < DE_LENGTH_OF_ARRAY(wait); ++waitIdx)
1162 const OcclusionQueryResultsMode resultsMode[] = { RESULTS_MODE_GET, RESULTS_MODE_COPY };
1163 const char* const resultsModeStr[] = { "get", "copy" };
1165 for (int resultsModeIdx = 0; resultsModeIdx < DE_LENGTH_OF_ARRAY(resultsMode); ++resultsModeIdx)
1168 const bool testAvailability[] = { false, true };
1169 const char* const testAvailabilityStr[] = { "without", "with"};
1171 for (int testAvailabilityIdx = 0; testAvailabilityIdx < DE_LENGTH_OF_ARRAY(testAvailability); ++testAvailabilityIdx)
1173 const bool discardHalf[] = { false, true };
1174 const char* const discardHalfStr[] = { "", "_discard" };
1176 for (int discardHalfIdx = 0; discardHalfIdx < DE_LENGTH_OF_ARRAY(discardHalf); ++discardHalfIdx)
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];
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.
1191 if (testVector.queryResultsAvailability)
1193 testVector.queryResultsStride *= 2;
1196 std::ostringstream testName;
1197 std::ostringstream testDescr;
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];
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];
1215 addChild(new QueryPoolOcclusionTest<OcclusionQueryTestInstance>(m_testCtx, testName.str().c_str(), testDescr.str().c_str(), testVector));
1224 // Test different strides
1226 const OcclusionQueryResultsMode resultsMode[] = { RESULTS_MODE_GET, RESULTS_MODE_COPY };
1227 const char* const resultsModeStr[] = { "get", "copy" };
1229 for (int resultsModeIdx = 0; resultsModeIdx < DE_LENGTH_OF_ARRAY(resultsMode); ++resultsModeIdx)
1231 const OcclusionQueryResultSize resultSizes[] = { RESULT_SIZE_32_BIT, RESULT_SIZE_64_BIT };
1232 const char* const resultSizeStr[] = { "32", "64" };
1234 const bool testAvailability[] = { false, true };
1235 const char* const testAvailabilityStr[] = { "without", "with" };
1237 for (int testAvailabilityIdx = 0; testAvailabilityIdx < DE_LENGTH_OF_ARRAY(testAvailability); ++testAvailabilityIdx)
1239 for (int resultSizeIdx = 0; resultSizeIdx < DE_LENGTH_OF_ARRAY(resultSizes); ++resultSizeIdx)
1241 const vk::VkDeviceSize resultSize = (resultSizes[resultSizeIdx] == RESULT_SIZE_32_BIT ? sizeof(deUint32) : sizeof(deUint64));
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[] =
1255 for (int strideIdx = 0; strideIdx < DE_LENGTH_OF_ARRAY(strides); strideIdx++)
1257 OcclusionQueryTestVector testVector = baseTestVector;
1258 testVector.queryResultsMode = resultsMode[resultsModeIdx];
1259 testVector.queryResultSize = resultSizes[resultSizeIdx];
1260 testVector.queryResultsAvailability = testAvailability[testAvailabilityIdx];
1261 testVector.queryResultsStride = strides[strideIdx];
1263 const vk::VkDeviceSize elementSize = (testVector.queryResultsAvailability ? resultSize * 2 : resultSize);
1265 if (elementSize > testVector.queryResultsStride)
1270 std::ostringstream testName;
1271 std::ostringstream testDescr;
1273 testName << resultsModeStr[resultsModeIdx]
1274 << "_results_size_" << resultSizeStr[resultSizeIdx]
1275 << "_stride_" << strides[strideIdx]
1276 << "_" << testAvailabilityStr[testAvailabilityIdx] << "_availability";
1278 testDescr << resultsModeStr[resultsModeIdx] << " results "
1279 << testAvailabilityStr[testAvailabilityIdx] << " availability bit as "
1280 << resultSizeStr[resultSizeIdx] << "bit variables, with stride" << strides[strideIdx];
1282 addChild(new QueryPoolOcclusionTest<OcclusionQueryTestInstance>(m_testCtx, testName.str().c_str(), testDescr.str().c_str(), testVector));