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