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