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 YCbCr Format Tests 22 *//*--------------------------------------------------------------------*/ 23 24 #include "vktYCbCrFormatTests.hpp" 25 #include "vktTestCaseUtil.hpp" 26 #include "vktTestGroupUtil.hpp" 27 #include "vktShaderExecutor.hpp" 28 #include "vktYCbCrUtil.hpp" 29 30 #include "vkStrUtil.hpp" 31 #include "vkRef.hpp" 32 #include "vkRefUtil.hpp" 33 #include "vkTypeUtil.hpp" 34 #include "vkQueryUtil.hpp" 35 #include "vkMemUtil.hpp" 36 #include "vkImageUtil.hpp" 37 #include "vkDeviceUtil.hpp" 38 #include "vkPlatform.hpp" 39 40 #include "tcuTestLog.hpp" 41 #include "tcuVectorUtil.hpp" 42 43 #include "deStringUtil.hpp" 44 #include "deSharedPtr.hpp" 45 #include "deUniquePtr.hpp" 46 #include "deRandom.hpp" 47 #include "deSTLUtil.hpp" 48 49 namespace vkt 50 { 51 namespace ycbcr 52 { 53 namespace 54 { 55 56 // \todo [2017-05-24 pyry] Extend: 57 // * VK_IMAGE_TILING_LINEAR 58 // * Other shader types 59 60 using namespace vk; 61 using namespace shaderexecutor; 62 63 using tcu::UVec2; 64 using tcu::Vec2; 65 using tcu::Vec4; 66 using tcu::TestLog; 67 using de::MovePtr; 68 using de::UniquePtr; 69 using std::vector; 70 using std::string; 71 72 typedef de::SharedPtr<Allocation> AllocationSp; 73 typedef de::SharedPtr<vk::Unique<VkBuffer> > VkBufferSp; 74 75 Move<VkImage> createTestImage (const DeviceInterface& vkd, 76 VkDevice device, 77 VkFormat format, 78 const UVec2& size, 79 VkImageCreateFlags createFlags, 80 VkImageTiling tiling, 81 VkImageLayout layout) 82 { 83 const VkImageCreateInfo createInfo = 84 { 85 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, 86 DE_NULL, 87 createFlags, 88 VK_IMAGE_TYPE_2D, 89 format, 90 makeExtent3D(size.x(), size.y(), 1u), 91 1u, // mipLevels 92 1u, // arrayLayers 93 VK_SAMPLE_COUNT_1_BIT, 94 tiling, 95 VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT, 96 VK_SHARING_MODE_EXCLUSIVE, 97 0u, 98 (const deUint32*)DE_NULL, 99 layout, 100 }; 101 102 return createImage(vkd, device, &createInfo); 103 } 104 105 Move<VkImageView> createImageView (const DeviceInterface& vkd, 106 VkDevice device, 107 VkImage image, 108 VkFormat format, 109 VkSamplerYcbcrConversion conversion) 110 { 111 const VkSamplerYcbcrConversionInfo conversionInfo = 112 { 113 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, 114 DE_NULL, 115 conversion 116 }; 117 const VkImageViewCreateInfo viewInfo = 118 { 119 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 120 &conversionInfo, 121 (VkImageViewCreateFlags)0, 122 image, 123 VK_IMAGE_VIEW_TYPE_2D, 124 format, 125 { 126 VK_COMPONENT_SWIZZLE_IDENTITY, 127 VK_COMPONENT_SWIZZLE_IDENTITY, 128 VK_COMPONENT_SWIZZLE_IDENTITY, 129 VK_COMPONENT_SWIZZLE_IDENTITY, 130 }, 131 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }, 132 }; 133 134 return createImageView(vkd, device, &viewInfo); 135 } 136 137 Move<VkDescriptorSetLayout> createDescriptorSetLayout (const DeviceInterface& vkd, VkDevice device, VkSampler sampler) 138 { 139 const VkDescriptorSetLayoutBinding binding = 140 { 141 0u, // binding 142 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 143 1u, // descriptorCount 144 VK_SHADER_STAGE_ALL, 145 &sampler 146 }; 147 const VkDescriptorSetLayoutCreateInfo layoutInfo = 148 { 149 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, 150 DE_NULL, 151 (VkDescriptorSetLayoutCreateFlags)0u, 152 1u, 153 &binding, 154 }; 155 156 return createDescriptorSetLayout(vkd, device, &layoutInfo); 157 } 158 159 Move<VkDescriptorPool> createDescriptorPool (const DeviceInterface& vkd, VkDevice device) 160 { 161 const VkDescriptorPoolSize poolSizes[] = 162 { 163 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u }, 164 }; 165 const VkDescriptorPoolCreateInfo poolInfo = 166 { 167 VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, 168 DE_NULL, 169 (VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 170 1u, // maxSets 171 DE_LENGTH_OF_ARRAY(poolSizes), 172 poolSizes, 173 }; 174 175 return createDescriptorPool(vkd, device, & poolInfo); 176 } 177 178 Move<VkDescriptorSet> createDescriptorSet (const DeviceInterface& vkd, 179 VkDevice device, 180 VkDescriptorPool descPool, 181 VkDescriptorSetLayout descLayout, 182 VkImageView imageView, 183 VkSampler sampler) 184 { 185 Move<VkDescriptorSet> descSet; 186 187 { 188 const VkDescriptorSetAllocateInfo allocInfo = 189 { 190 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, 191 DE_NULL, 192 descPool, 193 1u, 194 &descLayout, 195 }; 196 197 descSet = allocateDescriptorSet(vkd, device, &allocInfo); 198 } 199 200 { 201 const VkDescriptorImageInfo imageInfo = 202 { 203 sampler, 204 imageView, 205 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL 206 }; 207 const VkWriteDescriptorSet descriptorWrite = 208 { 209 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 210 DE_NULL, 211 *descSet, 212 0u, // dstBinding 213 0u, // dstArrayElement 214 1u, // descriptorCount 215 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 216 &imageInfo, 217 (const VkDescriptorBufferInfo*)DE_NULL, 218 (const VkBufferView*)DE_NULL, 219 }; 220 221 vkd.updateDescriptorSets(device, 1u, &descriptorWrite, 0u, DE_NULL); 222 } 223 224 return descSet; 225 } 226 227 struct TestParameters 228 { 229 VkFormat format; 230 UVec2 size; 231 VkImageCreateFlags flags; 232 VkImageTiling tiling; 233 glu::ShaderType shaderType; 234 bool useMappedMemory; 235 236 TestParameters (VkFormat format_, 237 const UVec2& size_, 238 VkImageCreateFlags flags_, 239 VkImageTiling tiling_, 240 glu::ShaderType shaderType_, 241 bool useMappedMemory_) 242 : format (format_) 243 , size (size_) 244 , flags (flags_) 245 , tiling (tiling_) 246 , shaderType (shaderType_) 247 , useMappedMemory (useMappedMemory_) 248 { 249 } 250 251 TestParameters (void) 252 : format (VK_FORMAT_UNDEFINED) 253 , flags (0u) 254 , tiling (VK_IMAGE_TILING_OPTIMAL) 255 , shaderType (glu::SHADERTYPE_LAST) 256 , useMappedMemory (false) 257 { 258 } 259 }; 260 261 ShaderSpec getShaderSpec (const TestParameters&) 262 { 263 ShaderSpec spec; 264 265 spec.inputs.push_back(Symbol("texCoord", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP))); 266 spec.outputs.push_back(Symbol("result", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP))); 267 268 spec.globalDeclarations = 269 "layout(binding = 0, set = 1) uniform highp sampler2D u_image;\n"; 270 271 spec.source = 272 "result = texture(u_image, texCoord);\n"; 273 274 return spec; 275 } 276 277 void checkSupport (Context& context, const TestParameters params) 278 { 279 checkImageSupport(context, params.format, params.flags, params.tiling); 280 } 281 282 void generateLookupCoordinates (const UVec2& imageSize, vector<Vec2>* dst) 283 { 284 dst->resize(imageSize.x() * imageSize.y()); 285 286 for (deUint32 texelY = 0; texelY < imageSize.y(); ++texelY) 287 for (deUint32 texelX = 0; texelX < imageSize.x(); ++texelX) 288 { 289 const float x = ((float)texelX + 0.5f) / (float)imageSize.x(); 290 const float y = ((float)texelY + 0.5f) / (float)imageSize.y(); 291 292 (*dst)[texelY*imageSize.x() + texelX] = Vec2(x, y); 293 } 294 } 295 296 tcu::TestStatus testFormat (Context& context, TestParameters params) 297 { 298 const DeviceInterface& vkd = context.getDeviceInterface(); 299 const VkDevice device = context.getDevice(); 300 301 const VkFormat format = params.format; 302 const PlanarFormatDescription formatInfo = getPlanarFormatDescription(format); 303 const UVec2 size = params.size; 304 const VkImageCreateFlags createFlags = params.flags; 305 const VkImageTiling tiling = params.tiling; 306 const bool mappedMemory = params.useMappedMemory; 307 308 const Unique<VkImage> image (createTestImage(vkd, device, format, size, createFlags, tiling, mappedMemory ? VK_IMAGE_LAYOUT_PREINITIALIZED : VK_IMAGE_LAYOUT_UNDEFINED)); 309 const vector<AllocationSp> allocations (allocateAndBindImageMemory(vkd, device, context.getDefaultAllocator(), *image, format, createFlags, mappedMemory ? MemoryRequirement::HostVisible : MemoryRequirement::Any)); 310 311 const VkSamplerYcbcrConversionCreateInfo 312 conversionInfo = 313 { 314 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO, 315 DE_NULL, 316 format, 317 VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, 318 VK_SAMPLER_YCBCR_RANGE_ITU_FULL, 319 { 320 VK_COMPONENT_SWIZZLE_IDENTITY, 321 VK_COMPONENT_SWIZZLE_IDENTITY, 322 VK_COMPONENT_SWIZZLE_IDENTITY, 323 VK_COMPONENT_SWIZZLE_IDENTITY, 324 }, 325 VK_CHROMA_LOCATION_MIDPOINT, 326 VK_CHROMA_LOCATION_MIDPOINT, 327 VK_FILTER_NEAREST, 328 VK_FALSE, // forceExplicitReconstruction 329 }; 330 const Unique<VkSamplerYcbcrConversion> conversion (createSamplerYcbcrConversion(vkd, device, &conversionInfo)); 331 const Unique<VkImageView> imageView (createImageView(vkd, device, *image, format, *conversion)); 332 333 const VkSamplerYcbcrConversionInfo samplerConversionInfo = 334 { 335 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, 336 DE_NULL, 337 *conversion, 338 }; 339 340 const VkSamplerCreateInfo samplerInfo = 341 { 342 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, 343 &samplerConversionInfo, 344 0u, 345 VK_FILTER_NEAREST, // magFilter 346 VK_FILTER_NEAREST, // minFilter 347 VK_SAMPLER_MIPMAP_MODE_NEAREST, // mipmapMode 348 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU 349 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV 350 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW 351 0.0f, // mipLodBias 352 VK_FALSE, // anisotropyEnable 353 1.0f, // maxAnisotropy 354 VK_FALSE, // compareEnable 355 VK_COMPARE_OP_ALWAYS, // compareOp 356 0.0f, // minLod 357 0.0f, // maxLod 358 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor 359 VK_FALSE, // unnormalizedCoords 360 }; 361 362 const Unique<VkSampler> sampler (createSampler(vkd, device, &samplerInfo)); 363 364 const Unique<VkDescriptorSetLayout> descLayout (createDescriptorSetLayout(vkd, device, *sampler)); 365 const Unique<VkDescriptorPool> descPool (createDescriptorPool(vkd, device)); 366 const Unique<VkDescriptorSet> descSet (createDescriptorSet(vkd, device, *descPool, *descLayout, *imageView, *sampler)); 367 368 MultiPlaneImageData imageData (format, size); 369 370 const VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = 371 { 372 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, 373 DE_NULL, 374 params.format, 375 VK_IMAGE_TYPE_2D, 376 params.tiling, 377 VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT, 378 params.flags, 379 }; 380 VkSamplerYcbcrConversionImageFormatProperties ycbcrProperties = 381 { 382 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES, 383 DE_NULL, 384 0, 385 }; 386 VkImageFormatProperties2 extProperties = 387 { 388 VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, 389 &ycbcrProperties, 390 { 391 { 392 0, // width 393 0, // height 394 0, // depth 395 }, 396 0u, // maxMipLevels 397 0u, // maxArrayLayers 398 0, // sampleCounts 399 0u, // maxResourceSize 400 }, 401 }; 402 VkResult propsResult; 403 const PlatformInterface& vkp = context.getPlatformInterface(); 404 const Unique<VkInstance> instance (createInstanceWithExtension(vkp, context.getUsedApiVersion(), "VK_KHR_get_physical_device_properties2")); 405 const InstanceDriver vki (vkp, *instance); 406 407 // Verify that a yuv image consumes at least one descriptor 408 propsResult = vki.getPhysicalDeviceImageFormatProperties2(context.getPhysicalDevice(), &imageFormatInfo, &extProperties); 409 410 TCU_CHECK(propsResult == VK_SUCCESS); 411 TCU_CHECK(ycbcrProperties.combinedImageSamplerDescriptorCount >= 1); 412 413 // Prepare texture data 414 fillGradient(&imageData, Vec4(0.0f), Vec4(1.0f)); 415 416 if (mappedMemory) 417 { 418 // Fill and prepare image 419 fillImageMemory(vkd, 420 device, 421 context.getUniversalQueueFamilyIndex(), 422 *image, 423 allocations, 424 imageData, 425 (VkAccessFlags)VK_ACCESS_SHADER_READ_BIT, 426 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); 427 } 428 else 429 { 430 // Upload and prepare image 431 uploadImage(vkd, 432 device, 433 context.getUniversalQueueFamilyIndex(), 434 context.getDefaultAllocator(), 435 *image, 436 imageData, 437 (VkAccessFlags)VK_ACCESS_SHADER_READ_BIT, 438 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); 439 } 440 441 { 442 vector<Vec2> texCoord; 443 vector<Vec4> result; 444 vector<Vec4> reference; 445 bool allOk = true; 446 Vec4 threshold (0.02f); 447 448 generateLookupCoordinates(size, &texCoord); 449 450 result.resize(texCoord.size()); 451 reference.resize(texCoord.size()); 452 453 { 454 UniquePtr<ShaderExecutor> executor (createExecutor(context, params.shaderType, getShaderSpec(params), *descLayout)); 455 const void* inputs[] = { texCoord[0].getPtr() }; 456 void* outputs[] = { result[0].getPtr() }; 457 458 executor->execute((int)texCoord.size(), inputs, outputs, *descSet); 459 } 460 461 for (deUint32 channelNdx = 0; channelNdx < 4; channelNdx++) 462 { 463 if (formatInfo.hasChannelNdx(channelNdx)) 464 { 465 const tcu::ConstPixelBufferAccess channelAccess = imageData.getChannelAccess(channelNdx); 466 const tcu::Sampler refSampler = mapVkSampler(samplerInfo); 467 const tcu::Texture2DView refTexView (1u, &channelAccess); 468 469 for (size_t ndx = 0; ndx < texCoord.size(); ++ndx) 470 { 471 const Vec2& coord = texCoord[ndx]; 472 reference[ndx][channelNdx] = refTexView.sample(refSampler, coord.x(), coord.y(), 0.0f)[0]; 473 } 474 } 475 else 476 { 477 for (size_t ndx = 0; ndx < texCoord.size(); ++ndx) 478 reference[ndx][channelNdx] = channelNdx == 3 ? 1.0f : 0.0f; 479 } 480 } 481 482 for (size_t ndx = 0; ndx < texCoord.size(); ++ndx) 483 { 484 if (boolAny(greaterThanEqual(abs(result[ndx] - reference[ndx]), threshold))) 485 { 486 context.getTestContext().getLog() 487 << TestLog::Message << "ERROR: At " << texCoord[ndx] 488 << ": got " << result[ndx] 489 << ", expected " << reference[ndx] 490 << TestLog::EndMessage; 491 allOk = false; 492 } 493 } 494 495 if (allOk) 496 return tcu::TestStatus::pass("All samples passed"); 497 else 498 { 499 const tcu::ConstPixelBufferAccess refAccess (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), 500 tcu::IVec3((int)size.x(), (int)size.y(), 1u), 501 reference[0].getPtr()); 502 const tcu::ConstPixelBufferAccess resAccess (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), 503 tcu::IVec3((int)size.x(), (int)size.y(), 1u), 504 result[0].getPtr()); 505 506 context.getTestContext().getLog() 507 << TestLog::Image("Result", "Result Image", resAccess, Vec4(1.0f), Vec4(0.0f)) 508 << TestLog::Image("Reference", "Reference Image", refAccess, Vec4(1.0f), Vec4(0.0f)); 509 510 return tcu::TestStatus::fail("Got invalid results"); 511 } 512 } 513 } 514 515 void initPrograms (SourceCollections& dst, TestParameters params) 516 { 517 const ShaderSpec spec = getShaderSpec(params); 518 519 generateSources(params.shaderType, spec, dst); 520 } 521 522 void populatePerFormatGroup (tcu::TestCaseGroup* group, VkFormat format) 523 { 524 const UVec2 size (66, 32); 525 const struct 526 { 527 const char* name; 528 glu::ShaderType value; 529 } shaderTypes[] = 530 { 531 { "vertex", glu::SHADERTYPE_VERTEX }, 532 { "fragment", glu::SHADERTYPE_FRAGMENT }, 533 { "geometry", glu::SHADERTYPE_GEOMETRY }, 534 { "tess_control", glu::SHADERTYPE_TESSELLATION_CONTROL }, 535 { "tess_eval", glu::SHADERTYPE_TESSELLATION_EVALUATION }, 536 { "compute", glu::SHADERTYPE_COMPUTE } 537 }; 538 const struct 539 { 540 const char* name; 541 VkImageTiling value; 542 } tilings[] = 543 { 544 { "optimal", VK_IMAGE_TILING_OPTIMAL }, 545 { "linear", VK_IMAGE_TILING_LINEAR } 546 }; 547 548 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++) 549 for (int tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(tilings); tilingNdx++) 550 { 551 const VkImageTiling tiling = tilings[tilingNdx].value; 552 const char* const tilingName = tilings[tilingNdx].name; 553 const glu::ShaderType shaderType = shaderTypes[shaderTypeNdx].value; 554 const char* const shaderTypeName = shaderTypes[shaderTypeNdx].name; 555 const string name = string(shaderTypeName) + "_" + tilingName; 556 557 addFunctionCaseWithPrograms(group, name, "", checkSupport, initPrograms, testFormat, TestParameters(format, size, 0u, tiling, shaderType, false)); 558 559 if (getPlaneCount(format) > 1) 560 addFunctionCaseWithPrograms(group, name + "_disjoint", "", checkSupport, initPrograms, testFormat, TestParameters(format, size, (VkImageCreateFlags)VK_IMAGE_CREATE_DISJOINT_BIT, tiling, shaderType, false)); 561 562 if (tiling == VK_IMAGE_TILING_LINEAR) 563 { 564 addFunctionCaseWithPrograms(group, name + "_mapped", "", checkSupport, initPrograms, testFormat, TestParameters(format, size, 0u, tiling, shaderType, true)); 565 566 if (getPlaneCount(format) > 1) 567 addFunctionCaseWithPrograms(group, name + "_disjoint_mapped", "", checkSupport, initPrograms, testFormat, TestParameters(format, size, (VkImageCreateFlags)VK_IMAGE_CREATE_DISJOINT_BIT, tiling, shaderType, true)); 568 } 569 } 570 } 571 572 void populateFormatGroup (tcu::TestCaseGroup* group) 573 { 574 for (int formatNdx = VK_YCBCR_FORMAT_FIRST; formatNdx < VK_YCBCR_FORMAT_LAST; formatNdx++) 575 { 576 const VkFormat format = (VkFormat)formatNdx; 577 const string formatName = de::toLower(de::toString(format).substr(10)); 578 579 group->addChild(createTestGroup<VkFormat>(group->getTestContext(), formatName, "", populatePerFormatGroup, format)); 580 } 581 } 582 583 } // namespace 584 585 tcu::TestCaseGroup* createFormatTests (tcu::TestContext& testCtx) 586 { 587 return createTestGroup(testCtx, "format", "YCbCr Format Tests", populateFormatGroup); 588 } 589 590 } // ycbcr 591 } // vkt 592