• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 Google LLC.
6  *
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 Test no-op image layout transitions in VK_KHR_synchronization2
23  *//*--------------------------------------------------------------------*/
24 
25 #include "deUniquePtr.hpp"
26 
27 #include "tcuTextureUtil.hpp"
28 #include "tcuImageCompare.hpp"
29 
30 #include "vkBarrierUtil.hpp"
31 #include "vkImageUtil.hpp"
32 #include "vkCmdUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkImageWithMemory.hpp"
36 #include "vktTestCaseUtil.hpp"
37 #include "vktSynchronizationUtil.hpp"
38 #include "tcuTestLog.hpp"
39 
40 #include <string>
41 
42 using namespace vk;
43 
44 namespace vkt
45 {
46 namespace synchronization
47 {
48 namespace
49 {
50 
51 using tcu::Vec4;
52 using std::vector;
53 using de::MovePtr;
54 using tcu::TextureLevel;
55 
56 const int			WIDTH	= 64;
57 const int			HEIGHT	= 64;
58 const VkFormat		FORMAT	= VK_FORMAT_R8G8B8A8_UNORM;
59 
makeImageCreateInfo()60 inline VkImageCreateInfo makeImageCreateInfo ()
61 {
62 	const VkImageUsageFlags	usage		= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT
63 										  | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
64 	const VkImageCreateInfo	imageParams	=
65 	{
66 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//  VkStructureType         sType;
67 		DE_NULL,								//  const void*             pNext;
68 		0,										//  VkImageCreateFlags      flags;
69 		VK_IMAGE_TYPE_2D,						//  VkImageType             imageType;
70 		FORMAT,									//  VkFormat                format;
71 		makeExtent3D(WIDTH, HEIGHT, 1u),		//  VkExtent3D              extent;
72 		1u,										//  deUint32                mipLevels;
73 		1u,										//  deUint32                arrayLayers;
74 		VK_SAMPLE_COUNT_1_BIT,					//  VkSampleCountFlagBits   samples;
75 		VK_IMAGE_TILING_OPTIMAL,				//  VkImageTiling           tiling;
76 		usage,									//  VkImageUsageFlags       usage;
77 		VK_SHARING_MODE_EXCLUSIVE,				//  VkSharingMode           sharingMode;
78 		0u,										//  deUint32                queueFamilyIndexCount;
79 		DE_NULL,								//  const deUint32*         pQueueFamilyIndices;
80 		VK_IMAGE_LAYOUT_UNDEFINED,				//  VkImageLayout           initialLayout;
81 	};
82 
83 	return imageParams;
84 }
85 
makeVertexBuffer(const DeviceInterface & vk,const VkDevice device,const deUint32 queueFamilyIndex)86 Move<VkBuffer> makeVertexBuffer (const DeviceInterface& vk, const VkDevice device, const deUint32 queueFamilyIndex)
87 {
88 	const VkBufferCreateInfo vertexBufferParams =
89 	{
90 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType      sType;
91 		DE_NULL,								// const void*          pNext;
92 		0u,										// VkBufferCreateFlags  flags;
93 		1024u,									// VkDeviceSize         size;
94 		VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,		// VkBufferUsageFlags   usage;
95 		VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode        sharingMode;
96 		1u,										// deUint32             queueFamilyIndexCount;
97 		&queueFamilyIndex						// const deUint32*      pQueueFamilyIndices;
98 	};
99 
100 	Move<VkBuffer>			vertexBuffer		= createBuffer(vk, device, &vertexBufferParams);;
101 	return vertexBuffer;
102 }
103 
104 class SynchronizationImageLayoutTransitionTestInstance : public TestInstance
105 {
106 public:
107 					SynchronizationImageLayoutTransitionTestInstance	(Context&			context);
108 	tcu::TestStatus	iterate												(void);
109 };
110 
SynchronizationImageLayoutTransitionTestInstance(Context & context)111 SynchronizationImageLayoutTransitionTestInstance::SynchronizationImageLayoutTransitionTestInstance (Context& context)
112 	: TestInstance	(context)
113 {
114 }
115 
116 template<typename T>
sizeInBytes(const vector<T> & vec)117 inline size_t sizeInBytes (const vector<T>& vec)
118 {
119 	return vec.size() * sizeof(vec[0]);
120 }
121 
122 // Draw a quad covering the whole framebuffer
genFullQuadVertices(void)123 vector<Vec4> genFullQuadVertices (void)
124 {
125 	vector<Vec4> vertices;
126 	vertices.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
127 	vertices.push_back(Vec4( 1.0f, -1.0f, 0.0f, 1.0f));
128 	vertices.push_back(Vec4(-1.0f,  1.0f, 0.0f, 1.0f));
129 	vertices.push_back(Vec4( 1.0f, -1.0f, 0.0f, 1.0f));
130 	vertices.push_back(Vec4( 1.0f,  1.0f, 0.0f, 1.0f));
131 	vertices.push_back(Vec4(-1.0f,  1.0f, 0.0f, 1.0f));
132 
133 	return vertices;
134 }
135 
136 struct Vertex
137 {
Vertexvkt::synchronization::__anon343906920111::Vertex138 	Vertex(Vec4 vertices_) : vertices(vertices_) {}
139 	Vec4 vertices;
140 
141 	static VkVertexInputBindingDescription				getBindingDescription		(void);
142 	static vector<VkVertexInputAttributeDescription>	getAttributeDescriptions	(void);
143 };
144 
getBindingDescription(void)145 VkVertexInputBindingDescription Vertex::getBindingDescription (void)
146 {
147 	static const VkVertexInputBindingDescription desc =
148 	{
149 		0u,										// deUint32             binding;
150 		static_cast<deUint32>(sizeof(Vertex)),	// deUint32             stride;
151 		VK_VERTEX_INPUT_RATE_VERTEX,			// VkVertexInputRate    inputRate;
152 	};
153 
154 	return desc;
155 }
156 
getAttributeDescriptions(void)157 vector<VkVertexInputAttributeDescription> Vertex::getAttributeDescriptions (void)
158 {
159 	static const vector<VkVertexInputAttributeDescription> desc =
160 	{
161 		{
162 			0u,													// deUint32    location;
163 			0u,													// deUint32    binding;
164 			VK_FORMAT_R32G32B32A32_SFLOAT,						// VkFormat    format;
165 			static_cast<deUint32>(offsetof(Vertex, vertices)),	// deUint32    offset;
166 		},
167 	};
168 
169 	return desc;
170 }
171 
iterate(void)172 tcu::TestStatus SynchronizationImageLayoutTransitionTestInstance::iterate (void)
173 {
174 	const DeviceInterface&						vk						= m_context.getDeviceInterface();
175 	const VkDevice								device					= m_context.getDevice();
176 	Allocator&									allocator				= m_context.getDefaultAllocator();
177 	const VkQueue								queue					= m_context.getUniversalQueue();
178 	const deUint32								queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
179 	const VkDeviceSize							bufferSize				= 16 * 1024;
180 
181 	const VkExtent2D							renderSize				= {deUint32(WIDTH), deUint32(HEIGHT)};
182 	const VkRect2D								renderArea				= makeRect2D(makeExtent3D(WIDTH, HEIGHT, 1u));
183 	const vector<VkRect2D>						scissors				(1u, renderArea);
184 	const vector<VkViewport>					viewports				(1u, makeViewport(makeExtent3D(WIDTH, HEIGHT, 1u)));
185 
186 	const vector<Vec4>							vertices				= genFullQuadVertices();
187 	Move<VkBuffer>								vertexBuffer			= makeVertexBuffer(vk, device, queueFamilyIndex);
188 	MovePtr<Allocation>							vertexBufferAlloc		= bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible);
189 	const VkDeviceSize							vertexBufferOffset		= 0ull;
190 
191 	deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], sizeInBytes(vertices));
192 	flushAlloc(vk, device, *vertexBufferAlloc);
193 
194 	const VkImageCreateInfo						targetCreateInfo		= makeImageCreateInfo();
195 	const VkImageSubresourceRange				targetSubresourceRange	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1, 0, 1);
196 	const ImageWithMemory						targetImage				(vk, device, m_context.getDefaultAllocator(), targetCreateInfo, MemoryRequirement::Any);
197 	Move<VkImageView>							targetImageView			= makeImageView(vk, device, *targetImage, VK_IMAGE_VIEW_TYPE_2D, FORMAT, targetSubresourceRange);
198 
199 	const Move<VkCommandPool>					cmdPool					= createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
200 	const Move<VkCommandBuffer>					cmdBuffer				= allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
201 
202 	Move<VkRenderPass>							renderPass				= makeRenderPass(vk, device, FORMAT, VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD);
203 	Move<VkFramebuffer>							framebuffer				= makeFramebuffer(vk, device, *renderPass, targetImageView.get(), renderSize.width, renderSize.height);
204 
205 	const Move<VkShaderModule>					vertexModule			= createShaderModule (vk, device, m_context.getBinaryCollection().get("vert1"), 0u);
206 	const Move<VkShaderModule>					fragmentModule			= createShaderModule (vk, device, m_context.getBinaryCollection().get("frag1"), 0u);
207 
208 	const Move<VkPipelineLayout>				pipelineLayout			= makePipelineLayout (vk, device, DE_NULL);
209 
210 	const VkPipelineColorBlendAttachmentState	clrBlendAttachmentState	=
211 	{
212 		VK_TRUE,								// VkBool32                 blendEnable;
213 		VK_BLEND_FACTOR_SRC_ALPHA,				// VkBlendFactor            srcColorBlendFactor;
214 		VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,	// VkBlendFactor            dstColorBlendFactor;
215 		VK_BLEND_OP_ADD,						// VkBlendOp                colorBlendOp;
216 		VK_BLEND_FACTOR_ONE,					// VkBlendFactor            srcAlphaBlendFactor;
217 		VK_BLEND_FACTOR_ONE,					// VkBlendFactor            dstAlphaBlendFactor;
218 		VK_BLEND_OP_MAX,						// VkBlendOp                alphaBlendOp;
219 		(VkColorComponentFlags)0xF				// VkColorComponentFlags    colorWriteMask;
220 	};
221 
222 	const VkPipelineColorBlendStateCreateInfo	clrBlendStateCreateInfo	=
223 	{
224 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType                               sType;
225 		DE_NULL,													// const void*                                   pNext;
226 		(VkPipelineColorBlendStateCreateFlags)0u,					// VkPipelineColorBlendStateCreateFlags          flags;
227 		VK_FALSE,													// VkBool32                                      logicOpEnable;
228 		VK_LOGIC_OP_CLEAR,											// VkLogicOp                                     logicOp;
229 		1u,															// deUint32                                      attachmentCount;
230 		&clrBlendAttachmentState,									// const VkPipelineColorBlendAttachmentState*    pAttachments;
231 		{ 1.0f, 1.0f, 1.0f, 1.0f }									// float                                         blendConstants[4];
232 	};
233 
234 	const VkVertexInputBindingDescription		vtxBindingDescription	= Vertex::getBindingDescription();
235 	const auto									vtxAttrDescriptions		= Vertex::getAttributeDescriptions();
236 
237 	const VkPipelineVertexInputStateCreateInfo	vtxInputStateCreateInfo	=
238 	{
239 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	// VkStructureType                             sType;
240 		DE_NULL,													// const void*                                 pNext;
241 		(VkPipelineVertexInputStateCreateFlags)0,					// VkPipelineVertexInputStateCreateFlags       flags;
242 		1u,															// deUint32                                    vertexBindingDescriptionCount;
243 		&vtxBindingDescription,										// const VkVertexInputBindingDescription*      pVertexBindingDescriptions
244 		static_cast<deUint32>(vtxAttrDescriptions.size()),			// deUint32                                    vertexAttributeDescriptionCount
245 		vtxAttrDescriptions.data(),									// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions
246 	};
247 
248 	const Move<VkPipeline>						graphicsPipeline		= makeGraphicsPipeline(vk, device, pipelineLayout.get(), vertexModule.get(), DE_NULL, DE_NULL,
249 																							   DE_NULL, fragmentModule.get(), renderPass.get(),
250 																							   viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
251 																							   0u, 0u, &vtxInputStateCreateInfo, DE_NULL,
252 																							   DE_NULL, DE_NULL, &clrBlendStateCreateInfo);
253 
254 	const VkBufferCreateInfo					resultBufferCreateInfo	= makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
255 	Move<VkBuffer>								resultBuffer			= createBuffer(vk, device, &resultBufferCreateInfo);
256 	MovePtr<Allocation>							resultBufferMemory		= allocator.allocate(getBufferMemoryRequirements(vk, device, *resultBuffer), MemoryRequirement::HostVisible);
257 	MovePtr<TextureLevel>						resultImage				(new TextureLevel(mapVkFormat(FORMAT), renderSize.width, renderSize.height, 1));
258 
259 	VK_CHECK(vk.bindBufferMemory(device, *resultBuffer, resultBufferMemory->getMemory(), resultBufferMemory->getOffset()));
260 
261 	const Vec4									clearColor				(0.0f, 0.0f, 0.0f, 0.0f);
262 
263 	clearColorImage(vk, device, m_context.getUniversalQueue(), m_context.getUniversalQueueFamilyIndex(),
264 					targetImage.get(), clearColor, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
265 					VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 1);
266 
267 	beginCommandBuffer(vk, *cmdBuffer);
268 
269 	vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
270 	vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
271 
272 	beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, WIDTH, HEIGHT), 0, DE_NULL);
273 	vk.cmdDraw(*cmdBuffer, static_cast<deUint32>(vertices.size()), 1u, 0u, 0u);
274 	endRenderPass(vk, *cmdBuffer);
275 
276 	// Define an execution dependency and skip the layout transition. This is allowed when oldLayout
277 	// and newLayout are both UNDEFINED. The test will fail if the driver discards the contents of
278 	// the image.
279 	const VkImageMemoryBarrier2KHR				imageMemoryBarrier2		= makeImageMemoryBarrier2(
280 		VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,	// VkPipelineStageFlags2KHR    srcStageMask
281 		VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,			// VkAccessFlags2KHR           srcAccessMask
282 		VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,	// VkPipelineStageFlags2KHR    dstStageMask
283 		VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,			// VkAccessFlags2KHR           dstAccessMask
284 		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout               oldLayout
285 		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout               newLayout
286 		targetImage.get(),								// VkImage                     image
287 		targetSubresourceRange							// VkImageSubresourceRange     subresourceRange
288 	);
289 	VkDependencyInfoKHR							dependencyInfo			= makeCommonDependencyInfo(DE_NULL, DE_NULL, &imageMemoryBarrier2);
290 #ifndef CTS_USES_VULKANSC
291 	vk.cmdPipelineBarrier2(cmdBuffer.get(), &dependencyInfo);
292 #else
293 	vk.cmdPipelineBarrier2KHR(cmdBuffer.get(), &dependencyInfo);
294 #endif // CTS_USES_VULKANSC
295 
296 	beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(0, 0, WIDTH, HEIGHT), 0, DE_NULL);
297 	vk.cmdDraw(*cmdBuffer, static_cast<deUint32>(vertices.size()), 1u, 0u, 0u);
298 	endRenderPass(vk, *cmdBuffer);
299 
300 	// Read the result buffer data
301 	copyImageToBuffer(vk, *cmdBuffer, *targetImage, *resultBuffer, tcu::IVec2(WIDTH, HEIGHT), VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
302 
303 	endCommandBuffer(vk, *cmdBuffer);
304 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
305 
306 	invalidateAlloc(vk, device, *resultBufferMemory);
307 
308 	tcu::clear(resultImage->getAccess(), tcu::IVec4(0));
309 	tcu::copy(resultImage->getAccess(), tcu::ConstPixelBufferAccess(resultImage.get()->getFormat(),
310 			  resultImage.get()->getSize(), resultBufferMemory->getHostPtr()));
311 
312 	TextureLevel								textureLevel			(mapVkFormat(FORMAT), WIDTH, HEIGHT, 1);
313 	const tcu::PixelBufferAccess				expectedImage			= textureLevel.getAccess();
314 
315 	const float									alpha					= 0.4f;
316 	const float									red						= (2.0f - alpha) * alpha;
317 	const float									green					= red;
318 	const float									blue					= 0;
319 	const Vec4									color					= Vec4(red, green, blue, alpha);
320 
321 	for (int y = 0; y < HEIGHT; y++)
322 		for (int x = 0; x < WIDTH; x++)
323 			expectedImage.setPixel(color, x, y, 0);
324 
325 	bool ok = tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Image comparison", "", expectedImage, resultImage->getAccess(), tcu::Vec4(0.01f), tcu::COMPARE_LOG_RESULT);
326 	return ok ? tcu::TestStatus::pass("Pass") : tcu::TestStatus::fail("Fail");
327 }
328 
329 class SynchronizationImageLayoutTransitionTest : public TestCase
330 {
331 public:
332 						SynchronizationImageLayoutTransitionTest	(tcu::TestContext&	testCtx,
333 																	 const std::string&	name,
334 																	 const std::string&	description);
335 
336 	virtual void		checkSupport								(Context&			context) const;
337 	void				initPrograms								(SourceCollections& programCollection) const;
338 	TestInstance*		createInstance								(Context&			context) const;
339 };
340 
SynchronizationImageLayoutTransitionTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description)341 SynchronizationImageLayoutTransitionTest::SynchronizationImageLayoutTransitionTest (tcu::TestContext&	testCtx,
342 																					const std::string&	name,
343 																					const std::string&	description)
344 	: TestCase	(testCtx, name, description)
345 {
346 }
347 
initPrograms(SourceCollections & programCollection) const348 void SynchronizationImageLayoutTransitionTest::initPrograms (SourceCollections& programCollection) const
349 {
350 	std::ostringstream vertexSrc;
351 	vertexSrc
352 		<< glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
353 		<< "layout(location = 0) in vec4 a_position;\n"
354 		<< "void main (void) {\n"
355 		<< "    gl_Position = a_position;\n"
356 		<< "}\n";
357 
358 	std::ostringstream fragmentSrc;
359 	fragmentSrc
360 		<< glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
361 		<< "layout(location = 0) out vec4 outColor;\n"
362 		<< "void main() {\n"
363 		<< "    outColor = vec4(1., 1., 0., .4);\n"
364 		<< "}\n";
365 
366 	programCollection.glslSources.add("vert1") << glu::VertexSource(vertexSrc.str());
367 	programCollection.glslSources.add("frag1") << glu::FragmentSource(fragmentSrc.str());
368 }
369 
checkSupport(Context & context) const370 void SynchronizationImageLayoutTransitionTest::checkSupport (Context& context) const
371 {
372 	context.requireDeviceFunctionality("VK_KHR_synchronization2");
373 }
374 
createInstance(Context & context) const375 TestInstance* SynchronizationImageLayoutTransitionTest::createInstance (Context& context) const
376 {
377 	return new SynchronizationImageLayoutTransitionTestInstance(context);
378 }
379 
380 } // anonymous ns
381 
createImageLayoutTransitionTests(tcu::TestContext & testCtx)382 tcu::TestCaseGroup* createImageLayoutTransitionTests	(tcu::TestContext& testCtx)
383 {
384 	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "layout_transition", "No-op image layout transition tests"));
385 	testGroup->addChild(new SynchronizationImageLayoutTransitionTest(testCtx, "no_op", ""));
386 
387 	return testGroup.release();
388 }
389 
390 } // synchronization
391 } // vkt
392