xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/image/vktImageMismatchedWriteOpTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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             DE_NULL,                                     // 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, (const VkMemoryBarrier *)DE_NULL, 1, &bufferBarrier, 1,
334                                &beforeCopyBarrier);
335     }
336 
337     vki.cmdCopyBufferToImage(cmdBuffer, m_buffer.getBuffer(), *m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u,
338                              &copyRegion);
339 
340     {
341         const VkBufferMemoryBarrier bufferBarrier = makeBufferMemoryBarrier(
342             VK_ACCESS_TRANSFER_READ_BIT, (VkAccessFlags)0, m_buffer.getBuffer(), 0ull, m_buffer.getSize());
343 
344         m_layout = VK_IMAGE_LAYOUT_GENERAL;
345         const VkImageMemoryBarrier afterCopyBarrier =
346             makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT,
347                                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, m_layout, *m_image, fullImageSubresourceRange);
348 
349         vki.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
350                                (VkDependencyFlags)0, 0, (const VkMemoryBarrier *)DE_NULL, 1, &bufferBarrier, 1,
351                                &afterCopyBarrier);
352     }
353 }
354 
download(const VkCommandBuffer cmdBuffer)355 void StorageImage2D::download(const VkCommandBuffer cmdBuffer)
356 {
357     const DeviceInterface &vki = m_context.getDeviceInterface();
358     const VkImageSubresourceRange fullImageSubresourceRange =
359         makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
360     const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(tcu::IVec3(m_width, m_height, 1)), 1u);
361 
362     {
363         const VkBufferMemoryBarrier bufferBarrier = makeBufferMemoryBarrier(
364             (VkAccessFlags)0, VK_ACCESS_TRANSFER_WRITE_BIT, m_buffer.getBuffer(), 0ull, m_buffer.getSize());
365 
366         const VkImageMemoryBarrier beforeCopyBarrier =
367             makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, m_layout,
368                                    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *m_image, fullImageSubresourceRange);
369 
370         vki.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
371                                (VkDependencyFlags)0, 0, (const VkMemoryBarrier *)DE_NULL, 1, &bufferBarrier, 1,
372                                &beforeCopyBarrier);
373     }
374 
375     vki.cmdCopyImageToBuffer(cmdBuffer, *m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_buffer.getBuffer(), 1,
376                              &copyRegion);
377 
378     {
379         const VkBufferMemoryBarrier bufferBarrier = makeBufferMemoryBarrier(
380             VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, m_buffer.getBuffer(), 0ull, m_buffer.getSize());
381 
382         const VkImageMemoryBarrier afterCopyBarrier =
383             makeImageMemoryBarrier(VK_ACCESS_TRANSFER_READ_BIT, (VkAccessFlags)0, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
384                                    m_layout, *m_image, fullImageSubresourceRange);
385 
386         vki.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
387                                (VkDependencyFlags)0, 0, (const VkMemoryBarrier *)DE_NULL, 1, &bufferBarrier, 1,
388                                &afterCopyBarrier);
389     }
390 }
391 
StorageBuffer2D(Context & context,const tcu::TextureFormat & format,uint32_t width,uint32_t height)392 StorageBuffer2D::StorageBuffer2D(Context &context, const tcu::TextureFormat &format, uint32_t width, uint32_t height)
393     : m_context(context)
394     , m_format(format)
395     , m_width(width)
396     , m_height(height)
397     , m_bufferSize(m_width * m_height * m_format.getPixelSize())
398 {
399     const DeviceInterface &vki      = m_context.getDeviceInterface();
400     const VkDevice dev              = m_context.getDevice();
401     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
402     Allocator &allocator            = m_context.getDefaultAllocator();
403 
404     const VkBufferUsageFlags bufferUsageFlags =
405         VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
406 
407     const VkBufferCreateInfo bufferCreateInfo = {
408         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
409         DE_NULL,                              // const void* pNext;
410         0u,                                   // VkBufferCreateFlags flags;
411         m_bufferSize,                         // VkDeviceSize size;
412         bufferUsageFlags,                     // VkBufferUsageFlags usage;
413         VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
414         1u,                                   // uint32_t queueFamilyIndexCount;
415         &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
416     };
417 
418     m_buffer = createBuffer(vki, dev, &bufferCreateInfo);
419 
420     m_bufferMemory =
421         allocator.allocate(getBufferMemoryRequirements(vki, dev, *m_buffer), MemoryRequirement::HostVisible);
422     VK_CHECK(vki.bindBufferMemory(dev, *m_buffer, m_bufferMemory->getMemory(), m_bufferMemory->getOffset()));
423 
424     m_access.emplace_back(m_format, tcu::IVec3(m_width, m_height, 1), m_bufferMemory->getHostPtr());
425 }
426 
gluePixels(const tcu::Vec4 & a,const tcu::Vec4 & b,const int pivot)427 tcu::Vec4 gluePixels(const tcu::Vec4 &a, const tcu::Vec4 &b, const int pivot)
428 {
429     tcu::Vec4 result;
430     for (int i = 0; i < pivot; ++i)
431         result[i] = a[i];
432     for (int i = pivot; i < 4; ++i)
433         result[i] = b[i];
434     return result;
435 }
436 
437 template <class T, int N>
comparePixels(const tcu::Vector<T,N> & res,const tcu::Vector<T,N> & ref,const int targetWidth,const T eps={})438 bool comparePixels(const tcu::Vector<T, N> &res, const tcu::Vector<T, N> &ref, const int targetWidth, const T eps = {})
439 {
440     bool ok = true;
441 
442     for (int i = 0; ok && i < targetWidth; ++i)
443     {
444         ok &= EPSILON_COMPARE(res[i], ref[i], eps);
445     }
446 
447     return ok;
448 }
449 
450 } // namespace ut
451 
createInstance(Context & context) const452 TestInstance *MismatchedVectorSizesTest::createInstance(Context &context) const
453 {
454     return (new MismatchedVectorSizesTestInstance(context, m_params, this));
455 }
456 
createInstance(Context & context) const457 TestInstance *MismatchedSignednessAndTypeTest::createInstance(Context &context) const
458 {
459     return (new MismatchedSignednessAndTypeTestInstance(context, m_params, this));
460 }
461 
462 const VkFormat allFormats[] = {
463     VK_FORMAT_R32G32B32A32_SFLOAT,
464     VK_FORMAT_R32G32_SFLOAT,
465     VK_FORMAT_R32_SFLOAT,
466     VK_FORMAT_R16G16B16A16_SFLOAT,
467     VK_FORMAT_R16G16_SFLOAT,
468     VK_FORMAT_R16_SFLOAT,
469     VK_FORMAT_R16G16B16A16_UNORM,
470     VK_FORMAT_R16G16_UNORM,
471     VK_FORMAT_R16_UNORM,
472     VK_FORMAT_R16G16B16A16_SNORM,
473     VK_FORMAT_R16G16_SNORM,
474     VK_FORMAT_R16_SNORM,
475     VK_FORMAT_A2B10G10R10_UNORM_PACK32,
476     VK_FORMAT_B10G11R11_UFLOAT_PACK32,
477     VK_FORMAT_R8G8B8A8_UNORM,
478     VK_FORMAT_R8G8_UNORM,
479     VK_FORMAT_R8_UNORM,
480     VK_FORMAT_R8G8B8A8_SNORM,
481     VK_FORMAT_R8G8_SNORM,
482     VK_FORMAT_R8_SNORM,
483     VK_FORMAT_R32G32B32A32_SINT,
484     VK_FORMAT_R32G32_SINT,
485     VK_FORMAT_R32_SINT,
486     VK_FORMAT_R16G16B16A16_SINT,
487     VK_FORMAT_R16G16_SINT,
488     VK_FORMAT_R16_SINT,
489     VK_FORMAT_R8G8B8A8_SINT,
490     VK_FORMAT_R8G8_SINT,
491     VK_FORMAT_R8_SINT,
492     VK_FORMAT_R32G32B32A32_UINT,
493     VK_FORMAT_R32G32_UINT,
494     VK_FORMAT_R32_UINT,
495     VK_FORMAT_R16G16B16A16_UINT,
496     VK_FORMAT_R16G16_UINT,
497     VK_FORMAT_R16_UINT,
498     VK_FORMAT_A2B10G10R10_UINT_PACK32,
499     VK_FORMAT_R8G8B8A8_UINT,
500     VK_FORMAT_R8G8_UINT,
501     VK_FORMAT_R8_UINT,
502 
503     VK_FORMAT_R64_SINT,
504     VK_FORMAT_R64_UINT,
505 };
506 
findFormatsByChannelClass(TextureChannelClass channelClass)507 std::vector<VkFormat> findFormatsByChannelClass(TextureChannelClass channelClass)
508 {
509     std::vector<VkFormat> result;
510     for (const VkFormat &f : allFormats)
511     {
512         if (getTextureChannelClass(mapVkFormat(f).type) == channelClass)
513             result.emplace_back(f);
514     }
515     DE_ASSERT(!result.empty());
516     return result;
517 }
518 
getChannelStr(const TextureFormat::ChannelType & type)519 const char *getChannelStr(const TextureFormat::ChannelType &type)
520 {
521     switch (type)
522     {
523     case TextureFormat::FLOAT:
524         return "float";
525     case TextureFormat::SIGNED_INT32:
526         return "sint";
527     case TextureFormat::UNSIGNED_INT32:
528         return "uint";
529     case TextureFormat::FLOAT64:
530         return "double";
531     case TextureFormat::SIGNED_INT64:
532         return "slong";
533     case TextureFormat::UNSIGNED_INT64:
534         return "ulong";
535     default:
536         DE_ASSERT(false);
537     }
538 
539     return nullptr;
540 }
541 
makeChannelType(tcu::TextureChannelClass channelClass,bool doubled)542 TextureFormat::ChannelType makeChannelType(tcu::TextureChannelClass channelClass, bool doubled)
543 {
544     auto channelType = TextureFormat::ChannelType::CHANNELTYPE_LAST;
545     switch (channelClass)
546     {
547     case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
548         channelType = doubled ? TextureFormat::ChannelType::SIGNED_INT64 : TextureFormat::ChannelType::SIGNED_INT32;
549         break;
550     case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
551         channelType = doubled ? TextureFormat::ChannelType::UNSIGNED_INT64 : TextureFormat::ChannelType::UNSIGNED_INT32;
552         break;
553     default:
554         channelType = doubled ? TextureFormat::ChannelType::FLOAT64 : TextureFormat::ChannelType::FLOAT;
555     }
556     return channelType;
557 }
558 
makeBufferFormat(tcu::TextureChannelClass channelClass,bool doubled)559 TextureFormat makeBufferFormat(tcu::TextureChannelClass channelClass, bool doubled)
560 {
561     return TextureFormat(TextureFormat::ChannelOrder::RGBA, makeChannelType(channelClass, doubled));
562 }
563 
checkSupport(Context & context) const564 void MismatchedWriteOpTest::checkSupport(Context &context) const
565 {
566     // capabilities that may be used in the shader
567     if (is64BitIntegerFormat(m_params->vkFormat))
568     {
569         const VkPhysicalDeviceFeatures deviceFeatures =
570             getPhysicalDeviceFeatures(context.getInstanceInterface(), context.getPhysicalDevice());
571         if (!deviceFeatures.shaderInt64)
572         {
573             TCU_THROW(NotSupportedError, "Device feature shaderInt64 is not supported");
574         }
575         context.requireDeviceFunctionality("VK_EXT_shader_image_atomic_int64");
576     }
577 
578     // extensions used statically in the shader
579     context.requireDeviceFunctionality("VK_KHR_variable_pointers");
580     context.requireDeviceFunctionality("VK_KHR_storage_buffer_storage_class");
581 
582     VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(
583         context.getInstanceInterface(), context.getPhysicalDevice(), m_params->vkFormat);
584 
585     if ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0)
586     {
587         TCU_THROW(NotSupportedError, "Creating storage image with this format is not supported");
588     }
589 }
590 
getBufferFormat(void) const591 TextureFormat MismatchedWriteOpTest::getBufferFormat(void) const
592 {
593     const TextureFormat texFormat = mapVkFormat(m_params->vkFormat);
594     return makeBufferFormat(getTextureChannelClass(texFormat.type), is64BitIntegerFormat(m_params->vkFormat));
595 }
596 
getProgramCodeAndVariables(StringTemplate & code,strings & variables) const597 void MismatchedWriteOpTest::getProgramCodeAndVariables(StringTemplate &code, strings &variables) const
598 {
599     std::string shaderTemplate(R"(
600 
601                               OpCapability Shader
602                               OpCapability StorageImageExtendedFormats
603 
604                               ${CAPABILITY_INT64}
605                               OpExtension      "SPV_KHR_variable_pointers"
606                               OpExtension      "SPV_KHR_storage_buffer_storage_class"
607                               ${EXTENSIONS}
608 
609                     %std450 = OpExtInstImport  "GLSL.std.450"
610                               OpMemoryModel    Logical GLSL450
611 
612                               OpEntryPoint     GLCompute %main "main" %gid %image %buffer
613                               OpExecutionMode  %main LocalSize 1 1 1
614 
615                               OpDecorate       %gid BuiltIn GlobalInvocationId
616 
617                               OpDecorate       %image DescriptorSet 0
618                               OpDecorate       %image Binding 0
619 
620                               OpDecorate       %rta    ArrayStride ${ARRAY_STRIDE}
621                               OpMemberDecorate %struct 0 Offset 0
622                               OpDecorate       %struct Block
623                               OpDecorate       %buffer DescriptorSet 0
624                               OpDecorate       %buffer Binding 1
625 
626                       %void = OpTypeVoid
627                    %fn_void = OpTypeFunction %void
628 
629                     ${TYPES_INT64}
630 
631                      %float = OpTypeFloat 32
632                       %sint = OpTypeInt 32 1
633                       %uint = OpTypeInt 32 0
634 
635                    %v4float = OpTypeVector %float 4
636                    %v3float = OpTypeVector %float 3
637                    %v2float = OpTypeVector %float 2
638 
639                     %v4sint = OpTypeVector %sint 4
640                     %v3sint = OpTypeVector %sint 3
641                     %v2sint = OpTypeVector %sint 2
642 
643                     %v4uint = OpTypeVector %uint 4
644                     %v3uint = OpTypeVector %uint 3
645                     %v2uint = OpTypeVector %uint 2
646 
647              %v3uint_in_ptr = OpTypePointer Input %v3uint
648                        %gid = OpVariable %v3uint_in_ptr Input
649 
650                 %image_type = OpTypeImage %${SAMPLED_TYPE} 2D 0 0 0 2 ${SPIRV_IMAGE_FORMAT}
651                  %image_ptr = OpTypePointer UniformConstant %image_type
652                      %image = OpVariable %image_ptr UniformConstant
653 
654                %image_width = OpConstant %sint ${IMAGE_WIDTH}
655               %image_height = OpConstant %sint ${IMAGE_HEIGHT}
656 
657                 %rta_offset = OpConstant %uint 0
658                        %rta = OpTypeRuntimeArray %v4${SAMPLED_TYPE}
659                     %struct = OpTypeStruct %rta
660                   %ssbo_ptr = OpTypePointer StorageBuffer %struct
661                     %buffer = OpVariable %ssbo_ptr StorageBuffer
662 
663                 %red_offset = OpConstant %uint 0
664               %green_offset = OpConstant %uint 1
665                %blue_offset = OpConstant %uint 2
666               %alpha_offset = OpConstant %uint 3
667 
668        %${SAMPLED_TYPE}_PTR = OpTypePointer StorageBuffer %${SAMPLED_TYPE}
669               %var_sint_ptr = OpTypePointer Function %sint
670 
671                 ; Entry main procedure
672                       %main = OpFunction %void None %fn_void
673                      %entry = OpLabel
674 
675                      %index = OpVariable %var_sint_ptr Function
676 
677                 ; Transform gl_GlobalInvocationID.xyz to ivec2(gl_GlobalInvocationID.xy)
678                         %id = OpLoad %v3uint %gid
679 
680                     %u_id_x = OpCompositeExtract %uint %id 0
681                     %s_id_x = OpBitcast %sint %u_id_x
682 
683                     %u_id_y = OpCompositeExtract %uint %id 1
684                     %s_id_y = OpBitcast %sint %u_id_y
685 
686                      %id_xy = OpCompositeConstruct %v2sint %s_id_x %s_id_y
687 
688                 ; Calculate index in buffer
689                        %mul = OpIMul %sint %s_id_y %image_width
690                        %add = OpIAdd %sint %mul %s_id_x
691                               OpStore %index %add
692 
693                 ; Final image variable used to read from or write to
694                        %img = OpLoad %image_type %image
695 
696                 ; Accessors to buffer components
697                        %idx = OpLoad %sint %index
698               %alpha_access = OpAccessChain %${SAMPLED_TYPE}_PTR %buffer %rta_offset %idx %alpha_offset
699                %blue_access = OpAccessChain %${SAMPLED_TYPE}_PTR %buffer %rta_offset %idx %blue_offset
700               %green_access = OpAccessChain %${SAMPLED_TYPE}_PTR %buffer %rta_offset %idx %green_offset
701                 %red_access = OpAccessChain %${SAMPLED_TYPE}_PTR %buffer %rta_offset %idx %red_offset
702 
703                        %red = OpLoad %${SAMPLED_TYPE} %red_access
704                      %green = OpLoad %${SAMPLED_TYPE} %green_access
705                       %blue = OpLoad %${SAMPLED_TYPE} %blue_access
706                      %alpha = OpLoad %${SAMPLED_TYPE} %alpha_access
707 
708                               ${WRITE_TO_IMAGE}
709 
710                               OpReturn
711                               OpFunctionEnd
712     )");
713 
714     const std::string typesInt64(R"(
715                      %slong = OpTypeInt 64 1
716                      %ulong = OpTypeInt 64 0
717 
718                    %v4slong = OpTypeVector %slong 4
719                    %v3slong = OpTypeVector %slong 3
720                    %v2slong = OpTypeVector %slong 2
721 
722                    %v4ulong = OpTypeVector %ulong 4
723                    %v3ulong = OpTypeVector %ulong 3
724                    %v2ulong = OpTypeVector %ulong 2
725     )");
726 
727     const tcu::TextureFormat buffFormat = getBufferFormat();
728 
729     variables["SPIRV_IMAGE_FORMAT"] = getSpirvFormat(m_params->vkFormat);
730     variables["CAPABILITY_INT64"]   = "";
731     variables["EXTENSIONS"]         = "";
732     variables["TYPES_INT64"]        = "";
733 
734     if (is64BitIntegerFormat(m_params->vkFormat))
735     {
736         variables["EXTENSIONS"]       = "OpExtension       \"SPV_EXT_shader_image_int64\"";
737         variables["CAPABILITY_INT64"] = "OpCapability Int64ImageEXT\n"
738                                         "OpCapability Int64";
739         variables["TYPES_INT64"]      = typesInt64;
740     }
741 
742     variables["SAMPLED_TYPE"] = getChannelStr(buffFormat.type);
743     variables["IMAGE_WIDTH"]  = std::to_string(m_params->textureWidth);
744     variables["IMAGE_HEIGHT"] = std::to_string(m_params->textureHeight);
745     variables["ARRAY_STRIDE"] =
746         std::to_string(tcu::getChannelSize(buffFormat.type) * tcu::getNumUsedChannels(buffFormat.order));
747 
748     code.setString(shaderTemplate);
749 }
750 
initPrograms(SourceCollections & programCollection) const751 void MismatchedVectorSizesTest::initPrograms(SourceCollections &programCollection) const
752 {
753     strings variables{};
754     StringTemplate shaderTemplate{};
755 
756     const StringTemplate writeFromSingleComponent(R"(
757                      OpImageWrite %img %id_xy %red
758     )");
759     const StringTemplate writeFromTwoComponents(R"(
760                %rg = OpCompositeConstruct %v2${SAMPLED_TYPE} %red %green
761                      OpImageWrite %img %id_xy %rg
762     )");
763 
764     const StringTemplate writeFromThreeComponents(R"(
765               %rgb = OpCompositeConstruct %v3${SAMPLED_TYPE} %red %green %blue
766                      OpImageWrite %img %id_xy %rgb
767     )");
768     const StringTemplate writeFromFourComponents(R"(
769              %rgba = OpCompositeConstruct %v4${SAMPLED_TYPE} %red %green %blue %alpha
770                      OpImageWrite %img %id_xy %rgba
771     )");
772 
773     getProgramCodeAndVariables(shaderTemplate, variables);
774 
775     variables["WRITE_TO_IMAGE"] = (m_sourceWidth == 1 ? writeFromSingleComponent :
776                                    m_sourceWidth == 2 ? writeFromTwoComponents :
777                                    m_sourceWidth == 3 ? writeFromThreeComponents :
778                                                         writeFromFourComponents)
779                                       .specialize(variables);
780     programCollection.spirvAsmSources.add("comp")
781         << shaderTemplate.specialize(variables)
782         << vk::SpirVAsmBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, true);
783 }
784 
initPrograms(SourceCollections & programCollection) const785 void MismatchedSignednessAndTypeTest::initPrograms(SourceCollections &programCollection) const
786 {
787     strings variables{};
788     StringTemplate shaderTemplate{};
789 
790     const StringTemplate writeToImage(R"(
791             %color = OpCompositeConstruct %v4${SAMPLED_TYPE} %red %green %blue %alpha
792                      OpImageWrite %img %id_xy %color
793     )");
794 
795     getProgramCodeAndVariables(shaderTemplate, variables);
796 
797     variables["WRITE_TO_IMAGE"] = writeToImage.specialize(variables);
798 
799     programCollection.spirvAsmSources.add("comp")
800         << shaderTemplate.specialize(variables)
801         << vk::SpirVAsmBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, true);
802 }
803 
clear(tcu::PixelBufferAccess & pixels) const804 void MismatchedWriteOpTestInstance::clear(tcu::PixelBufferAccess &pixels) const
805 {
806     const auto channelClass = tcu::getTextureChannelClass(mapVkFormat(m_params->vkFormat).type);
807     switch (channelClass)
808     {
809     case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
810         tcu::clear(pixels, tcu::IVec4(-1, -2, -3, -4));
811         break;
812 
813     case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
814         tcu::clear(pixels, tcu::UVec4(1, 2, 3, 4));
815         break;
816 
817     default:
818         tcu::clear(pixels, tcu::Vec4(0.2f, 0.3f, 0.4f, 0.5f));
819     }
820 }
821 
populate(tcu::PixelBufferAccess & pixels) const822 void MismatchedWriteOpTestInstance::populate(tcu::PixelBufferAccess &pixels) const
823 {
824     const auto texFormat    = mapVkFormat(m_params->vkFormat);
825     const auto bitDepth     = tcu::getTextureFormatBitDepth(texFormat);
826     const auto channelClass = tcu::getTextureChannelClass(texFormat.type);
827 
828     const tcu::IVec4 signedMinValues(bitDepth[0] ? deIntMinValue32(deMin32(bitDepth[0], 32)) : (-1),
829                                      bitDepth[1] ? deIntMinValue32(deMin32(bitDepth[1], 32)) : (-1),
830                                      bitDepth[2] ? deIntMinValue32(deMin32(bitDepth[2], 32)) : (-1),
831                                      bitDepth[3] ? deIntMinValue32(deMin32(bitDepth[3], 32)) : (-1));
832 
833     const tcu::IVec4 signedMaxValues(bitDepth[0] ? deIntMaxValue32(deMin32(bitDepth[0], 32)) : 1,
834                                      bitDepth[1] ? deIntMaxValue32(deMin32(bitDepth[1], 32)) : 1,
835                                      bitDepth[2] ? deIntMaxValue32(deMin32(bitDepth[2], 32)) : 1,
836                                      bitDepth[3] ? deIntMaxValue32(deMin32(bitDepth[3], 32)) : 1);
837 
838     const tcu::UVec4 unsignedMinValues(0u);
839 
840     const tcu::UVec4 unsignedMaxValues(bitDepth[0] ? deUintMaxValue32(deMin32(bitDepth[0], 32)) : 1u,
841                                        bitDepth[1] ? deUintMaxValue32(deMin32(bitDepth[1], 32)) : 1u,
842                                        bitDepth[2] ? deUintMaxValue32(deMin32(bitDepth[2], 32)) : 1u,
843                                        bitDepth[3] ? deUintMaxValue32(deMin32(bitDepth[3], 32)) : 1u);
844 
845     auto nextSigned = [&](tcu::IVec4 &color)
846     {
847         color[0] = (static_cast<int64_t>(color[0] + 2) < signedMaxValues[0]) ? (color[0] + 2) : signedMinValues[0];
848         color[1] = (static_cast<int64_t>(color[1] + 3) < signedMaxValues[1]) ? (color[1] + 3) : signedMinValues[1];
849         color[2] = (static_cast<int64_t>(color[2] + 5) < signedMaxValues[2]) ? (color[2] + 5) : signedMinValues[2];
850         color[3] = (static_cast<int64_t>(color[3] + 7) < signedMaxValues[3]) ? (color[3] + 7) : signedMinValues[3];
851     };
852 
853     auto nextUnsigned = [&](tcu::UVec4 &color)
854     {
855         color[0] = (static_cast<uint64_t>(color[0] + 2) < unsignedMaxValues[0]) ? (color[0] + 2) : unsignedMinValues[0];
856         color[1] = (static_cast<uint64_t>(color[1] + 3) < unsignedMaxValues[1]) ? (color[1] + 3) : unsignedMinValues[1];
857         color[2] = (static_cast<uint64_t>(color[2] + 5) < unsignedMaxValues[2]) ? (color[2] + 5) : unsignedMinValues[2];
858         color[3] = (static_cast<uint64_t>(color[3] + 7) < unsignedMaxValues[3]) ? (color[3] + 7) : unsignedMinValues[3];
859     };
860 
861     uint64_t floatsData[4];
862     tcu::PixelBufferAccess floatsAccess(texFormat, 1, 1, 1, floatsData);
863     tcu::Vec4 tmpFloats(0.0f);
864 
865     const float divider(static_cast<float>(m_params->textureHeight));
866     const tcu::Vec4 ufloatStep(1.0f / (divider * 1.0f), 1.0f / (divider * 2.0f), 1.0f / (divider * 3.0f),
867                                1.0f / (divider * 5.0f));
868     const tcu::Vec4 sfloatStep(2.0f / (divider * 1.0f), 2.0f / (divider * 2.0f), 2.0f / (divider * 3.0f),
869                                2.0f / (divider * 5.0f));
870 
871     tcu::IVec4 signedColor(0);
872     tcu::UVec4 unsignedColor(0u);
873     tcu::Vec4 ufloatColor(0.0f);
874     tcu::Vec4 sfloatColor(-1.0f);
875 
876     for (int y = 0; y < m_params->textureHeight; ++y)
877     {
878         for (int x = 0; x < m_params->textureWidth; ++x)
879         {
880             switch (channelClass)
881             {
882             case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
883                 pixels.setPixel(signedColor, x, y);
884                 break;
885 
886             case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
887                 pixels.setPixel(unsignedColor, x, y);
888                 break;
889 
890             case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
891                 floatsAccess.setPixel(sfloatColor, 0, 0);
892                 tmpFloats =
893                     ut::gluePixels(floatsAccess.getPixel(0, 0), sfloatColor, tcu::getNumUsedChannels(texFormat.order));
894                 pixels.setPixel(tmpFloats, x, y);
895                 break;
896 
897             // TEXTURECHANNELCLASS_FLOATING_POINT or
898             // TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT
899             default:
900                 floatsAccess.setPixel(ufloatColor, 0, 0);
901                 tmpFloats =
902                     ut::gluePixels(floatsAccess.getPixel(0, 0), ufloatColor, tcu::getNumUsedChannels(texFormat.order));
903                 pixels.setPixel(tmpFloats, x, y);
904                 break;
905             }
906         }
907 
908         nextSigned(signedColor);
909         nextUnsigned(unsignedColor);
910         sfloatColor += sfloatStep;
911         ufloatColor += ufloatStep;
912     }
913 }
914 
iterate(void)915 tcu::TestStatus MismatchedWriteOpTestInstance::iterate(void)
916 {
917     const DeviceInterface &vki      = m_context.getDeviceInterface();
918     const VkDevice dev              = m_context.getDevice();
919     const VkQueue queue             = m_context.getUniversalQueue();
920     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
921 
922     Move<VkCommandPool> cmdPool = createCommandPool(vki, dev, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
923     Move<VkCommandBuffer> cmdBuffer   = allocateCommandBuffer(vki, dev, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
924     Move<VkShaderModule> shaderModule = createShaderModule(vki, dev, m_context.getBinaryCollection().get("comp"), 0);
925 
926     Move<VkDescriptorSetLayout> descriptorSetLayout =
927         DescriptorSetLayoutBuilder()
928             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
929             .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
930             .build(vki, dev);
931     Move<VkDescriptorPool> descriptorPool = DescriptorPoolBuilder()
932                                                 .addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
933                                                 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
934                                                 .build(vki, dev, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
935     Move<VkDescriptorSet> descriptorSet   = makeDescriptorSet(vki, dev, *descriptorPool, *descriptorSetLayout);
936     Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vki, dev, *descriptorSetLayout);
937     Move<VkPipeline> pipeline             = makeComputePipeline(vki, dev, *pipelineLayout, *shaderModule);
938 
939     ut::StorageImage2D image(m_context, m_params->vkFormat, m_params->textureWidth, m_params->textureHeight);
940 
941     ut::StorageBuffer2D buffer(m_context, m_test->getBufferFormat(), m_params->textureWidth, m_params->textureHeight);
942 
943     VkDescriptorImageInfo inputImageInfo = makeDescriptorImageInfo(DE_NULL, image.getView(), VK_IMAGE_LAYOUT_GENERAL);
944     VkDescriptorBufferInfo outputBufferInfo = makeDescriptorBufferInfo(buffer.getBuffer(), 0u, buffer.getSize());
945 
946     DescriptorSetUpdateBuilder builder;
947     builder
948         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
949                      VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &inputImageInfo)
950         .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u),
951                      VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outputBufferInfo)
952         .update(vki, dev);
953 
954     populate(buffer.getPixelAccess());
955     clear(image.getPixelAccess());
956 
957     beginCommandBuffer(vki, *cmdBuffer);
958     image.upload(*cmdBuffer);
959     vki.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
960     vki.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(),
961                               0u, DE_NULL);
962     vki.cmdDispatch(*cmdBuffer, m_params->textureWidth, m_params->textureHeight, 1);
963     image.download(*cmdBuffer);
964     endCommandBuffer(vki, *cmdBuffer);
965 
966     image.flush();
967     buffer.flush();
968 
969     submitCommandsAndWait(vki, dev, queue, *cmdBuffer);
970 
971     image.invalidate();
972     buffer.invalidate();
973 
974     return compare(image.getPixelAccess(), buffer.getPixelAccess()) ? tcu::TestStatus::pass("") :
975                                                                       tcu::TestStatus::fail("Pixel comparison failed");
976 }
977 
compare(tcu::PixelBufferAccess & result,tcu::PixelBufferAccess & reference) const978 bool MismatchedVectorSizesTestInstance::compare(tcu::PixelBufferAccess &result, tcu::PixelBufferAccess &reference) const
979 {
980     const tcu::TextureFormat texFormat          = mapVkFormat(m_params->vkFormat);
981     const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(texFormat.type);
982     const int targetWidth                       = getNumUsedChannels(texFormat.order);
983 
984     bool doContinue = true;
985 
986     for (int y = 0; doContinue && y < m_params->textureHeight; ++y)
987     {
988         for (int x = 0; doContinue && x < m_params->textureWidth; ++x)
989         {
990             switch (channelClass)
991             {
992             case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
993                 doContinue = ut::comparePixels(result.getPixelInt(x, y), reference.getPixelInt(x, y), targetWidth);
994                 break;
995             case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
996                 doContinue = ut::comparePixels(result.getPixelUint(x, y), reference.getPixelUint(x, y), targetWidth);
997                 break;
998             default:
999                 doContinue = ut::comparePixels(result.getPixel(x, y), reference.getPixel(x, y), targetWidth, 0.0005f);
1000                 break;
1001             }
1002         }
1003     }
1004 
1005     return doContinue;
1006 }
1007 
compare(tcu::PixelBufferAccess & result,tcu::PixelBufferAccess & reference) const1008 bool MismatchedSignednessAndTypeTestInstance::compare(tcu::PixelBufferAccess &result,
1009                                                       tcu::PixelBufferAccess &reference) const
1010 {
1011     DE_UNREF(result);
1012     DE_UNREF(reference);
1013     return true;
1014 }
1015 
1016 } // namespace
1017 
createImageWriteOpTests(tcu::TestContext & testCtx)1018 tcu::TestCaseGroup *createImageWriteOpTests(tcu::TestContext &testCtx)
1019 {
1020     std::stringstream ss;
1021 
1022     auto genVectorSizesTestName = [&](const VkFormat &f, const int sourceWidth) -> std::string
1023     {
1024         ss.str(std::string());
1025         ss << de::toLower(getSpirvFormat(f)) << "_from";
1026         if (sourceWidth > 1)
1027             ss << "_vec" << sourceWidth;
1028         else
1029             ss << "_scalar";
1030 
1031         return ss.str();
1032     };
1033 
1034     // Test image OpImageWrite operation in various aspects.
1035     auto testGroup = new tcu::TestCaseGroup(testCtx, "mismatched_write_op");
1036     // Case OpImageWrite operation on mismatched vector sizes.
1037     auto testGroupMismatchedVectorSizes = new tcu::TestCaseGroup(testCtx, "mismatched_vector_sizes");
1038     auto testGroupMismatchedSignedness  = new tcu::TestCaseGroup(testCtx, "mismatched_signedness_and_type");
1039 
1040     for (const VkFormat &f : allFormats)
1041     {
1042         const auto switchClass = getTextureChannelClass(mapVkFormat(f).type);
1043         auto compatibleFormats = findFormatsByChannelClass(switchClass);
1044 
1045         auto end   = compatibleFormats.cend();
1046         auto begin = compatibleFormats.cbegin();
1047         for (auto i = begin; i != end; ++i)
1048         {
1049             if (is64BitIntegerFormat(i[0]) || is64BitIntegerFormat(f))
1050                 continue;
1051 
1052             const std::string testName = de::toLower(getSpirvFormat(i[0])) + "_from_" + de::toLower(getSpirvFormat(f));
1053             auto params =
1054                 new MismatchedWriteOpTest::Params{f, 12, 8 * static_cast<int>(std::distance(begin, i) + 1), i[0]};
1055             testGroupMismatchedSignedness->addChild(
1056                 new MismatchedSignednessAndTypeTest(testCtx, testName, MismatchedVectorSizesTest::ParamsSp(params)));
1057         }
1058 
1059         for (int sourceWidth = 4; sourceWidth > 0; --sourceWidth)
1060         {
1061             if (sourceWidth >= getNumUsedChannels(f))
1062             {
1063                 auto params = new MismatchedWriteOpTest::Params{f, 12 * sourceWidth, 8 * (4 - sourceWidth + 1), f};
1064                 testGroupMismatchedVectorSizes->addChild(
1065                     new MismatchedVectorSizesTest(testCtx, genVectorSizesTestName(f, sourceWidth),
1066                                                   MismatchedVectorSizesTest::ParamsSp(params), sourceWidth));
1067             }
1068         }
1069     }
1070 
1071     testGroup->addChild(testGroupMismatchedVectorSizes);
1072     testGroup->addChild(testGroupMismatchedSignedness);
1073 
1074     return testGroup;
1075 }
1076 
1077 } // namespace image
1078 } // namespace vkt
1079