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 ©Region);
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 ©Region);
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