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::__anonac7b84a30111::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::__anonac7b84a30111::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 if (isIntFormat(f)) {
428 IVec4* result_ptr = reinterpret_cast<IVec4*>(&result);
429 IVec4 ivec = *(result_ptr);
430 return Vec4((float)ivec.x(), (float)ivec.y(), (float)ivec.z(), (float)ivec.w());
431 }
432 else if (isUintFormat(f)) {
433 UVec4* result_ptr = reinterpret_cast<UVec4*>(&result);
434 UVec4 uvec = *(result_ptr);
435 return Vec4((float)uvec.x(), (float)uvec.y(), (float)uvec.z(), (float)uvec.w());
436 }
437 else {
438 return result;
439 }
440 }
441
testPlaneView(Context & context,TestParameters params)442 tcu::TestStatus testPlaneView (Context& context, TestParameters params)
443 {
444 de::Random randomGen (deInt32Hash((deUint32)params.format) ^
445 deInt32Hash((deUint32)params.planeNdx) ^
446 deInt32Hash((deUint32)params.shaderType));
447
448 const InstanceInterface& vk = context.getInstanceInterface();
449 const DeviceInterface& vkd = context.getDeviceInterface();
450 const VkDevice device = context.getDevice();
451
452 const VkFormat format = params.format;
453 const VkImageCreateFlags createFlags = params.createFlags;
454 const PlanarFormatDescription formatInfo = getPlanarFormatDescription(format);
455 const UVec2 size = params.size;
456 const UVec2 planeExtent = getPlaneExtent(formatInfo, size, params.planeNdx, 0);
457 const Unique<VkImage> image (createTestImage(vkd, device, format, size, createFlags));
458 const Unique<VkImage> imageAlias ((params.viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS)
459 ? createTestImage(vkd, device, params.planeCompatibleFormat, planeExtent, createFlags)
460 : Move<VkImage>());
461 const vector<AllocationSp> allocations (allocateAndBindImageMemory(vkd, device, context.getDefaultAllocator(), *image, format, createFlags));
462
463 if (imageAlias)
464 {
465 if ((createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0)
466 {
467 VkBindImagePlaneMemoryInfo planeInfo =
468 {
469 VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO,
470 DE_NULL,
471 VK_IMAGE_ASPECT_PLANE_0_BIT
472 };
473
474 VkBindImageMemoryInfo coreInfo =
475 {
476 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
477 &planeInfo,
478 *imageAlias,
479 allocations[params.planeNdx]->getMemory(),
480 allocations[params.planeNdx]->getOffset(),
481 };
482
483 VK_CHECK(vkd.bindImageMemory2(device, 1, &coreInfo));
484 }
485 else
486 {
487 VK_CHECK(vkd.bindImageMemory(device, *imageAlias, allocations[params.planeNdx]->getMemory(), allocations[params.planeNdx]->getOffset()));
488 }
489 }
490
491 const VkSamplerYcbcrConversionCreateInfo conversionInfo =
492 {
493 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
494 DE_NULL,
495 format,
496 VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
497 VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
498 {
499 VK_COMPONENT_SWIZZLE_IDENTITY,
500 VK_COMPONENT_SWIZZLE_IDENTITY,
501 VK_COMPONENT_SWIZZLE_IDENTITY,
502 VK_COMPONENT_SWIZZLE_IDENTITY,
503 },
504 VK_CHROMA_LOCATION_MIDPOINT,
505 VK_CHROMA_LOCATION_MIDPOINT,
506 VK_FILTER_NEAREST,
507 VK_FALSE, // forceExplicitReconstruction
508 };
509 const Unique<VkSamplerYcbcrConversion> conversion (createSamplerYcbcrConversion(vkd, device, &conversionInfo));
510 const VkSamplerYcbcrConversionInfo samplerConversionInfo =
511 {
512 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
513 DE_NULL,
514 *conversion,
515 };
516 const Unique<VkImageView> wholeView (createImageView(vkd, device, *image, format, VK_IMAGE_ASPECT_COLOR_BIT, &samplerConversionInfo));
517 const Unique<VkImageView> planeView (createImageView(vkd,
518 device,
519 !imageAlias ? *image : *imageAlias,
520 params.planeCompatibleFormat,
521 !imageAlias ? getPlaneAspect(params.planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT,
522 DE_NULL));
523
524 const VkSamplerCreateInfo wholeSamplerInfo =
525 {
526 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
527 &samplerConversionInfo,
528 0u,
529 VK_FILTER_NEAREST, // magFilter
530 VK_FILTER_NEAREST, // minFilter
531 VK_SAMPLER_MIPMAP_MODE_NEAREST, // mipmapMode
532 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
533 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV
534 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW
535 0.0f, // mipLodBias
536 VK_FALSE, // anisotropyEnable
537 1.0f, // maxAnisotropy
538 VK_FALSE, // compareEnable
539 VK_COMPARE_OP_ALWAYS, // compareOp
540 0.0f, // minLod
541 0.0f, // maxLod
542 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor
543 VK_FALSE, // unnormalizedCoords
544 };
545 const VkSamplerCreateInfo planeSamplerInfo =
546 {
547 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
548 DE_NULL,
549 0u,
550 VK_FILTER_NEAREST, // magFilter
551 VK_FILTER_NEAREST, // minFilter
552 VK_SAMPLER_MIPMAP_MODE_NEAREST, // mipmapMode
553 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
554 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV
555 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW
556 0.0f, // mipLodBias
557 VK_FALSE, // anisotropyEnable
558 1.0f, // maxAnisotropy
559 VK_FALSE, // compareEnable
560 VK_COMPARE_OP_ALWAYS, // compareOp
561 0.0f, // minLod
562 0.0f, // maxLod
563 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor
564 VK_FALSE, // unnormalizedCoords
565 };
566
567 deUint32 combinedSamplerDescriptorCount = 1;
568 {
569 const VkPhysicalDeviceImageFormatInfo2 imageFormatInfo =
570 {
571 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, // sType;
572 DE_NULL, // pNext;
573 format, // format;
574 VK_IMAGE_TYPE_2D, // type;
575 VK_IMAGE_TILING_OPTIMAL, // tiling;
576 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
577 VK_IMAGE_USAGE_SAMPLED_BIT, // usage;
578 createFlags // flags;
579 };
580
581 VkSamplerYcbcrConversionImageFormatProperties samplerYcbcrConversionImage = {};
582 samplerYcbcrConversionImage.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES;
583 samplerYcbcrConversionImage.pNext = DE_NULL;
584
585 VkImageFormatProperties2 imageFormatProperties = {};
586 imageFormatProperties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
587 imageFormatProperties.pNext = &samplerYcbcrConversionImage;
588
589 VkResult result = vk.getPhysicalDeviceImageFormatProperties2(context.getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties);
590 if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
591 TCU_THROW(NotSupportedError, "Format not supported.");
592 VK_CHECK(result);
593 combinedSamplerDescriptorCount = samplerYcbcrConversionImage.combinedImageSamplerDescriptorCount;
594 }
595
596 const Unique<VkSampler> wholeSampler(createSampler(vkd, device, &wholeSamplerInfo));
597 const Unique<VkSampler> planeSampler(createSampler(vkd, device, &planeSamplerInfo));
598
599 const Unique<VkDescriptorSetLayout> descLayout (createDescriptorSetLayout(vkd, device, *wholeSampler));
600 const Unique<VkDescriptorPool> descPool (createDescriptorPool(vkd, device, combinedSamplerDescriptorCount));
601 const Unique<VkDescriptorSet> descSet (createDescriptorSet(vkd, device, *descPool, *descLayout, *planeView, *planeSampler, *wholeView, *wholeSampler));
602
603 MultiPlaneImageData imageData (format, size);
604
605 // Prepare texture data
606 fillRandom(&randomGen, &imageData);
607
608 if (imageAlias)
609 {
610 // Transition alias to right layout first
611 const VkImageMemoryBarrier initAliasBarrier =
612 {
613 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
614 DE_NULL,
615 (VkAccessFlags)0,
616 VK_ACCESS_SHADER_READ_BIT,
617 VK_IMAGE_LAYOUT_UNDEFINED,
618 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
619 VK_QUEUE_FAMILY_IGNORED,
620 VK_QUEUE_FAMILY_IGNORED,
621 *imageAlias,
622 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
623 };
624
625 executeImageBarrier(vkd,
626 device,
627 context.getUniversalQueueFamilyIndex(),
628 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
629 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
630 initAliasBarrier);
631 }
632
633 // Upload and prepare image
634 uploadImage(vkd,
635 device,
636 context.getUniversalQueueFamilyIndex(),
637 context.getDefaultAllocator(),
638 *image,
639 imageData,
640 (VkAccessFlags)VK_ACCESS_SHADER_READ_BIT,
641 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
642
643 {
644 const size_t numValues = 500;
645 vector<Vec2> texCoord (numValues);
646 vector<Vec4> resultWhole (numValues);
647 vector<Vec4> resultPlane (numValues);
648 vector<Vec4> referenceWhole (numValues);
649 vector<Vec4> referencePlane (numValues);
650 bool allOk = true;
651 Vec4 threshold (0.02f);
652
653 generateLookupCoordinates(size, numValues, &randomGen, &texCoord);
654
655 {
656 UniquePtr<ShaderExecutor> executor (createExecutor(context, params.shaderType, getShaderSpec(params), *descLayout));
657 const void* inputs[] = { texCoord[0].getPtr() };
658 void* outputs[] = { resultWhole[0].getPtr(), resultPlane[0].getPtr() };
659
660 executor->execute((int)numValues, inputs, outputs, *descSet);
661 }
662
663 // Whole image sampling reference
664 for (deUint32 channelNdx = 0; channelNdx < 4; channelNdx++)
665 {
666 if (formatInfo.hasChannelNdx(channelNdx))
667 {
668 const tcu::ConstPixelBufferAccess channelAccess = imageData.getChannelAccess(channelNdx);
669 const tcu::Sampler refSampler = mapVkSampler(wholeSamplerInfo);
670 const tcu::Texture2DView refTexView (1u, &channelAccess);
671
672 for (size_t ndx = 0; ndx < numValues; ++ndx)
673 {
674 const Vec2& coord = texCoord[ndx];
675 referenceWhole[ndx][channelNdx] = refTexView.sample(refSampler, coord.x(), coord.y(), 0.0f)[0];
676 }
677 }
678 else
679 {
680 for (size_t ndx = 0; ndx < numValues; ++ndx)
681 referenceWhole[ndx][channelNdx] = channelNdx == 3 ? 1.0f : 0.0f;
682 }
683 }
684
685 // Plane view sampling reference
686 {
687 const tcu::ConstPixelBufferAccess planeAccess (mapVkFormat(params.planeCompatibleFormat),
688 tcu::IVec3((int)planeExtent.x(), (int)planeExtent.y(), 1),
689 imageData.getPlanePtr(params.planeNdx));
690 const tcu::Sampler refSampler = mapVkSampler(planeSamplerInfo);
691 const tcu::Texture2DView refTexView (1u, &planeAccess);
692
693 for (size_t ndx = 0; ndx < numValues; ++ndx)
694 {
695 const Vec2& coord = texCoord[ndx];
696 referencePlane[ndx] = refTexView.sample(refSampler, coord.x(), coord.y(), 0.0f);
697 }
698 }
699
700 for (int viewNdx = 0; viewNdx < 2; ++viewNdx)
701 {
702 const char* const viewName = (viewNdx == 0) ? "complete image" : "plane view";
703 const vector<Vec4>& reference = (viewNdx == 0) ? referenceWhole : referencePlane;
704 const vector<Vec4>& result = (viewNdx == 0) ? resultWhole : resultPlane;
705
706 for (size_t ndx = 0; ndx < numValues; ++ndx)
707 {
708 const Vec4 resultValue = (viewNdx == 0) ? result[ndx] : castResult(result[ndx], params.planeCompatibleFormat);
709 if (boolAny(greaterThanEqual(abs(resultValue - reference[ndx]), threshold)))
710 {
711 context.getTestContext().getLog()
712 << TestLog::Message << "ERROR: When sampling " << viewName << " at " << texCoord[ndx]
713 << ": got " << result[ndx]
714 << ", expected " << reference[ndx]
715 << TestLog::EndMessage;
716 allOk = false;
717 }
718 }
719 }
720
721 if (allOk)
722 return tcu::TestStatus::pass("All samples passed");
723 else
724 return tcu::TestStatus::fail("Got invalid results");
725 }
726 }
727
initPrograms(SourceCollections & dst,TestParameters params)728 void initPrograms (SourceCollections& dst, TestParameters params)
729 {
730 const ShaderSpec spec = getShaderSpec(params);
731
732 generateSources(params.shaderType, spec, dst);
733 }
734
addPlaneViewCase(tcu::TestCaseGroup * group,const TestParameters & params)735 void addPlaneViewCase (tcu::TestCaseGroup* group, const TestParameters& params)
736 {
737 std::ostringstream name;
738
739 name << de::toLower(de::toString(params.format).substr(10));
740
741 if ((params.viewType != TestParameters::VIEWTYPE_MEMORY_ALIAS) &&
742 ((params.createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0))
743 name << "_disjoint";
744
745 name << "_plane_" << params.planeNdx;
746
747 if (params.isCompatibilityFormat)
748 {
749 name << "_compatible_format_" << de::toLower(de::toString(params.planeCompatibleFormat).substr(10));
750 }
751
752 addFunctionCaseWithPrograms(group, name.str(), "", checkSupport, initPrograms, testPlaneView, params);
753 }
754
populateViewTypeGroup(tcu::TestCaseGroup * group,TestParameters::ViewType viewType)755 void populateViewTypeGroup (tcu::TestCaseGroup* group, TestParameters::ViewType viewType)
756 {
757 const glu::ShaderType shaderType = glu::SHADERTYPE_FRAGMENT;
758 const UVec2 size (32, 58);
759 const VkImageCreateFlags baseFlags = (VkImageCreateFlags)VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
760 | (viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS ? (VkImageCreateFlags)VK_IMAGE_CREATE_ALIAS_BIT : 0u);
761
762 auto addTests = [&](int formatNdx)
763 {
764 const VkFormat format = (VkFormat)formatNdx;
765 const deUint32 numPlanes = getPlaneCount(format);
766
767 if (numPlanes == 1)
768 return; // Plane views not possible
769
770 for (int isDisjoint = 0; isDisjoint < 2; ++isDisjoint)
771 {
772 const VkImageCreateFlags flags = baseFlags | (isDisjoint == 1 ? (VkImageCreateFlags)VK_IMAGE_CREATE_DISJOINT_BIT : 0u);
773
774 if ((viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS) &&
775 ((flags & VK_IMAGE_CREATE_DISJOINT_BIT) == 0))
776 continue; // Memory alias cases require disjoint planes
777
778 for (deUint32 planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
779 {
780 const VkFormat planeFormat = getPlaneCompatibleFormat(format, planeNdx);
781 // Add test case using image view with a format taken from the "Plane Format Compatibility Table"
782 addPlaneViewCase(group, TestParameters(viewType, format, size, flags, planeNdx, planeFormat, shaderType, DE_FALSE));
783
784 // Add test cases using image view with a format that is compatible with the plane's format.
785 // For example: VK_FORMAT_R4G4_UNORM_PACK8 is compatible with VK_FORMAT_R8_UNORM.
786 for (const auto& compatibleFormat : s_compatible_formats)
787 {
788 if (compatibleFormat == planeFormat)
789 continue;
790
791 if (!formatsAreCompatible(planeFormat, compatibleFormat))
792 continue;
793
794 addPlaneViewCase(group, TestParameters(viewType, format, size, flags, planeNdx, compatibleFormat, shaderType, DE_TRUE));
795 }
796 }
797 }
798 };
799
800 for (int formatNdx = VK_YCBCR_FORMAT_FIRST; formatNdx < VK_YCBCR_FORMAT_LAST; formatNdx++)
801 {
802 addTests(formatNdx);
803 }
804
805 for (int formatNdx = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT; formatNdx < VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT; formatNdx++)
806 {
807 addTests(formatNdx);
808 }
809 }
810
populateViewGroup(tcu::TestCaseGroup * group)811 void populateViewGroup (tcu::TestCaseGroup* group)
812 {
813 addTestGroup(group, "image_view", "Plane View via VkImageView", populateViewTypeGroup, TestParameters::VIEWTYPE_IMAGE_VIEW);
814 addTestGroup(group, "memory_alias", "Plane View via Memory Aliasing", populateViewTypeGroup, TestParameters::VIEWTYPE_MEMORY_ALIAS);
815 }
816
817 } // anonymous
818
createViewTests(tcu::TestContext & testCtx)819 tcu::TestCaseGroup* createViewTests (tcu::TestContext& testCtx)
820 {
821 return createTestGroup(testCtx, "plane_view", "YCbCr Plane View Tests", populateViewGroup);
822 }
823
824 } // ycbcr
825
826 } // vkt
827
828