1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2020 The Khronos Group 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 filtering tests.
22 *//*--------------------------------------------------------------------*/
23
24 #include "tcuVectorUtil.hpp"
25 #include "tcuTexVerifierUtil.hpp"
26 #include "tcuImageCompare.hpp"
27 #include "vkImageUtil.hpp"
28 #include "vkMemUtil.hpp"
29 #include "vkPrograms.hpp"
30 #include "vkRefUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkBarrierUtil.hpp"
33 #include "vktTestCase.hpp"
34 #include "vktTestGroupUtil.hpp"
35 #include "vktYCbCrFilteringTests.hpp"
36 #include "vktDrawUtil.hpp"
37 #include "vktYCbCrUtil.hpp"
38 #include "gluTextureTestUtil.hpp"
39 #include <string>
40 #include <vector>
41
42 using namespace vk;
43 using namespace vkt::drawutil;
44
45 namespace vkt
46 {
47 namespace ycbcr
48 {
49 namespace
50 {
51
52 using std::vector;
53 using std::string;
54 using tcu::TestLog;
55 using tcu::Sampler;
56 using namespace glu::TextureTestUtil;
57
58 class LinearFilteringTestInstance: public TestInstance
59 {
60 public:
61 LinearFilteringTestInstance(Context& context, VkFormat format, VkFilter chromaFiltering);
62 ~LinearFilteringTestInstance() = default;
63
64 protected:
65
66 VkSamplerCreateInfo getSamplerInfo (const VkSamplerYcbcrConversionInfo* samplerConversionInfo);
67 Move<VkDescriptorSetLayout> createDescriptorSetLayout (VkSampler sampler);
68 Move<VkDescriptorPool> createDescriptorPool (const deUint32 combinedSamplerDescriptorCount);
69 Move<VkDescriptorSet> createDescriptorSet (VkDescriptorPool descPool,
70 VkDescriptorSetLayout descLayout);
71 Move<VkSamplerYcbcrConversion> createYCbCrConversion (void);
72 Move<VkImage> createImage (deUint32 width, deUint32 height);
73 Move<VkImageView> createImageView (const VkSamplerYcbcrConversionInfo& samplerConversionInfo, VkImage image);
74 void bindImage (VkDescriptorSet descriptorSet,
75 VkImageView imageView,
76 VkSampler sampler);
77 tcu::TestStatus iterate (void);
78
79 private:
80
81 struct FilterCase
82 {
83 const tcu::UVec2 imageSize;
84 const tcu::UVec2 renderSize;
85 };
86
87 const VkFormat m_format;
88 const VkFilter m_chromaFiltering;
89 const DeviceInterface& m_vkd;
90 const VkDevice m_device;
91 int m_caseIndex;
92 const vector<FilterCase> m_cases;
93 };
94
LinearFilteringTestInstance(Context & context,VkFormat format,VkFilter chromaFiltering)95 LinearFilteringTestInstance::LinearFilteringTestInstance(Context& context, VkFormat format, VkFilter chromaFiltering)
96 : TestInstance (context)
97 , m_format (format)
98 , m_chromaFiltering (chromaFiltering)
99 , m_vkd (m_context.getDeviceInterface())
100 , m_device (m_context.getDevice())
101 , m_caseIndex (0)
102 , m_cases {
103 { { 8, 8}, {64, 64} },
104 { {64, 32}, {32, 64} }
105 }
106 {
107 }
108
getSamplerInfo(const VkSamplerYcbcrConversionInfo * samplerConversionInfo)109 VkSamplerCreateInfo LinearFilteringTestInstance::getSamplerInfo(const VkSamplerYcbcrConversionInfo* samplerConversionInfo)
110 {
111 return
112 {
113 VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
114 samplerConversionInfo,
115 0u,
116 VK_FILTER_LINEAR, // magFilter
117 VK_FILTER_LINEAR, // minFilter
118 VK_SAMPLER_MIPMAP_MODE_NEAREST, // mipmapMode
119 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
120 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV
121 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW
122 0.0f, // mipLodBias
123 VK_FALSE, // anisotropyEnable
124 1.0f, // maxAnisotropy
125 VK_FALSE, // compareEnable
126 VK_COMPARE_OP_ALWAYS, // compareOp
127 0.0f, // minLod
128 0.0f, // maxLod
129 VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor
130 VK_FALSE, // unnormalizedCoords
131 };
132 }
133
createDescriptorSetLayout(VkSampler sampler)134 Move<VkDescriptorSetLayout> LinearFilteringTestInstance::createDescriptorSetLayout(VkSampler sampler)
135 {
136 const VkDescriptorSetLayoutBinding binding =
137 {
138 0u, // binding
139 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
140 1u, // descriptorCount
141 VK_SHADER_STAGE_ALL,
142 &sampler
143 };
144 const VkDescriptorSetLayoutCreateInfo layoutInfo =
145 {
146 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
147 DE_NULL,
148 (VkDescriptorSetLayoutCreateFlags)0u,
149 1u,
150 &binding,
151 };
152
153 return ::createDescriptorSetLayout(m_vkd, m_device, &layoutInfo);
154 }
155
createDescriptorPool(const deUint32 combinedSamplerDescriptorCount)156 Move<VkDescriptorPool> LinearFilteringTestInstance::createDescriptorPool(const deUint32 combinedSamplerDescriptorCount)
157 {
158 const VkDescriptorPoolSize poolSizes[] =
159 {
160 { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, combinedSamplerDescriptorCount },
161 };
162 const VkDescriptorPoolCreateInfo poolInfo =
163 {
164 VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
165 DE_NULL,
166 (VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
167 1u, // maxSets
168 DE_LENGTH_OF_ARRAY(poolSizes),
169 poolSizes,
170 };
171
172 return ::createDescriptorPool(m_vkd, m_device, &poolInfo);
173 }
174
createDescriptorSet(VkDescriptorPool descPool,VkDescriptorSetLayout descLayout)175 Move<VkDescriptorSet> LinearFilteringTestInstance::createDescriptorSet(VkDescriptorPool descPool,
176 VkDescriptorSetLayout descLayout)
177 {
178 const VkDescriptorSetAllocateInfo allocInfo =
179 {
180 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
181 DE_NULL,
182 descPool,
183 1u,
184 &descLayout,
185 };
186
187 return allocateDescriptorSet(m_vkd, m_device, &allocInfo);
188 }
189
createYCbCrConversion()190 Move<VkSamplerYcbcrConversion> LinearFilteringTestInstance::createYCbCrConversion()
191 {
192 const VkSamplerYcbcrConversionCreateInfo conversionInfo =
193 {
194 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
195 DE_NULL,
196 m_format,
197 VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
198 VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
199 {
200 VK_COMPONENT_SWIZZLE_IDENTITY,
201 VK_COMPONENT_SWIZZLE_IDENTITY,
202 VK_COMPONENT_SWIZZLE_IDENTITY,
203 VK_COMPONENT_SWIZZLE_IDENTITY,
204 },
205 VK_CHROMA_LOCATION_MIDPOINT,
206 VK_CHROMA_LOCATION_MIDPOINT,
207 m_chromaFiltering, // chromaFilter
208 VK_FALSE, // forceExplicitReconstruction
209 };
210
211 return createSamplerYcbcrConversion(m_vkd, m_device, &conversionInfo);
212 }
213
createImage(deUint32 width,deUint32 height)214 Move<VkImage> LinearFilteringTestInstance::createImage(deUint32 width, deUint32 height)
215 {
216 VkImageCreateFlags createFlags = 0u;
217 const VkImageCreateInfo createInfo =
218 {
219 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
220 DE_NULL,
221 createFlags,
222 VK_IMAGE_TYPE_2D,
223 m_format,
224 makeExtent3D(width, height, 1u),
225 1u, // mipLevels
226 1u, // arrayLayers
227 VK_SAMPLE_COUNT_1_BIT,
228 VK_IMAGE_TILING_OPTIMAL,
229 VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
230 VK_SHARING_MODE_EXCLUSIVE,
231 0u,
232 (const deUint32*)DE_NULL,
233 VK_IMAGE_LAYOUT_UNDEFINED,
234 };
235
236 return ::createImage(m_vkd, m_device, &createInfo);
237 }
238
createImageView(const VkSamplerYcbcrConversionInfo & samplerConversionInfo,VkImage image)239 Move<VkImageView> LinearFilteringTestInstance::createImageView(const VkSamplerYcbcrConversionInfo& samplerConversionInfo, VkImage image)
240 {
241 const VkImageViewCreateInfo viewInfo =
242 {
243 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
244 &samplerConversionInfo,
245 (VkImageViewCreateFlags)0,
246 image,
247 VK_IMAGE_VIEW_TYPE_2D,
248 m_format,
249 {
250 VK_COMPONENT_SWIZZLE_IDENTITY,
251 VK_COMPONENT_SWIZZLE_IDENTITY,
252 VK_COMPONENT_SWIZZLE_IDENTITY,
253 VK_COMPONENT_SWIZZLE_IDENTITY,
254 },
255 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },
256 };
257
258 return ::createImageView(m_vkd, m_device, &viewInfo);
259 }
260
bindImage(VkDescriptorSet descriptorSet,VkImageView imageView,VkSampler sampler)261 void LinearFilteringTestInstance::bindImage(VkDescriptorSet descriptorSet,
262 VkImageView imageView,
263 VkSampler sampler)
264 {
265 const VkDescriptorImageInfo imageInfo =
266 {
267 sampler,
268 imageView,
269 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
270 };
271 const VkWriteDescriptorSet descriptorWrite =
272 {
273 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
274 DE_NULL,
275 descriptorSet,
276 0u, // dstBinding
277 0u, // dstArrayElement
278 1u, // descriptorCount
279 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
280 &imageInfo,
281 (const VkDescriptorBufferInfo*)DE_NULL,
282 (const VkBufferView*)DE_NULL,
283 };
284
285 m_vkd.updateDescriptorSets(m_device, 1u, &descriptorWrite, 0u, DE_NULL);
286 }
287
iterate(void)288 tcu::TestStatus LinearFilteringTestInstance::iterate(void)
289 {
290 const tcu::UVec2 imageSize (m_cases[m_caseIndex].imageSize);
291 const tcu::UVec2 renderSize (m_cases[m_caseIndex].renderSize);
292 const auto& instInt (m_context.getInstanceInterface());
293 auto physicalDevice (m_context.getPhysicalDevice());
294 const Unique<VkSamplerYcbcrConversion> conversion (createYCbCrConversion());
295 const VkSamplerYcbcrConversionInfo samplerConvInfo { VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO, DE_NULL, *conversion };
296 const VkSamplerCreateInfo samplerCreateInfo (getSamplerInfo(&samplerConvInfo));
297 const Unique<VkSampler> sampler (createSampler(m_vkd, m_device, &samplerCreateInfo));
298
299 deUint32 combinedSamplerDescriptorCount = 1;
300 {
301 const VkPhysicalDeviceImageFormatInfo2 imageFormatInfo =
302 {
303 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, // sType
304 DE_NULL, // pNext
305 m_format, // format
306 VK_IMAGE_TYPE_2D, // type
307 VK_IMAGE_TILING_OPTIMAL, // tiling
308 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
309 VK_IMAGE_USAGE_SAMPLED_BIT, // usage
310 (VkImageCreateFlags)0u // flags
311 };
312
313 VkSamplerYcbcrConversionImageFormatProperties samplerYcbcrConversionImage = {};
314 samplerYcbcrConversionImage.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES;
315 samplerYcbcrConversionImage.pNext = DE_NULL;
316
317 VkImageFormatProperties2 imageFormatProperties = {};
318 imageFormatProperties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
319 imageFormatProperties.pNext = &samplerYcbcrConversionImage;
320
321 VK_CHECK(instInt.getPhysicalDeviceImageFormatProperties2(physicalDevice, &imageFormatInfo, &imageFormatProperties));
322 combinedSamplerDescriptorCount = samplerYcbcrConversionImage.combinedImageSamplerDescriptorCount;
323 }
324
325 const Unique<VkDescriptorSetLayout> descLayout (createDescriptorSetLayout(*sampler));
326 const Unique<VkDescriptorPool> descPool (createDescriptorPool(combinedSamplerDescriptorCount));
327 const Unique<VkDescriptorSet> descSet (createDescriptorSet(*descPool, *descLayout));
328 const Unique<VkImage> testImage (createImage(imageSize.x(), imageSize.y()));
329 const vector<AllocationSp> allocations (allocateAndBindImageMemory(m_vkd, m_device, m_context.getDefaultAllocator(), *testImage, m_format, 0u));
330 const Unique<VkImageView> imageView (createImageView(samplerConvInfo, *testImage));
331
332 // create and bind image with test data
333 MultiPlaneImageData imageData(m_format, imageSize);
334 fillGradient(&imageData, tcu::Vec4(0.0f), tcu::Vec4(1.0f));
335 uploadImage(m_vkd,
336 m_device,
337 m_context.getUniversalQueueFamilyIndex(),
338 m_context.getDefaultAllocator(),
339 *testImage,
340 imageData,
341 (VkAccessFlags)VK_ACCESS_SHADER_READ_BIT,
342 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
343 0);
344 bindImage(*descSet, *imageView, *sampler);
345
346 const vector<tcu::Vec4> vertices =
347 {
348 { -1.0f, -1.0f, 0.0f, 1.0f },
349 { +1.0f, -1.0f, 0.0f, 1.0f },
350 { -1.0f, +1.0f, 0.0f, 1.0f },
351 { +1.0f, +1.0f, 0.0f, 1.0f }
352 };
353 VulkanProgram program({
354 VulkanShader(VK_SHADER_STAGE_VERTEX_BIT, m_context.getBinaryCollection().get("vert")),
355 VulkanShader(VK_SHADER_STAGE_FRAGMENT_BIT, m_context.getBinaryCollection().get("frag"))
356 });
357 program.descriptorSet = *descSet;
358 program.descriptorSetLayout = *descLayout;
359
360 PipelineState pipelineState (m_context.getDeviceProperties().limits.subPixelPrecisionBits);
361 const DrawCallData drawCallData (VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices);
362 FrameBufferState frameBufferState (renderSize.x(), renderSize.y());
363 VulkanDrawContext renderer (m_context, frameBufferState);
364
365 // render full screen quad
366 renderer.registerDrawObject(pipelineState, program, drawCallData);
367 renderer.draw();
368
369 // get rendered image
370 tcu::ConstPixelBufferAccess resImage(renderer.getColorPixels());
371
372 // construct ChannelAccess objects required to create reference results
373 const vk::PlanarFormatDescription planeInfo = imageData.getDescription();
374 deUint32 nullAccessData (0u);
375 ChannelAccess nullAccess (tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT, 1u, tcu::IVec3(imageSize.x(), imageSize.y(), 1), tcu::IVec3(0, 0, 0), &nullAccessData, 0u);
376 deUint32 nullAccessAlphaData (~0u);
377 ChannelAccess nullAccessAlpha (tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT, 1u, tcu::IVec3(imageSize.x(), imageSize.y(), 1), tcu::IVec3(0, 0, 0), &nullAccessAlphaData, 0u);
378 ChannelAccess rChannelAccess (planeInfo.hasChannelNdx(0) ? getChannelAccess(imageData, planeInfo, imageSize, 0) : nullAccess);
379 ChannelAccess gChannelAccess (planeInfo.hasChannelNdx(1) ? getChannelAccess(imageData, planeInfo, imageSize, 1) : nullAccess);
380 ChannelAccess bChannelAccess (planeInfo.hasChannelNdx(2) ? getChannelAccess(imageData, planeInfo, imageSize, 2) : nullAccess);
381 ChannelAccess aChannelAccess (planeInfo.hasChannelNdx(3) ? getChannelAccess(imageData, planeInfo, imageSize, 3) : nullAccessAlpha);
382 const VkFormatProperties formatProperties (getPhysicalDeviceFormatProperties(instInt, physicalDevice, m_format));
383 const VkFormatFeatureFlags featureFlags (formatProperties.optimalTilingFeatures);
384 const bool explicitReconstruction (featureFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT);
385
386 // calulate texture coordinates used by fragment shader
387 vector<tcu::Vec2> sts;
388 for (deUint32 y = 0; y < renderSize.y(); y++)
389 for (deUint32 x = 0; x < renderSize.x(); x++)
390 {
391 const float s = ((float)x + 0.5f) / (float)renderSize.x();
392 const float t = ((float)y + 0.5f) / (float)renderSize.y();
393
394 sts.push_back(tcu::Vec2(s, t));
395 }
396
397 // calculate minimum and maximum values between which the results should be placed
398 const tcu::UVec4 bitDepth (getYCbCrBitDepth(m_format));
399 const std::vector<tcu::FloatFormat> filteringPrecision (getPrecision(m_format));
400 const std::vector<tcu::FloatFormat> conversionPrecision (getPrecision(m_format));
401 const deUint32 subTexelPrecisionBits (vk::getPhysicalDeviceProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()).limits.subTexelPrecisionBits);
402 const vk::VkComponentMapping componentMapping = { vk::VK_COMPONENT_SWIZZLE_IDENTITY, vk::VK_COMPONENT_SWIZZLE_IDENTITY, vk::VK_COMPONENT_SWIZZLE_IDENTITY, vk::VK_COMPONENT_SWIZZLE_IDENTITY };
403
404 std::vector<tcu::Vec4> minBound;
405 std::vector<tcu::Vec4> maxBound;
406 std::vector<tcu::Vec4> uvBound;
407 std::vector<tcu::IVec4> ijBound;
408 calculateBounds(rChannelAccess, gChannelAccess, bChannelAccess, aChannelAccess, bitDepth, sts, filteringPrecision, conversionPrecision, subTexelPrecisionBits, VK_FILTER_LINEAR, VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY, VK_SAMPLER_YCBCR_RANGE_ITU_FULL, m_chromaFiltering, VK_CHROMA_LOCATION_MIDPOINT, VK_CHROMA_LOCATION_MIDPOINT, componentMapping, explicitReconstruction, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, minBound, maxBound, uvBound, ijBound);
409
410 // log result and reference images
411 TestLog& log (m_context.getTestContext().getLog());
412 {
413 const tcu::Vec4 scale (1.0f);
414 const tcu::Vec4 bias (0.0f);
415 vector<deUint8> minData (renderSize.x() * renderSize.y() * sizeof(tcu::Vec4), 255);
416 vector<deUint8> maxData (renderSize.x() * renderSize.y() * sizeof(tcu::Vec4), 255);
417 tcu::TextureFormat refFormat (vk::mapVkFormat(frameBufferState.colorFormat));
418 tcu::PixelBufferAccess minImage (refFormat, renderSize.x(), renderSize.y(), 1, minData.data());
419 tcu::PixelBufferAccess maxImage (refFormat, renderSize.x(), renderSize.y(), 1, maxData.data());
420 {
421 deUint32 ndx = 0;
422 for (deUint32 y = 0; y < renderSize.y(); y++)
423 for (deUint32 x = 0; x < renderSize.x(); x++)
424 {
425 minImage.setPixel(minBound[ndx], x, y);
426 maxImage.setPixel(maxBound[ndx], x, y);
427 ndx++;
428 }
429 }
430
431 log << TestLog::Image("MinBoundImage", "MinBoundImage", minImage, scale, bias);
432 log << TestLog::Image("MaxBoundImage", "MaxBoundImage", maxImage, scale, bias);
433 log << TestLog::Image("ResImage", "ResImage", resImage, scale, bias);
434 }
435
436 bool isOk = true;
437 {
438 deUint32 ndx = 0;
439 VkFilter textureFilter = VK_FILTER_LINEAR;
440 size_t errorCount = 0;
441
442 for (deUint32 y = 0; y < renderSize.y(); y++)
443 for (deUint32 x = 0; x < renderSize.x(); x++)
444 {
445 tcu::Vec4 resValue = resImage.getPixel(x, y);
446 bool fail = tcu::boolAny(tcu::lessThan(resValue, minBound[ndx])) || tcu::boolAny(tcu::greaterThan(resValue, maxBound[ndx]));
447
448 if (fail)
449 {
450 log << TestLog::Message << "Fail: " << sts[ndx] << " " << resValue << TestLog::EndMessage;
451 log << TestLog::Message << " Min : " << minBound[ndx] << TestLog::EndMessage;
452 log << TestLog::Message << " Max : " << maxBound[ndx] << TestLog::EndMessage;
453 log << TestLog::Message << " Threshold: " << (maxBound[ndx] - minBound[ndx]) << TestLog::EndMessage;
454 log << TestLog::Message << " UMin : " << uvBound[ndx][0] << TestLog::EndMessage;
455 log << TestLog::Message << " UMax : " << uvBound[ndx][1] << TestLog::EndMessage;
456 log << TestLog::Message << " VMin : " << uvBound[ndx][2] << TestLog::EndMessage;
457 log << TestLog::Message << " VMax : " << uvBound[ndx][3] << TestLog::EndMessage;
458 log << TestLog::Message << " IMin : " << ijBound[ndx][0] << TestLog::EndMessage;
459 log << TestLog::Message << " IMax : " << ijBound[ndx][1] << TestLog::EndMessage;
460 log << TestLog::Message << " JMin : " << ijBound[ndx][2] << TestLog::EndMessage;
461 log << TestLog::Message << " JMax : " << ijBound[ndx][3] << TestLog::EndMessage;
462
463 if (isXChromaSubsampled(m_format))
464 {
465 log << TestLog::Message << " LumaAlphaValues : " << TestLog::EndMessage;
466 log << TestLog::Message << " Offset : (" << ijBound[ndx][0] << ", " << ijBound[ndx][2] << ")" << TestLog::EndMessage;
467
468 for (deInt32 k = ijBound[ndx][2]; k <= ijBound[ndx][3] + (textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); k++)
469 {
470 const deInt32 wrappedK = wrap(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, k, gChannelAccess.getSize().y());
471 bool first = true;
472 std::ostringstream line;
473
474 for (deInt32 j = ijBound[ndx][0]; j <= ijBound[ndx][1] + (textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); j++)
475 {
476 const deInt32 wrappedJ = wrap(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, j, gChannelAccess.getSize().x());
477
478 if (!first)
479 {
480 line << ", ";
481 first = false;
482 }
483
484 line << "(" << std::setfill(' ') << std::setw(5) << gChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0))
485 << ", " << std::setfill(' ') << std::setw(5) << aChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0)) << ")";
486 }
487 log << TestLog::Message << " " << line.str() << TestLog::EndMessage;
488 }
489
490 {
491 const tcu::IVec2 chromaJRange(divFloor(ijBound[ndx][0], 2) - 1, divFloor(ijBound[ndx][1] + (textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0), 2) + 1);
492 const tcu::IVec2 chromaKRange(isYChromaSubsampled(m_format)
493 ? tcu::IVec2(divFloor(ijBound[ndx][2], 2) - 1, divFloor(ijBound[ndx][3] + (textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0), 2) + 1)
494 : tcu::IVec2(ijBound[ndx][2], ijBound[ndx][3] + (textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0)));
495
496 log << TestLog::Message << " ChromaValues : " << TestLog::EndMessage;
497 log << TestLog::Message << " Offset : (" << chromaJRange[0] << ", " << chromaKRange[0] << ")" << TestLog::EndMessage;
498
499 for (deInt32 k = chromaKRange[0]; k <= chromaKRange[1]; k++)
500 {
501 const deInt32 wrappedK = wrap(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, k, rChannelAccess.getSize().y());
502 bool first = true;
503 std::ostringstream line;
504
505 for (deInt32 j = chromaJRange[0]; j <= chromaJRange[1]; j++)
506 {
507 const deInt32 wrappedJ = wrap(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, j, rChannelAccess.getSize().x());
508
509 if (!first)
510 {
511 line << ", ";
512 first = false;
513 }
514
515 line << "(" << std::setfill(' ') << std::setw(5) << rChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0))
516 << ", " << std::setfill(' ') << std::setw(5) << bChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0)) << ")";
517 }
518 log << TestLog::Message << " " << line.str() << TestLog::EndMessage;
519 }
520 }
521 }
522 else
523 {
524 log << TestLog::Message << " Values : " << TestLog::EndMessage;
525 log << TestLog::Message << " Offset : (" << ijBound[ndx][0] << ", " << ijBound[ndx][2] << ")" << TestLog::EndMessage;
526
527 for (deInt32 k = ijBound[ndx][2]; k <= ijBound[ndx][3] + (textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); k++)
528 {
529 const deInt32 wrappedK = wrap(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, k, rChannelAccess.getSize().y());
530 bool first = true;
531 std::ostringstream line;
532
533 for (deInt32 j = ijBound[ndx][0]; j <= ijBound[ndx][1] + (textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); j++)
534 {
535 const deInt32 wrappedJ = wrap(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, j, rChannelAccess.getSize().x());
536
537 if (!first)
538 {
539 line << ", ";
540 first = false;
541 }
542
543 line << "(" << std::setfill(' ') << std::setw(5) << rChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0))
544 << ", " << std::setfill(' ') << std::setw(5) << gChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0))
545 << ", " << std::setfill(' ') << std::setw(5) << bChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0))
546 << ", " << std::setfill(' ') << std::setw(5) << aChannelAccess.getChannelUint(tcu::IVec3(wrappedJ, wrappedK, 0)) << ")";
547 }
548 log << TestLog::Message << " " << line.str() << TestLog::EndMessage;
549 }
550 }
551
552 errorCount++;
553 isOk = false;
554
555 if (errorCount > 30)
556 {
557 log << TestLog::Message << "Encountered " << errorCount << " errors. Omitting rest of the per result logs." << TestLog::EndMessage;
558 break;
559 }
560 }
561 ndx++;
562 }
563 }
564
565 if (!isOk)
566 return tcu::TestStatus::fail("Result comparison failed");
567 if (++m_caseIndex < (int)m_cases.size())
568 return tcu::TestStatus::incomplete();
569 return tcu::TestStatus::pass("Pass");
570 }
571
572 class LinearFilteringTestCase : public vkt::TestCase
573 {
574 public:
575 LinearFilteringTestCase(tcu::TestContext &context, const char* name, const char* description, VkFormat format, VkFilter chromaFiltering);
576
577 protected:
578 void checkSupport(Context& context) const;
579 vkt::TestInstance* createInstance(vkt::Context& context) const;
580 void initPrograms(SourceCollections& programCollection) const;
581
582 private:
583 VkFormat m_format;
584 VkFilter m_chromaFiltering;
585 };
586
LinearFilteringTestCase(tcu::TestContext & context,const char * name,const char * description,VkFormat format,VkFilter chromaFiltering)587 LinearFilteringTestCase::LinearFilteringTestCase(tcu::TestContext &context, const char* name, const char* description, VkFormat format, VkFilter chromaFiltering)
588 : TestCase(context, name, description)
589 , m_format(format)
590 , m_chromaFiltering(chromaFiltering)
591 {
592 }
593
checkSupport(Context & context) const594 void LinearFilteringTestCase::checkSupport(Context& context) const
595 {
596 context.requireDeviceFunctionality("VK_KHR_sampler_ycbcr_conversion");
597
598 const auto& instInt = context.getInstanceInterface();
599 auto physicalDevice = context.getPhysicalDevice();
600 const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(instInt, physicalDevice, m_format);
601 const VkFormatFeatureFlags featureFlags = formatProperties.optimalTilingFeatures;
602
603 if ((featureFlags & VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT) == 0)
604 TCU_THROW(NotSupportedError, "YCbCr conversion is not supported for format");
605
606 if ((featureFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT) == 0)
607 TCU_THROW(NotSupportedError, "Linear filtering not supported for format");
608
609 if (m_chromaFiltering != VK_FILTER_LINEAR &&
610 (featureFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT) == 0)
611 TCU_THROW(NotSupportedError, "Different chroma, min, and mag filters not supported for format");
612 }
613
createInstance(vkt::Context & context) const614 vkt::TestInstance* LinearFilteringTestCase::createInstance(vkt::Context& context) const
615 {
616 return new LinearFilteringTestInstance(context, m_format, m_chromaFiltering);
617 }
618
initPrograms(SourceCollections & programCollection) const619 void LinearFilteringTestCase::initPrograms(SourceCollections& programCollection) const
620 {
621 static const char* vertShader =
622 "#version 450\n"
623 "precision mediump int; precision highp float;\n"
624 "layout(location = 0) in vec4 a_position;\n"
625 "layout(location = 0) out vec2 v_texCoord;\n"
626 "out gl_PerVertex { vec4 gl_Position; };\n"
627 "\n"
628 "void main (void)\n"
629 "{\n"
630 " v_texCoord = a_position.xy * 0.5 + 0.5;\n"
631 " gl_Position = a_position;\n"
632 "}\n";
633
634 static const char* fragShader =
635 "#version 450\n"
636 "precision mediump int; precision highp float;\n"
637 "layout(location = 0) in vec2 v_texCoord;\n"
638 "layout(location = 0) out mediump vec4 dEQP_FragColor;\n"
639 "layout (set=0, binding=0) uniform sampler2D u_sampler;\n"
640 "void main (void)\n"
641 "{\n"
642 " dEQP_FragColor = vec4(texture(u_sampler, v_texCoord));\n"
643 "}\n";
644
645 programCollection.glslSources.add("vert") << glu::VertexSource(vertShader);
646 programCollection.glslSources.add("frag") << glu::FragmentSource(fragShader);
647 }
648
649 } // anonymous
650
createFilteringTests(tcu::TestContext & testCtx)651 tcu::TestCaseGroup* createFilteringTests (tcu::TestContext& testCtx)
652 {
653 struct YCbCrFormatData
654 {
655 const char* const name;
656 const VkFormat format;
657 };
658
659 static const std::vector<YCbCrFormatData> ycbcrFormats =
660 {
661 { "g8_b8_r8_3plane_420_unorm", VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM },
662 { "g8_b8r8_2plane_420_unorm", VK_FORMAT_G8_B8R8_2PLANE_420_UNORM },
663 };
664
665 de::MovePtr<tcu::TestCaseGroup> filteringTests(new tcu::TestCaseGroup(testCtx, "filtering", "YCbCr filtering tests"));
666
667 for (const auto& ycbcrFormat : ycbcrFormats)
668 {
669 {
670 const std::string name = std::string("linear_sampler_") + ycbcrFormat.name;
671 filteringTests->addChild(new LinearFilteringTestCase(filteringTests->getTestContext(), name.c_str(), "", ycbcrFormat.format, VK_FILTER_NEAREST));
672 }
673
674 {
675 const std::string name = std::string("linear_sampler_with_chroma_linear_filtering_") + ycbcrFormat.name;
676 filteringTests->addChild(new LinearFilteringTestCase(filteringTests->getTestContext(), name.c_str(), "", ycbcrFormat.format, VK_FILTER_LINEAR));
677 }
678 }
679
680 return filteringTests.release();
681 }
682
683 } // ycbcr
684
685 } // vkt
686