1 /*------------------------------------------------------------------------- 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2017 Google Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Tests for render pass multisample resolve 22 *//*--------------------------------------------------------------------*/ 23 24 #include "vktRenderPassMultisampleResolveTests.hpp" 25 26 #include "vktTestCaseUtil.hpp" 27 #include "vktTestGroupUtil.hpp" 28 29 #include "vkDefs.hpp" 30 #include "vkDeviceUtil.hpp" 31 #include "vkImageUtil.hpp" 32 #include "vkMemUtil.hpp" 33 #include "vkPlatform.hpp" 34 #include "vkPrograms.hpp" 35 #include "vkQueryUtil.hpp" 36 #include "vkRef.hpp" 37 #include "vkRefUtil.hpp" 38 #include "vkTypeUtil.hpp" 39 40 #include "tcuFloat.hpp" 41 #include "tcuImageCompare.hpp" 42 #include "tcuFormatUtil.hpp" 43 #include "tcuMaybe.hpp" 44 #include "tcuResultCollector.hpp" 45 #include "tcuTestLog.hpp" 46 #include "tcuTextureUtil.hpp" 47 #include "tcuVectorUtil.hpp" 48 49 #include "deUniquePtr.hpp" 50 #include "deSharedPtr.hpp" 51 52 using namespace vk; 53 54 using tcu::BVec4; 55 using tcu::IVec2; 56 using tcu::IVec4; 57 using tcu::UVec2; 58 using tcu::UVec4; 59 using tcu::Vec2; 60 using tcu::Vec4; 61 62 using tcu::Maybe; 63 using tcu::just; 64 using tcu::nothing; 65 66 using tcu::ConstPixelBufferAccess; 67 using tcu::PixelBufferAccess; 68 69 using tcu::TestLog; 70 71 using std::pair; 72 using std::string; 73 using std::vector; 74 75 typedef de::SharedPtr<vk::Unique<VkImage> > VkImageSp; 76 typedef de::SharedPtr<vk::Unique<VkImageView> > VkImageViewSp; 77 typedef de::SharedPtr<vk::Unique<VkBuffer> > VkBufferSp; 78 typedef de::SharedPtr<vk::Unique<VkPipeline> > VkPipelineSp; 79 80 namespace vkt 81 { 82 namespace 83 { 84 enum 85 { 86 MAX_COLOR_ATTACHMENT_COUNT = 4u 87 }; 88 89 template<typename T> 90 de::SharedPtr<T> safeSharedPtr (T* ptr) 91 { 92 try 93 { 94 return de::SharedPtr<T>(ptr); 95 } 96 catch (...) 97 { 98 delete ptr; 99 throw; 100 } 101 } 102 103 void bindBufferMemory (const DeviceInterface& vk, VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memOffset) 104 { 105 VK_CHECK(vk.bindBufferMemory(device, buffer, mem, memOffset)); 106 } 107 108 void bindImageMemory (const DeviceInterface& vk, VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memOffset) 109 { 110 VK_CHECK(vk.bindImageMemory(device, image, mem, memOffset)); 111 } 112 113 de::MovePtr<Allocation> createBufferMemory (const DeviceInterface& vk, 114 VkDevice device, 115 Allocator& allocator, 116 VkBuffer buffer) 117 { 118 de::MovePtr<Allocation> allocation (allocator.allocate(getBufferMemoryRequirements(vk, device, buffer), MemoryRequirement::HostVisible)); 119 bindBufferMemory(vk, device, buffer, allocation->getMemory(), allocation->getOffset()); 120 return allocation; 121 } 122 123 de::MovePtr<Allocation> createImageMemory (const DeviceInterface& vk, 124 VkDevice device, 125 Allocator& allocator, 126 VkImage image) 127 { 128 de::MovePtr<Allocation> allocation (allocator.allocate(getImageMemoryRequirements(vk, device, image), MemoryRequirement::Any)); 129 bindImageMemory(vk, device, image, allocation->getMemory(), allocation->getOffset()); 130 return allocation; 131 } 132 133 Move<VkImage> createImage (const DeviceInterface& vk, 134 VkDevice device, 135 VkImageCreateFlags flags, 136 VkImageType imageType, 137 VkFormat format, 138 VkExtent3D extent, 139 deUint32 mipLevels, 140 deUint32 arrayLayers, 141 VkSampleCountFlagBits samples, 142 VkImageTiling tiling, 143 VkImageUsageFlags usage, 144 VkSharingMode sharingMode, 145 deUint32 queueFamilyCount, 146 const deUint32* pQueueFamilyIndices, 147 VkImageLayout initialLayout) 148 { 149 const VkImageCreateInfo pCreateInfo = 150 { 151 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 152 DE_NULL, 153 flags, 154 imageType, 155 format, 156 extent, 157 mipLevels, 158 arrayLayers, 159 samples, 160 tiling, 161 usage, 162 sharingMode, 163 queueFamilyCount, 164 pQueueFamilyIndices, 165 initialLayout 166 }; 167 return createImage(vk, device, &pCreateInfo); 168 } 169 170 Move<VkImageView> createImageView (const DeviceInterface& vk, 171 VkDevice device, 172 VkImageViewCreateFlags flags, 173 VkImage image, 174 VkImageViewType viewType, 175 VkFormat format, 176 VkComponentMapping components, 177 VkImageSubresourceRange subresourceRange) 178 { 179 const VkImageViewCreateInfo pCreateInfo = 180 { 181 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 182 DE_NULL, 183 flags, 184 image, 185 viewType, 186 format, 187 components, 188 subresourceRange, 189 }; 190 return createImageView(vk, device, &pCreateInfo); 191 } 192 193 Move<VkImage> createImage (const InstanceInterface& vki, 194 VkPhysicalDevice physicalDevice, 195 const DeviceInterface& vkd, 196 VkDevice device, 197 VkFormat vkFormat, 198 VkSampleCountFlagBits sampleCountBit, 199 VkImageUsageFlags usage, 200 deUint32 width, 201 deUint32 height) 202 { 203 try 204 { 205 const tcu::TextureFormat format (mapVkFormat(vkFormat)); 206 const VkImageType imageType (VK_IMAGE_TYPE_2D); 207 const VkImageTiling imageTiling (VK_IMAGE_TILING_OPTIMAL); 208 const VkFormatProperties formatProperties (getPhysicalDeviceFormatProperties(vki, physicalDevice, vkFormat)); 209 const VkImageFormatProperties imageFormatProperties (getPhysicalDeviceImageFormatProperties(vki, physicalDevice, vkFormat, imageType, imageTiling, usage, 0u)); 210 const VkExtent3D imageExtent = 211 { 212 width, 213 height, 214 1u 215 }; 216 217 if ((tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order)) 218 && (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) 219 TCU_THROW(NotSupportedError, "Format can't be used as depth stencil attachment"); 220 221 if (!(tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order)) 222 && (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0) 223 TCU_THROW(NotSupportedError, "Format can't be used as color attachment"); 224 225 if (imageFormatProperties.maxExtent.width < imageExtent.width 226 || imageFormatProperties.maxExtent.height < imageExtent.height 227 || ((imageFormatProperties.sampleCounts & sampleCountBit) == 0)) 228 { 229 TCU_THROW(NotSupportedError, "Image type not supported"); 230 } 231 232 return createImage(vkd, device, 0u, imageType, vkFormat, imageExtent, 1u, 1u, sampleCountBit, imageTiling, usage, VK_SHARING_MODE_EXCLUSIVE, 0u, DE_NULL, VK_IMAGE_LAYOUT_UNDEFINED); 233 } 234 catch (const vk::Error& error) 235 { 236 if (error.getError() == VK_ERROR_FORMAT_NOT_SUPPORTED) 237 TCU_THROW(NotSupportedError, "Image format not supported"); 238 239 throw; 240 } 241 } 242 243 Move<VkImageView> createImageView (const DeviceInterface& vkd, 244 VkDevice device, 245 VkImage image, 246 VkFormat format, 247 VkImageAspectFlags aspect) 248 { 249 const VkImageSubresourceRange range = 250 { 251 aspect, 252 0u, 253 1u, 254 0u, 255 1u 256 }; 257 258 return createImageView(vkd, device, 0u, image, VK_IMAGE_VIEW_TYPE_2D, format, makeComponentMappingRGBA(), range); 259 } 260 261 VkDeviceSize getPixelSize (VkFormat vkFormat) 262 { 263 const tcu::TextureFormat format (mapVkFormat(vkFormat)); 264 265 return format.getPixelSize(); 266 } 267 268 Move<VkBuffer> createBuffer (const DeviceInterface& vkd, 269 VkDevice device, 270 VkFormat format, 271 deUint32 width, 272 deUint32 height) 273 { 274 const VkBufferUsageFlags bufferUsage (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); 275 const VkDeviceSize pixelSize (getPixelSize(format)); 276 const VkBufferCreateInfo createInfo = 277 { 278 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 279 DE_NULL, 280 0u, 281 282 width * height * pixelSize, 283 bufferUsage, 284 285 VK_SHARING_MODE_EXCLUSIVE, 286 0u, 287 DE_NULL 288 }; 289 return createBuffer(vkd, device, &createInfo); 290 } 291 292 VkSampleCountFlagBits sampleCountBitFromSampleCount (deUint32 count) 293 { 294 switch (count) 295 { 296 case 1: return VK_SAMPLE_COUNT_1_BIT; 297 case 2: return VK_SAMPLE_COUNT_2_BIT; 298 case 4: return VK_SAMPLE_COUNT_4_BIT; 299 case 8: return VK_SAMPLE_COUNT_8_BIT; 300 case 16: return VK_SAMPLE_COUNT_16_BIT; 301 case 32: return VK_SAMPLE_COUNT_32_BIT; 302 case 64: return VK_SAMPLE_COUNT_64_BIT; 303 304 default: 305 DE_FATAL("Invalid sample count"); 306 return (VkSampleCountFlagBits)0x0; 307 } 308 } 309 310 std::vector<VkImageSp> createMultisampleImages (const InstanceInterface& vki, 311 VkPhysicalDevice physicalDevice, 312 const DeviceInterface& vkd, 313 VkDevice device, 314 VkFormat format, 315 deUint32 sampleCount, 316 deUint32 width, 317 deUint32 height) 318 { 319 std::vector<VkImageSp> images (MAX_COLOR_ATTACHMENT_COUNT); 320 321 for (size_t imageNdx = 0; imageNdx < images.size(); imageNdx++) 322 images[imageNdx] = safeSharedPtr(new Unique<VkImage>(createImage(vki, physicalDevice, vkd, device, format, sampleCountBitFromSampleCount(sampleCount), VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, width, height))); 323 324 return images; 325 } 326 327 std::vector<VkImageSp> createSingleSampleImages (const InstanceInterface& vki, 328 VkPhysicalDevice physicalDevice, 329 const DeviceInterface& vkd, 330 VkDevice device, 331 VkFormat format, 332 deUint32 width, 333 deUint32 height) 334 { 335 std::vector<VkImageSp> images (MAX_COLOR_ATTACHMENT_COUNT); 336 337 for (size_t imageNdx = 0; imageNdx < images.size(); imageNdx++) 338 images[imageNdx] = safeSharedPtr(new Unique<VkImage>(createImage(vki, physicalDevice, vkd, device, format, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, width, height))); 339 340 return images; 341 } 342 343 std::vector<de::SharedPtr<Allocation> > createImageMemory (const DeviceInterface& vkd, 344 VkDevice device, 345 Allocator& allocator, 346 const std::vector<VkImageSp> images) 347 { 348 std::vector<de::SharedPtr<Allocation> > memory (images.size()); 349 350 for (size_t memoryNdx = 0; memoryNdx < memory.size(); memoryNdx++) 351 memory[memoryNdx] = safeSharedPtr(createImageMemory(vkd, device, allocator, **images[memoryNdx]).release()); 352 353 return memory; 354 } 355 356 std::vector<VkImageViewSp> createImageViews (const DeviceInterface& vkd, 357 VkDevice device, 358 const std::vector<VkImageSp>& images, 359 VkFormat format, 360 VkImageAspectFlagBits aspect) 361 { 362 std::vector<VkImageViewSp> views (images.size()); 363 364 for (size_t imageNdx = 0; imageNdx < images.size(); imageNdx++) 365 views[imageNdx] = safeSharedPtr(new Unique<VkImageView>(createImageView(vkd, device, **images[imageNdx], format, aspect))); 366 367 return views; 368 } 369 370 std::vector<VkBufferSp> createBuffers (const DeviceInterface& vkd, 371 VkDevice device, 372 VkFormat format, 373 deUint32 width, 374 deUint32 height) 375 { 376 std::vector<VkBufferSp> buffers (MAX_COLOR_ATTACHMENT_COUNT); 377 378 for (size_t bufferNdx = 0; bufferNdx < buffers.size(); bufferNdx++) 379 buffers[bufferNdx] = safeSharedPtr(new Unique<VkBuffer>(createBuffer(vkd, device, format, width, height))); 380 381 return buffers; 382 } 383 384 std::vector<de::SharedPtr<Allocation> > createBufferMemory (const DeviceInterface& vkd, 385 VkDevice device, 386 Allocator& allocator, 387 const std::vector<VkBufferSp> buffers) 388 { 389 std::vector<de::SharedPtr<Allocation> > memory (buffers.size()); 390 391 for (size_t memoryNdx = 0; memoryNdx < memory.size(); memoryNdx++) 392 memory[memoryNdx] = safeSharedPtr(createBufferMemory(vkd, device, allocator, **buffers[memoryNdx]).release()); 393 394 return memory; 395 } 396 397 Move<VkRenderPass> createRenderPass (const DeviceInterface& vkd, 398 VkDevice device, 399 VkFormat format, 400 deUint32 sampleCount) 401 { 402 const VkSampleCountFlagBits samples (sampleCountBitFromSampleCount(sampleCount)); 403 std::vector<VkAttachmentDescription> attachments; 404 std::vector<VkAttachmentReference> colorAttachmentRefs; 405 std::vector<VkAttachmentReference> resolveAttachmentRefs; 406 407 for (size_t attachmentNdx = 0; attachmentNdx < 4; attachmentNdx++) 408 { 409 { 410 const VkAttachmentDescription multisampleAttachment = 411 { 412 0u, 413 414 format, 415 samples, 416 417 VK_ATTACHMENT_LOAD_OP_DONT_CARE, 418 VK_ATTACHMENT_STORE_OP_DONT_CARE, 419 420 VK_ATTACHMENT_LOAD_OP_DONT_CARE, 421 VK_ATTACHMENT_STORE_OP_DONT_CARE, 422 423 VK_IMAGE_LAYOUT_UNDEFINED, 424 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL 425 }; 426 const VkAttachmentReference attachmentRef = 427 { 428 (deUint32)attachments.size(), 429 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL 430 }; 431 colorAttachmentRefs.push_back(attachmentRef); 432 attachments.push_back(multisampleAttachment); 433 } 434 { 435 const VkAttachmentDescription singlesampleAttachment = 436 { 437 0u, 438 439 format, 440 VK_SAMPLE_COUNT_1_BIT, 441 442 VK_ATTACHMENT_LOAD_OP_DONT_CARE, 443 VK_ATTACHMENT_STORE_OP_STORE, 444 445 VK_ATTACHMENT_LOAD_OP_DONT_CARE, 446 VK_ATTACHMENT_STORE_OP_DONT_CARE, 447 448 VK_IMAGE_LAYOUT_UNDEFINED, 449 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL 450 }; 451 const VkAttachmentReference attachmentRef = 452 { 453 (deUint32)attachments.size(), 454 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL 455 }; 456 resolveAttachmentRefs.push_back(attachmentRef); 457 attachments.push_back(singlesampleAttachment); 458 } 459 } 460 461 DE_ASSERT(colorAttachmentRefs.size() == resolveAttachmentRefs.size()); 462 DE_ASSERT(attachments.size() == colorAttachmentRefs.size() + resolveAttachmentRefs.size()); 463 464 { 465 const VkSubpassDescription subpass = 466 { 467 (VkSubpassDescriptionFlags)0, 468 VK_PIPELINE_BIND_POINT_GRAPHICS, 469 470 0u, 471 DE_NULL, 472 473 (deUint32)colorAttachmentRefs.size(), 474 &colorAttachmentRefs[0], 475 &resolveAttachmentRefs[0], 476 477 DE_NULL, 478 0u, 479 DE_NULL 480 }; 481 const VkRenderPassCreateInfo createInfo = 482 { 483 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, 484 DE_NULL, 485 (VkRenderPassCreateFlags)0u, 486 487 (deUint32)attachments.size(), 488 &attachments[0], 489 490 1u, 491 &subpass, 492 493 0u, 494 DE_NULL 495 }; 496 497 return createRenderPass(vkd, device, &createInfo); 498 } 499 } 500 501 Move<VkFramebuffer> createFramebuffer (const DeviceInterface& vkd, 502 VkDevice device, 503 VkRenderPass renderPass, 504 const std::vector<VkImageViewSp>& multisampleImageViews, 505 const std::vector<VkImageViewSp>& singlesampleImageViews, 506 deUint32 width, 507 deUint32 height) 508 { 509 std::vector<VkImageView> attachments; 510 511 attachments.reserve(multisampleImageViews.size() + singlesampleImageViews.size()); 512 513 DE_ASSERT(multisampleImageViews.size() == singlesampleImageViews.size()); 514 515 for (size_t ndx = 0; ndx < multisampleImageViews.size(); ndx++) 516 { 517 attachments.push_back(**multisampleImageViews[ndx]); 518 attachments.push_back(**singlesampleImageViews[ndx]); 519 } 520 521 const VkFramebufferCreateInfo createInfo = 522 { 523 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, 524 DE_NULL, 525 0u, 526 527 renderPass, 528 (deUint32)attachments.size(), 529 &attachments[0], 530 531 width, 532 height, 533 1u 534 }; 535 536 return createFramebuffer(vkd, device, &createInfo); 537 } 538 539 Move<VkPipelineLayout> createRenderPipelineLayout (const DeviceInterface& vkd, 540 VkDevice device) 541 { 542 const VkPushConstantRange pushConstant = 543 { 544 VK_SHADER_STAGE_FRAGMENT_BIT, 545 0u, 546 4u 547 }; 548 const VkPipelineLayoutCreateInfo createInfo = 549 { 550 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, 551 DE_NULL, 552 (vk::VkPipelineLayoutCreateFlags)0, 553 554 0u, 555 DE_NULL, 556 557 1u, 558 &pushConstant 559 }; 560 561 return createPipelineLayout(vkd, device, &createInfo); 562 } 563 564 Move<VkPipeline> createRenderPipeline (const DeviceInterface& vkd, 565 VkDevice device, 566 VkRenderPass renderPass, 567 VkPipelineLayout pipelineLayout, 568 const vk::ProgramCollection<vk::ProgramBinary>& binaryCollection, 569 deUint32 width, 570 deUint32 height, 571 deUint32 sampleCount) 572 { 573 const Unique<VkShaderModule> vertexShaderModule (createShaderModule(vkd, device, binaryCollection.get("quad-vert"), 0u)); 574 const Unique<VkShaderModule> fragmentShaderModule (createShaderModule(vkd, device, binaryCollection.get("quad-frag"), 0u)); 575 const VkSpecializationInfo emptyShaderSpecializations = 576 { 577 0u, 578 DE_NULL, 579 580 0u, 581 DE_NULL 582 }; 583 // Disable blending 584 const VkPipelineColorBlendAttachmentState attachmentBlendState = 585 { 586 VK_FALSE, 587 VK_BLEND_FACTOR_SRC_ALPHA, 588 VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, 589 VK_BLEND_OP_ADD, 590 VK_BLEND_FACTOR_ONE, 591 VK_BLEND_FACTOR_ONE, 592 VK_BLEND_OP_ADD, 593 VK_COLOR_COMPONENT_R_BIT|VK_COLOR_COMPONENT_G_BIT|VK_COLOR_COMPONENT_B_BIT|VK_COLOR_COMPONENT_A_BIT 594 }; 595 const VkPipelineColorBlendAttachmentState attachmentBlendStates[] = 596 { 597 attachmentBlendState, 598 attachmentBlendState, 599 attachmentBlendState, 600 attachmentBlendState, 601 }; 602 const VkPipelineShaderStageCreateInfo shaderStages[2] = 603 { 604 { 605 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 606 DE_NULL, 607 (VkPipelineShaderStageCreateFlags)0u, 608 VK_SHADER_STAGE_VERTEX_BIT, 609 *vertexShaderModule, 610 "main", 611 &emptyShaderSpecializations 612 }, 613 { 614 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, 615 DE_NULL, 616 (VkPipelineShaderStageCreateFlags)0u, 617 VK_SHADER_STAGE_FRAGMENT_BIT, 618 *fragmentShaderModule, 619 "main", 620 &emptyShaderSpecializations 621 } 622 }; 623 const VkPipelineVertexInputStateCreateInfo vertexInputState = 624 { 625 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, 626 DE_NULL, 627 (VkPipelineVertexInputStateCreateFlags)0u, 628 629 0u, 630 DE_NULL, 631 632 0u, 633 DE_NULL 634 }; 635 const VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = 636 { 637 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, 638 DE_NULL, 639 640 (VkPipelineInputAssemblyStateCreateFlags)0u, 641 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 642 VK_FALSE 643 }; 644 const VkViewport viewport = 645 { 646 0.0f, 0.0f, 647 (float)width, (float)height, 648 649 0.0f, 1.0f 650 }; 651 const VkRect2D scissor = 652 { 653 { 0u, 0u }, 654 { width, height } 655 }; 656 const VkPipelineViewportStateCreateInfo viewportState = 657 { 658 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, 659 DE_NULL, 660 (VkPipelineViewportStateCreateFlags)0u, 661 662 1u, 663 &viewport, 664 665 1u, 666 &scissor 667 }; 668 const VkPipelineRasterizationStateCreateInfo rasterState = 669 { 670 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, 671 DE_NULL, 672 (VkPipelineRasterizationStateCreateFlags)0u, 673 VK_TRUE, 674 VK_FALSE, 675 VK_POLYGON_MODE_FILL, 676 VK_CULL_MODE_NONE, 677 VK_FRONT_FACE_COUNTER_CLOCKWISE, 678 VK_FALSE, 679 0.0f, 680 0.0f, 681 0.0f, 682 1.0f 683 }; 684 const VkPipelineMultisampleStateCreateInfo multisampleState = 685 { 686 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, 687 DE_NULL, 688 (VkPipelineMultisampleStateCreateFlags)0u, 689 690 sampleCountBitFromSampleCount(sampleCount), 691 VK_FALSE, 692 0.0f, 693 DE_NULL, 694 VK_FALSE, 695 VK_FALSE, 696 }; 697 const VkPipelineDepthStencilStateCreateInfo depthStencilState = 698 { 699 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, 700 DE_NULL, 701 (VkPipelineDepthStencilStateCreateFlags)0u, 702 703 VK_FALSE, 704 VK_TRUE, 705 VK_COMPARE_OP_ALWAYS, 706 VK_FALSE, 707 VK_TRUE, 708 { 709 VK_STENCIL_OP_KEEP, 710 VK_STENCIL_OP_INCREMENT_AND_WRAP, 711 VK_STENCIL_OP_KEEP, 712 VK_COMPARE_OP_ALWAYS, 713 ~0u, 714 ~0u, 715 0xFFu / (sampleCount + 1) 716 }, 717 { 718 VK_STENCIL_OP_KEEP, 719 VK_STENCIL_OP_INCREMENT_AND_WRAP, 720 VK_STENCIL_OP_KEEP, 721 VK_COMPARE_OP_ALWAYS, 722 ~0u, 723 ~0u, 724 0xFFu / (sampleCount + 1) 725 }, 726 727 0.0f, 728 1.0f 729 }; 730 const VkPipelineColorBlendStateCreateInfo blendState = 731 { 732 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, 733 DE_NULL, 734 (VkPipelineColorBlendStateCreateFlags)0u, 735 736 VK_FALSE, 737 VK_LOGIC_OP_COPY, 738 DE_LENGTH_OF_ARRAY(attachmentBlendStates), 739 attachmentBlendStates, 740 { 0.0f, 0.0f, 0.0f, 0.0f } 741 }; 742 const VkGraphicsPipelineCreateInfo createInfo = 743 { 744 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, 745 DE_NULL, 746 (VkPipelineCreateFlags)0u, 747 748 2, 749 shaderStages, 750 751 &vertexInputState, 752 &inputAssemblyState, 753 DE_NULL, 754 &viewportState, 755 &rasterState, 756 &multisampleState, 757 &depthStencilState, 758 &blendState, 759 (const VkPipelineDynamicStateCreateInfo*)DE_NULL, 760 pipelineLayout, 761 762 renderPass, 763 0u, 764 DE_NULL, 765 0u 766 }; 767 768 return createGraphicsPipeline(vkd, device, DE_NULL, &createInfo); 769 } 770 771 struct TestConfig 772 { 773 TestConfig (VkFormat format_, 774 deUint32 sampleCount_) 775 : format (format_) 776 , sampleCount (sampleCount_) 777 { 778 } 779 780 VkFormat format; 781 deUint32 sampleCount; 782 }; 783 784 class MultisampleRenderPassTestInstance : public TestInstance 785 { 786 public: 787 MultisampleRenderPassTestInstance (Context& context, TestConfig config); 788 ~MultisampleRenderPassTestInstance (void); 789 790 tcu::TestStatus iterate (void); 791 792 private: 793 void submit (void); 794 void verify (void); 795 796 const VkFormat m_format; 797 const deUint32 m_sampleCount; 798 const deUint32 m_width; 799 const deUint32 m_height; 800 801 const std::vector<VkImageSp> m_multisampleImages; 802 const std::vector<de::SharedPtr<Allocation> > m_multisampleImageMemory; 803 const std::vector<VkImageViewSp> m_multisampleImageViews; 804 805 const std::vector<VkImageSp> m_singlesampleImages; 806 const std::vector<de::SharedPtr<Allocation> > m_singlesampleImageMemory; 807 const std::vector<VkImageViewSp> m_singlesampleImageViews; 808 809 const Unique<VkRenderPass> m_renderPass; 810 const Unique<VkFramebuffer> m_framebuffer; 811 812 const Unique<VkPipelineLayout> m_renderPipelineLayout; 813 const Unique<VkPipeline> m_renderPipeline; 814 815 const std::vector<VkBufferSp> m_buffers; 816 const std::vector<de::SharedPtr<Allocation> > m_bufferMemory; 817 818 const Unique<VkCommandPool> m_commandPool; 819 tcu::TextureLevel m_sum; 820 deUint32 m_sampleMask; 821 tcu::ResultCollector m_resultCollector; 822 }; 823 824 MultisampleRenderPassTestInstance::MultisampleRenderPassTestInstance (Context& context, TestConfig config) 825 : TestInstance (context) 826 , m_format (config.format) 827 , m_sampleCount (config.sampleCount) 828 , m_width (32u) 829 , m_height (32u) 830 831 , m_multisampleImages (createMultisampleImages(context.getInstanceInterface(), context.getPhysicalDevice(), context.getDeviceInterface(), context.getDevice(), m_format, m_sampleCount, m_width, m_height)) 832 , m_multisampleImageMemory (createImageMemory(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), m_multisampleImages)) 833 , m_multisampleImageViews (createImageViews(context.getDeviceInterface(), context.getDevice(), m_multisampleImages, m_format, VK_IMAGE_ASPECT_COLOR_BIT)) 834 835 , m_singlesampleImages (createSingleSampleImages(context.getInstanceInterface(), context.getPhysicalDevice(), context.getDeviceInterface(), context.getDevice(), m_format, m_width, m_height)) 836 , m_singlesampleImageMemory (createImageMemory(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), m_singlesampleImages)) 837 , m_singlesampleImageViews (createImageViews(context.getDeviceInterface(), context.getDevice(), m_singlesampleImages, m_format, VK_IMAGE_ASPECT_COLOR_BIT)) 838 839 , m_renderPass (createRenderPass(context.getDeviceInterface(), context.getDevice(), m_format, m_sampleCount)) 840 , m_framebuffer (createFramebuffer(context.getDeviceInterface(), context.getDevice(), *m_renderPass, m_multisampleImageViews, m_singlesampleImageViews, m_width, m_height)) 841 842 , m_renderPipelineLayout (createRenderPipelineLayout(context.getDeviceInterface(), context.getDevice())) 843 , m_renderPipeline (createRenderPipeline(context.getDeviceInterface(), context.getDevice(), *m_renderPass, *m_renderPipelineLayout, context.getBinaryCollection(), m_width, m_height, m_sampleCount)) 844 845 , m_buffers (createBuffers(context.getDeviceInterface(), context.getDevice(), m_format, m_width, m_height)) 846 , m_bufferMemory (createBufferMemory(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), m_buffers)) 847 848 , m_commandPool (createCommandPool(context.getDeviceInterface(), context.getDevice(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, context.getUniversalQueueFamilyIndex())) 849 , m_sum (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), m_width, m_height) 850 , m_sampleMask (0x0u) 851 { 852 tcu::clear(m_sum.getAccess(), Vec4(0.0f, 0.0f, 0.0f, 0.0f)); 853 } 854 855 MultisampleRenderPassTestInstance::~MultisampleRenderPassTestInstance (void) 856 { 857 } 858 859 void MultisampleRenderPassTestInstance::submit (void) 860 { 861 const DeviceInterface& vkd (m_context.getDeviceInterface()); 862 const VkDevice device (m_context.getDevice()); 863 const Unique<VkCommandBuffer> commandBuffer (allocateCommandBuffer(vkd, device, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 864 865 { 866 const VkCommandBufferBeginInfo beginInfo = 867 { 868 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 869 DE_NULL, 870 871 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 872 DE_NULL 873 }; 874 875 VK_CHECK(vkd.beginCommandBuffer(*commandBuffer, &beginInfo)); 876 } 877 878 { 879 const VkRenderPassBeginInfo beginInfo = 880 { 881 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, 882 DE_NULL, 883 884 *m_renderPass, 885 *m_framebuffer, 886 887 { 888 { 0u, 0u }, 889 { m_width, m_height } 890 }, 891 892 0u, 893 DE_NULL 894 }; 895 vkd.cmdBeginRenderPass(*commandBuffer, &beginInfo, VK_SUBPASS_CONTENTS_INLINE); 896 } 897 898 // Memory barriers between previous copies and rendering 899 { 900 std::vector<VkImageMemoryBarrier> barriers; 901 902 for (size_t dstNdx = 0; dstNdx < m_singlesampleImages.size(); dstNdx++) 903 { 904 const VkImageMemoryBarrier barrier = 905 { 906 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 907 DE_NULL, 908 909 VK_ACCESS_TRANSFER_READ_BIT, 910 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 911 912 VK_IMAGE_LAYOUT_UNDEFINED, 913 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 914 915 VK_QUEUE_FAMILY_IGNORED, 916 VK_QUEUE_FAMILY_IGNORED, 917 918 **m_singlesampleImages[dstNdx], 919 { 920 VK_IMAGE_ASPECT_COLOR_BIT, 921 0u, 922 1u, 923 0u, 924 1u 925 } 926 }; 927 928 barriers.push_back(barrier); 929 } 930 931 vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, (deUint32)barriers.size(), &barriers[0]); 932 } 933 934 // Clear everything to black 935 { 936 const tcu::TextureFormat format (mapVkFormat(m_format)); 937 const tcu::TextureChannelClass channelClass (tcu::getTextureChannelClass(format.type)); 938 VkClearValue value; 939 940 switch (channelClass) 941 { 942 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: 943 value = makeClearValueColorF32(-1.0f, -1.0f, -1.0f, -1.0f); 944 break; 945 946 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: 947 value = makeClearValueColorF32(0.0f, 0.0f, 0.0f, 0.0f); 948 break; 949 950 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: 951 value = makeClearValueColorF32(-1.0f, -1.0f, -1.0f, -1.0f); 952 break; 953 954 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: 955 value = makeClearValueColorI32(-128, -128, -128, -128); 956 break; 957 958 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: 959 value = makeClearValueColorU32(0u, 0u, 0u, 0u); 960 break; 961 962 default: 963 DE_FATAL("Unknown channel class"); 964 } 965 const VkClearAttachment colors[] = 966 { 967 { 968 VK_IMAGE_ASPECT_COLOR_BIT, 969 0u, 970 value 971 }, 972 { 973 VK_IMAGE_ASPECT_COLOR_BIT, 974 1u, 975 value 976 }, 977 { 978 VK_IMAGE_ASPECT_COLOR_BIT, 979 2u, 980 value 981 }, 982 { 983 VK_IMAGE_ASPECT_COLOR_BIT, 984 3u, 985 value 986 } 987 }; 988 const VkClearRect rect = 989 { 990 { 991 { 0u, 0u }, 992 { m_width, m_height } 993 }, 994 0u, 995 1u, 996 }; 997 vkd.cmdClearAttachments(*commandBuffer, DE_LENGTH_OF_ARRAY(colors), colors, 1u, &rect); 998 } 999 1000 // Render black samples 1001 { 1002 vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_renderPipeline); 1003 vkd.cmdPushConstants(*commandBuffer, *m_renderPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(m_sampleMask), &m_sampleMask); 1004 vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u); 1005 } 1006 1007 vkd.cmdEndRenderPass(*commandBuffer); 1008 1009 // Memory barriers between rendering and copies 1010 { 1011 std::vector<VkImageMemoryBarrier> barriers; 1012 1013 for (size_t dstNdx = 0; dstNdx < m_singlesampleImages.size(); dstNdx++) 1014 { 1015 const VkImageMemoryBarrier barrier = 1016 { 1017 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 1018 DE_NULL, 1019 1020 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 1021 VK_ACCESS_TRANSFER_READ_BIT, 1022 1023 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1024 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 1025 1026 VK_QUEUE_FAMILY_IGNORED, 1027 VK_QUEUE_FAMILY_IGNORED, 1028 1029 **m_singlesampleImages[dstNdx], 1030 { 1031 VK_IMAGE_ASPECT_COLOR_BIT, 1032 0u, 1033 1u, 1034 0u, 1035 1u 1036 } 1037 }; 1038 1039 barriers.push_back(barrier); 1040 } 1041 1042 vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, (deUint32)barriers.size(), &barriers[0]); 1043 } 1044 1045 // Copy image memory to buffers 1046 for (size_t dstNdx = 0; dstNdx < m_singlesampleImages.size(); dstNdx++) 1047 { 1048 const VkBufferImageCopy region = 1049 { 1050 0u, 1051 0u, 1052 0u, 1053 { 1054 VK_IMAGE_ASPECT_COLOR_BIT, 1055 0u, 1056 0u, 1057 1u, 1058 }, 1059 { 0u, 0u, 0u }, 1060 { m_width, m_height, 1u } 1061 }; 1062 1063 vkd.cmdCopyImageToBuffer(*commandBuffer, **m_singlesampleImages[dstNdx], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **m_buffers[dstNdx], 1u, ®ion); 1064 } 1065 1066 // Memory barriers between copies and host access 1067 { 1068 std::vector<VkBufferMemoryBarrier> barriers; 1069 1070 for (size_t dstNdx = 0; dstNdx < m_buffers.size(); dstNdx++) 1071 { 1072 const VkBufferMemoryBarrier barrier = 1073 { 1074 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 1075 DE_NULL, 1076 1077 VK_ACCESS_TRANSFER_WRITE_BIT, 1078 VK_ACCESS_HOST_READ_BIT, 1079 1080 VK_QUEUE_FAMILY_IGNORED, 1081 VK_QUEUE_FAMILY_IGNORED, 1082 1083 **m_buffers[dstNdx], 1084 0u, 1085 VK_WHOLE_SIZE 1086 }; 1087 1088 barriers.push_back(barrier); 1089 } 1090 1091 vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, (deUint32)barriers.size(), &barriers[0], 0u, DE_NULL); 1092 } 1093 1094 VK_CHECK(vkd.endCommandBuffer(*commandBuffer)); 1095 1096 { 1097 const VkSubmitInfo submitInfo = 1098 { 1099 VK_STRUCTURE_TYPE_SUBMIT_INFO, 1100 DE_NULL, 1101 1102 0u, 1103 DE_NULL, 1104 DE_NULL, 1105 1106 1u, 1107 &*commandBuffer, 1108 1109 0u, 1110 DE_NULL 1111 }; 1112 1113 VK_CHECK(vkd.queueSubmit(m_context.getUniversalQueue(), 1u, &submitInfo, (VkFence)0u)); 1114 1115 VK_CHECK(vkd.queueWaitIdle(m_context.getUniversalQueue())); 1116 } 1117 } 1118 1119 void MultisampleRenderPassTestInstance::verify (void) 1120 { 1121 const Vec4 errorColor (1.0f, 0.0f, 0.0f, 1.0f); 1122 const Vec4 okColor (0.0f, 0.0f, 0.0f, 1.0f); 1123 const tcu::TextureFormat format (mapVkFormat(m_format)); 1124 const tcu::TextureChannelClass channelClass (tcu::getTextureChannelClass(format.type)); 1125 const void* const ptrs[] = 1126 { 1127 m_bufferMemory[0]->getHostPtr(), 1128 m_bufferMemory[1]->getHostPtr(), 1129 m_bufferMemory[2]->getHostPtr(), 1130 m_bufferMemory[3]->getHostPtr() 1131 }; 1132 const tcu::ConstPixelBufferAccess accesses[] = 1133 { 1134 tcu::ConstPixelBufferAccess(format, m_width, m_height, 1, ptrs[0]), 1135 tcu::ConstPixelBufferAccess(format, m_width, m_height, 1, ptrs[1]), 1136 tcu::ConstPixelBufferAccess(format, m_width, m_height, 1, ptrs[2]), 1137 tcu::ConstPixelBufferAccess(format, m_width, m_height, 1, ptrs[3]) 1138 }; 1139 tcu::TextureLevel errorMask (tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), m_width, m_height); 1140 tcu::TestLog& log (m_context.getTestContext().getLog()); 1141 1142 switch (channelClass) 1143 { 1144 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: 1145 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: 1146 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: 1147 { 1148 const int componentCount (tcu::getNumUsedChannels(format.order)); 1149 bool isOk = true; 1150 float clearValue; 1151 float renderValue; 1152 1153 switch (channelClass) 1154 { 1155 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: 1156 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: 1157 clearValue = -1.0f; 1158 renderValue = 1.0f; 1159 break; 1160 1161 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: 1162 clearValue = 0.0f; 1163 renderValue = 1.0f; 1164 break; 1165 1166 default: 1167 clearValue = 0.0f; 1168 renderValue = 0.0f; 1169 DE_FATAL("Unknown channel class"); 1170 } 1171 1172 for (deUint32 y = 0; y < m_height; y++) 1173 for (deUint32 x = 0; x < m_width; x++) 1174 { 1175 // Color has to be black if no samples were covered, white if all samples were covered or same in every attachment 1176 const Vec4 firstColor (accesses[0].getPixel(x, y)); 1177 const Vec4 refColor (m_sampleMask == 0x0u 1178 ? Vec4(clearValue, 1179 componentCount > 1 ? clearValue : 0.0f, 1180 componentCount > 2 ? clearValue : 0.0f, 1181 componentCount > 3 ? clearValue : 1.0f) 1182 : m_sampleMask == ((0x1u << m_sampleCount) - 1u) 1183 ? Vec4(renderValue, 1184 componentCount > 1 ? renderValue : 0.0f, 1185 componentCount > 2 ? renderValue : 0.0f, 1186 componentCount > 3 ? renderValue : 1.0f) 1187 : firstColor); 1188 1189 errorMask.getAccess().setPixel(okColor, x, y); 1190 1191 for (size_t attachmentNdx = 0; attachmentNdx < MAX_COLOR_ATTACHMENT_COUNT; attachmentNdx++) 1192 { 1193 const Vec4 color (accesses[attachmentNdx].getPixel(x, y)); 1194 1195 if (refColor != color) 1196 { 1197 isOk = false; 1198 errorMask.getAccess().setPixel(errorColor, x, y); 1199 break; 1200 } 1201 } 1202 1203 { 1204 const Vec4 old = m_sum.getAccess().getPixel(x, y); 1205 1206 m_sum.getAccess().setPixel(old + firstColor, x, y); 1207 } 1208 } 1209 1210 if (!isOk) 1211 { 1212 const std::string sectionName ("ResolveVerifyWithMask" + de::toString(m_sampleMask)); 1213 const tcu::ScopedLogSection section (log, sectionName, sectionName); 1214 1215 for (size_t attachmentNdx = 0; attachmentNdx < MAX_COLOR_ATTACHMENT_COUNT; attachmentNdx++) 1216 { 1217 const std::string name ("Attachment" + de::toString(attachmentNdx)); 1218 m_context.getTestContext().getLog() << tcu::LogImage(name.c_str(), name.c_str(), accesses[attachmentNdx]); 1219 } 1220 1221 m_context.getTestContext().getLog() << tcu::LogImage("ErrorMask", "ErrorMask", errorMask.getAccess()); 1222 1223 if (m_sampleMask == 0x0u) 1224 { 1225 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Empty sample mask didn't produce all " << clearValue << " pixels" << tcu::TestLog::EndMessage; 1226 m_resultCollector.fail("Empty sample mask didn't produce correct pixel values"); 1227 } 1228 else if (m_sampleMask == ((0x1u << m_sampleCount) - 1u)) 1229 { 1230 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Full sample mask didn't produce all " << renderValue << " pixels" << tcu::TestLog::EndMessage; 1231 m_resultCollector.fail("Full sample mask didn't produce correct pixel values"); 1232 } 1233 else 1234 { 1235 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Resolve is inconsistent between attachments" << tcu::TestLog::EndMessage; 1236 m_resultCollector.fail("Resolve is inconsistent between attachments"); 1237 } 1238 } 1239 break; 1240 } 1241 1242 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: 1243 { 1244 const int componentCount (tcu::getNumUsedChannels(format.order)); 1245 const UVec4 bitDepth (tcu::getTextureFormatBitDepth(format).cast<deUint32>()); 1246 const UVec4 renderValue (tcu::select((UVec4(1u) << tcu::min(UVec4(8u), bitDepth)) - UVec4(1u), 1247 UVec4(0u, 0u, 0u, 1u), 1248 tcu::lessThan(IVec4(0, 1, 2, 3), IVec4(componentCount)))); 1249 const UVec4 clearValue (tcu::select(UVec4(0u), 1250 UVec4(0u, 0u, 0u, 1u), 1251 tcu::lessThan(IVec4(0, 1, 2, 3), IVec4(componentCount)))); 1252 bool unexpectedValues = false; 1253 bool inconsistentComponents = false; 1254 bool inconsistentAttachments = false; 1255 1256 for (deUint32 y = 0; y < m_height; y++) 1257 for (deUint32 x = 0; x < m_width; x++) 1258 { 1259 // Color has to be all zeros if no samples were covered, all 255 if all samples were covered or consistent across all attachments 1260 const UVec4 refColor (m_sampleMask == 0x0u 1261 ? clearValue 1262 : m_sampleMask == ((0x1u << m_sampleCount) - 1u) 1263 ? renderValue 1264 : accesses[0].getPixelUint(x, y)); 1265 1266 errorMask.getAccess().setPixel(okColor, x, y); 1267 1268 // If reference value was taken from first attachment, check that it is valid value i.e. clear or render value 1269 if (m_sampleMask != 0x0u && m_sampleMask != ((0x1u << m_sampleCount) - 1u)) 1270 { 1271 // Each component must be resolved same way 1272 const BVec4 isRenderValue (refColor == renderValue); 1273 const BVec4 isClearValue (refColor == clearValue); 1274 1275 unexpectedValues = tcu::anyNotEqual(tcu::logicalOr(isRenderValue, isClearValue), BVec4(true)); 1276 inconsistentComponents = !(tcu::allEqual(isRenderValue, BVec4(true)) || tcu::allEqual(isClearValue, BVec4(true))); 1277 1278 if (unexpectedValues || inconsistentComponents) 1279 errorMask.getAccess().setPixel(errorColor, x, y); 1280 } 1281 1282 for (size_t attachmentNdx = 0; attachmentNdx < MAX_COLOR_ATTACHMENT_COUNT; attachmentNdx++) 1283 { 1284 const UVec4 color (accesses[attachmentNdx].getPixelUint(x, y)); 1285 1286 if (refColor != color) 1287 { 1288 inconsistentAttachments = true; 1289 errorMask.getAccess().setPixel(errorColor, x, y); 1290 break; 1291 } 1292 } 1293 } 1294 1295 if (unexpectedValues || inconsistentComponents || inconsistentAttachments) 1296 { 1297 const std::string sectionName ("ResolveVerifyWithMask" + de::toString(m_sampleMask)); 1298 const tcu::ScopedLogSection section (log, sectionName, sectionName); 1299 1300 for (size_t attachmentNdx = 0; attachmentNdx < MAX_COLOR_ATTACHMENT_COUNT; attachmentNdx++) 1301 { 1302 const std::string name ("Attachment" + de::toString(attachmentNdx)); 1303 m_context.getTestContext().getLog() << tcu::LogImage(name.c_str(), name.c_str(), accesses[attachmentNdx]); 1304 } 1305 1306 m_context.getTestContext().getLog() << tcu::LogImage("ErrorMask", "ErrorMask", errorMask.getAccess()); 1307 1308 if (m_sampleMask == 0x0u) 1309 { 1310 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Empty sample mask didn't produce all " << clearValue << " pixels" << tcu::TestLog::EndMessage; 1311 m_resultCollector.fail("Empty sample mask didn't produce correct pixels"); 1312 } 1313 else if (m_sampleMask == ((0x1u << m_sampleCount) - 1u)) 1314 { 1315 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Full sample mask didn't produce all " << renderValue << " pixels" << tcu::TestLog::EndMessage; 1316 m_resultCollector.fail("Full sample mask didn't produce correct pixels"); 1317 } 1318 else 1319 { 1320 if (unexpectedValues) 1321 { 1322 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Resolve produced unexpected values i.e. not " << clearValue << " or " << renderValue << tcu::TestLog::EndMessage; 1323 m_resultCollector.fail("Resolve produced unexpected values"); 1324 } 1325 1326 if (inconsistentComponents) 1327 { 1328 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Different components of attachment were resolved to different values." << tcu::TestLog::EndMessage; 1329 m_resultCollector.fail("Different components of attachment were resolved to different values."); 1330 } 1331 1332 if (inconsistentAttachments) 1333 { 1334 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Different attachments were resolved to different values." << tcu::TestLog::EndMessage; 1335 m_resultCollector.fail("Different attachments were resolved to different values."); 1336 } 1337 } 1338 } 1339 break; 1340 } 1341 1342 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: 1343 { 1344 const int componentCount (tcu::getNumUsedChannels(format.order)); 1345 const IVec4 bitDepth (tcu::getTextureFormatBitDepth(format)); 1346 const IVec4 renderValue (tcu::select((IVec4(1) << (tcu::min(IVec4(8), bitDepth) - IVec4(1))) - IVec4(1), 1347 IVec4(0, 0, 0, 1), 1348 tcu::lessThan(IVec4(0, 1, 2, 3), IVec4(componentCount)))); 1349 const IVec4 clearValue (tcu::select(-(IVec4(1) << (tcu::min(IVec4(8), bitDepth) - IVec4(1))), 1350 IVec4(0, 0, 0, 1), 1351 tcu::lessThan(IVec4(0, 1, 2, 3), IVec4(componentCount)))); 1352 bool unexpectedValues = false; 1353 bool inconsistentComponents = false; 1354 bool inconsistentAttachments = false; 1355 1356 for (deUint32 y = 0; y < m_height; y++) 1357 for (deUint32 x = 0; x < m_width; x++) 1358 { 1359 // Color has to be all zeros if no samples were covered, all 255 if all samples were covered or consistent across all attachments 1360 const IVec4 refColor (m_sampleMask == 0x0u 1361 ? clearValue 1362 : m_sampleMask == ((0x1u << m_sampleCount) - 1u) 1363 ? renderValue 1364 : accesses[0].getPixelInt(x, y)); 1365 1366 errorMask.getAccess().setPixel(okColor, x, y); 1367 1368 // If reference value was taken from first attachment, check that it is valid value i.e. clear or render value 1369 if (m_sampleMask != 0x0u && m_sampleMask != ((0x1u << m_sampleCount) - 1u)) 1370 { 1371 // Each component must be resolved same way 1372 const BVec4 isRenderValue (refColor == renderValue); 1373 const BVec4 isClearValue (refColor == clearValue); 1374 1375 unexpectedValues = tcu::anyNotEqual(tcu::logicalOr(isRenderValue, isClearValue), BVec4(true)); 1376 inconsistentComponents = !(tcu::allEqual(isRenderValue, BVec4(true)) || tcu::allEqual(isClearValue, BVec4(true))); 1377 1378 if (unexpectedValues || inconsistentComponents) 1379 errorMask.getAccess().setPixel(errorColor, x, y); 1380 } 1381 } 1382 1383 if (unexpectedValues || inconsistentComponents || inconsistentAttachments) 1384 { 1385 const std::string sectionName ("ResolveVerifyWithMask" + de::toString(m_sampleMask)); 1386 const tcu::ScopedLogSection section (log, sectionName, sectionName); 1387 1388 for (size_t attachmentNdx = 0; attachmentNdx < MAX_COLOR_ATTACHMENT_COUNT; attachmentNdx++) 1389 { 1390 const std::string name ("Attachment" + de::toString(attachmentNdx)); 1391 m_context.getTestContext().getLog() << tcu::LogImage(name.c_str(), name.c_str(), accesses[attachmentNdx]); 1392 } 1393 1394 m_context.getTestContext().getLog() << tcu::LogImage("ErrorMask", "ErrorMask", errorMask.getAccess()); 1395 1396 if (m_sampleMask == 0x0u) 1397 { 1398 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Empty sample mask didn't produce all " << clearValue << " pixels" << tcu::TestLog::EndMessage; 1399 m_resultCollector.fail("Empty sample mask didn't produce correct pixels"); 1400 } 1401 else if (m_sampleMask == ((0x1u << m_sampleCount) - 1u)) 1402 { 1403 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Full sample mask didn't produce all " << renderValue << " pixels" << tcu::TestLog::EndMessage; 1404 m_resultCollector.fail("Full sample mask didn't produce correct pixels"); 1405 } 1406 else 1407 { 1408 if (unexpectedValues) 1409 { 1410 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Resolve produced unexpected values i.e. not " << clearValue << " or " << renderValue << tcu::TestLog::EndMessage; 1411 m_resultCollector.fail("Resolve produced unexpected values"); 1412 } 1413 1414 if (inconsistentComponents) 1415 { 1416 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Different components of attachment were resolved to different values." << tcu::TestLog::EndMessage; 1417 m_resultCollector.fail("Different components of attachment were resolved to different values."); 1418 } 1419 1420 if (inconsistentAttachments) 1421 { 1422 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Different attachments were resolved to different values." << tcu::TestLog::EndMessage; 1423 m_resultCollector.fail("Different attachments were resolved to different values."); 1424 } 1425 } 1426 } 1427 break; 1428 } 1429 1430 default: 1431 DE_FATAL("Unknown channel class"); 1432 } 1433 } 1434 1435 tcu::TestStatus MultisampleRenderPassTestInstance::iterate (void) 1436 { 1437 if (m_sampleMask == 0u) 1438 { 1439 const tcu::TextureFormat format (mapVkFormat(m_format)); 1440 const tcu::TextureChannelClass channelClass (tcu::getTextureChannelClass(format.type)); 1441 tcu::TestLog& log (m_context.getTestContext().getLog()); 1442 1443 switch (channelClass) 1444 { 1445 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: 1446 log << TestLog::Message << "Clearing target to zero and rendering 255 pixels with every possible sample mask" << TestLog::EndMessage; 1447 break; 1448 1449 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: 1450 log << TestLog::Message << "Clearing target to -128 and rendering 127 pixels with every possible sample mask" << TestLog::EndMessage; 1451 break; 1452 1453 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: 1454 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: 1455 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: 1456 log << TestLog::Message << "Clearing target to black and rendering white pixels with every possible sample mask" << TestLog::EndMessage; 1457 break; 1458 1459 default: 1460 DE_FATAL("Unknown channel class"); 1461 } 1462 } 1463 1464 submit(); 1465 verify(); 1466 1467 if (m_sampleMask == ((0x1u << m_sampleCount) - 1u)) 1468 { 1469 const tcu::TextureFormat format (mapVkFormat(m_format)); 1470 const tcu::TextureChannelClass channelClass (tcu::getTextureChannelClass(format.type)); 1471 tcu::TestLog& log (m_context.getTestContext().getLog()); 1472 1473 if (channelClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT 1474 || channelClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT 1475 || channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT) 1476 { 1477 const float threshold = 0.05f; 1478 const int componentCount (tcu::getNumUsedChannels(format.order)); 1479 const Vec4 errorColor (1.0f, 0.0f, 0.0f, 1.0f); 1480 const Vec4 okColor (0.0f, 0.0f, 0.0f, 1.0f); 1481 tcu::TextureLevel errorMask (tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), m_width, m_height); 1482 bool isOk = true; 1483 Vec4 maxDiff (0.0f); 1484 Vec4 expectedAverage; 1485 1486 switch (channelClass) 1487 { 1488 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: 1489 { 1490 expectedAverage = Vec4(0.5f, componentCount > 1 ? 0.5f : 0.0f, componentCount > 2 ? 0.5f : 0.0f, componentCount > 3 ? 0.5f : 1.0f); 1491 break; 1492 } 1493 1494 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: 1495 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: 1496 { 1497 expectedAverage = Vec4(0.0f, 0.0f, 0.0f, componentCount > 3 ? 0.0f : 1.0f); 1498 break; 1499 } 1500 1501 default: 1502 DE_FATAL("Unknown channel class"); 1503 } 1504 1505 for (deUint32 y = 0; y < m_height; y++) 1506 for (deUint32 x = 0; x < m_width; x++) 1507 { 1508 const Vec4 sum (m_sum.getAccess().getPixel(x, y)); 1509 const Vec4 average (sum / Vec4((float)(0x1u << m_sampleCount))); 1510 const Vec4 diff (tcu::abs(average - expectedAverage)); 1511 1512 m_sum.getAccess().setPixel(average, x, y); 1513 errorMask.getAccess().setPixel(okColor, x, y); 1514 1515 if (diff[0] > threshold 1516 || diff[1] > threshold 1517 || diff[2] > threshold 1518 || diff[3] > threshold) 1519 { 1520 isOk = false; 1521 maxDiff = tcu::max(maxDiff, diff); 1522 errorMask.getAccess().setPixel(errorColor, x, y); 1523 } 1524 } 1525 1526 log << TestLog::Image("Average resolved values in attachment 0", "Average resolved values in attachment 0", m_sum); 1527 1528 if (!isOk) 1529 { 1530 m_context.getTestContext().getLog() << tcu::LogImage("ErrorMask", "ErrorMask", errorMask.getAccess()); 1531 1532 log << TestLog::Message << "Average resolved values differ from expected average values by more than " << threshold << " max per component diff " << maxDiff << TestLog::EndMessage; 1533 } 1534 } 1535 1536 return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage()); 1537 } 1538 else 1539 { 1540 m_sampleMask++; 1541 return tcu::TestStatus::incomplete(); 1542 } 1543 } 1544 1545 struct Programs 1546 { 1547 void init (vk::SourceCollections& dst, TestConfig config) const 1548 { 1549 const tcu::TextureFormat format (mapVkFormat(config.format)); 1550 const tcu::TextureChannelClass channelClass (tcu::getTextureChannelClass(format.type)); 1551 1552 dst.glslSources.add("quad-vert") << glu::VertexSource( 1553 "#version 450\n" 1554 "out gl_PerVertex {\n" 1555 "\tvec4 gl_Position;\n" 1556 "};\n" 1557 "highp float;\n" 1558 "void main (void) {\n" 1559 "\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n" 1560 "\t ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n" 1561 "}\n"); 1562 1563 switch (channelClass) 1564 { 1565 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: 1566 dst.glslSources.add("quad-frag") << glu::FragmentSource( 1567 "#version 450\n" 1568 "layout(push_constant) uniform PushConstant {\n" 1569 "\thighp uint sampleMask;\n" 1570 "} pushConstants;\n" 1571 "layout(location = 0) out highp uvec4 o_color0;\n" 1572 "layout(location = 1) out highp uvec4 o_color1;\n" 1573 "layout(location = 2) out highp uvec4 o_color2;\n" 1574 "layout(location = 3) out highp uvec4 o_color3;\n" 1575 "void main (void)\n" 1576 "{\n" 1577 "\tgl_SampleMask[0] = int(pushConstants.sampleMask);\n" 1578 "\to_color0 = uvec4(255);\n" 1579 "\to_color1 = uvec4(255);\n" 1580 "\to_color2 = uvec4(255);\n" 1581 "\to_color3 = uvec4(255);\n" 1582 "}\n"); 1583 break; 1584 1585 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: 1586 dst.glslSources.add("quad-frag") << glu::FragmentSource( 1587 "#version 450\n" 1588 "layout(push_constant) uniform PushConstant {\n" 1589 "\thighp uint sampleMask;\n" 1590 "} pushConstants;\n" 1591 "layout(location = 0) out highp ivec4 o_color0;\n" 1592 "layout(location = 1) out highp ivec4 o_color1;\n" 1593 "layout(location = 2) out highp ivec4 o_color2;\n" 1594 "layout(location = 3) out highp ivec4 o_color3;\n" 1595 "void main (void)\n" 1596 "{\n" 1597 "\tgl_SampleMask[0] = int(pushConstants.sampleMask);\n" 1598 "\to_color0 = ivec4(127);\n" 1599 "\to_color1 = ivec4(127);\n" 1600 "\to_color2 = ivec4(127);\n" 1601 "\to_color3 = ivec4(127);\n" 1602 "}\n"); 1603 break; 1604 1605 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: 1606 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: 1607 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: 1608 dst.glslSources.add("quad-frag") << glu::FragmentSource( 1609 "#version 450\n" 1610 "layout(push_constant) uniform PushConstant {\n" 1611 "\thighp uint sampleMask;\n" 1612 "} pushConstants;\n" 1613 "layout(location = 0) out highp vec4 o_color0;\n" 1614 "layout(location = 1) out highp vec4 o_color1;\n" 1615 "layout(location = 2) out highp vec4 o_color2;\n" 1616 "layout(location = 3) out highp vec4 o_color3;\n" 1617 "void main (void)\n" 1618 "{\n" 1619 "\tgl_SampleMask[0] = int(pushConstants.sampleMask);\n" 1620 "\to_color0 = vec4(1.0);\n" 1621 "\to_color1 = vec4(1.0);\n" 1622 "\to_color2 = vec4(1.0);\n" 1623 "\to_color3 = vec4(1.0);\n" 1624 "}\n"); 1625 break; 1626 1627 default: 1628 DE_FATAL("Unknown channel class"); 1629 } 1630 } 1631 }; 1632 1633 std::string formatToName (VkFormat format) 1634 { 1635 const std::string formatStr = de::toString(format); 1636 const std::string prefix = "VK_FORMAT_"; 1637 1638 DE_ASSERT(formatStr.substr(0, prefix.length()) == prefix); 1639 1640 return de::toLower(formatStr.substr(prefix.length())); 1641 } 1642 1643 void initTests (tcu::TestCaseGroup* group) 1644 { 1645 static const VkFormat formats[] = 1646 { 1647 VK_FORMAT_R5G6B5_UNORM_PACK16, 1648 VK_FORMAT_R8_UNORM, 1649 VK_FORMAT_R8_SNORM, 1650 VK_FORMAT_R8_UINT, 1651 VK_FORMAT_R8_SINT, 1652 VK_FORMAT_R8G8_UNORM, 1653 VK_FORMAT_R8G8_SNORM, 1654 VK_FORMAT_R8G8_UINT, 1655 VK_FORMAT_R8G8_SINT, 1656 VK_FORMAT_R8G8B8A8_UNORM, 1657 VK_FORMAT_R8G8B8A8_SNORM, 1658 VK_FORMAT_R8G8B8A8_UINT, 1659 VK_FORMAT_R8G8B8A8_SINT, 1660 VK_FORMAT_R8G8B8A8_SRGB, 1661 VK_FORMAT_A8B8G8R8_UNORM_PACK32, 1662 VK_FORMAT_A8B8G8R8_SNORM_PACK32, 1663 VK_FORMAT_A8B8G8R8_UINT_PACK32, 1664 VK_FORMAT_A8B8G8R8_SINT_PACK32, 1665 VK_FORMAT_A8B8G8R8_SRGB_PACK32, 1666 VK_FORMAT_B8G8R8A8_UNORM, 1667 VK_FORMAT_B8G8R8A8_SRGB, 1668 VK_FORMAT_A2R10G10B10_UNORM_PACK32, 1669 VK_FORMAT_A2B10G10R10_UNORM_PACK32, 1670 VK_FORMAT_A2B10G10R10_UINT_PACK32, 1671 VK_FORMAT_R16_UNORM, 1672 VK_FORMAT_R16_SNORM, 1673 VK_FORMAT_R16_UINT, 1674 VK_FORMAT_R16_SINT, 1675 VK_FORMAT_R16_SFLOAT, 1676 VK_FORMAT_R16G16_UNORM, 1677 VK_FORMAT_R16G16_SNORM, 1678 VK_FORMAT_R16G16_UINT, 1679 VK_FORMAT_R16G16_SINT, 1680 VK_FORMAT_R16G16_SFLOAT, 1681 VK_FORMAT_R16G16B16A16_UNORM, 1682 VK_FORMAT_R16G16B16A16_SNORM, 1683 VK_FORMAT_R16G16B16A16_UINT, 1684 VK_FORMAT_R16G16B16A16_SINT, 1685 VK_FORMAT_R16G16B16A16_SFLOAT, 1686 VK_FORMAT_R32_UINT, 1687 VK_FORMAT_R32_SINT, 1688 VK_FORMAT_R32_SFLOAT, 1689 VK_FORMAT_R32G32_UINT, 1690 VK_FORMAT_R32G32_SINT, 1691 VK_FORMAT_R32G32_SFLOAT, 1692 VK_FORMAT_R32G32B32A32_UINT, 1693 VK_FORMAT_R32G32B32A32_SINT, 1694 VK_FORMAT_R32G32B32A32_SFLOAT, 1695 }; 1696 const deUint32 sampleCounts[] = 1697 { 1698 2u, 4u, 8u 1699 }; 1700 tcu::TestContext& testCtx (group->getTestContext()); 1701 1702 for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++) 1703 { 1704 const VkFormat format (formats[formatNdx]); 1705 const std::string formatName (formatToName(format)); 1706 de::MovePtr<tcu::TestCaseGroup> formatGroup (new tcu::TestCaseGroup(testCtx, formatName.c_str(), formatName.c_str())); 1707 1708 for (size_t sampleCountNdx = 0; sampleCountNdx < DE_LENGTH_OF_ARRAY(sampleCounts); sampleCountNdx++) 1709 { 1710 const deUint32 sampleCount (sampleCounts[sampleCountNdx]); 1711 const std::string testName ("samples_" + de::toString(sampleCount)); 1712 1713 formatGroup->addChild(new InstanceFactory1<MultisampleRenderPassTestInstance, TestConfig, Programs>(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName.c_str(), testName.c_str(), TestConfig(format, sampleCount))); 1714 } 1715 1716 group->addChild(formatGroup.release()); 1717 } 1718 } 1719 1720 } // anonymous 1721 1722 tcu::TestCaseGroup* createRenderPassMultisampleResolveTests (tcu::TestContext& testCtx) 1723 { 1724 return createTestGroup(testCtx, "multisample_resolve", "Multisample render pass resolve tests", initTests); 1725 } 1726 1727 } // vkt 1728