1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 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 OpImageQuery & YCbCr Tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktYCbCrImageQueryTests.hpp"
25 #include "vktTestCaseUtil.hpp"
26 #include "vktTestGroupUtil.hpp"
27 #include "vktShaderExecutor.hpp"
28 #include "vktYCbCrUtil.hpp"
29 #include "vktDrawUtil.hpp"
30
31 #include "vkStrUtil.hpp"
32 #include "vkRef.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkMemUtil.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkCmdUtil.hpp"
39 #include "vkBarrierUtil.hpp"
40
41 #include "tcuTestLog.hpp"
42 #include "tcuVectorUtil.hpp"
43 #include "tcuTexLookupVerifier.hpp"
44
45 #include "deStringUtil.hpp"
46 #include "deSharedPtr.hpp"
47 #include "deUniquePtr.hpp"
48 #include "deRandom.hpp"
49 #include "deSTLUtil.hpp"
50
51 namespace vkt
52 {
53 namespace ycbcr
54 {
55 namespace
56 {
57
58 using namespace vk;
59 using namespace shaderexecutor;
60
61 using tcu::UVec2;
62 using tcu::Vec2;
63 using tcu::Vec4;
64 using tcu::TestLog;
65 using de::MovePtr;
66 using de::UniquePtr;
67 using std::vector;
68 using std::string;
69
70 enum QueryType
71 {
72 QUERY_TYPE_IMAGE_SIZE_LOD, // OpImageQuerySizeLod
73 QUERY_TYPE_IMAGE_LOD, // OpImageQueryLod
74 QUERY_TYPE_IMAGE_LEVELS, // OpImageQueryLevels
75
76 QUERY_TYPE_LAST
77 };
78
79 struct TestParameters
80 {
81 QueryType query;
82 VkFormat format;
83 VkImageCreateFlags flags;
84 glu::ShaderType shaderType;
85
TestParametersvkt::ycbcr::__anonfe4268f30111::TestParameters86 TestParameters (QueryType query_, VkFormat format_, VkImageCreateFlags flags_, glu::ShaderType shaderType_)
87 : query (query_)
88 , format (format_)
89 , flags (flags_)
90 , shaderType(shaderType_)
91 {
92 }
93
TestParametersvkt::ycbcr::__anonfe4268f30111::TestParameters94 TestParameters (void)
95 : query (QUERY_TYPE_LAST)
96 , format (VK_FORMAT_UNDEFINED)
97 , flags (0u)
98 , shaderType(glu::SHADERTYPE_LAST)
99 {
100 }
101 };
102
getShaderSpec(const TestParameters & params,const SourceCollections * programCollection=nullptr)103 ShaderSpec getShaderSpec (const TestParameters& params, const SourceCollections* programCollection = nullptr)
104 {
105 ShaderSpec spec;
106 const char* expr = DE_NULL;
107 glu::DataType resultType = glu::TYPE_LAST;
108
109 switch (params.query)
110 {
111 case QUERY_TYPE_IMAGE_SIZE_LOD:
112 expr = "textureSize(u_image, lod)";
113 resultType = glu::TYPE_INT_VEC2;
114 break;
115
116 case QUERY_TYPE_IMAGE_LEVELS:
117 expr = "textureQueryLevels(u_image)";
118 resultType = glu::TYPE_INT;
119 break;
120
121 default:
122 DE_FATAL("Unknown query");
123 }
124
125 spec.glslVersion = glu::GLSL_VERSION_450;
126
127 spec.inputs.push_back(Symbol("lod", glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP)));
128 spec.outputs.push_back(Symbol("result", glu::VarType(resultType, glu::PRECISION_HIGHP)));
129
130 spec.globalDeclarations =
131 "layout(binding = 0, set = 1) uniform highp sampler2D u_image;\n";
132
133 spec.source =
134 string("result = ") + expr + ";\n";
135
136 const bool isMeshShadingStage = (params.shaderType == glu::SHADERTYPE_MESH || params.shaderType == glu::SHADERTYPE_TASK);
137
138 if (isMeshShadingStage && programCollection)
139 {
140 const ShaderBuildOptions buildOptions (programCollection->usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
141 spec.buildOptions = buildOptions;
142 }
143
144 return spec;
145 }
146
createTestImage(const DeviceInterface & vkd,VkDevice device,VkFormat format,const UVec2 & size,VkImageCreateFlags createFlags)147 Move<VkImage> createTestImage (const DeviceInterface& vkd,
148 VkDevice device,
149 VkFormat format,
150 const UVec2& size,
151 VkImageCreateFlags createFlags)
152 {
153 const VkImageCreateInfo createInfo =
154 {
155 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
156 DE_NULL,
157 createFlags,
158 VK_IMAGE_TYPE_2D,
159 format,
160 makeExtent3D(size.x(), size.y(), 1u),
161 1u, // mipLevels
162 1u, // arrayLayers
163 VK_SAMPLE_COUNT_1_BIT,
164 VK_IMAGE_TILING_OPTIMAL,
165 VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT,
166 VK_SHARING_MODE_EXCLUSIVE,
167 0u,
168 (const deUint32*)DE_NULL,
169 VK_IMAGE_LAYOUT_UNDEFINED,
170 };
171
172 return createImage(vkd, device, &createInfo);
173 }
174
createImageView(const DeviceInterface & vkd,VkDevice device,VkImage image,VkFormat format,VkSamplerYcbcrConversion conversion)175 Move<VkImageView> createImageView (const DeviceInterface& vkd,
176 VkDevice device,
177 VkImage image,
178 VkFormat format,
179 VkSamplerYcbcrConversion conversion)
180 {
181 const VkSamplerYcbcrConversionInfo samplerConversionInfo =
182 {
183 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
184 DE_NULL,
185 conversion
186 };
187
188 const VkImageViewCreateInfo viewInfo =
189 {
190 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
191 (conversion != DE_NULL) ? &samplerConversionInfo : DE_NULL,
192 (VkImageViewCreateFlags)0,
193 image,
194 VK_IMAGE_VIEW_TYPE_2D,
195 format,
196 {
197 VK_COMPONENT_SWIZZLE_IDENTITY,
198 VK_COMPONENT_SWIZZLE_IDENTITY,
199 VK_COMPONENT_SWIZZLE_IDENTITY,
200 VK_COMPONENT_SWIZZLE_IDENTITY,
201 },
202 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },
203 };
204
205 return createImageView(vkd, device, &viewInfo);
206 }
207
208 class TestImage
209 {
210 public:
211 TestImage (const Context& context,
212 const DeviceInterface& vkd,
213 VkDevice device,
214 Allocator& allocator,
215 VkFormat format,
216 const UVec2& size,
217 const VkImageCreateFlags createFlags,
218 VkSamplerYcbcrConversion conversion);
219
getSize(void) const220 const UVec2& getSize (void) const { return m_size; }
getImageView(void) const221 VkImageView getImageView (void) const { return *m_imageView; }
222
223 private:
224 const UVec2 m_size;
225 const Unique<VkImage> m_image;
226 const vector<AllocationSp> m_allocations;
227 const Unique<VkImageView> m_imageView;
228 };
229
TestImage(const Context & context,const DeviceInterface & vkd,VkDevice device,Allocator & allocator,VkFormat format,const UVec2 & size,const VkImageCreateFlags createFlags,VkSamplerYcbcrConversion conversion)230 TestImage::TestImage (const Context& context,
231 const DeviceInterface& vkd,
232 VkDevice device,
233 Allocator& allocator,
234 VkFormat format,
235 const UVec2& size,
236 const VkImageCreateFlags createFlags,
237 VkSamplerYcbcrConversion conversion)
238 : m_size (size)
239 , m_image (createTestImage(vkd, device, format, size, createFlags))
240 , m_allocations (allocateAndBindImageMemory(vkd, device, allocator, *m_image, format, createFlags))
241 , m_imageView (createImageView(vkd, device, *m_image, format, conversion))
242 {
243 // Transition image layout
244 {
245 Move<VkCommandPool> cmdPool;
246 Move<VkCommandBuffer> cmdBuffer;
247 const VkQueue queue = context.getUniversalQueue();
248 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
249
250 cmdPool = createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
251 cmdBuffer = allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
252
253 beginCommandBuffer(vkd, *cmdBuffer);
254
255 VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u };
256 const VkImageMemoryBarrier imageBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
257 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, *m_image, subresourceRange);
258
259 vkd.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
260 0u, DE_NULL, 0u, DE_NULL, 1u, &imageBarrier);
261
262 endCommandBuffer(vkd, *cmdBuffer);
263 submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
264 }
265 }
266
267 typedef de::SharedPtr<TestImage> TestImageSp;
268
createDescriptorSetLayout(const DeviceInterface & vkd,VkDevice device,VkSampler sampler)269 Move<VkDescriptorSetLayout> createDescriptorSetLayout (const DeviceInterface& vkd, VkDevice device, VkSampler sampler)
270 {
271 const VkDescriptorSetLayoutBinding binding =
272 {
273 0u, // binding
274 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
275 1u, // descriptorCount
276 VK_SHADER_STAGE_ALL,
277 &sampler
278 };
279 const VkDescriptorSetLayoutCreateInfo layoutInfo =
280 {
281 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
282 DE_NULL,
283 (VkDescriptorSetLayoutCreateFlags)0u,
284 1u,
285 &binding,
286 };
287
288 return createDescriptorSetLayout(vkd, device, &layoutInfo);
289 }
290
createDescriptorPool(const DeviceInterface & vkd,VkDevice device,const deUint32 combinedSamplerDescriptorCount)291 Move<VkDescriptorPool> createDescriptorPool (const DeviceInterface& vkd, VkDevice device, const deUint32 combinedSamplerDescriptorCount)
292 {
293 const VkDescriptorPoolSize poolSizes[] =
294 {
295 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, combinedSamplerDescriptorCount },
296 };
297 const VkDescriptorPoolCreateInfo poolInfo =
298 {
299 VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
300 DE_NULL,
301 (VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
302 1u, // maxSets
303 DE_LENGTH_OF_ARRAY(poolSizes),
304 poolSizes,
305 };
306
307 return createDescriptorPool(vkd, device, & poolInfo);
308 }
309
createDescriptorSet(const DeviceInterface & vkd,VkDevice device,VkDescriptorPool descPool,VkDescriptorSetLayout descLayout)310 Move<VkDescriptorSet> createDescriptorSet (const DeviceInterface& vkd,
311 VkDevice device,
312 VkDescriptorPool descPool,
313 VkDescriptorSetLayout descLayout)
314 {
315 const VkDescriptorSetAllocateInfo allocInfo =
316 {
317 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
318 DE_NULL,
319 descPool,
320 1u,
321 &descLayout,
322 };
323
324 return allocateDescriptorSet(vkd, device, &allocInfo);
325 }
326
bindImage(const DeviceInterface & vkd,VkDevice device,VkDescriptorSet descriptorSet,VkImageView imageView,VkSampler sampler)327 void bindImage (const DeviceInterface& vkd,
328 VkDevice device,
329 VkDescriptorSet descriptorSet,
330 VkImageView imageView,
331 VkSampler sampler)
332 {
333 const VkDescriptorImageInfo imageInfo =
334 {
335 sampler,
336 imageView,
337 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
338 };
339 const VkWriteDescriptorSet descriptorWrite =
340 {
341 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
342 DE_NULL,
343 descriptorSet,
344 0u, // dstBinding
345 0u, // dstArrayElement
346 1u, // descriptorCount
347 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
348 &imageInfo,
349 (const VkDescriptorBufferInfo*)DE_NULL,
350 (const VkBufferView*)DE_NULL,
351 };
352
353 vkd.updateDescriptorSets(device, 1u, &descriptorWrite, 0u, DE_NULL);
354 }
355
getMaxPlaneDivisor(const PlanarFormatDescription & formatDesc)356 UVec2 getMaxPlaneDivisor (const PlanarFormatDescription& formatDesc)
357 {
358 UVec2 maxDivisor (formatDesc.blockWidth, formatDesc.blockHeight);
359
360 for (deUint32 ndx = 0; ndx < formatDesc.numPlanes; ++ndx)
361 {
362 maxDivisor.x() = de::max<deUint32>(maxDivisor.x(), formatDesc.planes[ndx].widthDivisor);
363 maxDivisor.y() = de::max<deUint32>(maxDivisor.y(), formatDesc.planes[ndx].heightDivisor);
364 }
365
366 return maxDivisor;
367 }
368
testImageQuery(Context & context,TestParameters params)369 tcu::TestStatus testImageQuery (Context& context, TestParameters params)
370 {
371 const bool isYCbCrImage = isYCbCrFormat(params.format);
372 const InstanceInterface& vk = context.getInstanceInterface();
373 const DeviceInterface& vkd = context.getDeviceInterface();
374 const VkDevice device = context.getDevice();
375
376 const VkSamplerYcbcrConversionCreateInfo conversionInfo =
377 {
378 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
379 DE_NULL,
380 params.format,
381 VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
382 VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
383 {
384 VK_COMPONENT_SWIZZLE_IDENTITY,
385 VK_COMPONENT_SWIZZLE_IDENTITY,
386 VK_COMPONENT_SWIZZLE_IDENTITY,
387 VK_COMPONENT_SWIZZLE_IDENTITY,
388 },
389 VK_CHROMA_LOCATION_MIDPOINT,
390 VK_CHROMA_LOCATION_MIDPOINT,
391 VK_FILTER_NEAREST,
392 VK_FALSE, // forceExplicitReconstruction
393 };
394 const Unique<VkSamplerYcbcrConversion> conversion (isYCbCrImage
395 ? createSamplerYcbcrConversion(vkd, device, &conversionInfo)
396 : Move<VkSamplerYcbcrConversion>());
397
398 const VkSamplerYcbcrConversionInfo samplerConversionInfo =
399 {
400 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
401 DE_NULL,
402 *conversion,
403 };
404
405 const VkSamplerCreateInfo samplerInfo =
406 {
407 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
408 isYCbCrImage ? &samplerConversionInfo : DE_NULL,
409 0u,
410 VK_FILTER_NEAREST, // magFilter
411 VK_FILTER_NEAREST, // minFilter
412 VK_SAMPLER_MIPMAP_MODE_NEAREST, // mipmapMode
413 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
414 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV
415 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW
416 0.0f, // mipLodBias
417 VK_FALSE, // anisotropyEnable
418 1.0f, // maxAnisotropy
419 VK_FALSE, // compareEnable
420 VK_COMPARE_OP_ALWAYS, // compareOp
421 0.0f, // minLod
422 0.0f, // maxLod
423 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor
424 VK_FALSE, // unnormalizedCoords
425 };
426
427 deUint32 combinedSamplerDescriptorCount = 1;
428
429 if (isYCbCrImage)
430 {
431 const VkPhysicalDeviceImageFormatInfo2 imageFormatInfo =
432 {
433 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, // sType
434 DE_NULL, // pNext
435 params.format, // format
436 VK_IMAGE_TYPE_2D, // type
437 VK_IMAGE_TILING_OPTIMAL, // tiling
438 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
439 VK_IMAGE_USAGE_SAMPLED_BIT, // usage
440 params.flags // flags
441 };
442
443 VkSamplerYcbcrConversionImageFormatProperties samplerYcbcrConversionImage = {};
444 samplerYcbcrConversionImage.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES;
445 samplerYcbcrConversionImage.pNext = DE_NULL;
446
447 VkImageFormatProperties2 imageFormatProperties = {};
448 imageFormatProperties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
449 imageFormatProperties.pNext = &samplerYcbcrConversionImage;
450
451 VK_CHECK(vk.getPhysicalDeviceImageFormatProperties2(context.getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties));
452 combinedSamplerDescriptorCount = samplerYcbcrConversionImage.combinedImageSamplerDescriptorCount;
453 }
454
455 const Unique<VkSampler> sampler (createSampler(vkd, device, &samplerInfo));
456 const Unique<VkDescriptorSetLayout> descLayout (createDescriptorSetLayout(vkd, device, *sampler));
457 const Unique<VkDescriptorPool> descPool (createDescriptorPool(vkd, device, combinedSamplerDescriptorCount));
458 const Unique<VkDescriptorSet> descSet (createDescriptorSet(vkd, device, *descPool, *descLayout));
459
460 vector<TestImageSp> testImages;
461
462 if (params.query == QUERY_TYPE_IMAGE_SIZE_LOD)
463 {
464 const PlanarFormatDescription& formatDesc = getPlanarFormatDescription(params.format);
465 const UVec2 maxDivisor = getMaxPlaneDivisor(formatDesc);
466 vector<UVec2> testSizes;
467
468 testSizes.push_back(maxDivisor);
469 testSizes.push_back(maxDivisor * UVec2(2u, 1u));
470 testSizes.push_back(maxDivisor * UVec2(1u, 2u));
471 testSizes.push_back(maxDivisor * UVec2(63u, 79u));
472 testSizes.push_back(maxDivisor * UVec2(99u, 1u));
473 testSizes.push_back(maxDivisor * UVec2(421u, 1117u));
474
475 testImages.resize(testSizes.size());
476
477 for (size_t ndx = 0; ndx < testSizes.size(); ++ndx)
478 testImages[ndx] = TestImageSp(new TestImage(context, vkd, device, context.getDefaultAllocator(), params.format, testSizes[ndx], params.flags, *conversion));
479 }
480 else
481 testImages.push_back(TestImageSp(new TestImage(context, vkd, device, context.getDefaultAllocator(), params.format, UVec2(16, 18), params.flags, *conversion)));
482
483 {
484 UniquePtr<ShaderExecutor> executor (createExecutor(context, params.shaderType, getShaderSpec(params), *descLayout));
485 bool allOk = true;
486
487 for (size_t imageNdx = 0; imageNdx < testImages.size(); ++imageNdx)
488 {
489 const deUint32 lod = 0u;
490 UVec2 result (~0u, ~0u);
491 const void* inputs[] = { &lod };
492 void* outputs[] = { result.getPtr() };
493
494 bindImage(vkd, device, *descSet, testImages[imageNdx]->getImageView(), *sampler);
495
496 executor->execute(1, inputs, outputs, *descSet);
497
498 switch (params.query)
499 {
500 case QUERY_TYPE_IMAGE_SIZE_LOD:
501 {
502 const UVec2 reference = testImages[imageNdx]->getSize();
503
504 if (result != reference)
505 {
506 context.getTestContext().getLog()
507 << TestLog::Message << "ERROR: Image " << imageNdx
508 << ": got " << result
509 << ", expected " << reference
510 << TestLog::EndMessage;
511 allOk = false;
512 }
513 break;
514 }
515
516 case QUERY_TYPE_IMAGE_LEVELS:
517 {
518 if (result.x() != 1u)
519 {
520 context.getTestContext().getLog()
521 << TestLog::Message << "ERROR: Image " << imageNdx
522 << ": got " << result.x()
523 << ", expected " << 1
524 << TestLog::EndMessage;
525 allOk = false;
526 }
527 break;
528 }
529
530 default:
531 DE_FATAL("Invalid query type");
532 }
533 }
534
535 if (allOk)
536 return tcu::TestStatus::pass("Queries passed");
537 else
538 return tcu::TestStatus::fail("Got invalid results");
539 }
540 }
541
checkSupport(Context & context,TestParameters params)542 void checkSupport (Context& context, TestParameters params)
543 {
544 const bool isYCbCrImage = isYCbCrFormat(params.format);
545
546 if (isYCbCrImage)
547 checkImageSupport(context, params.format, params.flags);
548
549 checkSupportShader(context, params.shaderType);
550 }
551
testImageQueryLod(Context & context,TestParameters params)552 tcu::TestStatus testImageQueryLod (Context& context, TestParameters params)
553 {
554 const bool isYCbCrImage = isYCbCrFormat(params.format);
555 const InstanceInterface& vk = context.getInstanceInterface();
556 const DeviceInterface& vkd = context.getDeviceInterface();
557 const VkDevice device = context.getDevice();
558
559 const VkSamplerYcbcrConversionCreateInfo conversionInfo =
560 {
561 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
562 DE_NULL,
563 params.format,
564 VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
565 VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
566 {
567 VK_COMPONENT_SWIZZLE_IDENTITY,
568 VK_COMPONENT_SWIZZLE_IDENTITY,
569 VK_COMPONENT_SWIZZLE_IDENTITY,
570 VK_COMPONENT_SWIZZLE_IDENTITY,
571 },
572 VK_CHROMA_LOCATION_MIDPOINT,
573 VK_CHROMA_LOCATION_MIDPOINT,
574 VK_FILTER_NEAREST,
575 VK_FALSE, // forceExplicitReconstruction
576 };
577 const Unique<VkSamplerYcbcrConversion> conversion (isYCbCrImage
578 ? createSamplerYcbcrConversion(vkd, device, &conversionInfo)
579 : Move<VkSamplerYcbcrConversion>());
580
581 const VkSamplerYcbcrConversionInfo samplerConversionInfo =
582 {
583 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
584 DE_NULL,
585 *conversion,
586 };
587
588 const VkSamplerCreateInfo samplerInfo =
589 {
590 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
591 isYCbCrImage ? &samplerConversionInfo : DE_NULL,
592 0u,
593 VK_FILTER_NEAREST, // magFilter
594 VK_FILTER_NEAREST, // minFilter
595 VK_SAMPLER_MIPMAP_MODE_NEAREST, // mipmapMode
596 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
597 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV
598 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW
599 0.0f, // mipLodBias
600 VK_FALSE, // anisotropyEnable
601 1.0f, // maxAnisotropy
602 VK_FALSE, // compareEnable
603 VK_COMPARE_OP_ALWAYS, // compareOp
604 0.0f, // minLod
605 0.0f, // maxLod
606 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor
607 VK_FALSE, // unnormalizedCoords
608 };
609
610 deUint32 combinedSamplerDescriptorCount = 1;
611
612 if (isYCbCrImage)
613 {
614 const VkPhysicalDeviceImageFormatInfo2 imageFormatInfo =
615 {
616 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, // sType;
617 DE_NULL, // pNext;
618 params.format, // format;
619 VK_IMAGE_TYPE_2D, // type;
620 VK_IMAGE_TILING_OPTIMAL, // tiling;
621 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
622 VK_IMAGE_USAGE_SAMPLED_BIT, // usage;
623 params.flags // flags;
624 };
625
626 VkSamplerYcbcrConversionImageFormatProperties samplerYcbcrConversionImage = {};
627 samplerYcbcrConversionImage.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES;
628 samplerYcbcrConversionImage.pNext = DE_NULL;
629
630 VkImageFormatProperties2 imageFormatProperties = {};
631 imageFormatProperties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
632 imageFormatProperties.pNext = &samplerYcbcrConversionImage;
633
634 VK_CHECK(vk.getPhysicalDeviceImageFormatProperties2(context.getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties));
635 combinedSamplerDescriptorCount = samplerYcbcrConversionImage.combinedImageSamplerDescriptorCount;
636 }
637
638 const Unique<VkSampler> sampler (createSampler(vkd, device, &samplerInfo));
639 const Unique<VkDescriptorSetLayout> descLayout (createDescriptorSetLayout(vkd, device, *sampler));
640 const Unique<VkDescriptorPool> descPool (createDescriptorPool(vkd, device, combinedSamplerDescriptorCount));
641 const Unique<VkDescriptorSet> descSet (createDescriptorSet(vkd, device, *descPool, *descLayout));
642
643 vector<TestImageSp> testImages;
644
645 DE_ASSERT(params.query == QUERY_TYPE_IMAGE_LOD);
646 DE_ASSERT(params.shaderType == glu::SHADERTYPE_FRAGMENT);
647
648 {
649 const PlanarFormatDescription& formatDesc = getPlanarFormatDescription(params.format);
650 const UVec2 maxDivisor = getMaxPlaneDivisor(formatDesc);
651 vector<UVec2> testSizes;
652
653 testSizes.push_back(maxDivisor);
654 testSizes.push_back(maxDivisor * UVec2(2u, 1u));
655 testSizes.push_back(maxDivisor * UVec2(1u, 2u));
656 testSizes.push_back(maxDivisor * UVec2(4u, 123u));
657 testSizes.push_back(maxDivisor * UVec2(312u, 13u));
658 testSizes.push_back(maxDivisor * UVec2(841u, 917u));
659
660 testImages.resize(testSizes.size());
661
662 for (size_t ndx = 0; ndx < testSizes.size(); ++ndx)
663 testImages[ndx] = TestImageSp(new TestImage(context, vkd, device, context.getDefaultAllocator(), params.format, testSizes[ndx], params.flags, *conversion));
664 }
665
666 {
667 using namespace drawutil;
668
669 struct LocalUtil
670 {
671 static vector<Vec4> getVertices (void)
672 {
673 vector<Vec4> vertices;
674
675 vertices.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
676 vertices.push_back(Vec4(+1.0f, -1.0f, 0.0f, 1.0f));
677 vertices.push_back(Vec4(-1.0f, +1.0f, 0.0f, 1.0f));
678
679 vertices.push_back(Vec4(+1.0f, -1.0f, 0.0f, 1.0f));
680 vertices.push_back(Vec4(-1.0f, +1.0f, 0.0f, 1.0f));
681 vertices.push_back(Vec4(+1.0f, +1.0f, 0.0f, 1.0f));
682
683 return vertices;
684 }
685
686 static VulkanProgram getProgram (Context& ctx, VkDescriptorSetLayout descriptorLayout, VkDescriptorSet descriptorSet)
687 {
688 VulkanProgram prog(std::vector<VulkanShader>{
689 VulkanShader(VK_SHADER_STAGE_VERTEX_BIT, ctx.getBinaryCollection().get("vert")),
690 VulkanShader(VK_SHADER_STAGE_FRAGMENT_BIT, ctx.getBinaryCollection().get("frag"))
691 });
692 prog.descriptorSet = descriptorSet;
693 prog.descriptorSetLayout = descriptorLayout;
694
695 return prog;
696 }
697 };
698
699 const UVec2 renderSize(128, 256);
700 FrameBufferState frameBufferState(renderSize.x(), renderSize.y());
701 frameBufferState.colorFormat = VK_FORMAT_R32G32_SFLOAT;
702 const vector<Vec4> vertices (LocalUtil::getVertices());
703 PipelineState pipelineState(context.getDeviceProperties().limits.subPixelPrecisionBits);
704 const DrawCallData drawCallData(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, vertices);
705 const VulkanProgram program (LocalUtil::getProgram(context, *descLayout, *descSet));
706
707 bool allOk = true;
708
709 context.getTestContext().getLog()
710 << TestLog::Message << "Rendering " << renderSize << " quad" << TestLog::EndMessage;
711
712 for (size_t imageNdx = 0; imageNdx < testImages.size(); ++imageNdx)
713 {
714 context.getTestContext().getLog()
715 << TestLog::Message << "Testing image size " << testImages[imageNdx]->getSize() << TestLog::EndMessage;
716
717 bindImage(vkd, device, *descSet, testImages[imageNdx]->getImageView(), *sampler);
718
719 VulkanDrawContext renderer(context, frameBufferState);
720 renderer.registerDrawObject(pipelineState, program, drawCallData);
721 renderer.draw();
722
723 {
724 // Only du/dx and dv/dy are non-zero
725 const Vec2 dtdp = testImages[imageNdx]->getSize().cast<float>() / renderSize.cast<float>();
726 const tcu::LodPrecision lodPrec (16, 4); // Pretty lax since we are not verifying LOD precision
727 const Vec2 lodBounds (tcu::computeLodBoundsFromDerivates(dtdp.x(), 0.0f, 0.0f, dtdp.y(), lodPrec));
728 tcu::ConstPixelBufferAccess resultImg (renderer.getColorPixels());
729 const int maxErrors = 5;
730 int numErrors = 0;
731
732 for (int y = 0; y < resultImg.getHeight(); ++y)
733 for (int x = 0; x < resultImg.getWidth(); ++x)
734 {
735 const Vec2 result = resultImg.getPixel(x, y).swizzle(0,1);
736 const bool levelOk = result.x() == 0.0f;
737 const bool lodOk = de::inRange(result.y(), lodBounds.x(), lodBounds.y());
738
739 if (!levelOk || !lodOk)
740 {
741 if (numErrors < maxErrors)
742 {
743 context.getTestContext().getLog()
744 << TestLog::Message << "ERROR: At (" << x << ", " << y << ")"
745 << ": got " << result
746 << ", expected (0, [" << lodBounds.x() << ", " << lodBounds.y() << "])"
747 << TestLog::EndMessage;
748 }
749 else if (numErrors == maxErrors)
750 context.getTestContext().getLog() << TestLog::Message << "..." << TestLog::EndMessage;
751
752 numErrors += 1;
753 }
754 }
755
756 allOk = allOk && (numErrors == 0);
757 }
758 }
759
760 if (allOk)
761 return tcu::TestStatus::pass("Queries passed");
762 else
763 return tcu::TestStatus::fail("Got invalid results");
764 }
765 }
766
initImageQueryPrograms(SourceCollections & dst,TestParameters params)767 void initImageQueryPrograms (SourceCollections& dst, TestParameters params)
768 {
769 const ShaderSpec spec = getShaderSpec(params, &dst);
770
771 generateSources(params.shaderType, spec, dst);
772 }
773
initImageQueryLodPrograms(SourceCollections & dst,TestParameters)774 void initImageQueryLodPrograms (SourceCollections& dst, TestParameters)
775 {
776 dst.glslSources.add("vert")
777 << glu::VertexSource("#version 450\n"
778 "layout(location = 0) in highp vec4 a_position;\n"
779 "layout(location = 0) out highp vec2 v_texCoord;\n"
780 "\n"
781 "void main (void)\n"
782 "{\n"
783 " gl_Position = a_position;\n"
784 " v_texCoord = a_position.xy * 0.5 - 0.5;\n"
785 "}\n");
786 dst.glslSources.add("frag")
787 << glu::FragmentSource("#version 450\n"
788 "layout(binding = 0, set = 0) uniform highp sampler2D u_image;\n"
789 "layout(location = 0) in highp vec2 v_texCoord;\n"
790 "layout(location = 0) out highp vec2 o_lod;\n"
791 "\n"
792 "void main (void)\n"
793 "{\n"
794 " o_lod = textureQueryLod(u_image, v_texCoord);\n"
795 "}\n");
796 }
797
addImageQueryCase(tcu::TestCaseGroup * group,const TestParameters & params)798 void addImageQueryCase (tcu::TestCaseGroup* group, const TestParameters& params)
799 {
800 std::string name = de::toLower(de::toString(params.format).substr(10));
801 const bool isLod = params.query == QUERY_TYPE_IMAGE_LOD;
802
803 if ((params.flags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0)
804 name += "_disjoint";
805
806 addFunctionCaseWithPrograms(group,
807 name,
808 "",
809 checkSupport,
810 isLod ? initImageQueryLodPrograms : initImageQueryPrograms,
811 isLod ? testImageQueryLod : testImageQuery,
812 params);
813 }
814
815 struct QueryGroupParams
816 {
817 QueryType query;
818 glu::ShaderType shaderType;
819
QueryGroupParamsvkt::ycbcr::__anonfe4268f30111::QueryGroupParams820 QueryGroupParams (QueryType query_, glu::ShaderType shaderType_)
821 : query (query_)
822 , shaderType(shaderType_)
823 {}
824
QueryGroupParamsvkt::ycbcr::__anonfe4268f30111::QueryGroupParams825 QueryGroupParams (void)
826 : query (QUERY_TYPE_LAST)
827 , shaderType(glu::SHADERTYPE_LAST)
828 {}
829 };
830
populateQueryInShaderGroup(tcu::TestCaseGroup * group,QueryGroupParams params)831 void populateQueryInShaderGroup (tcu::TestCaseGroup* group, QueryGroupParams params)
832 {
833 // "Reference" formats for testing
834 addImageQueryCase(group, TestParameters(params.query, VK_FORMAT_R8G8B8A8_UNORM, 0u, params.shaderType));
835
836 for (int formatNdx = VK_YCBCR_FORMAT_FIRST; formatNdx < VK_YCBCR_FORMAT_LAST; formatNdx++)
837 {
838 const VkFormat format = (VkFormat)formatNdx;
839
840 addImageQueryCase(group, TestParameters(params.query, format, 0u, params.shaderType));
841
842 if (getPlaneCount(format) > 1)
843 addImageQueryCase(group, TestParameters(params.query, format, (VkImageCreateFlags)VK_IMAGE_CREATE_DISJOINT_BIT, params.shaderType));
844 }
845
846 for (int formatNdx = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT; formatNdx <= VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT; formatNdx++)
847 {
848 const VkFormat format = (VkFormat)formatNdx;
849
850 addImageQueryCase(group, TestParameters(params.query, format, 0u, params.shaderType));
851
852 if (getPlaneCount(format) > 1)
853 addImageQueryCase(group, TestParameters(params.query, format, (VkImageCreateFlags)VK_IMAGE_CREATE_DISJOINT_BIT, params.shaderType));
854 }
855 }
856
populateQueryGroup(tcu::TestCaseGroup * group,QueryType query)857 void populateQueryGroup (tcu::TestCaseGroup* group, QueryType query)
858 {
859 for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; ++shaderTypeNdx)
860 {
861 const glu::ShaderType shaderType = (glu::ShaderType)shaderTypeNdx;
862
863 if (query == QUERY_TYPE_IMAGE_LOD && shaderType != glu::SHADERTYPE_FRAGMENT)
864 continue;
865
866 if (!executorSupported(shaderType))
867 continue;
868
869 addTestGroup(group, glu::getShaderTypeName(shaderType), "", populateQueryInShaderGroup, QueryGroupParams(query, shaderType));
870 }
871 }
872
populateImageQueryGroup(tcu::TestCaseGroup * group)873 void populateImageQueryGroup (tcu::TestCaseGroup* group)
874 {
875 addTestGroup(group, "size_lod", "OpImageQuerySizeLod", populateQueryGroup, QUERY_TYPE_IMAGE_SIZE_LOD);
876 addTestGroup(group, "lod", "OpImageQueryLod", populateQueryGroup, QUERY_TYPE_IMAGE_LOD);
877 addTestGroup(group, "levels", "OpImageQueryLevels", populateQueryGroup, QUERY_TYPE_IMAGE_LEVELS);
878 }
879
880 } // namespace
881
createImageQueryTests(tcu::TestContext & testCtx)882 tcu::TestCaseGroup* createImageQueryTests (tcu::TestContext& testCtx)
883 {
884 return createTestGroup(testCtx, "query", "Image Query Tests", populateImageQueryGroup);
885 }
886
887 } // ycbcr
888 } // vkt
889