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