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