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 Image View Tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktYCbCrViewTests.hpp"
25 #include "vktYCbCrUtil.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
28 #include "vktShaderExecutor.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 "vkCmdUtil.hpp"
38
39 #include "tcuTestLog.hpp"
40 #include "tcuVectorUtil.hpp"
41
42 #include "deStringUtil.hpp"
43 #include "deSharedPtr.hpp"
44 #include "deUniquePtr.hpp"
45 #include "deRandom.hpp"
46 #include "deSTLUtil.hpp"
47
48 namespace vkt
49 {
50 namespace ycbcr
51 {
52 namespace
53 {
54
55 using namespace vk;
56 using namespace shaderexecutor;
57
58 using tcu::UVec2;
59 using tcu::Vec2;
60 using tcu::Vec4;
61 using tcu::TestLog;
62 using de::MovePtr;
63 using de::UniquePtr;
64 using std::vector;
65 using std::string;
66
67 // List of some formats compatible with formats listed in "Plane Format Compatibility Table".
68 const VkFormat s_compatible_formats[] =
69 {
70 // 8-bit compatibility class
71 // Compatible format for VK_FORMAT_R8_UNORM
72 VK_FORMAT_R4G4_UNORM_PACK8,
73 VK_FORMAT_R8_UINT,
74 VK_FORMAT_R8_SINT,
75 // 16-bit compatibility class
76 // Compatible formats with VK_FORMAT_R8G8_UNORM, VK_FORMAT_R10X6_UNORM_PACK16, VK_FORMAT_R12X4_UNORM_PACK16 and VK_FORMAT_R16_UNORM
77 VK_FORMAT_R8G8_UNORM,
78 VK_FORMAT_R8G8_UINT,
79 VK_FORMAT_R10X6_UNORM_PACK16,
80 VK_FORMAT_R12X4_UNORM_PACK16,
81 VK_FORMAT_R16_UNORM,
82 VK_FORMAT_R16_UINT,
83 VK_FORMAT_R16_SINT,
84 VK_FORMAT_R4G4B4A4_UNORM_PACK16,
85 // 32-bit compatibility class
86 // Compatible formats for VK_FORMAT_R10X6G10X6_UNORM_2PACK16, VK_FORMAT_R12X4G12X4_UNORM_2PACK16 and VK_FORMAT_R16G16_UNORM
87 VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
88 VK_FORMAT_R12X4G12X4_UNORM_2PACK16,
89 VK_FORMAT_R16G16_UNORM,
90 VK_FORMAT_R8G8B8A8_UNORM,
91 VK_FORMAT_R8G8B8A8_UINT,
92 VK_FORMAT_R32_UINT,
93 };
94
formatsAreCompatible(const VkFormat format0,const VkFormat format1)95 inline bool formatsAreCompatible (const VkFormat format0, const VkFormat format1)
96 {
97 return format0 == format1 || mapVkFormat(format0).getPixelSize() == mapVkFormat(format1).getPixelSize();
98 }
99
createTestImage(const DeviceInterface & vkd,VkDevice device,VkFormat format,const UVec2 & size,VkImageCreateFlags createFlags)100 Move<VkImage> createTestImage (const DeviceInterface& vkd,
101 VkDevice device,
102 VkFormat format,
103 const UVec2& size,
104 VkImageCreateFlags createFlags)
105 {
106 const VkImageCreateInfo createInfo =
107 {
108 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
109 DE_NULL,
110 createFlags,
111 VK_IMAGE_TYPE_2D,
112 format,
113 makeExtent3D(size.x(), size.y(), 1u),
114 1u, // mipLevels
115 1u, // arrayLayers
116 VK_SAMPLE_COUNT_1_BIT,
117 VK_IMAGE_TILING_OPTIMAL,
118 VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT,
119 VK_SHARING_MODE_EXCLUSIVE,
120 0u,
121 (const deUint32*)DE_NULL,
122 VK_IMAGE_LAYOUT_UNDEFINED,
123 };
124
125 return createImage(vkd, device, &createInfo);
126 }
127
createImageView(const DeviceInterface & vkd,VkDevice device,VkImage image,VkFormat format,VkImageAspectFlagBits imageAspect,const VkSamplerYcbcrConversionInfo * samplerConversionInfo)128 Move<VkImageView> createImageView (const DeviceInterface& vkd,
129 VkDevice device,
130 VkImage image,
131 VkFormat format,
132 VkImageAspectFlagBits imageAspect,
133 const VkSamplerYcbcrConversionInfo* samplerConversionInfo)
134 {
135 const VkImageViewCreateInfo viewInfo =
136 {
137 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
138 samplerConversionInfo,
139 (VkImageViewCreateFlags)0,
140 image,
141 VK_IMAGE_VIEW_TYPE_2D,
142 format,
143 {
144 VK_COMPONENT_SWIZZLE_IDENTITY,
145 VK_COMPONENT_SWIZZLE_IDENTITY,
146 VK_COMPONENT_SWIZZLE_IDENTITY,
147 VK_COMPONENT_SWIZZLE_IDENTITY,
148 },
149 { (VkImageAspectFlags)imageAspect, 0u, 1u, 0u, 1u },
150 };
151
152 return createImageView(vkd, device, &viewInfo);
153 }
154
155 // Descriptor layout for set 1:
156 // 0: Plane view bound as COMBINED_IMAGE_SAMPLER
157 // 1: "Whole" image bound as COMBINED_IMAGE_SAMPLER
158 // + immutable sampler (required for color conversion)
159
createDescriptorSetLayout(const DeviceInterface & vkd,VkDevice device,VkSampler conversionSampler)160 Move<VkDescriptorSetLayout> createDescriptorSetLayout (const DeviceInterface& vkd, VkDevice device, VkSampler conversionSampler)
161 {
162 const VkDescriptorSetLayoutBinding bindings[] =
163 {
164 {
165 0u, // binding
166 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
167 1u, // descriptorCount
168 VK_SHADER_STAGE_ALL,
169 (const VkSampler*)DE_NULL
170 },
171 {
172 1u, // binding
173 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
174 1u, // descriptorCount
175 VK_SHADER_STAGE_ALL,
176 &conversionSampler
177 }
178 };
179 const VkDescriptorSetLayoutCreateInfo layoutInfo =
180 {
181 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
182 DE_NULL,
183 (VkDescriptorSetLayoutCreateFlags)0u,
184 DE_LENGTH_OF_ARRAY(bindings),
185 bindings,
186 };
187
188 return createDescriptorSetLayout(vkd, device, &layoutInfo);
189 }
190
createDescriptorPool(const DeviceInterface & vkd,VkDevice device,const deUint32 combinedSamplerDescriptorCount)191 Move<VkDescriptorPool> createDescriptorPool (const DeviceInterface& vkd, VkDevice device, const deUint32 combinedSamplerDescriptorCount)
192 {
193 const VkDescriptorPoolSize poolSizes[] =
194 {
195 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2u * combinedSamplerDescriptorCount },
196 };
197 const VkDescriptorPoolCreateInfo poolInfo =
198 {
199 VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
200 DE_NULL,
201 (VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
202 1u, // maxSets
203 DE_LENGTH_OF_ARRAY(poolSizes),
204 poolSizes,
205 };
206
207 return createDescriptorPool(vkd, device, & poolInfo);
208 }
209
createDescriptorSet(const DeviceInterface & vkd,VkDevice device,VkDescriptorPool descPool,VkDescriptorSetLayout descLayout,VkImageView planeView,VkSampler planeViewSampler,VkImageView wholeView,VkSampler wholeViewSampler)210 Move<VkDescriptorSet> createDescriptorSet (const DeviceInterface& vkd,
211 VkDevice device,
212 VkDescriptorPool descPool,
213 VkDescriptorSetLayout descLayout,
214 VkImageView planeView,
215 VkSampler planeViewSampler,
216 VkImageView wholeView,
217 VkSampler wholeViewSampler)
218 {
219 Move<VkDescriptorSet> descSet;
220
221 {
222 const VkDescriptorSetAllocateInfo allocInfo =
223 {
224 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
225 DE_NULL,
226 descPool,
227 1u,
228 &descLayout,
229 };
230
231 descSet = allocateDescriptorSet(vkd, device, &allocInfo);
232 }
233
234 {
235 const VkDescriptorImageInfo imageInfo0 =
236 {
237 planeViewSampler,
238 planeView,
239 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
240 };
241 const VkDescriptorImageInfo imageInfo1 =
242 {
243 wholeViewSampler,
244 wholeView,
245 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
246 };
247 const VkWriteDescriptorSet descriptorWrites[] =
248 {
249 {
250 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
251 DE_NULL,
252 *descSet,
253 0u, // dstBinding
254 0u, // dstArrayElement
255 1u, // descriptorCount
256 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
257 &imageInfo0,
258 (const VkDescriptorBufferInfo*)DE_NULL,
259 (const VkBufferView*)DE_NULL,
260 },
261 {
262 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
263 DE_NULL,
264 *descSet,
265 1u, // dstBinding
266 0u, // dstArrayElement
267 1u, // descriptorCount
268 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
269 &imageInfo1,
270 (const VkDescriptorBufferInfo*)DE_NULL,
271 (const VkBufferView*)DE_NULL,
272 }
273 };
274
275 vkd.updateDescriptorSets(device, DE_LENGTH_OF_ARRAY(descriptorWrites), descriptorWrites, 0u, DE_NULL);
276 }
277
278 return descSet;
279 }
280
executeImageBarrier(const DeviceInterface & vkd,VkDevice device,deUint32 queueFamilyNdx,VkPipelineStageFlags srcStage,VkPipelineStageFlags dstStage,const VkImageMemoryBarrier & barrier)281 void executeImageBarrier (const DeviceInterface& vkd,
282 VkDevice device,
283 deUint32 queueFamilyNdx,
284 VkPipelineStageFlags srcStage,
285 VkPipelineStageFlags dstStage,
286 const VkImageMemoryBarrier& barrier)
287 {
288 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
289 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
290 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
291
292 beginCommandBuffer(vkd, *cmdBuffer);
293
294 vkd.cmdPipelineBarrier(*cmdBuffer,
295 srcStage,
296 dstStage,
297 (VkDependencyFlags)0u,
298 0u,
299 (const VkMemoryBarrier*)DE_NULL,
300 0u,
301 (const VkBufferMemoryBarrier*)DE_NULL,
302 1u,
303 &barrier);
304
305 endCommandBuffer(vkd, *cmdBuffer);
306
307 submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
308 }
309
310 struct TestParameters
311 {
312 enum ViewType
313 {
314 VIEWTYPE_IMAGE_VIEW = 0,
315 VIEWTYPE_MEMORY_ALIAS,
316
317 VIEWTYPE_LAST
318 };
319
320 ViewType viewType;
321 VkFormat format;
322 UVec2 size;
323 VkImageCreateFlags createFlags;
324 deUint32 planeNdx;
325 VkFormat planeCompatibleFormat;
326 glu::ShaderType shaderType;
327 deBool isCompatibilityFormat;
328
TestParametersvkt::ycbcr::__anon16ce7d170111::TestParameters329 TestParameters (ViewType viewType_, VkFormat format_, const UVec2& size_, VkImageCreateFlags createFlags_, deUint32 planeNdx_, VkFormat planeCompatibleFormat_, glu::ShaderType shaderType_, deBool isCompatibilityFormat_)
330 : viewType (viewType_)
331 , format (format_)
332 , size (size_)
333 , createFlags (createFlags_)
334 , planeNdx (planeNdx_)
335 , planeCompatibleFormat (planeCompatibleFormat_)
336 , shaderType (shaderType_)
337 , isCompatibilityFormat (isCompatibilityFormat_)
338 {
339 }
340
TestParametersvkt::ycbcr::__anon16ce7d170111::TestParameters341 TestParameters (void)
342 : viewType (VIEWTYPE_LAST)
343 , format (VK_FORMAT_UNDEFINED)
344 , createFlags (0u)
345 , planeNdx (0u)
346 , planeCompatibleFormat (VK_FORMAT_UNDEFINED)
347 , shaderType (glu::SHADERTYPE_LAST)
348 , isCompatibilityFormat (false)
349 {
350 }
351 };
352
getSamplerDecl(VkFormat f)353 static std::string getSamplerDecl(VkFormat f) {
354 if (isIntFormat(f)) return "isampler2D";
355 else if (isUintFormat(f)) return "usampler2D";
356 else return "sampler2D";
357 }
358
getShaderSpec(const TestParameters & params)359 ShaderSpec getShaderSpec (const TestParameters& params)
360 {
361 ShaderSpec spec;
362
363 spec.inputs.push_back(Symbol("texCoord", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
364 spec.outputs.push_back(Symbol("result0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
365 spec.outputs.push_back(Symbol("result1", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
366
367 const std::string sampler = getSamplerDecl(params.planeCompatibleFormat);
368 spec.globalDeclarations =
369 "layout(binding = 1, set = 1) uniform highp sampler2D u_image;\n"
370 "layout(binding = 0, set = 1) uniform highp " + sampler + " u_planeView;\n";
371
372 spec.source =
373 "result0 = texture(u_image, texCoord);\n"
374 "result1 = vec4(texture(u_planeView, texCoord));\n";
375
376 return spec;
377 }
378
379
generateLookupCoordinates(const UVec2 & imageSize,size_t numCoords,de::Random * rnd,vector<Vec2> * dst)380 void generateLookupCoordinates (const UVec2& imageSize, size_t numCoords, de::Random* rnd, vector<Vec2>* dst)
381 {
382 dst->resize(numCoords);
383
384 for (size_t coordNdx = 0; coordNdx < numCoords; ++coordNdx)
385 {
386 const deUint32 texelX = rnd->getUint32() % imageSize.x();
387 const deUint32 texelY = rnd->getUint32() % imageSize.y();
388 const float x = ((float)texelX + 0.5f) / (float)imageSize.x();
389 const float y = ((float)texelY + 0.5f) / (float)imageSize.y();
390
391 (*dst)[coordNdx] = Vec2(x, y);
392 }
393 }
394
checkImageUsageSupport(Context & context,VkFormat format,VkImageUsageFlags usage)395 void checkImageUsageSupport (Context& context,
396 VkFormat format,
397 VkImageUsageFlags usage)
398 {
399 const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(context.getInstanceInterface(),
400 context.getPhysicalDevice(),
401 format);
402 const VkFormatFeatureFlags featureFlags = formatProperties.optimalTilingFeatures;
403
404 if ((usage & VK_IMAGE_USAGE_SAMPLED_BIT) != 0
405 && (featureFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) == 0)
406 {
407 TCU_THROW(NotSupportedError, "Format doesn't support sampling");
408 }
409
410 // Other image usages are not handled currently
411 DE_ASSERT((usage & ~(VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT)) == 0);
412 }
413
checkSupport(Context & context,TestParameters params)414 void checkSupport(Context& context, TestParameters params)
415 {
416 const VkImageUsageFlags usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
417
418 checkImageSupport(context, params.format, params.createFlags);
419 checkImageUsageSupport(context, params.format, usage);
420 checkImageUsageSupport(context, params.planeCompatibleFormat, usage);
421 }
422
testPlaneView(Context & context,TestParameters params)423 tcu::TestStatus testPlaneView (Context& context, TestParameters params)
424 {
425 de::Random randomGen (deInt32Hash((deUint32)params.format) ^
426 deInt32Hash((deUint32)params.planeNdx) ^
427 deInt32Hash((deUint32)params.shaderType));
428
429 const InstanceInterface& vk = context.getInstanceInterface();
430 const DeviceInterface& vkd = context.getDeviceInterface();
431 const VkDevice device = context.getDevice();
432
433 const VkFormat format = params.format;
434 const VkImageCreateFlags createFlags = params.createFlags;
435 const PlanarFormatDescription formatInfo = getPlanarFormatDescription(format);
436 const UVec2 size = params.size;
437 const UVec2 planeExtent = getPlaneExtent(formatInfo, size, params.planeNdx, 0);
438 const Unique<VkImage> image (createTestImage(vkd, device, format, size, createFlags));
439 const Unique<VkImage> imageAlias ((params.viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS)
440 ? createTestImage(vkd, device, params.planeCompatibleFormat, planeExtent, createFlags)
441 : Move<VkImage>());
442 const vector<AllocationSp> allocations (allocateAndBindImageMemory(vkd, device, context.getDefaultAllocator(), *image, format, createFlags));
443
444 if (imageAlias)
445 {
446 if ((createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0)
447 {
448 VkBindImagePlaneMemoryInfo planeInfo =
449 {
450 VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR,
451 DE_NULL,
452 VK_IMAGE_ASPECT_PLANE_0_BIT_KHR
453 };
454
455 VkBindImageMemoryInfo coreInfo =
456 {
457 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR,
458 &planeInfo,
459 *imageAlias,
460 allocations[params.planeNdx]->getMemory(),
461 allocations[params.planeNdx]->getOffset(),
462 };
463
464 VK_CHECK(vkd.bindImageMemory2(device, 1, &coreInfo));
465 }
466 else
467 {
468 VK_CHECK(vkd.bindImageMemory(device, *imageAlias, allocations[params.planeNdx]->getMemory(), allocations[params.planeNdx]->getOffset()));
469 }
470 }
471
472 const VkSamplerYcbcrConversionCreateInfo conversionInfo =
473 {
474 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
475 DE_NULL,
476 format,
477 VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
478 VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
479 {
480 VK_COMPONENT_SWIZZLE_IDENTITY,
481 VK_COMPONENT_SWIZZLE_IDENTITY,
482 VK_COMPONENT_SWIZZLE_IDENTITY,
483 VK_COMPONENT_SWIZZLE_IDENTITY,
484 },
485 VK_CHROMA_LOCATION_MIDPOINT,
486 VK_CHROMA_LOCATION_MIDPOINT,
487 VK_FILTER_NEAREST,
488 VK_FALSE, // forceExplicitReconstruction
489 };
490 const Unique<VkSamplerYcbcrConversion> conversion (createSamplerYcbcrConversion(vkd, device, &conversionInfo));
491 const VkSamplerYcbcrConversionInfo samplerConversionInfo =
492 {
493 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
494 DE_NULL,
495 *conversion,
496 };
497 const Unique<VkImageView> wholeView (createImageView(vkd, device, *image, format, VK_IMAGE_ASPECT_COLOR_BIT, &samplerConversionInfo));
498 const Unique<VkImageView> planeView (createImageView(vkd,
499 device,
500 !imageAlias ? *image : *imageAlias,
501 params.planeCompatibleFormat,
502 !imageAlias ? getPlaneAspect(params.planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT,
503 DE_NULL));
504
505 const VkSamplerCreateInfo wholeSamplerInfo =
506 {
507 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
508 &samplerConversionInfo,
509 0u,
510 VK_FILTER_NEAREST, // magFilter
511 VK_FILTER_NEAREST, // minFilter
512 VK_SAMPLER_MIPMAP_MODE_NEAREST, // mipmapMode
513 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
514 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV
515 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW
516 0.0f, // mipLodBias
517 VK_FALSE, // anisotropyEnable
518 1.0f, // maxAnisotropy
519 VK_FALSE, // compareEnable
520 VK_COMPARE_OP_ALWAYS, // compareOp
521 0.0f, // minLod
522 0.0f, // maxLod
523 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor
524 VK_FALSE, // unnormalizedCoords
525 };
526 const VkSamplerCreateInfo planeSamplerInfo =
527 {
528 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
529 DE_NULL,
530 0u,
531 VK_FILTER_NEAREST, // magFilter
532 VK_FILTER_NEAREST, // minFilter
533 VK_SAMPLER_MIPMAP_MODE_NEAREST, // mipmapMode
534 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
535 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV
536 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW
537 0.0f, // mipLodBias
538 VK_FALSE, // anisotropyEnable
539 1.0f, // maxAnisotropy
540 VK_FALSE, // compareEnable
541 VK_COMPARE_OP_ALWAYS, // compareOp
542 0.0f, // minLod
543 0.0f, // maxLod
544 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor
545 VK_FALSE, // unnormalizedCoords
546 };
547
548 deUint32 combinedSamplerDescriptorCount = 1;
549 {
550 const VkPhysicalDeviceImageFormatInfo2 imageFormatInfo =
551 {
552 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, // sType;
553 DE_NULL, // pNext;
554 format, // format;
555 VK_IMAGE_TYPE_2D, // type;
556 VK_IMAGE_TILING_OPTIMAL, // tiling;
557 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
558 VK_IMAGE_USAGE_SAMPLED_BIT, // usage;
559 createFlags // flags;
560 };
561
562 VkSamplerYcbcrConversionImageFormatProperties samplerYcbcrConversionImage = {};
563 samplerYcbcrConversionImage.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES;
564 samplerYcbcrConversionImage.pNext = DE_NULL;
565
566 VkImageFormatProperties2 imageFormatProperties = {};
567 imageFormatProperties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
568 imageFormatProperties.pNext = &samplerYcbcrConversionImage;
569
570 VkResult result = vk.getPhysicalDeviceImageFormatProperties2(context.getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties);
571 if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
572 TCU_THROW(NotSupportedError, "Format not supported.");
573 VK_CHECK(result);
574 combinedSamplerDescriptorCount = samplerYcbcrConversionImage.combinedImageSamplerDescriptorCount;
575 }
576
577 const Unique<VkSampler> wholeSampler(createSampler(vkd, device, &wholeSamplerInfo));
578 const Unique<VkSampler> planeSampler(createSampler(vkd, device, &planeSamplerInfo));
579
580 const Unique<VkDescriptorSetLayout> descLayout (createDescriptorSetLayout(vkd, device, *wholeSampler));
581 const Unique<VkDescriptorPool> descPool (createDescriptorPool(vkd, device, combinedSamplerDescriptorCount));
582 const Unique<VkDescriptorSet> descSet (createDescriptorSet(vkd, device, *descPool, *descLayout, *planeView, *planeSampler, *wholeView, *wholeSampler));
583
584 MultiPlaneImageData imageData (format, size);
585
586 // Prepare texture data
587 fillRandom(&randomGen, &imageData);
588
589 if (imageAlias)
590 {
591 // Transition alias to right layout first
592 const VkImageMemoryBarrier initAliasBarrier =
593 {
594 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
595 DE_NULL,
596 (VkAccessFlags)0,
597 VK_ACCESS_SHADER_READ_BIT,
598 VK_IMAGE_LAYOUT_UNDEFINED,
599 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
600 VK_QUEUE_FAMILY_IGNORED,
601 VK_QUEUE_FAMILY_IGNORED,
602 *imageAlias,
603 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
604 };
605
606 executeImageBarrier(vkd,
607 device,
608 context.getUniversalQueueFamilyIndex(),
609 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
610 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
611 initAliasBarrier);
612 }
613
614 // Upload and prepare image
615 uploadImage(vkd,
616 device,
617 context.getUniversalQueueFamilyIndex(),
618 context.getDefaultAllocator(),
619 *image,
620 imageData,
621 (VkAccessFlags)VK_ACCESS_SHADER_READ_BIT,
622 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
623
624 {
625 const size_t numValues = 500;
626 vector<Vec2> texCoord (numValues);
627 vector<Vec4> resultWhole (numValues);
628 vector<Vec4> resultPlane (numValues);
629 vector<Vec4> referenceWhole (numValues);
630 vector<Vec4> referencePlane (numValues);
631 bool allOk = true;
632 Vec4 threshold (0.02f);
633
634 generateLookupCoordinates(size, numValues, &randomGen, &texCoord);
635
636 {
637 UniquePtr<ShaderExecutor> executor (createExecutor(context, params.shaderType, getShaderSpec(params), *descLayout));
638 const void* inputs[] = { texCoord[0].getPtr() };
639 void* outputs[] = { resultWhole[0].getPtr(), resultPlane[0].getPtr() };
640
641 executor->execute((int)numValues, inputs, outputs, *descSet);
642 }
643
644 // Whole image sampling reference
645 for (deUint32 channelNdx = 0; channelNdx < 4; channelNdx++)
646 {
647 if (formatInfo.hasChannelNdx(channelNdx))
648 {
649 const tcu::ConstPixelBufferAccess channelAccess = imageData.getChannelAccess(channelNdx);
650 const tcu::Sampler refSampler = mapVkSampler(wholeSamplerInfo);
651 const tcu::Texture2DView refTexView (1u, &channelAccess);
652
653 for (size_t ndx = 0; ndx < numValues; ++ndx)
654 {
655 const Vec2& coord = texCoord[ndx];
656 referenceWhole[ndx][channelNdx] = refTexView.sample(refSampler, coord.x(), coord.y(), 0.0f)[0];
657 }
658 }
659 else
660 {
661 for (size_t ndx = 0; ndx < numValues; ++ndx)
662 referenceWhole[ndx][channelNdx] = channelNdx == 3 ? 1.0f : 0.0f;
663 }
664 }
665
666 // Plane view sampling reference
667 {
668 const tcu::ConstPixelBufferAccess planeAccess (mapVkFormat(params.planeCompatibleFormat),
669 tcu::IVec3((int)planeExtent.x(), (int)planeExtent.y(), 1),
670 imageData.getPlanePtr(params.planeNdx));
671 const tcu::Sampler refSampler = mapVkSampler(planeSamplerInfo);
672 const tcu::Texture2DView refTexView (1u, &planeAccess);
673
674 for (size_t ndx = 0; ndx < numValues; ++ndx)
675 {
676 const Vec2& coord = texCoord[ndx];
677 referencePlane[ndx] = refTexView.sample(refSampler, coord.x(), coord.y(), 0.0f);
678 }
679 }
680
681 for (int viewNdx = 0; viewNdx < 2; ++viewNdx)
682 {
683 const char* const viewName = (viewNdx == 0) ? "complete image" : "plane view";
684 const vector<Vec4>& reference = (viewNdx == 0) ? referenceWhole : referencePlane;
685 const vector<Vec4>& result = (viewNdx == 0) ? resultWhole : resultPlane;
686
687 for (size_t ndx = 0; ndx < numValues; ++ndx)
688 {
689 if (boolAny(greaterThanEqual(abs(result[ndx] - reference[ndx]), threshold)))
690 {
691 context.getTestContext().getLog()
692 << TestLog::Message << "ERROR: When sampling " << viewName << " at " << texCoord[ndx]
693 << ": got " << result[ndx]
694 << ", expected " << reference[ndx]
695 << TestLog::EndMessage;
696 allOk = false;
697 }
698 }
699 }
700
701 if (allOk)
702 return tcu::TestStatus::pass("All samples passed");
703 else
704 return tcu::TestStatus::fail("Got invalid results");
705 }
706 }
707
initPrograms(SourceCollections & dst,TestParameters params)708 void initPrograms (SourceCollections& dst, TestParameters params)
709 {
710 const ShaderSpec spec = getShaderSpec(params);
711
712 generateSources(params.shaderType, spec, dst);
713 }
714
addPlaneViewCase(tcu::TestCaseGroup * group,const TestParameters & params)715 void addPlaneViewCase (tcu::TestCaseGroup* group, const TestParameters& params)
716 {
717 std::ostringstream name;
718
719 name << de::toLower(de::toString(params.format).substr(10));
720
721 if ((params.viewType != TestParameters::VIEWTYPE_MEMORY_ALIAS) &&
722 ((params.createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0))
723 name << "_disjoint";
724
725 name << "_plane_" << params.planeNdx;
726
727 if (params.isCompatibilityFormat)
728 {
729 name << "_compatible_format_" << de::toLower(de::toString(params.planeCompatibleFormat).substr(10));
730 }
731
732 addFunctionCaseWithPrograms(group, name.str(), "", checkSupport, initPrograms, testPlaneView, params);
733 }
734
populateViewTypeGroup(tcu::TestCaseGroup * group,TestParameters::ViewType viewType)735 void populateViewTypeGroup (tcu::TestCaseGroup* group, TestParameters::ViewType viewType)
736 {
737 const glu::ShaderType shaderType = glu::SHADERTYPE_FRAGMENT;
738 const UVec2 size (32, 58);
739 const VkImageCreateFlags baseFlags = (VkImageCreateFlags)VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
740 | (viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS ? (VkImageCreateFlags)VK_IMAGE_CREATE_ALIAS_BIT : 0u);
741
742 auto addTests = [&](int formatNdx)
743 {
744 const VkFormat format = (VkFormat)formatNdx;
745 const deUint32 numPlanes = getPlaneCount(format);
746
747 if (numPlanes == 1)
748 return; // Plane views not possible
749
750 for (int isDisjoint = 0; isDisjoint < 2; ++isDisjoint)
751 {
752 const VkImageCreateFlags flags = baseFlags | (isDisjoint == 1 ? (VkImageCreateFlags)VK_IMAGE_CREATE_DISJOINT_BIT : 0u);
753
754 if ((viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS) &&
755 ((flags & VK_IMAGE_CREATE_DISJOINT_BIT) == 0))
756 continue; // Memory alias cases require disjoint planes
757
758 for (deUint32 planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
759 {
760 const VkFormat planeFormat = getPlaneCompatibleFormat(format, planeNdx);
761 // Add test case using image view with a format taken from the "Plane Format Compatibility Table"
762 addPlaneViewCase(group, TestParameters(viewType, format, size, flags, planeNdx, planeFormat, shaderType, DE_FALSE));
763
764 // Add test cases using image view with a format that is compatible with the plane's format.
765 // For example: VK_FORMAT_R4G4_UNORM_PACK8 is compatible with VK_FORMAT_R8_UNORM.
766 for (const auto& compatibleFormat : s_compatible_formats)
767 {
768 if (compatibleFormat == planeFormat)
769 continue;
770
771 if (!formatsAreCompatible(planeFormat, compatibleFormat))
772 continue;
773
774 addPlaneViewCase(group, TestParameters(viewType, format, size, flags, planeNdx, compatibleFormat, shaderType, DE_TRUE));
775 }
776 }
777 }
778 };
779
780 for (int formatNdx = VK_YCBCR_FORMAT_FIRST; formatNdx < VK_YCBCR_FORMAT_LAST; formatNdx++)
781 {
782 addTests(formatNdx);
783 }
784
785 for (int formatNdx = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT; formatNdx < VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT; formatNdx++)
786 {
787 addTests(formatNdx);
788 }
789 }
790
populateViewGroup(tcu::TestCaseGroup * group)791 void populateViewGroup (tcu::TestCaseGroup* group)
792 {
793 addTestGroup(group, "image_view", "Plane View via VkImageView", populateViewTypeGroup, TestParameters::VIEWTYPE_IMAGE_VIEW);
794 addTestGroup(group, "memory_alias", "Plane View via Memory Aliasing", populateViewTypeGroup, TestParameters::VIEWTYPE_MEMORY_ALIAS);
795 }
796
797 } // anonymous
798
createViewTests(tcu::TestContext & testCtx)799 tcu::TestCaseGroup* createViewTests (tcu::TestContext& testCtx)
800 {
801 return createTestGroup(testCtx, "plane_view", "YCbCr Plane View Tests", populateViewGroup);
802 }
803
804 } // ycbcr
805 } // vkt
806
807