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