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