• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  * Copyright (c) 2016 The Android Open Source Project
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 Image OpImageWrite tests.
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktImageMismatchedWriteOpTests.hpp"
26 
27 #include "vktImageTexture.hpp"
28 #include "vkImageUtil.hpp"
29 #include "vkBuilderUtil.hpp"
30 #include "vkObjUtil.hpp"
31 #include "vktImageTestsUtil.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "vkBarrierUtil.hpp"
35 
36 #include "tcuStringTemplate.hpp"
37 #include "tcuTexture.hpp"
38 #include "tcuTextureUtil.hpp"
39 
40 #include <set>
41 
42 #define EPSILON_COMPARE(a, b, e) ((de::max((a), (b)) - de::min((a), (b))) <= (e))
43 
44 using namespace vk;
45 
46 namespace vkt
47 {
48 namespace image
49 {
50 namespace
51 {
52 
53 using tcu::StringTemplate;
54 using tcu::TextureChannelClass;
55 using tcu::TextureFormat;
56 using strings = std::map<std::string, std::string>;
57 
58 class MismatchedWriteOpTest : public TestCase
59 {
60 public:
61     struct Params
62     {
63         VkFormat vkFormat;
64         int textureWidth;
65         int textureHeight;
66         VkFormat spirvFormat;
67     };
68     typedef de::SharedPtr<Params> ParamsSp;
69 
MismatchedWriteOpTest(tcu::TestContext & testCtx,const std::string & name,const ParamsSp params)70     MismatchedWriteOpTest(tcu::TestContext &testCtx, const std::string &name, const ParamsSp params)
71         : TestCase(testCtx, name)
72         , m_params(params)
73     {
74     }
75 
76     virtual void checkSupport(Context &context) const override;
77     virtual TextureFormat getBufferFormat(void) const;
78     void getProgramCodeAndVariables(StringTemplate &code, strings &variables) const;
79 
80     template <class TestParams>
81     void getParams(TestParams &);
82 
83 protected:
84     const ParamsSp m_params;
85 };
86 
87 class MismatchedVectorSizesTest : public MismatchedWriteOpTest
88 {
89 public:
MismatchedVectorSizesTest(tcu::TestContext & testCtx,const std::string & name,const ParamsSp params,const int sourceWidth)90     MismatchedVectorSizesTest(tcu::TestContext &testCtx, const std::string &name, const ParamsSp params,
91                               const int sourceWidth)
92         : MismatchedWriteOpTest(testCtx, name, params)
93         , m_sourceWidth(sourceWidth)
94     {
95         DE_ASSERT(getNumUsedChannels(params->vkFormat) <= sourceWidth);
96     }
97 
98     virtual void initPrograms(SourceCollections &programCollection) const override;
99     virtual TestInstance *createInstance(Context &context) const override;
100 
101 private:
102     const int m_sourceWidth;
103 };
104 
105 class MismatchedSignednessAndTypeTest : public MismatchedWriteOpTest
106 {
107 public:
MismatchedSignednessAndTypeTest(tcu::TestContext & testCtx,const std::string & name,const ParamsSp params)108     MismatchedSignednessAndTypeTest(tcu::TestContext &testCtx, const std::string &name, const ParamsSp params)
109         : MismatchedWriteOpTest(testCtx, name, params)
110     {
111     }
112 
113     virtual void initPrograms(SourceCollections &programCollection) const override;
114     virtual TestInstance *createInstance(Context &context) const override;
115 };
116 
117 class MismatchedWriteOpTestInstance : public TestInstance
118 {
119 public:
120     using TestClass = MismatchedWriteOpTest;
121     using ParamsSp  = MismatchedWriteOpTest::ParamsSp;
122 
MismatchedWriteOpTestInstance(Context & context,const ParamsSp params,const TestClass * test)123     MismatchedWriteOpTestInstance(Context &context, const ParamsSp params, const TestClass *test)
124         : TestInstance(context)
125         , m_params(params)
126         , m_test(test)
127     {
128     }
129 
130     virtual tcu::TestStatus iterate(void) override;
131     virtual void clear(tcu::PixelBufferAccess &data) const;
132     virtual void populate(tcu::PixelBufferAccess &data) const;
133     virtual bool compare(tcu::PixelBufferAccess &result, tcu::PixelBufferAccess &reference) const = 0;
134 
135 protected:
136     const ParamsSp m_params;
137     const TestClass *m_test;
138 };
139 
140 class MismatchedVectorSizesTestInstance : public MismatchedWriteOpTestInstance
141 {
142 public:
MismatchedVectorSizesTestInstance(Context & context,const ParamsSp params,const TestClass * test)143     MismatchedVectorSizesTestInstance(Context &context, const ParamsSp params, const TestClass *test)
144         : MismatchedWriteOpTestInstance(context, params, test)
145     {
146     }
147 
148     bool compare(tcu::PixelBufferAccess &result, tcu::PixelBufferAccess &reference) const override;
149 };
150 
151 class MismatchedSignednessAndTypeTestInstance : public MismatchedWriteOpTestInstance
152 {
153 public:
MismatchedSignednessAndTypeTestInstance(Context & context,const ParamsSp params,const TestClass * test)154     MismatchedSignednessAndTypeTestInstance(Context &context, const ParamsSp params, const TestClass *test)
155         : MismatchedWriteOpTestInstance(context, params, test)
156     {
157     }
158 
159     bool compare(tcu::PixelBufferAccess &result, tcu::PixelBufferAccess &reference) const override;
160 };
161 
162 namespace ut
163 {
164 
165 class StorageBuffer2D
166 {
167 public:
168     StorageBuffer2D(Context &context, const tcu::TextureFormat &format, uint32_t width, uint32_t height);
169 
getBuffer(void) const170     VkBuffer getBuffer(void) const
171     {
172         return *m_buffer;
173     }
getSize(void) const174     VkDeviceSize getSize(void) const
175     {
176         return m_bufferSize;
177     }
178 
getPixelAccess(void)179     tcu::PixelBufferAccess &getPixelAccess(void)
180     {
181         return m_access[0];
182     }
183 
flush(void)184     void flush(void)
185     {
186         flushAlloc(m_context.getDeviceInterface(), m_context.getDevice(), *m_bufferMemory);
187     }
invalidate(void)188     void invalidate(void)
189     {
190         invalidateAlloc(m_context.getDeviceInterface(), m_context.getDevice(), *m_bufferMemory);
191     }
192 
193 protected:
194     friend class StorageImage2D;
getMemory(void) const195     Allocation &getMemory(void) const
196     {
197         return *m_bufferMemory;
198     }
199 
200 private:
201     Context &m_context;
202     const tcu::TextureFormat m_format;
203     const uint32_t m_width;
204     const uint32_t m_height;
205     const VkDeviceSize m_bufferSize;
206     Move<VkBuffer> m_buffer;
207     de::MovePtr<Allocation> m_bufferMemory;
208     std::vector<tcu::PixelBufferAccess> m_access;
209 };
210 
211 class StorageImage2D
212 {
213 public:
214     StorageImage2D(Context &context, VkFormat vkFormat, const int width, const int height, bool sparse = false);
215 
getView(void) const216     VkImageView getView(void) const
217     {
218         return *m_view;
219     }
220 
getPixelAccess(void)221     tcu::PixelBufferAccess &getPixelAccess(void)
222     {
223         return m_buffer.getPixelAccess();
224     }
225 
flush(void)226     void flush(void)
227     {
228         m_buffer.flush();
229     }
invalidate(void)230     void invalidate(void)
231     {
232         m_buffer.invalidate();
233     }
234 
235     void upload(const VkCommandBuffer cmdBuffer);
236     void download(const VkCommandBuffer cmdBuffer);
237 
238 private:
239     Context &m_context;
240     const bool m_sparse;
241     const int m_width;
242     const int m_height;
243     const vk::VkFormat m_vkFormat;
244     const tcu::TextureFormat m_texFormat;
245     StorageBuffer2D m_buffer;
246 
247     VkImageLayout m_layout;
248     Move<VkImage> m_image;
249     Move<VkImageView> m_view;
250     Move<VkSemaphore> m_semaphore;
251     std::vector<de::SharedPtr<Allocation>> m_allocations;
252     de::MovePtr<Allocation> m_imageMemory;
253 };
254 
StorageImage2D(Context & context,VkFormat vkFormat,const int width,const int height,bool sparse)255 StorageImage2D::StorageImage2D(Context &context, VkFormat vkFormat, const int width, const int height, bool sparse)
256     : m_context(context)
257     , m_sparse(sparse)
258     , m_width(width)
259     , m_height(height)
260     , m_vkFormat(vkFormat)
261     , m_texFormat(mapVkFormat(m_vkFormat))
262     , m_buffer(m_context, m_texFormat, m_width, m_height)
263 {
264     const DeviceInterface &vki      = m_context.getDeviceInterface();
265     const VkDevice dev              = m_context.getDevice();
266     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
267     Allocator &allocator            = m_context.getDefaultAllocator();
268 
269     // Create an image
270     {
271         VkImageCreateFlags imageCreateFlags =
272             m_sparse ? (VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) : 0u;
273         VkImageUsageFlags imageUsageFlags =
274             VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
275 
276         const VkImageCreateInfo imageCreateInfo = {
277             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,         // VkStructureType sType;
278             nullptr,                                     // const void* pNext;
279             imageCreateFlags,                            // VkImageCreateFlags flags;
280             VK_IMAGE_TYPE_2D,                            // VkImageType imageType;
281             m_vkFormat,                                  // VkFormat format;
282             {uint32_t(m_width), uint32_t(m_height), 1u}, // VkExtent3D extent;
283             1u,                                          // uint32_t mipLevels;
284             1u,                                          // uint32_t arrayLayers;
285             VK_SAMPLE_COUNT_1_BIT,                       // VkSampleCountFlagBits samples;
286             VK_IMAGE_TILING_OPTIMAL,                     // VkImageTiling tiling;
287             imageUsageFlags,                             // VkImageUsageFlags usage;
288             VK_SHARING_MODE_EXCLUSIVE,                   // VkSharingMode sharingMode;
289             1u,                                          // uint32_t queueFamilyIndexCount;
290             &queueFamilyIndex,                           // const uint32_t* pQueueFamilyIndices;
291             (m_layout = VK_IMAGE_LAYOUT_UNDEFINED)       // VkImageLayout initialLayout;
292         };
293 
294         m_image = createImage(vki, dev, &imageCreateInfo);
295 
296         if (m_sparse)
297         {
298             m_semaphore = createSemaphore(vki, dev);
299 
300 #ifndef CTS_USES_VULKANSC
301             allocateAndBindSparseImage(vki, dev, m_context.getPhysicalDevice(), m_context.getInstanceInterface(),
302                                        imageCreateInfo, *m_semaphore, m_context.getSparseQueue(), allocator,
303                                        m_allocations, mapVkFormat(m_vkFormat), *m_image);
304 #endif // CTS_USES_VULKANSC
305         }
306         else
307         {
308             m_imageMemory = allocator.allocate(getImageMemoryRequirements(vki, dev, *m_image), MemoryRequirement::Any);
309             VK_CHECK(vki.bindImageMemory(dev, *m_image, m_imageMemory->getMemory(), m_imageMemory->getOffset()));
310         }
311 
312         VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
313         m_view = makeImageView(vki, dev, *m_image, VK_IMAGE_VIEW_TYPE_2D, m_vkFormat, subresourceRange);
314     }
315 }
316 
upload(const VkCommandBuffer cmdBuffer)317 void StorageImage2D::upload(const VkCommandBuffer cmdBuffer)
318 {
319     const DeviceInterface &vki = m_context.getDeviceInterface();
320     const VkImageSubresourceRange fullImageSubresourceRange =
321         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
322     const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(tcu::IVec3(m_width, m_height, 1)), 1u);
323 
324     {
325         const VkBufferMemoryBarrier bufferBarrier = makeBufferMemoryBarrier(
326             VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, m_buffer.getBuffer(), 0ull, m_buffer.getSize());
327 
328         const VkImageMemoryBarrier beforeCopyBarrier =
329             makeImageMemoryBarrier((VkAccessFlagBits)0, VK_ACCESS_TRANSFER_WRITE_BIT, m_layout,
330                                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, *m_image, fullImageSubresourceRange);
331 
332         vki.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
333                                (VkDependencyFlags)0, 0, nullptr, 1, &bufferBarrier, 1, &beforeCopyBarrier);
334     }
335 
336     vki.cmdCopyBufferToImage(cmdBuffer, m_buffer.getBuffer(), *m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u,
337                              &copyRegion);
338 
339     {
340         const VkBufferMemoryBarrier bufferBarrier = makeBufferMemoryBarrier(
341             VK_ACCESS_TRANSFER_READ_BIT, (VkAccessFlags)0, m_buffer.getBuffer(), 0ull, m_buffer.getSize());
342 
343         m_layout = VK_IMAGE_LAYOUT_GENERAL;
344         const VkImageMemoryBarrier afterCopyBarrier =
345             makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT,
346                                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, m_layout, *m_image, fullImageSubresourceRange);
347 
348         vki.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
349                                (VkDependencyFlags)0, 0, nullptr, 1, &bufferBarrier, 1, &afterCopyBarrier);
350     }
351 }
352 
download(const VkCommandBuffer cmdBuffer)353 void StorageImage2D::download(const VkCommandBuffer cmdBuffer)
354 {
355     const DeviceInterface &vki = m_context.getDeviceInterface();
356     const VkImageSubresourceRange fullImageSubresourceRange =
357         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
358     const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(tcu::IVec3(m_width, m_height, 1)), 1u);
359 
360     {
361         const VkBufferMemoryBarrier bufferBarrier = makeBufferMemoryBarrier(
362             (VkAccessFlags)0, VK_ACCESS_TRANSFER_WRITE_BIT, m_buffer.getBuffer(), 0ull, m_buffer.getSize());
363 
364         const VkImageMemoryBarrier beforeCopyBarrier =
365             makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, m_layout,
366                                    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *m_image, fullImageSubresourceRange);
367 
368         vki.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
369                                (VkDependencyFlags)0, 0, nullptr, 1, &bufferBarrier, 1, &beforeCopyBarrier);
370     }
371 
372     vki.cmdCopyImageToBuffer(cmdBuffer, *m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_buffer.getBuffer(), 1,
373                              &copyRegion);
374 
375     {
376         const VkBufferMemoryBarrier bufferBarrier = makeBufferMemoryBarrier(
377             VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, m_buffer.getBuffer(), 0ull, m_buffer.getSize());
378 
379         const VkImageMemoryBarrier afterCopyBarrier =
380             makeImageMemoryBarrier(VK_ACCESS_TRANSFER_READ_BIT, (VkAccessFlags)0, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
381                                    m_layout, *m_image, fullImageSubresourceRange);
382 
383         vki.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
384                                (VkDependencyFlags)0, 0, nullptr, 1, &bufferBarrier, 1, &afterCopyBarrier);
385     }
386 }
387 
StorageBuffer2D(Context & context,const tcu::TextureFormat & format,uint32_t width,uint32_t height)388 StorageBuffer2D::StorageBuffer2D(Context &context, const tcu::TextureFormat &format, uint32_t width, uint32_t height)
389     : m_context(context)
390     , m_format(format)
391     , m_width(width)
392     , m_height(height)
393     , m_bufferSize(m_width * m_height * m_format.getPixelSize())
394 {
395     const DeviceInterface &vki      = m_context.getDeviceInterface();
396     const VkDevice dev              = m_context.getDevice();
397     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
398     Allocator &allocator            = m_context.getDefaultAllocator();
399 
400     const VkBufferUsageFlags bufferUsageFlags =
401         VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
402 
403     const VkBufferCreateInfo bufferCreateInfo = {
404         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
405         nullptr,                              // const void* pNext;
406         0u,                                   // VkBufferCreateFlags flags;
407         m_bufferSize,                         // VkDeviceSize size;
408         bufferUsageFlags,                     // VkBufferUsageFlags usage;
409         VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
410         1u,                                   // uint32_t queueFamilyIndexCount;
411         &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
412     };
413 
414     m_buffer = createBuffer(vki, dev, &bufferCreateInfo);
415 
416     m_bufferMemory =
417         allocator.allocate(getBufferMemoryRequirements(vki, dev, *m_buffer), MemoryRequirement::HostVisible);
418     VK_CHECK(vki.bindBufferMemory(dev, *m_buffer, m_bufferMemory->getMemory(), m_bufferMemory->getOffset()));
419 
420     m_access.emplace_back(m_format, tcu::IVec3(m_width, m_height, 1), m_bufferMemory->getHostPtr());
421 }
422 
gluePixels(const tcu::Vec4 & a,const tcu::Vec4 & b,const int pivot)423 tcu::Vec4 gluePixels(const tcu::Vec4 &a, const tcu::Vec4 &b, const int pivot)
424 {
425     tcu::Vec4 result;
426     for (int i = 0; i < pivot; ++i)
427         result[i] = a[i];
428     for (int i = pivot; i < 4; ++i)
429         result[i] = b[i];
430     return result;
431 }
432 
433 template <class T, int N>
comparePixels(const tcu::Vector<T,N> & res,const tcu::Vector<T,N> & ref,const int targetWidth,const T eps={})434 bool comparePixels(const tcu::Vector<T, N> &res, const tcu::Vector<T, N> &ref, const int targetWidth, const T eps = {})
435 {
436     bool ok = true;
437 
438     for (int i = 0; ok && i < targetWidth; ++i)
439     {
440         ok &= EPSILON_COMPARE(res[i], ref[i], eps);
441     }
442 
443     return ok;
444 }
445 
446 } // namespace ut
447 
createInstance(Context & context) const448 TestInstance *MismatchedVectorSizesTest::createInstance(Context &context) const
449 {
450     return (new MismatchedVectorSizesTestInstance(context, m_params, this));
451 }
452 
createInstance(Context & context) const453 TestInstance *MismatchedSignednessAndTypeTest::createInstance(Context &context) const
454 {
455     return (new MismatchedSignednessAndTypeTestInstance(context, m_params, this));
456 }
457 
458 const VkFormat allFormats[] = {
459     VK_FORMAT_R32G32B32A32_SFLOAT,
460     VK_FORMAT_R32G32_SFLOAT,
461     VK_FORMAT_R32_SFLOAT,
462     VK_FORMAT_R16G16B16A16_SFLOAT,
463     VK_FORMAT_R16G16_SFLOAT,
464     VK_FORMAT_R16_SFLOAT,
465     VK_FORMAT_R16G16B16A16_UNORM,
466     VK_FORMAT_R16G16_UNORM,
467     VK_FORMAT_R16_UNORM,
468     VK_FORMAT_R16G16B16A16_SNORM,
469     VK_FORMAT_R16G16_SNORM,
470     VK_FORMAT_R16_SNORM,
471     VK_FORMAT_A2B10G10R10_UNORM_PACK32,
472     VK_FORMAT_B10G11R11_UFLOAT_PACK32,
473     VK_FORMAT_R8G8B8A8_UNORM,
474     VK_FORMAT_R8G8_UNORM,
475     VK_FORMAT_R8_UNORM,
476     VK_FORMAT_R8G8B8A8_SNORM,
477     VK_FORMAT_R8G8_SNORM,
478     VK_FORMAT_R8_SNORM,
479     VK_FORMAT_R32G32B32A32_SINT,
480     VK_FORMAT_R32G32_SINT,
481     VK_FORMAT_R32_SINT,
482     VK_FORMAT_R16G16B16A16_SINT,
483     VK_FORMAT_R16G16_SINT,
484     VK_FORMAT_R16_SINT,
485     VK_FORMAT_R8G8B8A8_SINT,
486     VK_FORMAT_R8G8_SINT,
487     VK_FORMAT_R8_SINT,
488     VK_FORMAT_R32G32B32A32_UINT,
489     VK_FORMAT_R32G32_UINT,
490     VK_FORMAT_R32_UINT,
491     VK_FORMAT_R16G16B16A16_UINT,
492     VK_FORMAT_R16G16_UINT,
493     VK_FORMAT_R16_UINT,
494     VK_FORMAT_A2B10G10R10_UINT_PACK32,
495     VK_FORMAT_R8G8B8A8_UINT,
496     VK_FORMAT_R8G8_UINT,
497     VK_FORMAT_R8_UINT,
498 
499     VK_FORMAT_R64_SINT,
500     VK_FORMAT_R64_UINT,
501 };
502 
findFormatsByChannelClass(TextureChannelClass channelClass)503 std::vector<VkFormat> findFormatsByChannelClass(TextureChannelClass channelClass)
504 {
505     std::vector<VkFormat> result;
506     for (const VkFormat &f : allFormats)
507     {
508         if (getTextureChannelClass(mapVkFormat(f).type) == channelClass)
509             result.emplace_back(f);
510     }
511     DE_ASSERT(!result.empty());
512     return result;
513 }
514 
getChannelStr(const TextureFormat::ChannelType & type)515 const char *getChannelStr(const TextureFormat::ChannelType &type)
516 {
517     switch (type)
518     {
519     case TextureFormat::FLOAT:
520         return "float";
521     case TextureFormat::SIGNED_INT32:
522         return "sint";
523     case TextureFormat::UNSIGNED_INT32:
524         return "uint";
525     case TextureFormat::FLOAT64:
526         return "double";
527     case TextureFormat::SIGNED_INT64:
528         return "slong";
529     case TextureFormat::UNSIGNED_INT64:
530         return "ulong";
531     default:
532         DE_ASSERT(false);
533     }
534 
535     return nullptr;
536 }
537 
makeChannelType(tcu::TextureChannelClass channelClass,bool doubled)538 TextureFormat::ChannelType makeChannelType(tcu::TextureChannelClass channelClass, bool doubled)
539 {
540     auto channelType = TextureFormat::ChannelType::CHANNELTYPE_LAST;
541     switch (channelClass)
542     {
543     case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
544         channelType = doubled ? TextureFormat::ChannelType::SIGNED_INT64 : TextureFormat::ChannelType::SIGNED_INT32;
545         break;
546     case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
547         channelType = doubled ? TextureFormat::ChannelType::UNSIGNED_INT64 : TextureFormat::ChannelType::UNSIGNED_INT32;
548         break;
549     default:
550         channelType = doubled ? TextureFormat::ChannelType::FLOAT64 : TextureFormat::ChannelType::FLOAT;
551     }
552     return channelType;
553 }
554 
makeBufferFormat(tcu::TextureChannelClass channelClass,bool doubled)555 TextureFormat makeBufferFormat(tcu::TextureChannelClass channelClass, bool doubled)
556 {
557     return TextureFormat(TextureFormat::ChannelOrder::RGBA, makeChannelType(channelClass, doubled));
558 }
559 
checkSupport(Context & context) const560 void MismatchedWriteOpTest::checkSupport(Context &context) const
561 {
562     // capabilities that may be used in the shader
563     if (is64BitIntegerFormat(m_params->vkFormat))
564     {
565         const VkPhysicalDeviceFeatures deviceFeatures =
566             getPhysicalDeviceFeatures(context.getInstanceInterface(), context.getPhysicalDevice());
567         if (!deviceFeatures.shaderInt64)
568         {
569             TCU_THROW(NotSupportedError, "Device feature shaderInt64 is not supported");
570         }
571         context.requireDeviceFunctionality("VK_EXT_shader_image_atomic_int64");
572     }
573 
574     // extensions used statically in the shader
575     context.requireDeviceFunctionality("VK_KHR_variable_pointers");
576     context.requireDeviceFunctionality("VK_KHR_storage_buffer_storage_class");
577 
578     VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(
579         context.getInstanceInterface(), context.getPhysicalDevice(), m_params->vkFormat);
580 
581     if ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0)
582     {
583         TCU_THROW(NotSupportedError, "Creating storage image with this format is not supported");
584     }
585 }
586 
getBufferFormat(void) const587 TextureFormat MismatchedWriteOpTest::getBufferFormat(void) const
588 {
589     const TextureFormat texFormat = mapVkFormat(m_params->vkFormat);
590     return makeBufferFormat(getTextureChannelClass(texFormat.type), is64BitIntegerFormat(m_params->vkFormat));
591 }
592 
getProgramCodeAndVariables(StringTemplate & code,strings & variables) const593 void MismatchedWriteOpTest::getProgramCodeAndVariables(StringTemplate &code, strings &variables) const
594 {
595     std::string shaderTemplate(R"(
596 
597                               OpCapability Shader
598                               OpCapability StorageImageExtendedFormats
599 
600                               ${CAPABILITY_INT64}
601                               OpExtension      "SPV_KHR_variable_pointers"
602                               OpExtension      "SPV_KHR_storage_buffer_storage_class"
603                               ${EXTENSIONS}
604 
605                     %std450 = OpExtInstImport  "GLSL.std.450"
606                               OpMemoryModel    Logical GLSL450
607 
608                               OpEntryPoint     GLCompute %main "main" %gid %image %buffer
609                               OpExecutionMode  %main LocalSize 1 1 1
610 
611                               OpDecorate       %gid BuiltIn GlobalInvocationId
612 
613                               OpDecorate       %image DescriptorSet 0
614                               OpDecorate       %image Binding 0
615 
616                               OpDecorate       %rta    ArrayStride ${ARRAY_STRIDE}
617                               OpMemberDecorate %struct 0 Offset 0
618                               OpDecorate       %struct Block
619                               OpDecorate       %buffer DescriptorSet 0
620                               OpDecorate       %buffer Binding 1
621 
622                       %void = OpTypeVoid
623                    %fn_void = OpTypeFunction %void
624 
625                     ${TYPES_INT64}
626 
627                      %float = OpTypeFloat 32
628                       %sint = OpTypeInt 32 1
629                       %uint = OpTypeInt 32 0
630 
631                    %v4float = OpTypeVector %float 4
632                    %v3float = OpTypeVector %float 3
633                    %v2float = OpTypeVector %float 2
634 
635                     %v4sint = OpTypeVector %sint 4
636                     %v3sint = OpTypeVector %sint 3
637                     %v2sint = OpTypeVector %sint 2
638 
639                     %v4uint = OpTypeVector %uint 4
640                     %v3uint = OpTypeVector %uint 3
641                     %v2uint = OpTypeVector %uint 2
642 
643              %v3uint_in_ptr = OpTypePointer Input %v3uint
644                        %gid = OpVariable %v3uint_in_ptr Input
645 
646                 %image_type = OpTypeImage %${SAMPLED_TYPE} 2D 0 0 0 2 ${SPIRV_IMAGE_FORMAT}
647                  %image_ptr = OpTypePointer UniformConstant %image_type
648                      %image = OpVariable %image_ptr UniformConstant
649 
650                %image_width = OpConstant %sint ${IMAGE_WIDTH}
651               %image_height = OpConstant %sint ${IMAGE_HEIGHT}
652 
653                 %rta_offset = OpConstant %uint 0
654                        %rta = OpTypeRuntimeArray %v4${SAMPLED_TYPE}
655                     %struct = OpTypeStruct %rta
656                   %ssbo_ptr = OpTypePointer StorageBuffer %struct
657                     %buffer = OpVariable %ssbo_ptr StorageBuffer
658 
659                 %red_offset = OpConstant %uint 0
660               %green_offset = OpConstant %uint 1
661                %blue_offset = OpConstant %uint 2
662               %alpha_offset = OpConstant %uint 3
663 
664        %${SAMPLED_TYPE}_PTR = OpTypePointer StorageBuffer %${SAMPLED_TYPE}
665               %var_sint_ptr = OpTypePointer Function %sint
666 
667                 ; Entry main procedure
668                       %main = OpFunction %void None %fn_void
669                      %entry = OpLabel
670 
671                      %index = OpVariable %var_sint_ptr Function
672 
673                 ; Transform gl_GlobalInvocationID.xyz to ivec2(gl_GlobalInvocationID.xy)
674                         %id = OpLoad %v3uint %gid
675 
676                     %u_id_x = OpCompositeExtract %uint %id 0
677                     %s_id_x = OpBitcast %sint %u_id_x
678 
679                     %u_id_y = OpCompositeExtract %uint %id 1
680                     %s_id_y = OpBitcast %sint %u_id_y
681 
682                      %id_xy = OpCompositeConstruct %v2sint %s_id_x %s_id_y
683 
684                 ; Calculate index in buffer
685                        %mul = OpIMul %sint %s_id_y %image_width
686                        %add = OpIAdd %sint %mul %s_id_x
687                               OpStore %index %add
688 
689                 ; Final image variable used to read from or write to
690                        %img = OpLoad %image_type %image
691 
692                 ; Accessors to buffer components
693                        %idx = OpLoad %sint %index
694               %alpha_access = OpAccessChain %${SAMPLED_TYPE}_PTR %buffer %rta_offset %idx %alpha_offset
695                %blue_access = OpAccessChain %${SAMPLED_TYPE}_PTR %buffer %rta_offset %idx %blue_offset
696               %green_access = OpAccessChain %${SAMPLED_TYPE}_PTR %buffer %rta_offset %idx %green_offset
697                 %red_access = OpAccessChain %${SAMPLED_TYPE}_PTR %buffer %rta_offset %idx %red_offset
698 
699                        %red = OpLoad %${SAMPLED_TYPE} %red_access
700                      %green = OpLoad %${SAMPLED_TYPE} %green_access
701                       %blue = OpLoad %${SAMPLED_TYPE} %blue_access
702                      %alpha = OpLoad %${SAMPLED_TYPE} %alpha_access
703 
704                               ${WRITE_TO_IMAGE}
705 
706                               OpReturn
707                               OpFunctionEnd
708     )");
709 
710     const std::string typesInt64(R"(
711                      %slong = OpTypeInt 64 1
712                      %ulong = OpTypeInt 64 0
713 
714                    %v4slong = OpTypeVector %slong 4
715                    %v3slong = OpTypeVector %slong 3
716                    %v2slong = OpTypeVector %slong 2
717 
718                    %v4ulong = OpTypeVector %ulong 4
719                    %v3ulong = OpTypeVector %ulong 3
720                    %v2ulong = OpTypeVector %ulong 2
721     )");
722 
723     const tcu::TextureFormat buffFormat = getBufferFormat();
724 
725     variables["SPIRV_IMAGE_FORMAT"] = getSpirvFormat(m_params->vkFormat);
726     variables["CAPABILITY_INT64"]   = "";
727     variables["EXTENSIONS"]         = "";
728     variables["TYPES_INT64"]        = "";
729 
730     if (is64BitIntegerFormat(m_params->vkFormat))
731     {
732         variables["EXTENSIONS"]       = "OpExtension       \"SPV_EXT_shader_image_int64\"";
733         variables["CAPABILITY_INT64"] = "OpCapability Int64ImageEXT\n"
734                                         "OpCapability Int64";
735         variables["TYPES_INT64"]      = typesInt64;
736     }
737 
738     variables["SAMPLED_TYPE"] = getChannelStr(buffFormat.type);
739     variables["IMAGE_WIDTH"]  = std::to_string(m_params->textureWidth);
740     variables["IMAGE_HEIGHT"] = std::to_string(m_params->textureHeight);
741     variables["ARRAY_STRIDE"] =
742         std::to_string(tcu::getChannelSize(buffFormat.type) * tcu::getNumUsedChannels(buffFormat.order));
743 
744     code.setString(shaderTemplate);
745 }
746 
initPrograms(SourceCollections & programCollection) const747 void MismatchedVectorSizesTest::initPrograms(SourceCollections &programCollection) const
748 {
749     strings variables{};
750     StringTemplate shaderTemplate{};
751 
752     const StringTemplate writeFromSingleComponent(R"(
753                      OpImageWrite %img %id_xy %red
754     )");
755     const StringTemplate writeFromTwoComponents(R"(
756                %rg = OpCompositeConstruct %v2${SAMPLED_TYPE} %red %green
757                      OpImageWrite %img %id_xy %rg
758     )");
759 
760     const StringTemplate writeFromThreeComponents(R"(
761               %rgb = OpCompositeConstruct %v3${SAMPLED_TYPE} %red %green %blue
762                      OpImageWrite %img %id_xy %rgb
763     )");
764     const StringTemplate writeFromFourComponents(R"(
765              %rgba = OpCompositeConstruct %v4${SAMPLED_TYPE} %red %green %blue %alpha
766                      OpImageWrite %img %id_xy %rgba
767     )");
768 
769     getProgramCodeAndVariables(shaderTemplate, variables);
770 
771     variables["WRITE_TO_IMAGE"] = (m_sourceWidth == 1 ? writeFromSingleComponent :
772                                    m_sourceWidth == 2 ? writeFromTwoComponents :
773                                    m_sourceWidth == 3 ? writeFromThreeComponents :
774                                                         writeFromFourComponents)
775                                       .specialize(variables);
776     programCollection.spirvAsmSources.add("comp")
777         << shaderTemplate.specialize(variables)
778         << vk::SpirVAsmBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, true);
779 }
780 
initPrograms(SourceCollections & programCollection) const781 void MismatchedSignednessAndTypeTest::initPrograms(SourceCollections &programCollection) const
782 {
783     strings variables{};
784     StringTemplate shaderTemplate{};
785 
786     const StringTemplate writeToImage(R"(
787             %color = OpCompositeConstruct %v4${SAMPLED_TYPE} %red %green %blue %alpha
788                      OpImageWrite %img %id_xy %color
789     )");
790 
791     getProgramCodeAndVariables(shaderTemplate, variables);
792 
793     variables["WRITE_TO_IMAGE"] = writeToImage.specialize(variables);
794 
795     programCollection.spirvAsmSources.add("comp")
796         << shaderTemplate.specialize(variables)
797         << vk::SpirVAsmBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, true);
798 }
799 
clear(tcu::PixelBufferAccess & pixels) const800 void MismatchedWriteOpTestInstance::clear(tcu::PixelBufferAccess &pixels) const
801 {
802     const auto channelClass = tcu::getTextureChannelClass(mapVkFormat(m_params->vkFormat).type);
803     switch (channelClass)
804     {
805     case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
806         tcu::clear(pixels, tcu::IVec4(-1, -2, -3, -4));
807         break;
808 
809     case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
810         tcu::clear(pixels, tcu::UVec4(1, 2, 3, 4));
811         break;
812 
813     default:
814         tcu::clear(pixels, tcu::Vec4(0.2f, 0.3f, 0.4f, 0.5f));
815     }
816 }
817 
populate(tcu::PixelBufferAccess & pixels) const818 void MismatchedWriteOpTestInstance::populate(tcu::PixelBufferAccess &pixels) const
819 {
820     const auto texFormat    = mapVkFormat(m_params->vkFormat);
821     const auto bitDepth     = tcu::getTextureFormatBitDepth(texFormat);
822     const auto channelClass = tcu::getTextureChannelClass(texFormat.type);
823 
824     const tcu::IVec4 signedMinValues(bitDepth[0] ? deIntMinValue32(deMin32(bitDepth[0], 32)) : (-1),
825                                      bitDepth[1] ? deIntMinValue32(deMin32(bitDepth[1], 32)) : (-1),
826                                      bitDepth[2] ? deIntMinValue32(deMin32(bitDepth[2], 32)) : (-1),
827                                      bitDepth[3] ? deIntMinValue32(deMin32(bitDepth[3], 32)) : (-1));
828 
829     const tcu::IVec4 signedMaxValues(bitDepth[0] ? deIntMaxValue32(deMin32(bitDepth[0], 32)) : 1,
830                                      bitDepth[1] ? deIntMaxValue32(deMin32(bitDepth[1], 32)) : 1,
831                                      bitDepth[2] ? deIntMaxValue32(deMin32(bitDepth[2], 32)) : 1,
832                                      bitDepth[3] ? deIntMaxValue32(deMin32(bitDepth[3], 32)) : 1);
833 
834     const tcu::UVec4 unsignedMinValues(0u);
835 
836     const tcu::UVec4 unsignedMaxValues(bitDepth[0] ? deUintMaxValue32(deMin32(bitDepth[0], 32)) : 1u,
837                                        bitDepth[1] ? deUintMaxValue32(deMin32(bitDepth[1], 32)) : 1u,
838                                        bitDepth[2] ? deUintMaxValue32(deMin32(bitDepth[2], 32)) : 1u,
839                                        bitDepth[3] ? deUintMaxValue32(deMin32(bitDepth[3], 32)) : 1u);
840 
841     auto nextSigned = [&](tcu::IVec4 &color)
842     {
843         color[0] = (static_cast<int64_t>(color[0] + 2) < signedMaxValues[0]) ? (color[0] + 2) : signedMinValues[0];
844         color[1] = (static_cast<int64_t>(color[1] + 3) < signedMaxValues[1]) ? (color[1] + 3) : signedMinValues[1];
845         color[2] = (static_cast<int64_t>(color[2] + 5) < signedMaxValues[2]) ? (color[2] + 5) : signedMinValues[2];
846         color[3] = (static_cast<int64_t>(color[3] + 7) < signedMaxValues[3]) ? (color[3] + 7) : signedMinValues[3];
847     };
848 
849     auto nextUnsigned = [&](tcu::UVec4 &color)
850     {
851         color[0] = (static_cast<uint64_t>(color[0] + 2) < unsignedMaxValues[0]) ? (color[0] + 2) : unsignedMinValues[0];
852         color[1] = (static_cast<uint64_t>(color[1] + 3) < unsignedMaxValues[1]) ? (color[1] + 3) : unsignedMinValues[1];
853         color[2] = (static_cast<uint64_t>(color[2] + 5) < unsignedMaxValues[2]) ? (color[2] + 5) : unsignedMinValues[2];
854         color[3] = (static_cast<uint64_t>(color[3] + 7) < unsignedMaxValues[3]) ? (color[3] + 7) : unsignedMinValues[3];
855     };
856 
857     uint64_t floatsData[4];
858     tcu::PixelBufferAccess floatsAccess(texFormat, 1, 1, 1, floatsData);
859     tcu::Vec4 tmpFloats(0.0f);
860 
861     const float divider(static_cast<float>(m_params->textureHeight));
862     const tcu::Vec4 ufloatStep(1.0f / (divider * 1.0f), 1.0f / (divider * 2.0f), 1.0f / (divider * 3.0f),
863                                1.0f / (divider * 5.0f));
864     const tcu::Vec4 sfloatStep(2.0f / (divider * 1.0f), 2.0f / (divider * 2.0f), 2.0f / (divider * 3.0f),
865                                2.0f / (divider * 5.0f));
866 
867     tcu::IVec4 signedColor(0);
868     tcu::UVec4 unsignedColor(0u);
869     tcu::Vec4 ufloatColor(0.0f);
870     tcu::Vec4 sfloatColor(-1.0f);
871 
872     for (int y = 0; y < m_params->textureHeight; ++y)
873     {
874         for (int x = 0; x < m_params->textureWidth; ++x)
875         {
876             switch (channelClass)
877             {
878             case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
879                 pixels.setPixel(signedColor, x, y);
880                 break;
881 
882             case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
883                 pixels.setPixel(unsignedColor, x, y);
884                 break;
885 
886             case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
887                 floatsAccess.setPixel(sfloatColor, 0, 0);
888                 tmpFloats =
889                     ut::gluePixels(floatsAccess.getPixel(0, 0), sfloatColor, tcu::getNumUsedChannels(texFormat.order));
890                 pixels.setPixel(tmpFloats, x, y);
891                 break;
892 
893             // TEXTURECHANNELCLASS_FLOATING_POINT or
894             // TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT
895             default:
896                 floatsAccess.setPixel(ufloatColor, 0, 0);
897                 tmpFloats =
898                     ut::gluePixels(floatsAccess.getPixel(0, 0), ufloatColor, tcu::getNumUsedChannels(texFormat.order));
899                 pixels.setPixel(tmpFloats, x, y);
900                 break;
901             }
902         }
903 
904         nextSigned(signedColor);
905         nextUnsigned(unsignedColor);
906         sfloatColor += sfloatStep;
907         ufloatColor += ufloatStep;
908     }
909 }
910 
iterate(void)911 tcu::TestStatus MismatchedWriteOpTestInstance::iterate(void)
912 {
913     const DeviceInterface &vki      = m_context.getDeviceInterface();
914     const VkDevice dev              = m_context.getDevice();
915     const VkQueue queue             = m_context.getUniversalQueue();
916     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
917 
918     Move<VkCommandPool> cmdPool = createCommandPool(vki, dev, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
919     Move<VkCommandBuffer> cmdBuffer   = allocateCommandBuffer(vki, dev, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
920     Move<VkShaderModule> shaderModule = createShaderModule(vki, dev, m_context.getBinaryCollection().get("comp"), 0);
921 
922     Move<VkDescriptorSetLayout> descriptorSetLayout =
923         DescriptorSetLayoutBuilder()
924             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
925             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
926             .build(vki, dev);
927     Move<VkDescriptorPool> descriptorPool = DescriptorPoolBuilder()
928                                                 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
929                                                 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
930                                                 .build(vki, dev, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
931     Move<VkDescriptorSet> descriptorSet   = makeDescriptorSet(vki, dev, *descriptorPool, *descriptorSetLayout);
932     Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vki, dev, *descriptorSetLayout);
933     Move<VkPipeline> pipeline             = makeComputePipeline(vki, dev, *pipelineLayout, *shaderModule);
934 
935     ut::StorageImage2D image(m_context, m_params->vkFormat, m_params->textureWidth, m_params->textureHeight);
936 
937     ut::StorageBuffer2D buffer(m_context, m_test->getBufferFormat(), m_params->textureWidth, m_params->textureHeight);
938 
939     VkDescriptorImageInfo inputImageInfo =
940         makeDescriptorImageInfo(VK_NULL_HANDLE, image.getView(), VK_IMAGE_LAYOUT_GENERAL);
941     VkDescriptorBufferInfo outputBufferInfo = makeDescriptorBufferInfo(buffer.getBuffer(), 0u, buffer.getSize());
942 
943     DescriptorSetUpdateBuilder builder;
944     builder
945         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
946                      VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &inputImageInfo)
947         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
948                      VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outputBufferInfo)
949         .update(vki, dev);
950 
951     populate(buffer.getPixelAccess());
952     clear(image.getPixelAccess());
953 
954     beginCommandBuffer(vki, *cmdBuffer);
955     image.upload(*cmdBuffer);
956     vki.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
957     vki.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(),
958                               0u, nullptr);
959     vki.cmdDispatch(*cmdBuffer, m_params->textureWidth, m_params->textureHeight, 1);
960     image.download(*cmdBuffer);
961     endCommandBuffer(vki, *cmdBuffer);
962 
963     image.flush();
964     buffer.flush();
965 
966     submitCommandsAndWait(vki, dev, queue, *cmdBuffer);
967 
968     image.invalidate();
969     buffer.invalidate();
970 
971     return compare(image.getPixelAccess(), buffer.getPixelAccess()) ? tcu::TestStatus::pass("") :
972                                                                       tcu::TestStatus::fail("Pixel comparison failed");
973 }
974 
compare(tcu::PixelBufferAccess & result,tcu::PixelBufferAccess & reference) const975 bool MismatchedVectorSizesTestInstance::compare(tcu::PixelBufferAccess &result, tcu::PixelBufferAccess &reference) const
976 {
977     const tcu::TextureFormat texFormat          = mapVkFormat(m_params->vkFormat);
978     const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(texFormat.type);
979     const int targetWidth                       = getNumUsedChannels(texFormat.order);
980 
981     bool doContinue = true;
982 
983     for (int y = 0; doContinue && y < m_params->textureHeight; ++y)
984     {
985         for (int x = 0; doContinue && x < m_params->textureWidth; ++x)
986         {
987             switch (channelClass)
988             {
989             case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
990                 doContinue = ut::comparePixels(result.getPixelInt(x, y), reference.getPixelInt(x, y), targetWidth);
991                 break;
992             case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
993                 doContinue = ut::comparePixels(result.getPixelUint(x, y), reference.getPixelUint(x, y), targetWidth);
994                 break;
995             default:
996                 doContinue = ut::comparePixels(result.getPixel(x, y), reference.getPixel(x, y), targetWidth, 0.0005f);
997                 break;
998             }
999         }
1000     }
1001 
1002     return doContinue;
1003 }
1004 
compare(tcu::PixelBufferAccess & result,tcu::PixelBufferAccess & reference) const1005 bool MismatchedSignednessAndTypeTestInstance::compare(tcu::PixelBufferAccess &result,
1006                                                       tcu::PixelBufferAccess &reference) const
1007 {
1008     DE_UNREF(result);
1009     DE_UNREF(reference);
1010     return true;
1011 }
1012 
1013 } // namespace
1014 
createImageWriteOpTests(tcu::TestContext & testCtx)1015 tcu::TestCaseGroup *createImageWriteOpTests(tcu::TestContext &testCtx)
1016 {
1017     std::stringstream ss;
1018 
1019     auto genVectorSizesTestName = [&](const VkFormat &f, const int sourceWidth) -> std::string
1020     {
1021         ss.str(std::string());
1022         ss << de::toLower(getSpirvFormat(f)) << "_from";
1023         if (sourceWidth > 1)
1024             ss << "_vec" << sourceWidth;
1025         else
1026             ss << "_scalar";
1027 
1028         return ss.str();
1029     };
1030 
1031     // Test image OpImageWrite operation in various aspects.
1032     auto testGroup = new tcu::TestCaseGroup(testCtx, "mismatched_write_op");
1033     // Case OpImageWrite operation on mismatched vector sizes.
1034     auto testGroupMismatchedVectorSizes = new tcu::TestCaseGroup(testCtx, "mismatched_vector_sizes");
1035     auto testGroupMismatchedSignedness  = new tcu::TestCaseGroup(testCtx, "mismatched_signedness_and_type");
1036 
1037     for (const VkFormat &f : allFormats)
1038     {
1039         const auto switchClass = getTextureChannelClass(mapVkFormat(f).type);
1040         auto compatibleFormats = findFormatsByChannelClass(switchClass);
1041 
1042         auto end   = compatibleFormats.cend();
1043         auto begin = compatibleFormats.cbegin();
1044         for (auto i = begin; i != end; ++i)
1045         {
1046             if (is64BitIntegerFormat(i[0]) || is64BitIntegerFormat(f))
1047                 continue;
1048 
1049             const std::string testName = de::toLower(getSpirvFormat(i[0])) + "_from_" + de::toLower(getSpirvFormat(f));
1050             auto params =
1051                 new MismatchedWriteOpTest::Params{f, 12, 8 * static_cast<int>(std::distance(begin, i) + 1), i[0]};
1052             testGroupMismatchedSignedness->addChild(
1053                 new MismatchedSignednessAndTypeTest(testCtx, testName, MismatchedVectorSizesTest::ParamsSp(params)));
1054         }
1055 
1056         for (int sourceWidth = 4; sourceWidth > 0; --sourceWidth)
1057         {
1058             if (sourceWidth >= getNumUsedChannels(f))
1059             {
1060                 auto params = new MismatchedWriteOpTest::Params{f, 12 * sourceWidth, 8 * (4 - sourceWidth + 1), f};
1061                 testGroupMismatchedVectorSizes->addChild(
1062                     new MismatchedVectorSizesTest(testCtx, genVectorSizesTestName(f, sourceWidth),
1063                                                   MismatchedVectorSizesTest::ParamsSp(params), sourceWidth));
1064             }
1065         }
1066     }
1067 
1068     testGroup->addChild(testGroupMismatchedVectorSizes);
1069     testGroup->addChild(testGroupMismatchedSignedness);
1070 
1071     return testGroup;
1072 }
1073 
1074 } // namespace image
1075 } // namespace vkt
1076