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