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