• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  * Copyright (c) 2016 The Android Open Source Project
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief 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, &copyRegion);
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, &copyRegion);
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