Home | History | Annotate | Download | only in ycbcr
      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 
     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 
     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 
     76 MultiPlaneImageData::~MultiPlaneImageData (void)
     77 {
     78 }
     79 
     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 
    100 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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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