• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 Google Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief YCbCr Test Utilities
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktYCbCrUtil.hpp"
25 
26 #include "vkQueryUtil.hpp"
27 #include "vkRefUtil.hpp"
28 #include "vkTypeUtil.hpp"
29 
30 #include "tcuTextureUtil.hpp"
31 
32 #include "deSTLUtil.hpp"
33 #include "deUniquePtr.hpp"
34 
35 namespace vkt
36 {
37 namespace ycbcr
38 {
39 
40 using namespace vk;
41 
42 using de::MovePtr;
43 using tcu::UVec2;
44 using std::vector;
45 using std::string;
46 
47 typedef de::SharedPtr<Allocation>				AllocationSp;
48 typedef de::SharedPtr<vk::Unique<VkBuffer> >	VkBufferSp;
49 
50 // MultiPlaneImageData
51 
MultiPlaneImageData(VkFormat format,const UVec2 & size)52 MultiPlaneImageData::MultiPlaneImageData (VkFormat format, const UVec2& size)
53 	: m_format		(format)
54 	, m_description	(getPlanarFormatDescription(format))
55 	, m_size		(size)
56 {
57 	for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
58 	{
59 		const deUint32	planeW		= size.x() / m_description.planes[planeNdx].widthDivisor;
60 		const deUint32	planeH		= size.y() / m_description.planes[planeNdx].heightDivisor;
61 		const deUint32	planeSize	= m_description.planes[planeNdx].elementSizeBytes * planeW * planeH;
62 
63 		m_planeData[planeNdx].resize(planeSize);
64 	}
65 }
66 
MultiPlaneImageData(const MultiPlaneImageData & other)67 MultiPlaneImageData::MultiPlaneImageData (const MultiPlaneImageData& other)
68 	: m_format		(other.m_format)
69 	, m_description	(other.m_description)
70 	, m_size		(other.m_size)
71 {
72 	for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
73 		m_planeData[planeNdx] = other.m_planeData[planeNdx];
74 }
75 
~MultiPlaneImageData(void)76 MultiPlaneImageData::~MultiPlaneImageData (void)
77 {
78 }
79 
getChannelAccess(deUint32 channelNdx)80 tcu::PixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx)
81 {
82 	void*		planePtrs[PlanarFormatDescription::MAX_PLANES];
83 	deUint32	planeRowPitches[PlanarFormatDescription::MAX_PLANES];
84 
85 	for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
86 	{
87 		const deUint32	planeW		= m_size.x() / m_description.planes[planeNdx].widthDivisor;
88 
89 		planeRowPitches[planeNdx]	= m_description.planes[planeNdx].elementSizeBytes * planeW;
90 		planePtrs[planeNdx]			= &m_planeData[planeNdx][0];
91 	}
92 
93 	return vk::getChannelAccess(m_description,
94 								m_size,
95 								planeRowPitches,
96 								planePtrs,
97 								channelNdx);
98 }
99 
getChannelAccess(deUint32 channelNdx) const100 tcu::ConstPixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx) const
101 {
102 	const void*	planePtrs[PlanarFormatDescription::MAX_PLANES];
103 	deUint32	planeRowPitches[PlanarFormatDescription::MAX_PLANES];
104 
105 	for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
106 	{
107 		const deUint32	planeW		= m_size.x() / m_description.planes[planeNdx].widthDivisor;
108 
109 		planeRowPitches[planeNdx]	= m_description.planes[planeNdx].elementSizeBytes * planeW;
110 		planePtrs[planeNdx]			= &m_planeData[planeNdx][0];
111 	}
112 
113 	return vk::getChannelAccess(m_description,
114 								m_size,
115 								planeRowPitches,
116 								planePtrs,
117 								channelNdx);
118 }
119 
120 // Misc utilities
121 
122 namespace
123 {
124 
allocateStagingBuffers(const DeviceInterface & vkd,VkDevice device,Allocator & allocator,const MultiPlaneImageData & imageData,vector<VkBufferSp> * buffers,vector<AllocationSp> * allocations)125 void allocateStagingBuffers (const DeviceInterface&			vkd,
126 							 VkDevice						device,
127 							 Allocator&						allocator,
128 							 const MultiPlaneImageData&		imageData,
129 							 vector<VkBufferSp>*			buffers,
130 							 vector<AllocationSp>*			allocations)
131 {
132 	for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
133 	{
134 		const VkBufferCreateInfo	bufferInfo	=
135 		{
136 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
137 			DE_NULL,
138 			(VkBufferCreateFlags)0u,
139 			(VkDeviceSize)imageData.getPlaneSize(planeNdx),
140 			VK_BUFFER_USAGE_TRANSFER_SRC_BIT|VK_BUFFER_USAGE_TRANSFER_DST_BIT,
141 			VK_SHARING_MODE_EXCLUSIVE,
142 			0u,
143 			(const deUint32*)DE_NULL,
144 		};
145 		Move<VkBuffer>				buffer		(createBuffer(vkd, device, &bufferInfo));
146 		MovePtr<Allocation>			allocation	(allocator.allocate(getBufferMemoryRequirements(vkd, device, *buffer),
147 																	MemoryRequirement::HostVisible|MemoryRequirement::Any));
148 
149 		VK_CHECK(vkd.bindBufferMemory(device, *buffer, allocation->getMemory(), allocation->getOffset()));
150 
151 		buffers->push_back(VkBufferSp(new Unique<VkBuffer>(buffer)));
152 		allocations->push_back(AllocationSp(allocation.release()));
153 	}
154 }
155 
allocateAndWriteStagingBuffers(const DeviceInterface & vkd,VkDevice device,Allocator & allocator,const MultiPlaneImageData & imageData,vector<VkBufferSp> * buffers,vector<AllocationSp> * allocations)156 void allocateAndWriteStagingBuffers (const DeviceInterface&		vkd,
157 									  VkDevice						device,
158 									  Allocator&					allocator,
159 									  const MultiPlaneImageData&	imageData,
160 									  vector<VkBufferSp>*			buffers,
161 									  vector<AllocationSp>*			allocations)
162 {
163 	allocateStagingBuffers(vkd, device, allocator, imageData, buffers, allocations);
164 
165 	for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
166 	{
167 		deMemcpy((*allocations)[planeNdx]->getHostPtr(), imageData.getPlanePtr(planeNdx), imageData.getPlaneSize(planeNdx));
168 		flushMappedMemoryRange(vkd, device, (*allocations)[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE);
169 	}
170 }
171 
readStagingBuffers(MultiPlaneImageData * imageData,const DeviceInterface & vkd,VkDevice device,const vector<AllocationSp> & allocations)172 void readStagingBuffers (MultiPlaneImageData*			imageData,
173 						 const DeviceInterface&			vkd,
174 						 VkDevice						device,
175 						 const vector<AllocationSp>&	allocations)
176 {
177 	for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
178 	{
179 		invalidateMappedMemoryRange(vkd, device, allocations[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE);
180 		deMemcpy(imageData->getPlanePtr(planeNdx), allocations[planeNdx]->getHostPtr(), imageData->getPlaneSize(planeNdx));
181 	}
182 }
183 
184 } // anonymous
185 
checkImageSupport(Context & context,VkFormat format,VkImageCreateFlags createFlags,VkImageTiling tiling)186 void checkImageSupport (Context& context, VkFormat format, VkImageCreateFlags createFlags, VkImageTiling tiling)
187 {
188 	const bool													disjoint	= (createFlags & VK_IMAGE_CREATE_DISJOINT_BIT_KHR) != 0;
189 	const VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR*	features	= findStructure<VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR>(context.getDeviceFeatures2().pNext);
190 	vector<string>												reqExts;
191 
192 	reqExts.push_back("VK_KHR_sampler_ycbcr_conversion");
193 
194 	if (disjoint)
195 	{
196 		reqExts.push_back("VK_KHR_bind_memory2");
197 		reqExts.push_back("VK_KHR_get_memory_requirements2");
198 	}
199 
200 	for (vector<string>::const_iterator extIter = reqExts.begin(); extIter != reqExts.end(); ++extIter)
201 	{
202 		if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), *extIter))
203 			TCU_THROW(NotSupportedError, (*extIter + " is not supported").c_str());
204 	}
205 
206 	if (!features || features->samplerYcbcrConversion == VK_FALSE)
207 		TCU_THROW(NotSupportedError, "samplerYcbcrConversion is not supported");
208 
209 	{
210 		const VkFormatProperties	formatProperties	= getPhysicalDeviceFormatProperties(context.getInstanceInterface(),
211 																							context.getPhysicalDevice(),
212 																							format);
213 		const VkFormatFeatureFlags	featureFlags		= tiling == VK_IMAGE_TILING_OPTIMAL
214 														? formatProperties.optimalTilingFeatures
215 														: formatProperties.linearTilingFeatures;
216 
217 		if ((featureFlags & (VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR | VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR)) == 0)
218 			TCU_THROW(NotSupportedError, "YCbCr conversion is not supported for format");
219 
220 		if (disjoint && ((featureFlags & VK_FORMAT_FEATURE_DISJOINT_BIT_KHR) == 0))
221 			TCU_THROW(NotSupportedError, "Disjoint planes are not supported for format");
222 	}
223 }
224 
fillRandom(de::Random * randomGen,MultiPlaneImageData * imageData)225 void fillRandom (de::Random* randomGen, MultiPlaneImageData* imageData)
226 {
227 	// \todo [pyry] Optimize, take into account bits that must be 0
228 
229 	for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
230 	{
231 		const size_t	planeSize	= imageData->getPlaneSize(planeNdx);
232 		deUint8* const	planePtr	= (deUint8*)imageData->getPlanePtr(planeNdx);
233 
234 		for (size_t ndx = 0; ndx < planeSize; ++ndx)
235 			planePtr[ndx] = randomGen->getUint8();
236 	}
237 }
238 
fillGradient(MultiPlaneImageData * imageData,const tcu::Vec4 & minVal,const tcu::Vec4 & maxVal)239 void fillGradient (MultiPlaneImageData* imageData, const tcu::Vec4& minVal, const tcu::Vec4& maxVal)
240 {
241 	const PlanarFormatDescription&	formatInfo	= imageData->getDescription();
242 
243 	// \todo [pyry] Optimize: no point in re-rendering source gradient for each channel.
244 
245 	for (deUint32 channelNdx = 0; channelNdx < 4; channelNdx++)
246 	{
247 		if (formatInfo.hasChannelNdx(channelNdx))
248 		{
249 			const tcu::PixelBufferAccess		channelAccess	= imageData->getChannelAccess(channelNdx);
250 			tcu::TextureLevel					tmpTexture		(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT),  channelAccess.getWidth(), channelAccess.getHeight());
251 			const tcu::ConstPixelBufferAccess	tmpAccess		= tmpTexture.getAccess();
252 
253 			tcu::fillWithComponentGradients(tmpTexture, minVal, maxVal);
254 
255 			for (int y = 0; y < channelAccess.getHeight(); ++y)
256 			for (int x = 0; x < channelAccess.getWidth(); ++x)
257 			{
258 				channelAccess.setPixel(tcu::Vec4(tmpAccess.getPixel(x, y)[channelNdx]), x, y);
259 			}
260 		}
261 	}
262 }
263 
allocateAndBindImageMemory(const DeviceInterface & vkd,VkDevice device,Allocator & allocator,VkImage image,VkFormat format,VkImageCreateFlags createFlags,vk::MemoryRequirement requirement)264 vector<AllocationSp> allocateAndBindImageMemory (const DeviceInterface&	vkd,
265 												 VkDevice				device,
266 												 Allocator&				allocator,
267 												 VkImage				image,
268 												 VkFormat				format,
269 												 VkImageCreateFlags		createFlags,
270 												 vk::MemoryRequirement	requirement)
271 {
272 	vector<AllocationSp> allocations;
273 
274 	if ((createFlags & VK_IMAGE_CREATE_DISJOINT_BIT_KHR) != 0)
275 	{
276 		const deUint32	numPlanes	= getPlaneCount(format);
277 
278 		for (deUint32 planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
279 		{
280 			const VkImageAspectFlagBits	planeAspect	= getPlaneAspect(planeNdx);
281 			const VkMemoryRequirements	reqs		= getImagePlaneMemoryRequirements(vkd, device, image, planeAspect);
282 
283 			allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release()));
284 
285 			bindImagePlaneMemory(vkd, device, image, allocations.back()->getMemory(), allocations.back()->getOffset(), planeAspect);
286 		}
287 	}
288 	else
289 	{
290 		const VkMemoryRequirements	reqs	= getImageMemoryRequirements(vkd, device, image);
291 
292 		allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release()));
293 
294 		VK_CHECK(vkd.bindImageMemory(device, image, allocations.back()->getMemory(), allocations.back()->getOffset()));
295 	}
296 
297 	return allocations;
298 }
299 
uploadImage(const DeviceInterface & vkd,VkDevice device,deUint32 queueFamilyNdx,Allocator & allocator,VkImage image,const MultiPlaneImageData & imageData,VkAccessFlags nextAccess,VkImageLayout finalLayout)300 void uploadImage (const DeviceInterface&		vkd,
301 				  VkDevice						device,
302 				  deUint32						queueFamilyNdx,
303 				  Allocator&					allocator,
304 				  VkImage						image,
305 				  const MultiPlaneImageData&	imageData,
306 				  VkAccessFlags					nextAccess,
307 				  VkImageLayout					finalLayout)
308 {
309 	const VkQueue					queue			= getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
310 	const Unique<VkCommandPool>		cmdPool			(createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
311 	const Unique<VkCommandBuffer>	cmdBuffer		(allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
312 	vector<VkBufferSp>				stagingBuffers;
313 	vector<AllocationSp>			stagingMemory;
314 
315 	const PlanarFormatDescription&	formatDesc		= imageData.getDescription();
316 
317 	allocateAndWriteStagingBuffers(vkd, device, allocator, imageData, &stagingBuffers, &stagingMemory);
318 
319 	{
320 		const VkCommandBufferBeginInfo	beginInfo		=
321 		{
322 			VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
323 			DE_NULL,
324 			(VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
325 			(const VkCommandBufferInheritanceInfo*)DE_NULL
326 		};
327 
328 		VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
329 	}
330 
331 	{
332 		const VkImageMemoryBarrier		preCopyBarrier	=
333 		{
334 			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
335 			DE_NULL,
336 			(VkAccessFlags)0,
337 			VK_ACCESS_TRANSFER_WRITE_BIT,
338 			VK_IMAGE_LAYOUT_UNDEFINED,
339 			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
340 			VK_QUEUE_FAMILY_IGNORED,
341 			VK_QUEUE_FAMILY_IGNORED,
342 			image,
343 			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
344 		};
345 
346 		vkd.cmdPipelineBarrier(*cmdBuffer,
347 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
348 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
349 								(VkDependencyFlags)0u,
350 								0u,
351 								(const VkMemoryBarrier*)DE_NULL,
352 								0u,
353 								(const VkBufferMemoryBarrier*)DE_NULL,
354 								1u,
355 								&preCopyBarrier);
356 	}
357 
358 	for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
359 	{
360 		const VkImageAspectFlagBits	aspect	= (formatDesc.numPlanes > 1)
361 											? getPlaneAspect(planeNdx)
362 											: VK_IMAGE_ASPECT_COLOR_BIT;
363 		const deUint32				planeW	= (formatDesc.numPlanes > 1)
364 											? imageData.getSize().x() / formatDesc.planes[planeNdx].widthDivisor
365 											: imageData.getSize().x();
366 		const deUint32				planeH	= (formatDesc.numPlanes > 1)
367 											? imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor
368 											: imageData.getSize().y();
369 		const VkBufferImageCopy		copy	=
370 		{
371 			0u,		// bufferOffset
372 			0u,		// bufferRowLength
373 			0u,		// bufferImageHeight
374 			{ (VkImageAspectFlags)aspect, 0u, 0u, 1u },
375 			makeOffset3D(0u, 0u, 0u),
376 			makeExtent3D(planeW, planeH, 1u),
377 		};
378 
379 		vkd.cmdCopyBufferToImage(*cmdBuffer, **stagingBuffers[planeNdx], image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &copy);
380 	}
381 
382 	{
383 		const VkImageMemoryBarrier		postCopyBarrier	=
384 		{
385 			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
386 			DE_NULL,
387 			VK_ACCESS_TRANSFER_WRITE_BIT,
388 			nextAccess,
389 			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
390 			finalLayout,
391 			VK_QUEUE_FAMILY_IGNORED,
392 			VK_QUEUE_FAMILY_IGNORED,
393 			image,
394 			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
395 		};
396 
397 		vkd.cmdPipelineBarrier(*cmdBuffer,
398 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
399 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
400 								(VkDependencyFlags)0u,
401 								0u,
402 								(const VkMemoryBarrier*)DE_NULL,
403 								0u,
404 								(const VkBufferMemoryBarrier*)DE_NULL,
405 								1u,
406 								&postCopyBarrier);
407 	}
408 
409 	VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
410 
411 	{
412 		const Unique<VkFence>	fence		(createFence(vkd, device));
413 		const VkSubmitInfo		submitInfo	=
414 		{
415 			VK_STRUCTURE_TYPE_SUBMIT_INFO,
416 			DE_NULL,
417 			0u,
418 			(const VkSemaphore*)DE_NULL,
419 			(const VkPipelineStageFlags*)DE_NULL,
420 			1u,
421 			&*cmdBuffer,
422 			0u,
423 			(const VkSemaphore*)DE_NULL,
424 		};
425 
426 		VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
427 		VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
428 	}
429 }
430 
fillImageMemory(const vk::DeviceInterface & vkd,vk::VkDevice device,deUint32 queueFamilyNdx,vk::VkImage image,const std::vector<de::SharedPtr<vk::Allocation>> & allocations,const MultiPlaneImageData & imageData,vk::VkAccessFlags nextAccess,vk::VkImageLayout finalLayout)431 void fillImageMemory (const vk::DeviceInterface&							vkd,
432 					  vk::VkDevice											device,
433 					  deUint32												queueFamilyNdx,
434 					  vk::VkImage											image,
435 					  const std::vector<de::SharedPtr<vk::Allocation> >&	allocations,
436 					  const MultiPlaneImageData&							imageData,
437 					  vk::VkAccessFlags										nextAccess,
438 					  vk::VkImageLayout										finalLayout)
439 {
440 	const VkQueue					queue			= getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
441 	const Unique<VkCommandPool>		cmdPool			(createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
442 	const Unique<VkCommandBuffer>	cmdBuffer		(allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
443 	const PlanarFormatDescription&	formatDesc		= imageData.getDescription();
444 
445 	for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx)
446 	{
447 		const VkImageAspectFlagBits			aspect		= (formatDesc.numPlanes > 1)
448 														? getPlaneAspect(planeNdx)
449 														: VK_IMAGE_ASPECT_COLOR_BIT;
450 		const de::SharedPtr<Allocation>&	allocation	= allocations.size() > 1
451 														? allocations[planeNdx]
452 														: allocations[0];
453 		const size_t						planeSize	= imageData.getPlaneSize(planeNdx);
454 		const deUint32						planeH		= imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor;
455 		const VkImageSubresource			subresource	=
456 		{
457 			aspect,
458 			0u,
459 			0u,
460 		};
461 		VkSubresourceLayout			layout;
462 
463 		vkd.getImageSubresourceLayout(device, image, &subresource, &layout);
464 
465 		for (deUint32 row = 0; row < planeH; ++row)
466 		{
467 			const size_t		rowSize		= planeSize / planeH;
468 			void* const			dstPtr		= ((deUint8*)allocation->getHostPtr()) + layout.offset + layout.rowPitch * row;
469 			const void* const	srcPtr		= ((const deUint8*)imageData.getPlanePtr(planeNdx)) + row * rowSize;
470 
471 			deMemcpy(dstPtr, srcPtr, rowSize);
472 		}
473 		flushMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE);
474 	}
475 
476 	{
477 		const VkCommandBufferBeginInfo	beginInfo		=
478 		{
479 			VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
480 			DE_NULL,
481 			(VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
482 			(const VkCommandBufferInheritanceInfo*)DE_NULL
483 		};
484 
485 		VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
486 	}
487 
488 
489 	{
490 		const VkImageMemoryBarrier		postCopyBarrier	=
491 		{
492 			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
493 			DE_NULL,
494 			0u,
495 			nextAccess,
496 			VK_IMAGE_LAYOUT_PREINITIALIZED,
497 			finalLayout,
498 			VK_QUEUE_FAMILY_IGNORED,
499 			VK_QUEUE_FAMILY_IGNORED,
500 			image,
501 			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
502 		};
503 
504 		vkd.cmdPipelineBarrier(*cmdBuffer,
505 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
506 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
507 								(VkDependencyFlags)0u,
508 								0u,
509 								(const VkMemoryBarrier*)DE_NULL,
510 								0u,
511 								(const VkBufferMemoryBarrier*)DE_NULL,
512 								1u,
513 								&postCopyBarrier);
514 	}
515 
516 	VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
517 
518 	{
519 		const Unique<VkFence>	fence		(createFence(vkd, device));
520 		const VkSubmitInfo		submitInfo	=
521 		{
522 			VK_STRUCTURE_TYPE_SUBMIT_INFO,
523 			DE_NULL,
524 			0u,
525 			(const VkSemaphore*)DE_NULL,
526 			(const VkPipelineStageFlags*)DE_NULL,
527 			1u,
528 			&*cmdBuffer,
529 			0u,
530 			(const VkSemaphore*)DE_NULL,
531 		};
532 
533 		VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
534 		VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
535 	}
536 }
537 
downloadImage(const DeviceInterface & vkd,VkDevice device,deUint32 queueFamilyNdx,Allocator & allocator,VkImage image,MultiPlaneImageData * imageData,VkAccessFlags prevAccess,VkImageLayout initialLayout)538 void downloadImage (const DeviceInterface&	vkd,
539 					VkDevice				device,
540 					deUint32				queueFamilyNdx,
541 					Allocator&				allocator,
542 					VkImage					image,
543 					MultiPlaneImageData*	imageData,
544 					VkAccessFlags			prevAccess,
545 					VkImageLayout			initialLayout)
546 {
547 	const VkQueue					queue			= getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
548 	const Unique<VkCommandPool>		cmdPool			(createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
549 	const Unique<VkCommandBuffer>	cmdBuffer		(allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
550 	vector<VkBufferSp>				stagingBuffers;
551 	vector<AllocationSp>			stagingMemory;
552 
553 	const PlanarFormatDescription&	formatDesc		= imageData->getDescription();
554 
555 	allocateStagingBuffers(vkd, device, allocator, *imageData, &stagingBuffers, &stagingMemory);
556 
557 	{
558 		const VkCommandBufferBeginInfo	beginInfo		=
559 		{
560 			VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
561 			DE_NULL,
562 			(VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
563 			(const VkCommandBufferInheritanceInfo*)DE_NULL
564 		};
565 
566 		VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
567 	}
568 
569 	for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
570 	{
571 		const VkImageAspectFlagBits	aspect	= (formatDesc.numPlanes > 1)
572 											? getPlaneAspect(planeNdx)
573 											: VK_IMAGE_ASPECT_COLOR_BIT;
574 		{
575 			const VkImageMemoryBarrier		preCopyBarrier	=
576 			{
577 				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
578 				DE_NULL,
579 				prevAccess,
580 				VK_ACCESS_TRANSFER_READ_BIT,
581 				initialLayout,
582 				VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
583 				VK_QUEUE_FAMILY_IGNORED,
584 				VK_QUEUE_FAMILY_IGNORED,
585 				image,
586 				{
587 					aspect,
588 					0u,
589 					1u,
590 					0u,
591 					1u
592 				}
593 			};
594 
595 			vkd.cmdPipelineBarrier(*cmdBuffer,
596 									(VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
597 									(VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
598 									(VkDependencyFlags)0u,
599 									0u,
600 									(const VkMemoryBarrier*)DE_NULL,
601 									0u,
602 									(const VkBufferMemoryBarrier*)DE_NULL,
603 									1u,
604 									&preCopyBarrier);
605 		}
606 		{
607 			const deUint32				planeW	= (formatDesc.numPlanes > 1)
608 												? imageData->getSize().x() / formatDesc.planes[planeNdx].widthDivisor
609 												: imageData->getSize().x();
610 			const deUint32				planeH	= (formatDesc.numPlanes > 1)
611 												? imageData->getSize().y() / formatDesc.planes[planeNdx].heightDivisor
612 												: imageData->getSize().y();
613 			const VkBufferImageCopy		copy	=
614 			{
615 				0u,		// bufferOffset
616 				0u,		// bufferRowLength
617 				0u,		// bufferImageHeight
618 				{ (VkImageAspectFlags)aspect, 0u, 0u, 1u },
619 				makeOffset3D(0u, 0u, 0u),
620 				makeExtent3D(planeW, planeH, 1u),
621 			};
622 
623 			vkd.cmdCopyImageToBuffer(*cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, **stagingBuffers[planeNdx], 1u, &copy);
624 		}
625 		{
626 			const VkBufferMemoryBarrier		postCopyBarrier	=
627 			{
628 				VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
629 				DE_NULL,
630 				VK_ACCESS_TRANSFER_WRITE_BIT,
631 				VK_ACCESS_HOST_READ_BIT,
632 				VK_QUEUE_FAMILY_IGNORED,
633 				VK_QUEUE_FAMILY_IGNORED,
634 				**stagingBuffers[planeNdx],
635 				0u,
636 				VK_WHOLE_SIZE
637 			};
638 
639 			vkd.cmdPipelineBarrier(*cmdBuffer,
640 									(VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
641 									(VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
642 									(VkDependencyFlags)0u,
643 									0u,
644 									(const VkMemoryBarrier*)DE_NULL,
645 									1u,
646 									&postCopyBarrier,
647 									0u,
648 									(const VkImageMemoryBarrier*)DE_NULL);
649 		}
650 	}
651 
652 	VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
653 
654 	{
655 		const Unique<VkFence>	fence		(createFence(vkd, device));
656 		const VkSubmitInfo		submitInfo	=
657 		{
658 			VK_STRUCTURE_TYPE_SUBMIT_INFO,
659 			DE_NULL,
660 			0u,
661 			(const VkSemaphore*)DE_NULL,
662 			(const VkPipelineStageFlags*)DE_NULL,
663 			1u,
664 			&*cmdBuffer,
665 			0u,
666 			(const VkSemaphore*)DE_NULL,
667 		};
668 
669 		VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
670 		VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
671 	}
672 
673 	readStagingBuffers(imageData, vkd, device, stagingMemory);
674 }
675 
readImageMemory(const vk::DeviceInterface & vkd,vk::VkDevice device,deUint32 queueFamilyNdx,vk::VkImage image,const std::vector<de::SharedPtr<vk::Allocation>> & allocations,MultiPlaneImageData * imageData,vk::VkAccessFlags prevAccess,vk::VkImageLayout initialLayout)676 void readImageMemory (const vk::DeviceInterface&							vkd,
677 					  vk::VkDevice											device,
678 					  deUint32												queueFamilyNdx,
679 					  vk::VkImage											image,
680 					  const std::vector<de::SharedPtr<vk::Allocation> >&	allocations,
681 					  MultiPlaneImageData*									imageData,
682 					  vk::VkAccessFlags										prevAccess,
683 					  vk::VkImageLayout										initialLayout)
684 {
685 	const VkQueue					queue			= getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
686 	const Unique<VkCommandPool>		cmdPool			(createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
687 	const Unique<VkCommandBuffer>	cmdBuffer		(allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
688 	const PlanarFormatDescription&	formatDesc		= imageData->getDescription();
689 
690 	{
691 		const VkCommandBufferBeginInfo	beginInfo		=
692 		{
693 			VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
694 			DE_NULL,
695 			(VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
696 			(const VkCommandBufferInheritanceInfo*)DE_NULL
697 		};
698 
699 		VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
700 	}
701 
702 	{
703 		const VkImageMemoryBarrier		preCopyBarrier	=
704 		{
705 			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
706 			DE_NULL,
707 			prevAccess,
708 			vk::VK_ACCESS_HOST_READ_BIT,
709 			initialLayout,
710 			VK_IMAGE_LAYOUT_GENERAL,
711 			VK_QUEUE_FAMILY_IGNORED,
712 			VK_QUEUE_FAMILY_IGNORED,
713 			image,
714 			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
715 		};
716 
717 		vkd.cmdPipelineBarrier(*cmdBuffer,
718 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
719 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
720 								(VkDependencyFlags)0u,
721 								0u,
722 								(const VkMemoryBarrier*)DE_NULL,
723 								0u,
724 								(const VkBufferMemoryBarrier*)DE_NULL,
725 								1u,
726 								&preCopyBarrier);
727 	}
728 
729 	VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
730 
731 	{
732 		const Unique<VkFence>	fence		(createFence(vkd, device));
733 		const VkSubmitInfo		submitInfo	=
734 		{
735 			VK_STRUCTURE_TYPE_SUBMIT_INFO,
736 			DE_NULL,
737 			0u,
738 			(const VkSemaphore*)DE_NULL,
739 			(const VkPipelineStageFlags*)DE_NULL,
740 			1u,
741 			&*cmdBuffer,
742 			0u,
743 			(const VkSemaphore*)DE_NULL,
744 		};
745 
746 		VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
747 		VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
748 	}
749 
750 	for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx)
751 	{
752 		const VkImageAspectFlagBits			aspect		= (formatDesc.numPlanes > 1)
753 														? getPlaneAspect(planeNdx)
754 														: VK_IMAGE_ASPECT_COLOR_BIT;
755 		const de::SharedPtr<Allocation>&	allocation	= allocations.size() > 1
756 														? allocations[planeNdx]
757 														: allocations[0];
758 		const size_t						planeSize	= imageData->getPlaneSize(planeNdx);
759 		const deUint32						planeH		= imageData->getSize().y() / formatDesc.planes[planeNdx].heightDivisor;
760 		const VkImageSubresource			subresource	=
761 		{
762 			aspect,
763 			0u,
764 			0u,
765 		};
766 		VkSubresourceLayout			layout;
767 
768 		vkd.getImageSubresourceLayout(device, image, &subresource, &layout);
769 
770 		invalidateMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE);
771 
772 		for (deUint32 row = 0; row < planeH; ++row)
773 		{
774 			const size_t		rowSize	= planeSize / planeH;
775 			const void* const	srcPtr	= ((const deUint8*)allocation->getHostPtr()) + layout.offset + layout.rowPitch * row;
776 			void* const			dstPtr	= ((deUint8*)imageData->getPlanePtr(planeNdx)) + row * rowSize;
777 
778 			deMemcpy(dstPtr, srcPtr, rowSize);
779 		}
780 	}
781 }
782 
783 } // ycbcr
784 } // vkt
785