xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/texture/vktTextureConversionTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2020 The Khronos Group Inc.
6  * Copyright (c) 2020 Google Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Texture conversion tests.
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktTextureConversionTests.hpp"
26 #include "vktAmberTestCase.hpp"
27 #include "vktTestGroupUtil.hpp"
28 #include "vktTextureTestUtil.hpp"
29 #include "vkImageUtil.hpp"
30 #include "tcuTexture.hpp"
31 #include "tcuTextureUtil.hpp"
32 #include "tcuVectorUtil.hpp"
33 #include "deSharedPtr.hpp"
34 
35 #include <cmath>
36 #include <memory>
37 
38 namespace vkt
39 {
40 namespace texture
41 {
42 
43 using namespace vk;
44 
45 namespace
46 {
47 
48 using namespace texture::util;
49 using namespace glu::TextureTestUtil;
50 
51 class SnormLinearClampInstance : public TestInstance
52 {
53 public:
54     struct Params
55     {
56         VkFormat format;
57         int width;
58         int height;
59     };
60     SnormLinearClampInstance(vkt::Context &context, de::SharedPtr<Params> params);
61 
62     virtual tcu::TestStatus iterate(void) override;
63 
64 protected:
65     tcu::IVec4 computeColorDistance() const;
66     bool verifyPixels(const tcu::PixelBufferAccess &rendered, const tcu::PixelBufferAccess &reference,
67                       const ReferenceParams &samplerParams, const std::vector<float> &texCoords) const;
68 
69     static int lim(const tcu::TextureFormat &format, int channelIdx);
70 
71 private:
72     const de::SharedPtr<Params> m_params;
73     const tcu::TextureFormat m_inFormat;
74     const VkFormat m_outFormat;
75     TestTexture2DSp m_hwTexture;
76     tcu::Texture2D m_swTexture;
77     TextureRenderer m_renderer;
78 
79     const tcu::IVec4 m_cd;
80     const tcu::IVec4 m_a;
81     const tcu::IVec4 m_b;
82     const tcu::IVec4 m_c;
83     const tcu::IVec4 m_d;
84 
85 public:
86     static const int textureWidth  = 7;
87     static const int textureHeight = 7;
88 };
89 
SnormLinearClampInstance(vkt::Context & context,de::SharedPtr<Params> params)90 SnormLinearClampInstance::SnormLinearClampInstance(vkt::Context &context, de::SharedPtr<Params> params)
91     : TestInstance(context)
92     , m_params(params)
93     , m_inFormat(mapVkFormat(m_params->format))
94     , m_outFormat(VK_FORMAT_R32G32B32A32_SFLOAT)
95     , m_hwTexture(TestTexture2DSp(new pipeline::TestTexture2D(m_inFormat, textureWidth, textureHeight)))
96     , m_swTexture(m_inFormat, textureWidth, textureHeight, 1)
97     , m_renderer(context, VK_SAMPLE_COUNT_1_BIT, m_params->width, m_params->height, 1u, makeComponentMappingRGBA(),
98                  VK_IMAGE_TYPE_2D, VK_IMAGE_VIEW_TYPE_2D, m_outFormat)
99     , m_cd(computeColorDistance())
100     , m_a(lim(m_inFormat, 0), lim(m_inFormat, 1) + m_cd[1] * 2, lim(m_inFormat, 2), lim(m_inFormat, 3) + m_cd[3] * 2)
101     , m_b(lim(m_inFormat, 0) + m_cd[0] * 2, lim(m_inFormat, 1), lim(m_inFormat, 2) + m_cd[2] * 2, lim(m_inFormat, 3))
102     , m_c(lim(m_inFormat, 0) + m_cd[0] * 1, lim(m_inFormat, 1) + m_cd[1] * 1, lim(m_inFormat, 2) + m_cd[2] * 1,
103           lim(m_inFormat, 3) + m_cd[3] * 1)
104     , m_d(lim(m_inFormat, 0), lim(m_inFormat, 1), lim(m_inFormat, 2), lim(m_inFormat, 3))
105 {
106     tcu::IVec4 data[textureWidth * textureHeight] = {
107         m_a, m_b, m_c, m_d, m_c, m_b, m_a, m_b, m_a, m_c, m_d, m_c, m_a, m_b, m_c, m_c, m_c,
108         m_d, m_c, m_c, m_c, m_d, m_d, m_d, m_c, m_d, m_d, m_d, m_c, m_c, m_c, m_d, m_c, m_c,
109         m_c, m_b, m_a, m_c, m_d, m_c, m_a, m_b, m_a, m_b, m_c, m_d, m_c, m_b, m_a,
110     };
111 
112     m_swTexture.allocLevel(0);
113 
114     const tcu::PixelBufferAccess &swAccess = m_swTexture.getLevel(0);
115     const tcu::PixelBufferAccess &hwAccess = m_hwTexture->getLevel(0, 0);
116 
117     for (int y = 0; y < textureHeight; ++y)
118     {
119         for (int x = 0; x < textureWidth; ++x)
120         {
121             swAccess.setPixel(data[y * textureWidth + x], x, y);
122             hwAccess.setPixel(data[y * textureWidth + x], x, y);
123         }
124     }
125 
126     m_renderer.add2DTexture(m_hwTexture, VK_IMAGE_ASPECT_COLOR_BIT,
127                             TextureBinding::ImageBackingMode::IMAGE_BACKING_MODE_REGULAR);
128 }
129 
lim(const tcu::TextureFormat & format,int channelIdx)130 int SnormLinearClampInstance::lim(const tcu::TextureFormat &format, int channelIdx)
131 {
132     auto channelBits(getTextureFormatBitDepth(format));
133     return channelBits[channelIdx] ? (-deIntMaxValue32(channelBits[channelIdx])) : (-1);
134 }
135 
computeColorDistance() const136 tcu::IVec4 SnormLinearClampInstance::computeColorDistance() const
137 {
138     return tcu::IVec4(static_cast<int>(std::floor(static_cast<float>(-lim(m_inFormat, 0)) / 127.0f)),
139                       static_cast<int>(std::floor(static_cast<float>(-lim(m_inFormat, 0)) / 127.0f)),
140                       static_cast<int>(std::floor(static_cast<float>(-lim(m_inFormat, 0)) / 127.0f)),
141                       static_cast<int>(std::floor(static_cast<float>(-lim(m_inFormat, 0)) / 127.0f)));
142 }
143 
verifyPixels(const tcu::PixelBufferAccess & rendered,const tcu::PixelBufferAccess & reference,const ReferenceParams & samplerParams,const std::vector<float> & texCoords) const144 bool SnormLinearClampInstance::verifyPixels(const tcu::PixelBufferAccess &rendered,
145                                             const tcu::PixelBufferAccess &reference,
146                                             const ReferenceParams &samplerParams,
147                                             const std::vector<float> &texCoords) const
148 {
149     tcu::LodPrecision lodPrec;
150     tcu::LookupPrecision lookupPrec;
151 
152     const int nuc(getNumUsedChannels(m_inFormat.order));
153     const int width(m_renderer.getRenderWidth());
154     const int height(m_renderer.getRenderHeight());
155 
156     const tcu::IVec4 colorDistance(computeColorDistance());
157     std::unique_ptr<uint8_t[]> errorMaskData(new uint8_t[width * height * 4 * 4]);
158     tcu::PixelBufferAccess errorMask(mapVkFormat(m_outFormat), width, height, 1, errorMaskData.get());
159 
160     lodPrec.derivateBits = 18;
161     lodPrec.lodBits      = 5;
162 
163     lookupPrec.uvwBits        = tcu::IVec3(5, 5, 0);
164     lookupPrec.coordBits      = tcu::IVec3(20, 20, 0);
165     lookupPrec.colorMask      = tcu::BVec4(nuc >= 1, nuc >= 2, nuc >= 3, nuc >= 4);
166     lookupPrec.colorThreshold = tcu::Vec4(0.9f / float(colorDistance[0]), 0.9f / float(colorDistance[1]),
167                                           0.9f / float(colorDistance[2]), 0.9f / float(colorDistance[3]));
168 
169     const int numFailedPixels =
170         glu::TextureTestUtil::computeTextureLookupDiff(rendered, reference, errorMask, m_swTexture, texCoords.data(),
171                                                        samplerParams, lookupPrec, lodPrec, /*watchDog*/ nullptr);
172     if (numFailedPixels)
173     {
174         const int numTotalPixels = width * height;
175         auto &log                = m_context.getTestContext().getLog();
176         const auto formatName    = de::toLower(std::string(getFormatName(m_params->format)).substr(10));
177 
178         log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels
179             << " invalid pixels!" << tcu::TestLog::EndMessage;
180         log << tcu::TestLog::Message << "       " << float(numFailedPixels * 100) / float(numTotalPixels)
181             << "% failed from " << numTotalPixels << " compared pixel count." << tcu::TestLog::EndMessage;
182         log << tcu::TestLog::Message << "       ColorThreshold: " << lookupPrec.colorThreshold
183             << ", ColorMask: " << lookupPrec.colorMask << tcu::TestLog::EndMessage;
184 
185         log << tcu::TestLog::ImageSet("VerifyResult", "Verification result");
186         {
187             log << tcu::TestLog::Image("Res_" + formatName, "Rendered image", rendered);
188             log << tcu::TestLog::Image("Ref_" + formatName, "Reference image", reference);
189             log << tcu::TestLog::Image("Err_" + formatName, "Error mask image", errorMask);
190         }
191         log << tcu::TestLog::EndImageSet;
192     }
193 
194     int numOutOfRangePixels = 0;
195     for (int y = 0; y < height; ++y)
196     {
197         for (int x = 0; x < width; ++x)
198         {
199             const auto px = rendered.getPixel(x, y);
200             if (tcu::boolAny(tcu::lessThan(px, tcu::Vec4(-1.0f))) ||
201                 tcu::boolAny(tcu::greaterThan(px, tcu::Vec4(+1.0f))))
202                 ++numOutOfRangePixels;
203         }
204     }
205 
206     if (numOutOfRangePixels)
207     {
208         auto &log = m_context.getTestContext().getLog();
209         log << tcu::TestLog::Message << "ERROR: Found " << numOutOfRangePixels << " out of range [-1.0f, +1.0f]."
210             << tcu::TestLog::EndMessage;
211     }
212 
213     return (numFailedPixels == 0 && numOutOfRangePixels == 0);
214 }
215 
iterate(void)216 tcu::TestStatus SnormLinearClampInstance::iterate(void)
217 {
218     std::vector<float> texCoords(8);
219     ReferenceParams samplerParams(TEXTURETYPE_2D);
220     tcu::TextureFormat resultFormat(mapVkFormat(m_outFormat));
221 
222     // Setup renderers.
223     const int width(m_renderer.getRenderWidth());
224     const int height(m_renderer.getRenderHeight());
225     std::unique_ptr<uint8_t[]> renderedData(new uint8_t[width * height * 4 * 4]);
226     std::unique_ptr<uint8_t[]> referenceData(new uint8_t[width * height * 4 * 4]);
227     tcu::PixelBufferAccess rendered(resultFormat, width, height, 1, renderedData.get());
228     tcu::PixelBufferAccess reference(resultFormat, width, height, 1, referenceData.get());
229 
230     // Setup sampler params.
231     samplerParams.sampler =
232         util::createSampler(tcu::Sampler::WrapMode::REPEAT_GL, tcu::Sampler::WrapMode::REPEAT_GL,
233                             tcu::Sampler::FilterMode::LINEAR, tcu::Sampler::FilterMode::LINEAR, true);
234     samplerParams.samplerType = SAMPLERTYPE_FLOAT;
235     samplerParams.lodMode     = LODMODE_EXACT;
236     samplerParams.colorScale  = tcu::Vec4(1.0f);
237     samplerParams.colorBias   = tcu::Vec4(0.0f);
238 
239     // Compute texture coordinates.
240     computeQuadTexCoord2D(texCoords, tcu::Vec2(0.0f), tcu::Vec2(1.0f));
241 
242     // Peform online rendering with Vulkan.
243     m_renderer.renderQuad(rendered, 0, texCoords.data(), samplerParams);
244 
245     // Perform offline rendering with software renderer.
246     sampleTexture(reference, m_swTexture, texCoords.data(), samplerParams);
247 
248     return verifyPixels(rendered, reference, samplerParams, texCoords) ?
249                tcu::TestStatus::pass("") :
250                tcu::TestStatus::fail("Pixels verification failed");
251 }
252 
253 class SnormLinearClampTestCase : public TestCase
254 {
255 public:
256     using ParamsSp = de::SharedPtr<SnormLinearClampInstance::Params>;
257 
SnormLinearClampTestCase(tcu::TestContext & testCtx,const std::string & name,ParamsSp params)258     SnormLinearClampTestCase(tcu::TestContext &testCtx, const std::string &name, ParamsSp params)
259         : TestCase(testCtx, name)
260         , m_params(params)
261     {
262     }
263 
createInstance(vkt::Context & context) const264     vkt::TestInstance *createInstance(vkt::Context &context) const override
265     {
266         return new SnormLinearClampInstance(context, m_params);
267     }
268 
checkSupport(vkt::Context & context) const269     virtual void checkSupport(vkt::Context &context) const override
270     {
271         VkFormatProperties formatProperties;
272 
273         context.getInstanceInterface().getPhysicalDeviceFormatProperties(context.getPhysicalDevice(), m_params->format,
274                                                                          &formatProperties);
275 
276         if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT))
277             TCU_THROW(NotSupportedError, "Linear filtering for this image format is not supported");
278     }
279 
initPrograms(SourceCollections & programCollection) const280     virtual void initPrograms(SourceCollections &programCollection) const override
281     {
282         initializePrograms(programCollection, glu::Precision::PRECISION_HIGHP, std::vector<Program>({PROGRAM_2D_FLOAT}),
283                            DE_NULL, glu::Precision::PRECISION_HIGHP);
284     }
285 
286 private:
287     ParamsSp m_params;
288 };
289 
populateUfloatNegativeValuesTests(tcu::TestCaseGroup * group)290 void populateUfloatNegativeValuesTests(tcu::TestCaseGroup *group)
291 {
292 #ifndef CTS_USES_VULKANSC
293     tcu::TestContext &testCtx = group->getTestContext();
294     VkImageUsageFlags usage =
295         VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT;
296 
297     VkImageCreateInfo info = {
298         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType          sType
299         DE_NULL,                             // const void*              pNext
300         0,                                   // VkImageCreateFlags       flags
301         VK_IMAGE_TYPE_2D,                    // VkImageType              imageType
302         VK_FORMAT_B10G11R11_UFLOAT_PACK32,   // VkFormat                 format
303         {50u, 50u, 1u},                      // VkExtent3D               extent
304         1u,                                  // uint32_t                 mipLevels
305         1u,                                  // uint32_t                 arrayLayers
306         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits    samples
307         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling            tiling
308         usage,                               // VkImageUsageFlags        usage
309         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode            sharingMode
310         0u,                                  // uint32_t                 queueFamilyIndexCount
311         DE_NULL,                             // const uint32_t*          pQueueFamilyIndices
312         VK_IMAGE_LAYOUT_UNDEFINED            // VkImageLayout            initialLayout
313     };
314 
315     group->addChild(cts_amber::createAmberTestCase(testCtx, "b10g11r11", "texture/conversion/ufloat_negative_values",
316                                                    "b10g11r11-ufloat-pack32.amber", std::vector<std::string>(),
317                                                    std::vector<VkImageCreateInfo>(1, info)));
318 #else
319     DE_UNREF(group);
320 #endif
321 }
322 
populateSnormClampTests(tcu::TestCaseGroup * group)323 void populateSnormClampTests(tcu::TestCaseGroup *group)
324 {
325 #ifndef CTS_USES_VULKANSC
326     tcu::TestContext &testCtx = group->getTestContext();
327     VkImageUsageFlags usage =
328         VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
329 
330     VkImageCreateInfo info = {
331         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType          sType
332         DE_NULL,                             // const void*              pNext
333         0,                                   // VkImageCreateFlags       flags
334         VK_IMAGE_TYPE_1D,                    // VkImageType              imageType
335         VK_FORMAT_UNDEFINED,                 // VkFormat                 format
336         {1u, 1u, 1u},                        // VkExtent3D               extent
337         1u,                                  // uint32_t                 mipLevels
338         1u,                                  // uint32_t                 arrayLayers
339         VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits    samples
340         VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling            tiling
341         usage,                               // VkImageUsageFlags        usage
342         VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode            sharingMode
343         0u,                                  // uint32_t                 queueFamilyIndexCount
344         DE_NULL,                             // const uint32_t*          pQueueFamilyIndices
345         VK_IMAGE_LAYOUT_UNDEFINED            // VkImageLayout            initialLayout
346     };
347 
348     struct TestParams
349     {
350         std::string testName;
351         std::string amberFile;
352         VkFormat format;
353     } params[] = {
354         {"a2b10g10r10_snorm_pack32", "a2b10g10r10-snorm-pack32.amber", VK_FORMAT_A2B10G10R10_SNORM_PACK32},
355         {"a2r10g10b10_snorm_pack32", "a2r10g10b10-snorm-pack32.amber", VK_FORMAT_A2R10G10B10_SNORM_PACK32},
356         {"a8b8g8r8_snorm_pack32", "a8b8g8r8-snorm-pack32.amber", VK_FORMAT_A8B8G8R8_SNORM_PACK32},
357         {"b8g8r8a8_snorm", "b8g8r8a8-snorm.amber", VK_FORMAT_B8G8R8A8_SNORM},
358         {"b8g8r8_snorm", "b8g8r8-snorm.amber", VK_FORMAT_B8G8R8_SNORM},
359         {"r16g16b16a16_snorm", "r16g16b16a16-snorm.amber", VK_FORMAT_R16G16B16A16_SNORM},
360         {"r16g16b16_snorm", "r16g16b16-snorm.amber", VK_FORMAT_R16G16B16_SNORM},
361         {"r16g16_snorm", "r16g16-snorm.amber", VK_FORMAT_R16G16_SNORM},
362         {"r16_snorm", "r16-snorm.amber", VK_FORMAT_R16_SNORM},
363         {"r8g8b8a8_snorm", "r8g8b8a8-snorm.amber", VK_FORMAT_R8G8B8A8_SNORM},
364         {"r8g8b8_snorm", "r8g8b8-snorm.amber", VK_FORMAT_R8G8B8_SNORM},
365         {"r8g8_snorm", "r8g8-snorm.amber", VK_FORMAT_R8G8_SNORM},
366         {"r8_snorm", "r8-snorm.amber", VK_FORMAT_R8_SNORM},
367     };
368 
369     for (const auto &param : params)
370     {
371         info.format = param.format;
372         group->addChild(cts_amber::createAmberTestCase(
373             testCtx, param.testName.c_str(), "texture/conversion/snorm_clamp", param.amberFile.c_str(),
374             std::vector<std::string>(), std::vector<VkImageCreateInfo>(1, info)));
375     }
376 #else
377     DE_UNREF(group);
378 #endif
379 }
380 
populateSnormLinearClampTests(tcu::TestCaseGroup * group)381 void populateSnormLinearClampTests(tcu::TestCaseGroup *group)
382 {
383     struct TestParams
384     {
385         std::string testName;
386         VkFormat format;
387     } testParams[] = {
388         {"a2b10g10r10_snorm_pack32", VK_FORMAT_A2B10G10R10_SNORM_PACK32},
389         {"a2r10g10b10_snorm_pack32", VK_FORMAT_A2R10G10B10_SNORM_PACK32},
390         {"a8b8g8r8_snorm_pack32", VK_FORMAT_A8B8G8R8_SNORM_PACK32},
391         {"b8g8r8a8_snorm", VK_FORMAT_B8G8R8A8_SNORM},
392         {"b8g8r8_snorm", VK_FORMAT_B8G8R8_SNORM},
393         {"r16g16b16a16_snorm", VK_FORMAT_R16G16B16A16_SNORM},
394         {"r16g16b16_snorm", VK_FORMAT_R16G16B16_SNORM},
395         {"r16g16_snorm", VK_FORMAT_R16G16_SNORM},
396         {"r16_snorm", VK_FORMAT_R16_SNORM},
397         {"r8g8b8a8_snorm", VK_FORMAT_R8G8B8A8_SNORM},
398         {"r8g8b8_snorm", VK_FORMAT_R8G8B8_SNORM},
399         {"r8g8_snorm", VK_FORMAT_R8G8_SNORM},
400         {"r8_snorm", VK_FORMAT_R8_SNORM},
401     };
402 
403     tcu::TestContext &testCtx = group->getTestContext();
404     int sizeMultipler         = 20;
405 
406     for (const auto &testParam : testParams)
407     {
408         const int tw = SnormLinearClampInstance::textureWidth * sizeMultipler;
409         const int th = SnormLinearClampInstance::textureHeight * sizeMultipler;
410 
411         de::SharedPtr<SnormLinearClampInstance::Params> params(
412             new SnormLinearClampInstance::Params{testParam.format, tw, th});
413         group->addChild(new SnormLinearClampTestCase(testCtx, testParam.testName, params));
414 
415         sizeMultipler += 2;
416     }
417 }
418 
populateTextureConversionTests(tcu::TestCaseGroup * group)419 void populateTextureConversionTests(tcu::TestCaseGroup *group)
420 {
421     tcu::TestContext &testCtx = group->getTestContext();
422 
423     // Tests for converting negative floats to unsigned floats
424     group->addChild(createTestGroup(testCtx, "ufloat_negative_values", populateUfloatNegativeValuesTests));
425     // Tests for SNORM corner cases when smallest negative number gets clamped to -1
426     group->addChild(createTestGroup(testCtx, "snorm_clamp", populateSnormClampTests));
427     // Tests for SNORM corner cases when negative number gets clamped to -1 after applying linear filtering
428     group->addChild(createTestGroup(testCtx, "snorm_clamp_linear", populateSnormLinearClampTests));
429 }
430 
431 } // anonymous namespace
432 
createTextureConversionTests(tcu::TestContext & testCtx)433 tcu::TestCaseGroup *createTextureConversionTests(tcu::TestContext &testCtx)
434 {
435     return createTestGroup(testCtx, "conversion", populateTextureConversionTests);
436 }
437 
438 } // namespace texture
439 } // namespace vkt
440