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