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