• 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 #include "vkCmdUtil.hpp"
30 
31 #include "tcuTextureUtil.hpp"
32 #include "deMath.h"
33 #include "deFloat16.h"
34 #include "tcuVector.hpp"
35 #include "tcuVectorUtil.hpp"
36 
37 #include "deSTLUtil.hpp"
38 #include "deUniquePtr.hpp"
39 
40 namespace vkt
41 {
42 namespace ycbcr
43 {
44 
45 using namespace vk;
46 
47 using de::MovePtr;
48 using tcu::FloatFormat;
49 using tcu::Interval;
50 using tcu::IVec2;
51 using tcu::IVec4;
52 using tcu::UVec2;
53 using tcu::UVec4;
54 using tcu::Vec2;
55 using tcu::Vec4;
56 using std::vector;
57 using std::string;
58 
59 typedef de::SharedPtr<Allocation>				AllocationSp;
60 typedef de::SharedPtr<vk::Unique<VkBuffer> >	VkBufferSp;
61 
62 // MultiPlaneImageData
63 
MultiPlaneImageData(VkFormat format,const UVec2 & size)64 MultiPlaneImageData::MultiPlaneImageData (VkFormat format, const UVec2& size)
65 	: m_format		(format)
66 	, m_description	(getPlanarFormatDescription(format))
67 	, m_size		(size)
68 {
69 	for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
70 	{
71 		const deUint32	planeW		= size.x() / m_description.planes[planeNdx].widthDivisor;
72 		const deUint32	planeH		= size.y() / m_description.planes[planeNdx].heightDivisor;
73 		const deUint32	planeSize	= m_description.planes[planeNdx].elementSizeBytes * planeW * planeH;
74 
75 		m_planeData[planeNdx].resize(planeSize);
76 	}
77 }
78 
MultiPlaneImageData(const MultiPlaneImageData & other)79 MultiPlaneImageData::MultiPlaneImageData (const MultiPlaneImageData& other)
80 	: m_format		(other.m_format)
81 	, m_description	(other.m_description)
82 	, m_size		(other.m_size)
83 {
84 	for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
85 		m_planeData[planeNdx] = other.m_planeData[planeNdx];
86 }
87 
~MultiPlaneImageData(void)88 MultiPlaneImageData::~MultiPlaneImageData (void)
89 {
90 }
91 
getChannelAccess(deUint32 channelNdx)92 tcu::PixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx)
93 {
94 	void*		planePtrs[PlanarFormatDescription::MAX_PLANES];
95 	deUint32	planeRowPitches[PlanarFormatDescription::MAX_PLANES];
96 
97 	for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
98 	{
99 		const deUint32	planeW		= m_size.x() / m_description.planes[planeNdx].widthDivisor;
100 
101 		planeRowPitches[planeNdx]	= m_description.planes[planeNdx].elementSizeBytes * planeW;
102 		planePtrs[planeNdx]			= &m_planeData[planeNdx][0];
103 	}
104 
105 	return vk::getChannelAccess(m_description,
106 								m_size,
107 								planeRowPitches,
108 								planePtrs,
109 								channelNdx);
110 }
111 
getChannelAccess(deUint32 channelNdx) const112 tcu::ConstPixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx) const
113 {
114 	const void*	planePtrs[PlanarFormatDescription::MAX_PLANES];
115 	deUint32	planeRowPitches[PlanarFormatDescription::MAX_PLANES];
116 
117 	for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
118 	{
119 		const deUint32	planeW		= m_size.x() / m_description.planes[planeNdx].widthDivisor;
120 
121 		planeRowPitches[planeNdx]	= m_description.planes[planeNdx].elementSizeBytes * planeW;
122 		planePtrs[planeNdx]			= &m_planeData[planeNdx][0];
123 	}
124 
125 	return vk::getChannelAccess(m_description,
126 								m_size,
127 								planeRowPitches,
128 								planePtrs,
129 								channelNdx);
130 }
131 
132 // Misc utilities
133 
134 namespace
135 {
136 
allocateStagingBuffers(const DeviceInterface & vkd,VkDevice device,Allocator & allocator,const MultiPlaneImageData & imageData,vector<VkBufferSp> * buffers,vector<AllocationSp> * allocations)137 void allocateStagingBuffers (const DeviceInterface&			vkd,
138 							 VkDevice						device,
139 							 Allocator&						allocator,
140 							 const MultiPlaneImageData&		imageData,
141 							 vector<VkBufferSp>*			buffers,
142 							 vector<AllocationSp>*			allocations)
143 {
144 	for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
145 	{
146 		const VkBufferCreateInfo	bufferInfo	=
147 		{
148 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
149 			DE_NULL,
150 			(VkBufferCreateFlags)0u,
151 			(VkDeviceSize)imageData.getPlaneSize(planeNdx),
152 			VK_BUFFER_USAGE_TRANSFER_SRC_BIT|VK_BUFFER_USAGE_TRANSFER_DST_BIT,
153 			VK_SHARING_MODE_EXCLUSIVE,
154 			0u,
155 			(const deUint32*)DE_NULL,
156 		};
157 		Move<VkBuffer>				buffer		(createBuffer(vkd, device, &bufferInfo));
158 		MovePtr<Allocation>			allocation	(allocator.allocate(getBufferMemoryRequirements(vkd, device, *buffer),
159 																	MemoryRequirement::HostVisible|MemoryRequirement::Any));
160 
161 		VK_CHECK(vkd.bindBufferMemory(device, *buffer, allocation->getMemory(), allocation->getOffset()));
162 
163 		buffers->push_back(VkBufferSp(new Unique<VkBuffer>(buffer)));
164 		allocations->push_back(AllocationSp(allocation.release()));
165 	}
166 }
167 
allocateAndWriteStagingBuffers(const DeviceInterface & vkd,VkDevice device,Allocator & allocator,const MultiPlaneImageData & imageData,vector<VkBufferSp> * buffers,vector<AllocationSp> * allocations)168 void allocateAndWriteStagingBuffers (const DeviceInterface&		vkd,
169 									  VkDevice						device,
170 									  Allocator&					allocator,
171 									  const MultiPlaneImageData&	imageData,
172 									  vector<VkBufferSp>*			buffers,
173 									  vector<AllocationSp>*			allocations)
174 {
175 	allocateStagingBuffers(vkd, device, allocator, imageData, buffers, allocations);
176 
177 	for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
178 	{
179 		deMemcpy((*allocations)[planeNdx]->getHostPtr(), imageData.getPlanePtr(planeNdx), imageData.getPlaneSize(planeNdx));
180 		flushMappedMemoryRange(vkd, device, (*allocations)[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE);
181 	}
182 }
183 
readStagingBuffers(MultiPlaneImageData * imageData,const DeviceInterface & vkd,VkDevice device,const vector<AllocationSp> & allocations)184 void readStagingBuffers (MultiPlaneImageData*			imageData,
185 						 const DeviceInterface&			vkd,
186 						 VkDevice						device,
187 						 const vector<AllocationSp>&	allocations)
188 {
189 	for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
190 	{
191 		invalidateMappedMemoryRange(vkd, device, allocations[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE);
192 		deMemcpy(imageData->getPlanePtr(planeNdx), allocations[planeNdx]->getHostPtr(), imageData->getPlaneSize(planeNdx));
193 	}
194 }
195 
196 } // anonymous
197 
checkImageSupport(Context & context,VkFormat format,VkImageCreateFlags createFlags,VkImageTiling tiling)198 void checkImageSupport (Context& context, VkFormat format, VkImageCreateFlags createFlags, VkImageTiling tiling)
199 {
200 	const bool													disjoint	= (createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0;
201 	const VkPhysicalDeviceSamplerYcbcrConversionFeatures		features	= context.getSamplerYCbCrConversionFeatures();
202 	vector<string>												reqExts;
203 
204 	if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_sampler_ycbcr_conversion"))
205 		reqExts.push_back("VK_KHR_sampler_ycbcr_conversion");
206 
207 	if (disjoint)
208 	{
209 		if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_bind_memory2"))
210 			reqExts.push_back("VK_KHR_bind_memory2");
211 		if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_get_memory_requirements2"))
212 			reqExts.push_back("VK_KHR_get_memory_requirements2");
213 	}
214 
215 	for (vector<string>::const_iterator extIter = reqExts.begin(); extIter != reqExts.end(); ++extIter)
216 	{
217 		if (!isDeviceExtensionSupported(context.getUsedApiVersion(), context.getDeviceExtensions(), *extIter))
218 			TCU_THROW(NotSupportedError, (*extIter + " is not supported").c_str());
219 	}
220 
221 	if (features.samplerYcbcrConversion == VK_FALSE)
222 	{
223 		TCU_THROW(NotSupportedError, "samplerYcbcrConversion is not supported");
224 	}
225 
226 	{
227 		const VkFormatProperties	formatProperties	= getPhysicalDeviceFormatProperties(context.getInstanceInterface(),
228 																							context.getPhysicalDevice(),
229 																							format);
230 		const VkFormatFeatureFlags	featureFlags		= tiling == VK_IMAGE_TILING_OPTIMAL
231 														? formatProperties.optimalTilingFeatures
232 														: formatProperties.linearTilingFeatures;
233 
234 		if ((featureFlags & (VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT | VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) == 0)
235 			TCU_THROW(NotSupportedError, "YCbCr conversion is not supported for format");
236 
237 		if (disjoint && ((featureFlags & VK_FORMAT_FEATURE_DISJOINT_BIT) == 0))
238 			TCU_THROW(NotSupportedError, "Disjoint planes are not supported for format");
239 	}
240 }
241 
fillRandom(de::Random * randomGen,MultiPlaneImageData * imageData)242 void fillRandom (de::Random* randomGen, MultiPlaneImageData* imageData)
243 {
244 	// \todo [pyry] Optimize, take into account bits that must be 0
245 
246 	for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
247 	{
248 		const size_t	planeSize	= imageData->getPlaneSize(planeNdx);
249 		deUint8* const	planePtr	= (deUint8*)imageData->getPlanePtr(planeNdx);
250 
251 		for (size_t ndx = 0; ndx < planeSize; ++ndx)
252 			planePtr[ndx] = randomGen->getUint8();
253 	}
254 }
255 
fillGradient(MultiPlaneImageData * imageData,const tcu::Vec4 & minVal,const tcu::Vec4 & maxVal)256 void fillGradient (MultiPlaneImageData* imageData, const tcu::Vec4& minVal, const tcu::Vec4& maxVal)
257 {
258 	const PlanarFormatDescription&	formatInfo	= imageData->getDescription();
259 
260 	// \todo [pyry] Optimize: no point in re-rendering source gradient for each channel.
261 
262 	for (deUint32 channelNdx = 0; channelNdx < 4; channelNdx++)
263 	{
264 		if (formatInfo.hasChannelNdx(channelNdx))
265 		{
266 			const tcu::PixelBufferAccess		channelAccess	= imageData->getChannelAccess(channelNdx);
267 			tcu::TextureLevel					tmpTexture		(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT),  channelAccess.getWidth(), channelAccess.getHeight());
268 			const tcu::ConstPixelBufferAccess	tmpAccess		= tmpTexture.getAccess();
269 
270 			tcu::fillWithComponentGradients(tmpTexture, minVal, maxVal);
271 
272 			for (int y = 0; y < channelAccess.getHeight(); ++y)
273 			for (int x = 0; x < channelAccess.getWidth(); ++x)
274 			{
275 				channelAccess.setPixel(tcu::Vec4(tmpAccess.getPixel(x, y)[channelNdx]), x, y);
276 			}
277 		}
278 	}
279 }
280 
allocateAndBindImageMemory(const DeviceInterface & vkd,VkDevice device,Allocator & allocator,VkImage image,VkFormat format,VkImageCreateFlags createFlags,vk::MemoryRequirement requirement)281 vector<AllocationSp> allocateAndBindImageMemory (const DeviceInterface&	vkd,
282 												 VkDevice				device,
283 												 Allocator&				allocator,
284 												 VkImage				image,
285 												 VkFormat				format,
286 												 VkImageCreateFlags		createFlags,
287 												 vk::MemoryRequirement	requirement)
288 {
289 	vector<AllocationSp> allocations;
290 
291 	if ((createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0)
292 	{
293 		const deUint32	numPlanes	= getPlaneCount(format);
294 
295 		for (deUint32 planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
296 		{
297 			const VkImageAspectFlagBits	planeAspect	= getPlaneAspect(planeNdx);
298 			const VkMemoryRequirements	reqs		= getImagePlaneMemoryRequirements(vkd, device, image, planeAspect);
299 
300 			allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release()));
301 
302 			bindImagePlaneMemory(vkd, device, image, allocations.back()->getMemory(), allocations.back()->getOffset(), planeAspect);
303 		}
304 	}
305 	else
306 	{
307 		const VkMemoryRequirements	reqs	= getImageMemoryRequirements(vkd, device, image);
308 
309 		allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release()));
310 
311 		VK_CHECK(vkd.bindImageMemory(device, image, allocations.back()->getMemory(), allocations.back()->getOffset()));
312 	}
313 
314 	return allocations;
315 }
316 
uploadImage(const DeviceInterface & vkd,VkDevice device,deUint32 queueFamilyNdx,Allocator & allocator,VkImage image,const MultiPlaneImageData & imageData,VkAccessFlags nextAccess,VkImageLayout finalLayout)317 void uploadImage (const DeviceInterface&		vkd,
318 				  VkDevice						device,
319 				  deUint32						queueFamilyNdx,
320 				  Allocator&					allocator,
321 				  VkImage						image,
322 				  const MultiPlaneImageData&	imageData,
323 				  VkAccessFlags					nextAccess,
324 				  VkImageLayout					finalLayout)
325 {
326 	const VkQueue					queue			= getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
327 	const Unique<VkCommandPool>		cmdPool			(createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
328 	const Unique<VkCommandBuffer>	cmdBuffer		(allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
329 	vector<VkBufferSp>				stagingBuffers;
330 	vector<AllocationSp>			stagingMemory;
331 
332 	const PlanarFormatDescription&	formatDesc		= imageData.getDescription();
333 
334 	allocateAndWriteStagingBuffers(vkd, device, allocator, imageData, &stagingBuffers, &stagingMemory);
335 
336 	beginCommandBuffer(vkd, *cmdBuffer);
337 
338 	{
339 		const VkImageMemoryBarrier		preCopyBarrier	=
340 		{
341 			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
342 			DE_NULL,
343 			(VkAccessFlags)0,
344 			VK_ACCESS_TRANSFER_WRITE_BIT,
345 			VK_IMAGE_LAYOUT_UNDEFINED,
346 			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
347 			VK_QUEUE_FAMILY_IGNORED,
348 			VK_QUEUE_FAMILY_IGNORED,
349 			image,
350 			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
351 		};
352 
353 		vkd.cmdPipelineBarrier(*cmdBuffer,
354 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
355 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
356 								(VkDependencyFlags)0u,
357 								0u,
358 								(const VkMemoryBarrier*)DE_NULL,
359 								0u,
360 								(const VkBufferMemoryBarrier*)DE_NULL,
361 								1u,
362 								&preCopyBarrier);
363 	}
364 
365 	for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
366 	{
367 		const VkImageAspectFlagBits	aspect	= (formatDesc.numPlanes > 1)
368 											? getPlaneAspect(planeNdx)
369 											: VK_IMAGE_ASPECT_COLOR_BIT;
370 		const deUint32				planeW	= (formatDesc.numPlanes > 1)
371 											? imageData.getSize().x() / formatDesc.planes[planeNdx].widthDivisor
372 											: imageData.getSize().x();
373 		const deUint32				planeH	= (formatDesc.numPlanes > 1)
374 											? imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor
375 											: imageData.getSize().y();
376 		const VkBufferImageCopy		copy	=
377 		{
378 			0u,		// bufferOffset
379 			0u,		// bufferRowLength
380 			0u,		// bufferImageHeight
381 			{ (VkImageAspectFlags)aspect, 0u, 0u, 1u },
382 			makeOffset3D(0u, 0u, 0u),
383 			makeExtent3D(planeW, planeH, 1u),
384 		};
385 
386 		vkd.cmdCopyBufferToImage(*cmdBuffer, **stagingBuffers[planeNdx], image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &copy);
387 	}
388 
389 	{
390 		const VkImageMemoryBarrier		postCopyBarrier	=
391 		{
392 			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
393 			DE_NULL,
394 			VK_ACCESS_TRANSFER_WRITE_BIT,
395 			nextAccess,
396 			VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
397 			finalLayout,
398 			VK_QUEUE_FAMILY_IGNORED,
399 			VK_QUEUE_FAMILY_IGNORED,
400 			image,
401 			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
402 		};
403 
404 		vkd.cmdPipelineBarrier(*cmdBuffer,
405 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
406 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
407 								(VkDependencyFlags)0u,
408 								0u,
409 								(const VkMemoryBarrier*)DE_NULL,
410 								0u,
411 								(const VkBufferMemoryBarrier*)DE_NULL,
412 								1u,
413 								&postCopyBarrier);
414 	}
415 
416 	endCommandBuffer(vkd, *cmdBuffer);
417 
418 	submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
419 }
420 
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)421 void fillImageMemory (const vk::DeviceInterface&							vkd,
422 					  vk::VkDevice											device,
423 					  deUint32												queueFamilyNdx,
424 					  vk::VkImage											image,
425 					  const std::vector<de::SharedPtr<vk::Allocation> >&	allocations,
426 					  const MultiPlaneImageData&							imageData,
427 					  vk::VkAccessFlags										nextAccess,
428 					  vk::VkImageLayout										finalLayout)
429 {
430 	const VkQueue					queue			= getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
431 	const Unique<VkCommandPool>		cmdPool			(createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
432 	const Unique<VkCommandBuffer>	cmdBuffer		(allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
433 	const PlanarFormatDescription&	formatDesc		= imageData.getDescription();
434 
435 	for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx)
436 	{
437 		const VkImageAspectFlagBits			aspect		= (formatDesc.numPlanes > 1)
438 														? getPlaneAspect(planeNdx)
439 														: VK_IMAGE_ASPECT_COLOR_BIT;
440 		const de::SharedPtr<Allocation>&	allocation	= allocations.size() > 1
441 														? allocations[planeNdx]
442 														: allocations[0];
443 		const size_t						planeSize	= imageData.getPlaneSize(planeNdx);
444 		const deUint32						planeH		= imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor;
445 		const VkImageSubresource			subresource	=
446 		{
447 			static_cast<vk::VkImageAspectFlags>(aspect),
448 			0u,
449 			0u,
450 		};
451 		VkSubresourceLayout			layout;
452 
453 		vkd.getImageSubresourceLayout(device, image, &subresource, &layout);
454 
455 		for (deUint32 row = 0; row < planeH; ++row)
456 		{
457 			const size_t		rowSize		= planeSize / planeH;
458 			void* const			dstPtr		= ((deUint8*)allocation->getHostPtr()) + layout.offset + layout.rowPitch * row;
459 			const void* const	srcPtr		= ((const deUint8*)imageData.getPlanePtr(planeNdx)) + row * rowSize;
460 
461 			deMemcpy(dstPtr, srcPtr, rowSize);
462 		}
463 		flushMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE);
464 	}
465 
466 	beginCommandBuffer(vkd, *cmdBuffer);
467 
468 	{
469 		const VkImageMemoryBarrier		postCopyBarrier	=
470 		{
471 			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
472 			DE_NULL,
473 			0u,
474 			nextAccess,
475 			VK_IMAGE_LAYOUT_PREINITIALIZED,
476 			finalLayout,
477 			VK_QUEUE_FAMILY_IGNORED,
478 			VK_QUEUE_FAMILY_IGNORED,
479 			image,
480 			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
481 		};
482 
483 		vkd.cmdPipelineBarrier(*cmdBuffer,
484 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
485 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
486 								(VkDependencyFlags)0u,
487 								0u,
488 								(const VkMemoryBarrier*)DE_NULL,
489 								0u,
490 								(const VkBufferMemoryBarrier*)DE_NULL,
491 								1u,
492 								&postCopyBarrier);
493 	}
494 
495 	endCommandBuffer(vkd, *cmdBuffer);
496 
497 	submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
498 }
499 
downloadImage(const DeviceInterface & vkd,VkDevice device,deUint32 queueFamilyNdx,Allocator & allocator,VkImage image,MultiPlaneImageData * imageData,VkAccessFlags prevAccess,VkImageLayout initialLayout)500 void downloadImage (const DeviceInterface&	vkd,
501 					VkDevice				device,
502 					deUint32				queueFamilyNdx,
503 					Allocator&				allocator,
504 					VkImage					image,
505 					MultiPlaneImageData*	imageData,
506 					VkAccessFlags			prevAccess,
507 					VkImageLayout			initialLayout)
508 {
509 	const VkQueue					queue			= getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
510 	const Unique<VkCommandPool>		cmdPool			(createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
511 	const Unique<VkCommandBuffer>	cmdBuffer		(allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
512 	vector<VkBufferSp>				stagingBuffers;
513 	vector<AllocationSp>			stagingMemory;
514 
515 	const PlanarFormatDescription&	formatDesc		= imageData->getDescription();
516 
517 	allocateStagingBuffers(vkd, device, allocator, *imageData, &stagingBuffers, &stagingMemory);
518 
519 	beginCommandBuffer(vkd, *cmdBuffer);
520 
521 	for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
522 	{
523 		const VkImageAspectFlagBits	aspect	= (formatDesc.numPlanes > 1)
524 											? getPlaneAspect(planeNdx)
525 											: VK_IMAGE_ASPECT_COLOR_BIT;
526 		{
527 			const VkImageMemoryBarrier		preCopyBarrier	=
528 			{
529 				VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
530 				DE_NULL,
531 				prevAccess,
532 				VK_ACCESS_TRANSFER_READ_BIT,
533 				initialLayout,
534 				VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
535 				VK_QUEUE_FAMILY_IGNORED,
536 				VK_QUEUE_FAMILY_IGNORED,
537 				image,
538 				{
539 					static_cast<vk::VkImageAspectFlags>(aspect),
540 					0u,
541 					1u,
542 					0u,
543 					1u
544 				}
545 			};
546 
547 			vkd.cmdPipelineBarrier(*cmdBuffer,
548 									(VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
549 									(VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
550 									(VkDependencyFlags)0u,
551 									0u,
552 									(const VkMemoryBarrier*)DE_NULL,
553 									0u,
554 									(const VkBufferMemoryBarrier*)DE_NULL,
555 									1u,
556 									&preCopyBarrier);
557 		}
558 		{
559 			const deUint32				planeW	= (formatDesc.numPlanes > 1)
560 												? imageData->getSize().x() / formatDesc.planes[planeNdx].widthDivisor
561 												: imageData->getSize().x();
562 			const deUint32				planeH	= (formatDesc.numPlanes > 1)
563 												? imageData->getSize().y() / formatDesc.planes[planeNdx].heightDivisor
564 												: imageData->getSize().y();
565 			const VkBufferImageCopy		copy	=
566 			{
567 				0u,		// bufferOffset
568 				0u,		// bufferRowLength
569 				0u,		// bufferImageHeight
570 				{ (VkImageAspectFlags)aspect, 0u, 0u, 1u },
571 				makeOffset3D(0u, 0u, 0u),
572 				makeExtent3D(planeW, planeH, 1u),
573 			};
574 
575 			vkd.cmdCopyImageToBuffer(*cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **stagingBuffers[planeNdx], 1u, &copy);
576 		}
577 		{
578 			const VkBufferMemoryBarrier		postCopyBarrier	=
579 			{
580 				VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
581 				DE_NULL,
582 				VK_ACCESS_TRANSFER_WRITE_BIT,
583 				VK_ACCESS_HOST_READ_BIT,
584 				VK_QUEUE_FAMILY_IGNORED,
585 				VK_QUEUE_FAMILY_IGNORED,
586 				**stagingBuffers[planeNdx],
587 				0u,
588 				VK_WHOLE_SIZE
589 			};
590 
591 			vkd.cmdPipelineBarrier(*cmdBuffer,
592 									(VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
593 									(VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
594 									(VkDependencyFlags)0u,
595 									0u,
596 									(const VkMemoryBarrier*)DE_NULL,
597 									1u,
598 									&postCopyBarrier,
599 									0u,
600 									(const VkImageMemoryBarrier*)DE_NULL);
601 		}
602 	}
603 
604 	endCommandBuffer(vkd, *cmdBuffer);
605 
606 	submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
607 
608 	readStagingBuffers(imageData, vkd, device, stagingMemory);
609 }
610 
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)611 void readImageMemory (const vk::DeviceInterface&							vkd,
612 					  vk::VkDevice											device,
613 					  deUint32												queueFamilyNdx,
614 					  vk::VkImage											image,
615 					  const std::vector<de::SharedPtr<vk::Allocation> >&	allocations,
616 					  MultiPlaneImageData*									imageData,
617 					  vk::VkAccessFlags										prevAccess,
618 					  vk::VkImageLayout										initialLayout)
619 {
620 	const VkQueue					queue			= getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
621 	const Unique<VkCommandPool>		cmdPool			(createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
622 	const Unique<VkCommandBuffer>	cmdBuffer		(allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
623 	const PlanarFormatDescription&	formatDesc		= imageData->getDescription();
624 
625 	beginCommandBuffer(vkd, *cmdBuffer);
626 
627 	{
628 		const VkImageMemoryBarrier		preCopyBarrier	=
629 		{
630 			VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
631 			DE_NULL,
632 			prevAccess,
633 			vk::VK_ACCESS_HOST_READ_BIT,
634 			initialLayout,
635 			VK_IMAGE_LAYOUT_GENERAL,
636 			VK_QUEUE_FAMILY_IGNORED,
637 			VK_QUEUE_FAMILY_IGNORED,
638 			image,
639 			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
640 		};
641 
642 		vkd.cmdPipelineBarrier(*cmdBuffer,
643 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
644 								(VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
645 								(VkDependencyFlags)0u,
646 								0u,
647 								(const VkMemoryBarrier*)DE_NULL,
648 								0u,
649 								(const VkBufferMemoryBarrier*)DE_NULL,
650 								1u,
651 								&preCopyBarrier);
652 	}
653 
654 	endCommandBuffer(vkd, *cmdBuffer);
655 
656 	submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
657 
658 	for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx)
659 	{
660 		const VkImageAspectFlagBits			aspect		= (formatDesc.numPlanes > 1)
661 														? getPlaneAspect(planeNdx)
662 														: VK_IMAGE_ASPECT_COLOR_BIT;
663 		const de::SharedPtr<Allocation>&	allocation	= allocations.size() > 1
664 														? allocations[planeNdx]
665 														: allocations[0];
666 		const size_t						planeSize	= imageData->getPlaneSize(planeNdx);
667 		const deUint32						planeH		= imageData->getSize().y() / formatDesc.planes[planeNdx].heightDivisor;
668 		const VkImageSubresource			subresource	=
669 		{
670 			static_cast<vk::VkImageAspectFlags>(aspect),
671 			0u,
672 			0u,
673 		};
674 		VkSubresourceLayout			layout;
675 
676 		vkd.getImageSubresourceLayout(device, image, &subresource, &layout);
677 
678 		invalidateMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE);
679 
680 		for (deUint32 row = 0; row < planeH; ++row)
681 		{
682 			const size_t		rowSize	= planeSize / planeH;
683 			const void* const	srcPtr	= ((const deUint8*)allocation->getHostPtr()) + layout.offset + layout.rowPitch * row;
684 			void* const			dstPtr	= ((deUint8*)imageData->getPlanePtr(planeNdx)) + row * rowSize;
685 
686 			deMemcpy(dstPtr, srcPtr, rowSize);
687 		}
688 	}
689 }
690 
691 // ChannelAccess utilities
692 namespace
693 {
694 
695 //! Extend < 32b signed integer to 32b
signExtend(deUint32 src,int bits)696 inline deInt32 signExtend (deUint32 src, int bits)
697 {
698 	const deUint32 signBit = 1u << (bits-1);
699 
700 	src |= ~((src & signBit) - 1);
701 
702 	return (deInt32)src;
703 }
704 
divRoundUp(deUint32 a,deUint32 b)705 deUint32 divRoundUp (deUint32 a, deUint32 b)
706 {
707 	if (a % b == 0)
708 		return a / b;
709 	else
710 		return (a / b) + 1;
711 }
712 
713 // \todo Taken from tcuTexture.cpp
714 // \todo [2011-09-21 pyry] Move to tcutil?
715 template <typename T>
convertSatRte(float f)716 inline T convertSatRte (float f)
717 {
718 	// \note Doesn't work for 64-bit types
719 	DE_STATIC_ASSERT(sizeof(T) < sizeof(deUint64));
720 	DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
721 
722 	deInt64	minVal	= std::numeric_limits<T>::min();
723 	deInt64 maxVal	= std::numeric_limits<T>::max();
724 	float	q		= deFloatFrac(f);
725 	deInt64 intVal	= (deInt64)(f-q);
726 
727 	// Rounding.
728 	if (q == 0.5f)
729 	{
730 		if (intVal % 2 != 0)
731 			intVal++;
732 	}
733 	else if (q > 0.5f)
734 		intVal++;
735 	// else Don't add anything
736 
737 	// Saturate.
738 	intVal = de::max(minVal, de::min(maxVal, intVal));
739 
740 	return (T)intVal;
741 }
742 
743 } // anonymous
744 
ChannelAccess(tcu::TextureChannelClass channelClass,deUint8 channelSize,const tcu::IVec3 & size,const tcu::IVec3 & bitPitch,void * data,deUint32 bitOffset)745 ChannelAccess::ChannelAccess (tcu::TextureChannelClass	channelClass,
746 							  deUint8					channelSize,
747 							  const tcu::IVec3&			size,
748 							  const tcu::IVec3&			bitPitch,
749 							  void*						data,
750 							  deUint32					bitOffset)
751 	: m_channelClass	(channelClass)
752 	, m_channelSize		(channelSize)
753 	, m_size			(size)
754 	, m_bitPitch		(bitPitch)
755 
756 	, m_data			((deUint8*)data + (bitOffset / 8))
757 	, m_bitOffset		(bitOffset % 8)
758 {
759 }
760 
getChannelUint(const tcu::IVec3 & pos) const761 deUint32 ChannelAccess::getChannelUint (const tcu::IVec3& pos) const
762 {
763 	DE_ASSERT(pos[0] < m_size[0]);
764 	DE_ASSERT(pos[1] < m_size[1]);
765 	DE_ASSERT(pos[2] < m_size[2]);
766 
767 	const deInt32			bitOffset	(m_bitOffset + tcu::dot(m_bitPitch, pos));
768 	const deUint8* const	firstByte	= ((const deUint8*)m_data) + (bitOffset / 8);
769 	const deUint32			byteCount	= divRoundUp((bitOffset + m_channelSize) - 8u * (bitOffset / 8u), 8u);
770 	const deUint32			mask		(m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
771 	const deUint32			offset		= bitOffset % 8;
772 	deUint32				bits		= 0u;
773 
774 	deMemcpy(&bits, firstByte, byteCount);
775 
776 	return (bits >> offset) & mask;
777 }
778 
setChannel(const tcu::IVec3 & pos,deUint32 x)779 void ChannelAccess::setChannel (const tcu::IVec3& pos, deUint32 x)
780 {
781 	DE_ASSERT(pos[0] < m_size[0]);
782 	DE_ASSERT(pos[1] < m_size[1]);
783 	DE_ASSERT(pos[2] < m_size[2]);
784 
785 	const deInt32	bitOffset	(m_bitOffset + tcu::dot(m_bitPitch, pos));
786 	deUint8* const	firstByte	= ((deUint8*)m_data) + (bitOffset / 8);
787 	const deUint32	byteCount	= divRoundUp((bitOffset + m_channelSize) - 8u * (bitOffset / 8u), 8u);
788 	const deUint32	mask		(m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
789 	const deUint32	offset		= bitOffset % 8;
790 
791 	const deUint32	bits		= (x & mask) << offset;
792 	deUint32		oldBits		= 0;
793 
794 	deMemcpy(&oldBits, firstByte, byteCount);
795 
796 	{
797 		const deUint32	newBits	= bits | (oldBits & (~(mask << offset)));
798 
799 		deMemcpy(firstByte, &newBits,  byteCount);
800 	}
801 }
802 
getChannel(const tcu::IVec3 & pos) const803 float ChannelAccess::getChannel (const tcu::IVec3& pos) const
804 {
805 	const deUint32	bits	(getChannelUint(pos));
806 
807 	switch (m_channelClass)
808 	{
809 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
810 			return (float)bits / (float)(m_channelSize == 32 ? ~0x0u : ((0x1u << m_channelSize) - 1u));
811 
812 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
813 			return (float)bits;
814 
815 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
816 			return de::max(-1.0f, (float)signExtend(bits, m_channelSize) / (float)((0x1u << (m_channelSize - 1u)) - 1u));
817 
818 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
819 			return (float)signExtend(bits, m_channelSize);
820 
821 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
822 			if (m_channelSize == 32)
823 				return tcu::Float32(bits).asFloat();
824 			else
825 			{
826 				DE_FATAL("Float type not supported");
827 				return -1.0f;
828 			}
829 
830 		default:
831 			DE_FATAL("Unknown texture channel class");
832 			return -1.0f;
833 	}
834 }
835 
getChannel(const tcu::FloatFormat & conversionFormat,const tcu::IVec3 & pos) const836 tcu::Interval ChannelAccess::getChannel (const tcu::FloatFormat&	conversionFormat,
837 										 const tcu::IVec3&			pos) const
838 {
839 	const deUint32	bits	(getChannelUint(pos));
840 
841 	switch (m_channelClass)
842 	{
843 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
844 			return conversionFormat.roundOut(conversionFormat.roundOut((double)bits, false)
845 											/ conversionFormat.roundOut((double)(m_channelSize == 32 ? ~0x0u : ((0x1u << m_channelSize) - 1u)), false), false);
846 
847 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
848 			return conversionFormat.roundOut((double)bits, false);
849 
850 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
851 		{
852 			const tcu::Interval result (conversionFormat.roundOut(conversionFormat.roundOut((double)signExtend(bits, m_channelSize), false)
853 																/ conversionFormat.roundOut((double)((0x1u << (m_channelSize - 1u)) - 1u), false), false));
854 
855 			return tcu::Interval(de::max(-1.0, result.lo()), de::max(-1.0, result.hi()));
856 		}
857 
858 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
859 			return conversionFormat.roundOut((double)signExtend(bits, m_channelSize), false);
860 
861 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
862 			if (m_channelSize == 32)
863 				return conversionFormat.roundOut(tcu::Float32(bits).asFloat(), false);
864 			else
865 			{
866 				DE_FATAL("Float type not supported");
867 				return tcu::Interval();
868 			}
869 
870 		default:
871 			DE_FATAL("Unknown texture channel class");
872 			return tcu::Interval();
873 	}
874 }
875 
setChannel(const tcu::IVec3 & pos,float x)876 void ChannelAccess::setChannel (const tcu::IVec3& pos, float x)
877 {
878 	DE_ASSERT(pos[0] < m_size[0]);
879 	DE_ASSERT(pos[1] < m_size[1]);
880 	DE_ASSERT(pos[2] < m_size[2]);
881 
882 	const deUint32	mask	(m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
883 
884 	switch (m_channelClass)
885 	{
886 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
887 		{
888 			const deUint32	maxValue	(mask);
889 			const deUint32	value		(de::min(maxValue, (deUint32)convertSatRte<deUint32>(x * (float)maxValue)));
890 			setChannel(pos, value);
891 			break;
892 		}
893 
894 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
895 		{
896 			const deInt32	range	((0x1u << (m_channelSize - 1u)) - 1u);
897 			const deUint32	value	((deUint32)de::clamp<deInt32>(convertSatRte<deInt32>(x * (float)range), -range, range));
898 			setChannel(pos, value);
899 			break;
900 		}
901 
902 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
903 		{
904 			const deUint32	maxValue	(mask);
905 			const deUint32	value		(de::min(maxValue, (deUint32)x));
906 			setChannel(pos, value);
907 			break;
908 		}
909 
910 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
911 		{
912 			const deInt32	minValue	(-(deInt32)(1u << (m_channelSize - 1u)));
913 			const deInt32	maxValue	((deInt32)((1u << (m_channelSize - 1u)) - 1u));
914 			const deUint32	value		((deUint32)de::clamp((deInt32)x, minValue, maxValue));
915 			setChannel(pos, value);
916 			break;
917 		}
918 
919 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
920 		{
921 			if (m_channelSize == 32)
922 			{
923 				const deUint32	value		= tcu::Float32(x).bits();
924 				setChannel(pos, value);
925 			}
926 			else
927 				DE_FATAL("Float type not supported");
928 			break;
929 		}
930 
931 		default:
932 			DE_FATAL("Unknown texture channel class");
933 	}
934 }
935 
getChannelAccess(MultiPlaneImageData & data,const vk::PlanarFormatDescription & formatInfo,const UVec2 & size,int channelNdx)936 ChannelAccess getChannelAccess (MultiPlaneImageData&				data,
937 								const vk::PlanarFormatDescription&	formatInfo,
938 								const UVec2&						size,
939 								int									channelNdx)
940 {
941 	DE_ASSERT(formatInfo.hasChannelNdx(channelNdx));
942 
943 	const deUint32	planeNdx			= formatInfo.channels[channelNdx].planeNdx;
944 	const deUint32	valueOffsetBits		= formatInfo.channels[channelNdx].offsetBits;
945 	const deUint32	pixelStrideBytes	= formatInfo.channels[channelNdx].strideBytes;
946 	const deUint32	pixelStrideBits		= pixelStrideBytes * 8;
947 	const deUint8	sizeBits			= formatInfo.channels[channelNdx].sizeBits;
948 
949 	DE_ASSERT(size.x() % formatInfo.planes[planeNdx].widthDivisor == 0);
950 	DE_ASSERT(size.y() % formatInfo.planes[planeNdx].heightDivisor == 0);
951 
952 	deUint32		accessWidth			= size.x() / formatInfo.planes[planeNdx].widthDivisor;
953 	const deUint32	accessHeight		= size.y() / formatInfo.planes[planeNdx].heightDivisor;
954 	const deUint32	elementSizeBytes	= formatInfo.planes[planeNdx].elementSizeBytes;
955 
956 	const deUint32	rowPitch			= formatInfo.planes[planeNdx].elementSizeBytes * accessWidth;
957 	const deUint32	rowPitchBits		= rowPitch * 8;
958 
959 	if (pixelStrideBytes != elementSizeBytes)
960 	{
961 		DE_ASSERT(elementSizeBytes % pixelStrideBytes == 0);
962 		accessWidth *= elementSizeBytes/pixelStrideBytes;
963 	}
964 
965 	return ChannelAccess((tcu::TextureChannelClass)formatInfo.channels[channelNdx].type, sizeBits, tcu::IVec3(accessWidth, accessHeight, 1u), tcu::IVec3((int)pixelStrideBits, (int)rowPitchBits, 0), data.getPlanePtr(planeNdx), (deUint32)valueOffsetBits);
966 }
967 
isXChromaSubsampled(vk::VkFormat format)968 bool isXChromaSubsampled (vk::VkFormat format)
969 {
970 	switch (format)
971 	{
972 		case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
973 		case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
974 		case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
975 		case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
976 		case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
977 		case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
978 		case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
979 		case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
980 		case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
981 		case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
982 		case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
983 		case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
984 		case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
985 		case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
986 		case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
987 		case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
988 		case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
989 		case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
990 		case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
991 		case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
992 		case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
993 		case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
994 		case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
995 		case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
996 			return true;
997 
998 		default:
999 			return false;
1000 	}
1001 }
1002 
isYChromaSubsampled(vk::VkFormat format)1003 bool isYChromaSubsampled (vk::VkFormat format)
1004 {
1005 	switch (format)
1006 	{
1007 		case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1008 		case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1009 		case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1010 		case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1011 		case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1012 		case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1013 		case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1014 		case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1015 			return true;
1016 
1017 		default:
1018 			return false;
1019 	}
1020 }
1021 
areLsb6BitsDontCare(vk::VkFormat srcFormat,vk::VkFormat dstFormat)1022 bool areLsb6BitsDontCare(vk::VkFormat srcFormat, vk::VkFormat dstFormat)
1023 {
1024 	if ((srcFormat == vk::VK_FORMAT_R10X6_UNORM_PACK16)	                        ||
1025 		(dstFormat == vk::VK_FORMAT_R10X6_UNORM_PACK16)                         ||
1026 		(srcFormat == vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16)                   ||
1027 		(dstFormat == vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16)                   ||
1028 		(srcFormat == vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16)         ||
1029 		(dstFormat == vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16)         ||
1030 		(srcFormat == vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16)     ||
1031 		(dstFormat == vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16)     ||
1032 		(srcFormat == vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16)     ||
1033 		(dstFormat == vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16)     ||
1034 		(srcFormat == vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16)  ||
1035 		(dstFormat == vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16)  ||
1036 		(srcFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16) ||
1037 		(dstFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16) ||
1038 		(srcFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16) ||
1039 		(dstFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16) ||
1040 		(srcFormat == vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16)  ||
1041 		(dstFormat == vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16)  ||
1042 		(srcFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16) ||
1043 		(dstFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16))
1044 	{
1045 		return true;
1046 	}
1047 
1048 	return false;
1049 }
1050 
areLsb4BitsDontCare(vk::VkFormat srcFormat,vk::VkFormat dstFormat)1051 bool areLsb4BitsDontCare(vk::VkFormat srcFormat, vk::VkFormat dstFormat)
1052 {
1053 	if ((srcFormat == vk::VK_FORMAT_R12X4_UNORM_PACK16)                         ||
1054 		(dstFormat == vk::VK_FORMAT_R12X4_UNORM_PACK16)                         ||
1055 		(srcFormat == vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16)                   ||
1056 		(dstFormat == vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16)                   ||
1057 		(srcFormat == vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16)         ||
1058 		(dstFormat == vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16)         ||
1059 		(srcFormat == vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16)     ||
1060 		(dstFormat == vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16)     ||
1061 		(srcFormat == vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16)     ||
1062 		(dstFormat == vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16)     ||
1063 		(srcFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16) ||
1064 		(dstFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16) ||
1065 		(srcFormat == vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16)  ||
1066 		(dstFormat == vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16)  ||
1067 		(srcFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16) ||
1068 		(dstFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16) ||
1069 		(srcFormat == vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16)  ||
1070 		(dstFormat == vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16)  ||
1071 		(srcFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16) ||
1072 		(dstFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16))
1073 	{
1074 		return true;
1075 	}
1076 
1077 	return false;
1078 }
1079 
1080 // \note Used for range expansion
getYCbCrBitDepth(vk::VkFormat format)1081 tcu::UVec4 getYCbCrBitDepth (vk::VkFormat format)
1082 {
1083 	switch (format)
1084 	{
1085 		case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
1086 		case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
1087 		case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1088 		case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1089 		case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
1090 		case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
1091 		case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
1092 			return tcu::UVec4(8, 8, 8, 0);
1093 
1094 		case vk::VK_FORMAT_R10X6_UNORM_PACK16:
1095 			return tcu::UVec4(10, 0, 0, 0);
1096 
1097 		case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
1098 			return tcu::UVec4(10, 10, 0, 0);
1099 
1100 		case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
1101 			return tcu::UVec4(10, 10, 10, 10);
1102 
1103 		case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
1104 		case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
1105 		case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1106 		case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1107 		case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
1108 		case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
1109 		case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
1110 			return tcu::UVec4(10, 10, 10, 0);
1111 
1112 		case vk::VK_FORMAT_R12X4_UNORM_PACK16:
1113 			return tcu::UVec4(12, 0, 0, 0);
1114 
1115 		case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
1116 			return tcu::UVec4(12, 12, 0, 0);
1117 
1118 		case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
1119 		case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
1120 		case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
1121 		case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1122 		case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1123 		case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
1124 		case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
1125 		case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
1126 			return tcu::UVec4(12, 12, 12, 12);
1127 
1128 		case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
1129 		case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
1130 		case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1131 		case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1132 		case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
1133 		case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
1134 		case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
1135 			return tcu::UVec4(16, 16, 16, 0);
1136 
1137 		default:
1138 			return tcu::getTextureFormatBitDepth(vk::mapVkFormat(format)).cast<deUint32>();
1139 	}
1140 }
1141 
1142 // \note Taken from explicit lod filtering tests
getYCbCrFilteringPrecision(vk::VkFormat format)1143 tcu::FloatFormat getYCbCrFilteringPrecision (vk::VkFormat format)
1144 {
1145 	const tcu::FloatFormat	reallyLow	(0, 0, 6, false, tcu::YES);
1146 	const tcu::FloatFormat	low			(0, 0, 7, false, tcu::YES);
1147 	const tcu::FloatFormat	fp16		(-14, 15, 10, false);
1148 	const tcu::FloatFormat	fp32		(-126, 127, 23, true);
1149 
1150 	switch (format)
1151 	{
1152 		case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16:
1153 		case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16:
1154 		case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
1155 		case vk::VK_FORMAT_B5G6R5_UNORM_PACK16:
1156 		case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16:
1157 		case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16:
1158 		case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16:
1159 			return reallyLow;
1160 
1161 		case vk::VK_FORMAT_R8G8B8_UNORM:
1162 		case vk::VK_FORMAT_B8G8R8_UNORM:
1163 		case vk::VK_FORMAT_R8G8B8A8_UNORM:
1164 		case vk::VK_FORMAT_B8G8R8A8_UNORM:
1165 		case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32:
1166 		case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
1167 		case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
1168 		case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1169 		case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1170 		case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
1171 		case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
1172 		case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
1173 		case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32:
1174 		case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1175 			return low;
1176 
1177 		case vk::VK_FORMAT_R16G16B16_UNORM:
1178 		case vk::VK_FORMAT_R16G16B16A16_UNORM:
1179 		case vk::VK_FORMAT_R10X6_UNORM_PACK16:
1180 		case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
1181 		case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
1182 		case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
1183 		case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
1184 		case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1185 		case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1186 		case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
1187 		case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
1188 		case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
1189 		case vk::VK_FORMAT_R12X4_UNORM_PACK16:
1190 		case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
1191 		case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
1192 		case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
1193 		case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
1194 		case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1195 		case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1196 		case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
1197 		case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
1198 		case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
1199 		case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
1200 		case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
1201 		case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1202 		case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1203 		case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
1204 		case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
1205 		case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
1206 			return fp16;
1207 
1208 		default:
1209 			DE_FATAL("Precision not defined for format");
1210 			return fp32;
1211 	}
1212 }
1213 
1214 // \note Taken from explicit lod filtering tests
getYCbCrConversionPrecision(vk::VkFormat format)1215 tcu::FloatFormat getYCbCrConversionPrecision (vk::VkFormat format)
1216 {
1217 	const tcu::FloatFormat	reallyLow	(0, 0, 8, false, tcu::YES);
1218 	const tcu::FloatFormat	fp16		(-14, 15, 10, false);
1219 	const tcu::FloatFormat	fp32		(-126, 127, 23, true);
1220 
1221 	switch (format)
1222 	{
1223 		case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16:
1224 		case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16:
1225 		case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
1226 		case vk::VK_FORMAT_B5G6R5_UNORM_PACK16:
1227 		case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16:
1228 		case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16:
1229 		case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16:
1230 			return reallyLow;
1231 
1232 		case vk::VK_FORMAT_R8G8B8_UNORM:
1233 		case vk::VK_FORMAT_B8G8R8_UNORM:
1234 		case vk::VK_FORMAT_R8G8B8A8_UNORM:
1235 		case vk::VK_FORMAT_B8G8R8A8_UNORM:
1236 		case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32:
1237 		case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
1238 		case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
1239 		case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1240 		case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1241 		case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
1242 		case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
1243 		case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
1244 			return reallyLow;
1245 
1246 		case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32:
1247 		case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1248 		case vk::VK_FORMAT_R16G16B16_UNORM:
1249 		case vk::VK_FORMAT_R16G16B16A16_UNORM:
1250 		case vk::VK_FORMAT_R10X6_UNORM_PACK16:
1251 		case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
1252 		case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
1253 		case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
1254 		case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
1255 		case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1256 		case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1257 		case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
1258 		case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
1259 		case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
1260 		case vk::VK_FORMAT_R12X4_UNORM_PACK16:
1261 		case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
1262 		case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
1263 		case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
1264 		case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
1265 		case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1266 		case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1267 		case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
1268 		case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
1269 		case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
1270 		case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
1271 		case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
1272 		case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1273 		case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1274 		case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
1275 		case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
1276 		case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
1277 			return fp16;
1278 
1279 		default:
1280 			DE_FATAL("Precision not defined for format");
1281 			return fp32;
1282 	}
1283 }
1284 
getYCbCrFormatChannelCount(vk::VkFormat format)1285 deUint32 getYCbCrFormatChannelCount (vk::VkFormat format)
1286 {
1287 	switch (format)
1288 	{
1289 		case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16:
1290 		case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1291 		case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32:
1292 		case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32:
1293 		case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16:
1294 		case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16:
1295 		case vk::VK_FORMAT_B8G8R8A8_UNORM:
1296 		case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
1297 		case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
1298 		case vk::VK_FORMAT_R16G16B16A16_UNORM:
1299 		case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16:
1300 		case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16:
1301 		case vk::VK_FORMAT_R8G8B8A8_UNORM:
1302 			return 4;
1303 
1304 		case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
1305 		case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
1306 		case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
1307 		case vk::VK_FORMAT_B5G6R5_UNORM_PACK16:
1308 		case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
1309 		case vk::VK_FORMAT_B8G8R8_UNORM:
1310 		case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
1311 		case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1312 		case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
1313 		case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1314 		case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
1315 		case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
1316 		case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
1317 		case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1318 		case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
1319 		case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1320 		case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
1321 		case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
1322 		case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
1323 		case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1324 		case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
1325 		case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1326 		case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
1327 		case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
1328 		case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
1329 		case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1330 		case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
1331 		case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1332 		case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
1333 		case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
1334 		case vk::VK_FORMAT_R16G16B16_UNORM:
1335 		case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
1336 		case vk::VK_FORMAT_R8G8B8_UNORM:
1337 			return 3;
1338 
1339 		case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
1340 		case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
1341 			return 2;
1342 
1343 		case vk::VK_FORMAT_R10X6_UNORM_PACK16:
1344 		case vk::VK_FORMAT_R12X4_UNORM_PACK16:
1345 			return 1;
1346 
1347 		default:
1348 			DE_FATAL("Unknown number of channels");
1349 			return -1;
1350 	}
1351 }
1352 
1353 // YCbCr color conversion utilities
1354 namespace
1355 {
1356 
rangeExpandChroma(vk::VkSamplerYcbcrRange range,const tcu::FloatFormat & conversionFormat,const deUint32 bits,const tcu::Interval & sample)1357 tcu::Interval rangeExpandChroma (vk::VkSamplerYcbcrRange		range,
1358 								 const tcu::FloatFormat&		conversionFormat,
1359 								 const deUint32					bits,
1360 								 const tcu::Interval&			sample)
1361 {
1362 	const deUint32	values	(0x1u << bits);
1363 
1364 	switch (range)
1365 	{
1366 		case vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL:
1367 			return conversionFormat.roundOut(sample - conversionFormat.roundOut(tcu::Interval((double)(0x1u << (bits - 1u)) / (double)((0x1u << bits) - 1u)), false), false);
1368 
1369 		case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW:
1370 		{
1371 			const tcu::Interval	a			(conversionFormat.roundOut(sample * tcu::Interval((double)(values - 1u)), false));
1372 			const tcu::Interval	dividend	(conversionFormat.roundOut(a - tcu::Interval((double)(128u * (0x1u << (bits - 8u)))), false));
1373 			const tcu::Interval	divisor		((double)(224u * (0x1u << (bits - 8u))));
1374 			const tcu::Interval	result		(conversionFormat.roundOut(dividend / divisor, false));
1375 
1376 			return result;
1377 		}
1378 
1379 		default:
1380 			DE_FATAL("Unknown YCbCrRange");
1381 			return tcu::Interval();
1382 	}
1383 }
1384 
rangeExpandLuma(vk::VkSamplerYcbcrRange range,const tcu::FloatFormat & conversionFormat,const deUint32 bits,const tcu::Interval & sample)1385 tcu::Interval rangeExpandLuma (vk::VkSamplerYcbcrRange		range,
1386 							   const tcu::FloatFormat&		conversionFormat,
1387 							   const deUint32				bits,
1388 							   const tcu::Interval&			sample)
1389 {
1390 	const deUint32	values	(0x1u << bits);
1391 
1392 	switch (range)
1393 	{
1394 		case vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL:
1395 			return conversionFormat.roundOut(sample, false);
1396 
1397 		case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW:
1398 		{
1399 			const tcu::Interval	a			(conversionFormat.roundOut(sample * tcu::Interval((double)(values - 1u)), false));
1400 			const tcu::Interval	dividend	(conversionFormat.roundOut(a - tcu::Interval((double)(16u * (0x1u << (bits - 8u)))), false));
1401 			const tcu::Interval	divisor		((double)(219u * (0x1u << (bits - 8u))));
1402 			const tcu::Interval	result		(conversionFormat.roundOut(dividend / divisor, false));
1403 
1404 			return result;
1405 		}
1406 
1407 		default:
1408 			DE_FATAL("Unknown YCbCrRange");
1409 			return tcu::Interval();
1410 	}
1411 }
1412 
clampMaybe(const tcu::Interval & x,double min,double max)1413 tcu::Interval clampMaybe (const tcu::Interval&	x,
1414 						  double				min,
1415 						  double				max)
1416 {
1417 	tcu::Interval result = x;
1418 
1419 	DE_ASSERT(min <= max);
1420 
1421 	if (x.lo() < min)
1422 		result = result | tcu::Interval(min);
1423 
1424 	if (x.hi() > max)
1425 		result = result | tcu::Interval(max);
1426 
1427 	return result;
1428 }
1429 
convertColor(vk::VkSamplerYcbcrModelConversion colorModel,vk::VkSamplerYcbcrRange range,const tcu::FloatFormat & conversionFormat,const tcu::UVec4 & bitDepth,const tcu::Interval input[4],tcu::Interval output[4])1430 void convertColor (vk::VkSamplerYcbcrModelConversion	colorModel,
1431 				   vk::VkSamplerYcbcrRange				range,
1432 				   const tcu::FloatFormat&				conversionFormat,
1433 				   const tcu::UVec4&					bitDepth,
1434 				   const tcu::Interval					input[4],
1435 				   tcu::Interval						output[4])
1436 {
1437 	switch (colorModel)
1438 	{
1439 		case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY:
1440 		{
1441 			for (size_t ndx = 0; ndx < 4; ndx++)
1442 				output[ndx] = input[ndx];
1443 			break;
1444 		}
1445 
1446 		case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY:
1447 		{
1448 			output[0] = clampMaybe(rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]), -0.5, 0.5);
1449 			output[1] = clampMaybe(rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]), 0.0, 1.0);
1450 			output[2] = clampMaybe(rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]), -0.5, 0.5);
1451 			output[3] = input[3];
1452 			break;
1453 		}
1454 
1455 		case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601:
1456 		{
1457 			const tcu::Interval	y			(rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]));
1458 			const tcu::Interval	cr			(rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]));
1459 			const tcu::Interval	cb			(rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]));
1460 
1461 			const tcu::Interval	yClamped	(clampMaybe(y,   0.0, 1.0));
1462 			const tcu::Interval	crClamped	(clampMaybe(cr, -0.5, 0.5));
1463 			const tcu::Interval	cbClamped	(clampMaybe(cb, -0.5, 0.5));
1464 
1465 			output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.402 * crClamped, false), false);
1466 			output[1] = conversionFormat.roundOut(conversionFormat.roundOut(yClamped - conversionFormat.roundOut((0.202008 / 0.587) * cbClamped, false), false) - conversionFormat.roundOut((0.419198 / 0.587) * crClamped, false), false);
1467 			output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.772 * cbClamped, false), false);
1468 			output[3] = input[3];
1469 			break;
1470 		}
1471 
1472 		case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709:
1473 		{
1474 			const tcu::Interval	y			(rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]));
1475 			const tcu::Interval	cr			(rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]));
1476 			const tcu::Interval	cb			(rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]));
1477 
1478 			const tcu::Interval	yClamped	(clampMaybe(y,   0.0, 1.0));
1479 			const tcu::Interval	crClamped	(clampMaybe(cr, -0.5, 0.5));
1480 			const tcu::Interval	cbClamped	(clampMaybe(cb, -0.5, 0.5));
1481 
1482 			output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.5748 * crClamped, false), false);
1483 			output[1] = conversionFormat.roundOut(conversionFormat.roundOut(yClamped - conversionFormat.roundOut((0.13397432 / 0.7152) * cbClamped, false), false) - conversionFormat.roundOut((0.33480248 / 0.7152) * crClamped, false), false);
1484 			output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.8556 * cbClamped, false), false);
1485 			output[3] = input[3];
1486 			break;
1487 		}
1488 
1489 		case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020:
1490 		{
1491 			const tcu::Interval	y			(rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]));
1492 			const tcu::Interval	cr			(rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]));
1493 			const tcu::Interval	cb			(rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]));
1494 
1495 			const tcu::Interval	yClamped	(clampMaybe(y,   0.0, 1.0));
1496 			const tcu::Interval	crClamped	(clampMaybe(cr, -0.5, 0.5));
1497 			const tcu::Interval	cbClamped	(clampMaybe(cb, -0.5, 0.5));
1498 
1499 			output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.4746 * crClamped, false), false);
1500 			output[1] = conversionFormat.roundOut(conversionFormat.roundOut(yClamped - conversionFormat.roundOut(conversionFormat.roundOut(0.11156702 / 0.6780, false) * cbClamped, false), false) - conversionFormat.roundOut(conversionFormat.roundOut(0.38737742 / 0.6780, false) * crClamped, false), false);
1501 			output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.8814 * cbClamped, false), false);
1502 			output[3] = input[3];
1503 			break;
1504 		}
1505 
1506 		default:
1507 			DE_FATAL("Unknown YCbCrModel");
1508 	}
1509 
1510 	if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY)
1511 	{
1512 		for (int ndx = 0; ndx < 3; ndx++)
1513 			output[ndx] = clampMaybe(output[ndx], 0.0, 1.0);
1514 	}
1515 }
1516 
mirror(int coord)1517 int mirror (int coord)
1518 {
1519 	return coord >= 0 ? coord : -(1 + coord);
1520 }
1521 
imod(int a,int b)1522 int imod (int a, int b)
1523 {
1524 	int m = a % b;
1525 	return m < 0 ? m + b : m;
1526 }
1527 
frac(const tcu::Interval & x)1528 tcu::Interval frac (const tcu::Interval& x)
1529 {
1530 	if (x.hi() - x.lo() >= 1.0)
1531 		return tcu::Interval(0.0, 1.0);
1532 	else
1533 	{
1534 		const tcu::Interval ret (deFrac(x.lo()), deFrac(x.hi()));
1535 
1536 		return ret;
1537 	}
1538 }
1539 
calculateUV(const tcu::FloatFormat & coordFormat,const tcu::Interval & st,const int size)1540 tcu::Interval calculateUV (const tcu::FloatFormat&	coordFormat,
1541 						   const tcu::Interval&		st,
1542 						   const int				size)
1543 {
1544 	return coordFormat.roundOut(coordFormat.roundOut(st, false) * tcu::Interval((double)size), false);
1545 }
1546 
calculateNearestIJRange(const tcu::FloatFormat & coordFormat,const tcu::Interval & uv)1547 tcu::IVec2 calculateNearestIJRange (const tcu::FloatFormat&	coordFormat,
1548 								    const tcu::Interval&	uv)
1549 {
1550 	const tcu::Interval	ij	(coordFormat.roundOut(coordFormat.roundOut(uv, false) - tcu::Interval(0.5), false));
1551 
1552 	return tcu::IVec2(deRoundToInt32(ij.lo() - coordFormat.ulp(ij.lo(), 1)), deRoundToInt32(ij.hi() + coordFormat.ulp(ij.hi(), 1)));
1553 }
1554 
1555 // Calculate range of pixel coordinates that can be used as lower coordinate for linear sampling
calculateLinearIJRange(const tcu::FloatFormat & coordFormat,const tcu::Interval & uv)1556 tcu::IVec2 calculateLinearIJRange (const tcu::FloatFormat&	coordFormat,
1557 								   const tcu::Interval&		uv)
1558 {
1559 	const tcu::Interval	ij	(coordFormat.roundOut(uv - tcu::Interval(0.5), false));
1560 
1561 	return tcu::IVec2(deFloorToInt32(ij.lo()), deFloorToInt32(ij.hi()));
1562 }
1563 
calculateAB(const deUint32 subTexelPrecisionBits,const tcu::Interval & uv,int ij)1564 tcu::Interval calculateAB (const deUint32		subTexelPrecisionBits,
1565 						   const tcu::Interval&	uv,
1566 						   int					ij)
1567 {
1568 	const deUint32		subdivisions	= 0x1u << subTexelPrecisionBits;
1569 	const tcu::Interval	ab				(frac((uv - 0.5) & tcu::Interval((double)ij, (double)(ij + 1))));
1570 	const tcu::Interval	gridAB			(ab * tcu::Interval(subdivisions));
1571 	const tcu::Interval	rounded			(de::max(deFloor(gridAB.lo()) / subdivisions, 0.0) , de::min(deCeil(gridAB.hi()) / subdivisions, 1.0));
1572 
1573 	return rounded;
1574 }
1575 
lookupWrapped(const ChannelAccess & access,const tcu::FloatFormat & conversionFormat,vk::VkSamplerAddressMode addressModeU,vk::VkSamplerAddressMode addressModeV,const tcu::IVec2 & coord)1576 tcu::Interval lookupWrapped (const ChannelAccess&		access,
1577 							 const tcu::FloatFormat&	conversionFormat,
1578 							 vk::VkSamplerAddressMode	addressModeU,
1579 							 vk::VkSamplerAddressMode	addressModeV,
1580 							 const tcu::IVec2&			coord)
1581 {
1582 	return access.getChannel(conversionFormat,
1583 							 tcu::IVec3(wrap(addressModeU, coord.x(), access.getSize().x()), wrap(addressModeV, coord.y(), access.getSize().y()), 0));
1584 }
1585 
linearInterpolate(const tcu::FloatFormat & filteringFormat,const tcu::Interval & a,const tcu::Interval & b,const tcu::Interval & p00,const tcu::Interval & p10,const tcu::Interval & p01,const tcu::Interval & p11)1586 tcu::Interval linearInterpolate (const tcu::FloatFormat&	filteringFormat,
1587 								 const tcu::Interval&		a,
1588 								 const tcu::Interval&		b,
1589 								 const tcu::Interval&		p00,
1590 								 const tcu::Interval&		p10,
1591 								 const tcu::Interval&		p01,
1592 								 const tcu::Interval&		p11)
1593 {
1594 	const tcu::Interval	p[4] =
1595 	{
1596 		p00,
1597 		p10,
1598 		p01,
1599 		p11
1600 	};
1601 	tcu::Interval		result	(0.0);
1602 
1603 	for (size_t ndx = 0; ndx < 4; ndx++)
1604 	{
1605 		const tcu::Interval	weightA	(filteringFormat.roundOut((ndx % 2) == 0 ? (1.0 - a) : a, false));
1606 		const tcu::Interval	weightB	(filteringFormat.roundOut((ndx / 2) == 0 ? (1.0 - b) : b, false));
1607 		const tcu::Interval	weight	(filteringFormat.roundOut(weightA * weightB, false));
1608 
1609 		result = filteringFormat.roundOut(result + filteringFormat.roundOut(p[ndx] * weight, false), false);
1610 	}
1611 
1612 	return result;
1613 }
1614 
calculateImplicitChromaUV(const tcu::FloatFormat & coordFormat,vk::VkChromaLocation offset,const tcu::Interval & uv)1615 tcu::Interval calculateImplicitChromaUV (const tcu::FloatFormat&	coordFormat,
1616 										 vk::VkChromaLocation		offset,
1617 										 const tcu::Interval&		uv)
1618 {
1619 	if (offset == vk::VK_CHROMA_LOCATION_COSITED_EVEN)
1620 		return coordFormat.roundOut(0.5 * coordFormat.roundOut(uv + 0.5, false), false);
1621 	else
1622 		return coordFormat.roundOut(0.5 * uv, false);
1623 }
1624 
linearSample(const ChannelAccess & access,const tcu::FloatFormat & conversionFormat,const tcu::FloatFormat & filteringFormat,vk::VkSamplerAddressMode addressModeU,vk::VkSamplerAddressMode addressModeV,const tcu::IVec2 & coord,const tcu::Interval & a,const tcu::Interval & b)1625 tcu::Interval linearSample (const ChannelAccess&		access,
1626 						    const tcu::FloatFormat&		conversionFormat,
1627 						    const tcu::FloatFormat&		filteringFormat,
1628 						    vk::VkSamplerAddressMode	addressModeU,
1629 						    vk::VkSamplerAddressMode	addressModeV,
1630 						    const tcu::IVec2&			coord,
1631 						    const tcu::Interval&		a,
1632 						    const tcu::Interval&		b)
1633 {
1634 	return linearInterpolate(filteringFormat, a, b,
1635 									lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(0, 0)),
1636 									lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(1, 0)),
1637 									lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(0, 1)),
1638 									lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(1, 1)));
1639 }
1640 
reconstructLinearXChromaSample(const tcu::FloatFormat & filteringFormat,const tcu::FloatFormat & conversionFormat,vk::VkChromaLocation offset,vk::VkSamplerAddressMode addressModeU,vk::VkSamplerAddressMode addressModeV,const ChannelAccess & access,int i,int j)1641 tcu::Interval reconstructLinearXChromaSample (const tcu::FloatFormat&	filteringFormat,
1642 											  const tcu::FloatFormat&	conversionFormat,
1643 											  vk::VkChromaLocation		offset,
1644 											  vk::VkSamplerAddressMode	addressModeU,
1645 											  vk::VkSamplerAddressMode	addressModeV,
1646 											  const ChannelAccess&		access,
1647 											  int						i,
1648 											  int						j)
1649 {
1650 	const int subI	= divFloor(i, 2);
1651 
1652 	if (offset == vk::VK_CHROMA_LOCATION_COSITED_EVEN)
1653 	{
1654 		if (i % 2 == 0)
1655 			return lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j));
1656 		else
1657 		{
1658 			const tcu::Interval	a	(filteringFormat.roundOut(0.5 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)), false));
1659 			const tcu::Interval	b	(filteringFormat.roundOut(0.5 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, j)), false));
1660 
1661 			return filteringFormat.roundOut(a + b, false);
1662 		}
1663 	}
1664 	else if (offset == vk::VK_CHROMA_LOCATION_MIDPOINT)
1665 	{
1666 		if (i % 2 == 0)
1667 		{
1668 			const tcu::Interval	a	(filteringFormat.roundOut(0.25 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI - 1, j)), false));
1669 			const tcu::Interval	b	(filteringFormat.roundOut(0.75 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)), false));
1670 
1671 			return filteringFormat.roundOut(a + b, false);
1672 		}
1673 		else
1674 		{
1675 			const tcu::Interval	a	(filteringFormat.roundOut(0.25 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, j)), false));
1676 			const tcu::Interval	b	(filteringFormat.roundOut(0.75 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)), false));
1677 
1678 			return filteringFormat.roundOut(a + b, false);
1679 		}
1680 	}
1681 	else
1682 	{
1683 		DE_FATAL("Unknown sample location");
1684 		return tcu::Interval();
1685 	}
1686 }
1687 
reconstructLinearXYChromaSample(const tcu::FloatFormat & filteringFormat,const tcu::FloatFormat & conversionFormat,vk::VkChromaLocation xOffset,vk::VkChromaLocation yOffset,vk::VkSamplerAddressMode addressModeU,vk::VkSamplerAddressMode addressModeV,const ChannelAccess & access,int i,int j)1688 tcu::Interval reconstructLinearXYChromaSample (const tcu::FloatFormat&	filteringFormat,
1689 										  const tcu::FloatFormat&		conversionFormat,
1690 										  vk::VkChromaLocation			xOffset,
1691 										  vk::VkChromaLocation			yOffset,
1692 										  vk::VkSamplerAddressMode		addressModeU,
1693 										  vk::VkSamplerAddressMode		addressModeV,
1694 										  const ChannelAccess&			access,
1695 										  int							i,
1696 										  int							j)
1697 {
1698 	const int		subI	= xOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
1699 							? divFloor(i, 2)
1700 							: (i % 2 == 0 ? divFloor(i, 2) - 1 : divFloor(i, 2));
1701 	const int		subJ	= yOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
1702 							? divFloor(j, 2)
1703 							: (j % 2 == 0 ? divFloor(j, 2) - 1 : divFloor(j, 2));
1704 
1705 	const double	a		= xOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
1706 							? (i % 2 == 0 ? 0.0 : 0.5)
1707 							: (i % 2 == 0 ? 0.25 : 0.75);
1708 	const double	b		= yOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
1709 							? (j % 2 == 0 ? 0.0 : 0.5)
1710 							: (j % 2 == 0 ? 0.25 : 0.75);
1711 
1712 	return linearInterpolate(filteringFormat, a, b,
1713 								lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, subJ)),
1714 								lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, subJ)),
1715 								lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, subJ + 1)),
1716 								lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, subJ + 1)));
1717 }
1718 
swizzle(vk::VkComponentSwizzle swizzle,const ChannelAccess & identityPlane,const ChannelAccess & rPlane,const ChannelAccess & gPlane,const ChannelAccess & bPlane,const ChannelAccess & aPlane)1719 const ChannelAccess& swizzle (vk::VkComponentSwizzle	swizzle,
1720 							  const ChannelAccess&		identityPlane,
1721 							  const ChannelAccess&		rPlane,
1722 							  const ChannelAccess&		gPlane,
1723 							  const ChannelAccess&		bPlane,
1724 							  const ChannelAccess&		aPlane)
1725 {
1726 	switch (swizzle)
1727 	{
1728 		case vk::VK_COMPONENT_SWIZZLE_IDENTITY:	return identityPlane;
1729 		case vk::VK_COMPONENT_SWIZZLE_R:		return rPlane;
1730 		case vk::VK_COMPONENT_SWIZZLE_G:		return gPlane;
1731 		case vk::VK_COMPONENT_SWIZZLE_B:		return bPlane;
1732 		case vk::VK_COMPONENT_SWIZZLE_A:		return aPlane;
1733 
1734 		default:
1735 			DE_FATAL("Unsupported swizzle");
1736 			return identityPlane;
1737 	}
1738 }
1739 
1740 } // anonymous
1741 
wrap(vk::VkSamplerAddressMode addressMode,int coord,int size)1742 int wrap (vk::VkSamplerAddressMode	addressMode,
1743 		  int						coord,
1744 		  int						size)
1745 {
1746 	switch (addressMode)
1747 	{
1748 		case vk::VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT:
1749 			return (size - 1) - mirror(imod(coord, 2 * size) - size);
1750 
1751 		case vk::VK_SAMPLER_ADDRESS_MODE_REPEAT:
1752 			return imod(coord, size);
1753 
1754 		case vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
1755 			return de::clamp(coord, 0, size - 1);
1756 
1757 		case vk::VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE:
1758 			return de::clamp(mirror(coord), 0, size - 1);
1759 
1760 		default:
1761 			DE_FATAL("Unknown wrap mode");
1762 			return ~0;
1763 	}
1764 }
1765 
divFloor(int a,int b)1766 int divFloor (int a, int b)
1767 {
1768 	if (a % b == 0)
1769 		return a / b;
1770 	else if (a > 0)
1771 		return a / b;
1772 	else
1773 		return (a / b) - 1;
1774 }
1775 
calculateBounds(const ChannelAccess & rPlane,const ChannelAccess & gPlane,const ChannelAccess & bPlane,const ChannelAccess & aPlane,const UVec4 & bitDepth,const vector<Vec2> & sts,const FloatFormat & filteringFormat,const FloatFormat & conversionFormat,const deUint32 subTexelPrecisionBits,vk::VkFilter filter,vk::VkSamplerYcbcrModelConversion colorModel,vk::VkSamplerYcbcrRange range,vk::VkFilter chromaFilter,vk::VkChromaLocation xChromaOffset,vk::VkChromaLocation yChromaOffset,const vk::VkComponentMapping & componentMapping,bool explicitReconstruction,vk::VkSamplerAddressMode addressModeU,vk::VkSamplerAddressMode addressModeV,std::vector<Vec4> & minBounds,std::vector<Vec4> & maxBounds,std::vector<Vec4> & uvBounds,std::vector<IVec4> & ijBounds)1776 void calculateBounds (const ChannelAccess&					rPlane,
1777 					  const ChannelAccess&					gPlane,
1778 					  const ChannelAccess&					bPlane,
1779 					  const ChannelAccess&					aPlane,
1780 					  const UVec4&							bitDepth,
1781 					  const vector<Vec2>&					sts,
1782 					  const FloatFormat&					filteringFormat,
1783 					  const FloatFormat&					conversionFormat,
1784 					  const deUint32						subTexelPrecisionBits,
1785 					  vk::VkFilter							filter,
1786 					  vk::VkSamplerYcbcrModelConversion		colorModel,
1787 					  vk::VkSamplerYcbcrRange				range,
1788 					  vk::VkFilter							chromaFilter,
1789 					  vk::VkChromaLocation					xChromaOffset,
1790 					  vk::VkChromaLocation					yChromaOffset,
1791 					  const vk::VkComponentMapping&			componentMapping,
1792 					  bool									explicitReconstruction,
1793 					  vk::VkSamplerAddressMode				addressModeU,
1794 					  vk::VkSamplerAddressMode				addressModeV,
1795 					  std::vector<Vec4>&					minBounds,
1796 					  std::vector<Vec4>&					maxBounds,
1797 					  std::vector<Vec4>&					uvBounds,
1798 					  std::vector<IVec4>&					ijBounds)
1799 {
1800 	const FloatFormat		highp			(-126, 127, 23, true,
1801 											 tcu::MAYBE,	// subnormals
1802 											 tcu::YES,		// infinities
1803 											 tcu::MAYBE);	// NaN
1804 	const FloatFormat		coordFormat		(-32, 32, 16, true);
1805 	const ChannelAccess&	rAccess			(swizzle(componentMapping.r, rPlane, rPlane, gPlane, bPlane, aPlane));
1806 	const ChannelAccess&	gAccess			(swizzle(componentMapping.g, gPlane, rPlane, gPlane, bPlane, aPlane));
1807 	const ChannelAccess&	bAccess			(swizzle(componentMapping.b, bPlane, rPlane, gPlane, bPlane, aPlane));
1808 	const ChannelAccess&	aAccess			(swizzle(componentMapping.a, aPlane, rPlane, gPlane, bPlane, aPlane));
1809 
1810 	const bool				subsampledX		= gAccess.getSize().x() > rAccess.getSize().x();
1811 	const bool				subsampledY		= gAccess.getSize().y() > rAccess.getSize().y();
1812 
1813 	minBounds.resize(sts.size(), Vec4(TCU_INFINITY));
1814 	maxBounds.resize(sts.size(), Vec4(-TCU_INFINITY));
1815 
1816 	uvBounds.resize(sts.size(), Vec4(TCU_INFINITY, -TCU_INFINITY, TCU_INFINITY, -TCU_INFINITY));
1817 	ijBounds.resize(sts.size(), IVec4(0x7FFFFFFF, -1 -0x7FFFFFFF, 0x7FFFFFFF, -1 -0x7FFFFFFF));
1818 
1819 	// Chroma plane sizes must match
1820 	DE_ASSERT(rAccess.getSize() == bAccess.getSize());
1821 
1822 	// Luma plane sizes must match
1823 	DE_ASSERT(gAccess.getSize() == aAccess.getSize());
1824 
1825 	// Luma plane size must match chroma plane or be twice as big
1826 	DE_ASSERT(rAccess.getSize().x() == gAccess.getSize().x() || 2 * rAccess.getSize().x() == gAccess.getSize().x());
1827 	DE_ASSERT(rAccess.getSize().y() == gAccess.getSize().y() || 2 * rAccess.getSize().y() == gAccess.getSize().y());
1828 
1829 	for (size_t ndx = 0; ndx < sts.size(); ndx++)
1830 	{
1831 		const Vec2	st		(sts[ndx]);
1832 		Interval	bounds[4];
1833 
1834 		const Interval	u	(calculateUV(coordFormat, st[0], gAccess.getSize().x()));
1835 		const Interval	v	(calculateUV(coordFormat, st[1], gAccess.getSize().y()));
1836 
1837 		uvBounds[ndx][0] = (float)u.lo();
1838 		uvBounds[ndx][1] = (float)u.hi();
1839 
1840 		uvBounds[ndx][2] = (float)v.lo();
1841 		uvBounds[ndx][3] = (float)v.hi();
1842 
1843 		if (filter == vk::VK_FILTER_NEAREST)
1844 		{
1845 			const IVec2	iRange	(calculateNearestIJRange(coordFormat, u));
1846 			const IVec2	jRange	(calculateNearestIJRange(coordFormat, v));
1847 
1848 			ijBounds[ndx][0] = iRange[0];
1849 			ijBounds[ndx][1] = iRange[1];
1850 
1851 			ijBounds[ndx][2] = jRange[0];
1852 			ijBounds[ndx][3] = jRange[1];
1853 
1854 			for (int j = jRange.x(); j <= jRange.y(); j++)
1855 			for (int i = iRange.x(); i <= iRange.y(); i++)
1856 			{
1857 				const Interval	gValue	(lookupWrapped(gAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)));
1858 				const Interval	aValue	(lookupWrapped(aAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)));
1859 
1860 				if (subsampledX || subsampledY)
1861 				{
1862 					if (explicitReconstruction)
1863 					{
1864 						if (chromaFilter == vk::VK_FILTER_NEAREST)
1865 						{
1866 							// Nearest, Reconstructed chroma with explicit nearest filtering
1867 							const int		subI		= subsampledX ? i / 2 : i;
1868 							const int		subJ		= subsampledY ? j / 2 : j;
1869 							const Interval	srcColor[]	=
1870 							{
1871 								lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ)),
1872 								gValue,
1873 								lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ)),
1874 								aValue
1875 							};
1876 							Interval		dstColor[4];
1877 
1878 							convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1879 
1880 							for (size_t compNdx = 0; compNdx < 4; compNdx++)
1881 								bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1882 						}
1883 						else if (chromaFilter == vk::VK_FILTER_LINEAR)
1884 						{
1885 							if (subsampledX && subsampledY)
1886 							{
1887 								// Nearest, Reconstructed both chroma samples with explicit linear filtering
1888 								const Interval	rValue	(reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i, j));
1889 								const Interval	bValue	(reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i, j));
1890 								const Interval	srcColor[]	=
1891 								{
1892 									rValue,
1893 									gValue,
1894 									bValue,
1895 									aValue
1896 								};
1897 								Interval		dstColor[4];
1898 
1899 								convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1900 
1901 								for (size_t compNdx = 0; compNdx < 4; compNdx++)
1902 									bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1903 							}
1904 							else if (subsampledX)
1905 							{
1906 								// Nearest, Reconstructed x chroma samples with explicit linear filtering
1907 								const Interval	rValue	(reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i, j));
1908 								const Interval	bValue	(reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i, j));
1909 								const Interval	srcColor[]	=
1910 								{
1911 									rValue,
1912 									gValue,
1913 									bValue,
1914 									aValue
1915 								};
1916 								Interval		dstColor[4];
1917 
1918 								convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1919 
1920 								for (size_t compNdx = 0; compNdx < 4; compNdx++)
1921 									bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1922 							}
1923 							else
1924 								DE_FATAL("Unexpected chroma reconstruction");
1925 						}
1926 						else
1927 							DE_FATAL("Unknown filter");
1928 					}
1929 					else
1930 					{
1931 						const Interval	chromaU	(subsampledX ? calculateImplicitChromaUV(coordFormat, xChromaOffset, u) : u);
1932 						const Interval	chromaV	(subsampledY ? calculateImplicitChromaUV(coordFormat, yChromaOffset, v) : v);
1933 
1934 						if (chromaFilter == vk::VK_FILTER_NEAREST)
1935 						{
1936 							// Nearest, reconstructed chroma samples with implicit nearest filtering
1937 							const IVec2	chromaIRange	(subsampledX ? calculateNearestIJRange(coordFormat, chromaU) : IVec2(i, i));
1938 							const IVec2	chromaJRange	(subsampledY ? calculateNearestIJRange(coordFormat, chromaV) : IVec2(j, j));
1939 
1940 							for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
1941 							for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
1942 							{
1943 								const Interval	srcColor[]	=
1944 								{
1945 									lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
1946 									gValue,
1947 									lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
1948 									aValue
1949 								};
1950 								Interval		dstColor[4];
1951 
1952 								convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1953 
1954 								for (size_t compNdx = 0; compNdx < 4; compNdx++)
1955 									bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1956 							}
1957 						}
1958 						else if (chromaFilter == vk::VK_FILTER_LINEAR)
1959 						{
1960 							// Nearest, reconstructed chroma samples with implicit linear filtering
1961 							const IVec2	chromaIRange	(subsampledX ? calculateLinearIJRange(coordFormat, chromaU) : IVec2(i, i));
1962 							const IVec2	chromaJRange	(subsampledY ? calculateLinearIJRange(coordFormat, chromaV) : IVec2(j, j));
1963 
1964 							for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
1965 							for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
1966 							{
1967 								const Interval	chromaA	(calculateAB(subTexelPrecisionBits, chromaU, chromaI));
1968 								const Interval	chromaB	(calculateAB(subTexelPrecisionBits, chromaV, chromaJ));
1969 
1970 								const Interval	srcColor[]	=
1971 								{
1972 									linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB),
1973 									gValue,
1974 									linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB),
1975 									aValue
1976 								};
1977 								Interval		dstColor[4];
1978 
1979 								convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1980 
1981 								for (size_t compNdx = 0; compNdx < 4; compNdx++)
1982 									bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1983 							}
1984 						}
1985 						else
1986 							DE_FATAL("Unknown filter");
1987 					}
1988 				}
1989 				else
1990 				{
1991 					// Linear, no chroma subsampling
1992 					const Interval	srcColor[]	=
1993 					{
1994 						lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)),
1995 						gValue,
1996 						lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)),
1997 						aValue
1998 					};
1999 					Interval dstColor[4];
2000 
2001 					convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2002 
2003 					for (size_t compNdx = 0; compNdx < 4; compNdx++)
2004 						bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2005 				}
2006 			}
2007 		}
2008 		else if (filter == vk::VK_FILTER_LINEAR)
2009 		{
2010 			const IVec2	iRange	(calculateLinearIJRange(coordFormat, u));
2011 			const IVec2	jRange	(calculateLinearIJRange(coordFormat, v));
2012 
2013 			ijBounds[ndx][0] = iRange[0];
2014 			ijBounds[ndx][1] = iRange[1];
2015 
2016 			ijBounds[ndx][2] = jRange[0];
2017 			ijBounds[ndx][3] = jRange[1];
2018 
2019 			for (int j = jRange.x(); j <= jRange.y(); j++)
2020 			for (int i = iRange.x(); i <= iRange.y(); i++)
2021 			{
2022 				const Interval	lumaA		(calculateAB(subTexelPrecisionBits, u, i));
2023 				const Interval	lumaB		(calculateAB(subTexelPrecisionBits, v, j));
2024 
2025 				const Interval	gValue		(linearSample(gAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), lumaA, lumaB));
2026 				const Interval	aValue		(linearSample(aAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), lumaA, lumaB));
2027 
2028 				if (subsampledX || subsampledY)
2029 				{
2030 					if (explicitReconstruction)
2031 					{
2032 						if (chromaFilter == vk::VK_FILTER_NEAREST)
2033 						{
2034 							const Interval	srcColor[]	=
2035 							{
2036 								linearInterpolate(filteringFormat, lumaA, lumaB,
2037 																lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i       / (subsampledX ? 2 : 1), j       / (subsampledY ? 2 : 1))),
2038 																lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), j       / (subsampledY ? 2 : 1))),
2039 																lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i       / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1))),
2040 																lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1)))),
2041 								gValue,
2042 								linearInterpolate(filteringFormat, lumaA, lumaB,
2043 																lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i       / (subsampledX ? 2 : 1), j       / (subsampledY ? 2 : 1))),
2044 																lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), j       / (subsampledY ? 2 : 1))),
2045 																lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i       / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1))),
2046 																lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1)))),
2047 								aValue
2048 							};
2049 							Interval		dstColor[4];
2050 
2051 							convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2052 
2053 							for (size_t compNdx = 0; compNdx < 4; compNdx++)
2054 								bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2055 						}
2056 						else if (chromaFilter == vk::VK_FILTER_LINEAR)
2057 						{
2058 							if (subsampledX && subsampledY)
2059 							{
2060 								// Linear, Reconstructed xx chroma samples with explicit linear filtering
2061 								const Interval	rValue	(linearInterpolate(filteringFormat, lumaA, lumaB,
2062 																			reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i, j),
2063 																			reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j),
2064 																			reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i , j + 1),
2065 																			reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j + 1)));
2066 								const Interval	bValue	(linearInterpolate(filteringFormat, lumaA, lumaB,
2067 																			reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i, j),
2068 																			reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j),
2069 																			reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i , j + 1),
2070 																			reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j + 1)));
2071 								const Interval	srcColor[]	=
2072 								{
2073 									rValue,
2074 									gValue,
2075 									bValue,
2076 									aValue
2077 								};
2078 								Interval		dstColor[4];
2079 
2080 								convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2081 
2082 								for (size_t compNdx = 0; compNdx < 4; compNdx++)
2083 									bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2084 
2085 							}
2086 							else if (subsampledX)
2087 							{
2088 								// Linear, Reconstructed x chroma samples with explicit linear filtering
2089 								const Interval	rValue	(linearInterpolate(filteringFormat, lumaA, lumaB,
2090 																			reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i, j),
2091 																			reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j),
2092 																			reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i , j + 1),
2093 																			reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j + 1)));
2094 								const Interval	bValue	(linearInterpolate(filteringFormat, lumaA, lumaB,
2095 																			reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i, j),
2096 																			reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j),
2097 																			reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i , j + 1),
2098 																			reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j + 1)));
2099 								const Interval	srcColor[]	=
2100 								{
2101 									rValue,
2102 									gValue,
2103 									bValue,
2104 									aValue
2105 								};
2106 								Interval		dstColor[4];
2107 
2108 								convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2109 
2110 								for (size_t compNdx = 0; compNdx < 4; compNdx++)
2111 									bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2112 							}
2113 							else
2114 								DE_FATAL("Unknown subsampling config");
2115 						}
2116 						else
2117 							DE_FATAL("Unknown chroma filter");
2118 					}
2119 					else
2120 					{
2121 						const Interval	chromaU	(subsampledX ? calculateImplicitChromaUV(coordFormat, xChromaOffset, u) : u);
2122 						const Interval	chromaV	(subsampledY ? calculateImplicitChromaUV(coordFormat, yChromaOffset, v) : v);
2123 
2124 						if (chromaFilter == vk::VK_FILTER_NEAREST)
2125 						{
2126 							const IVec2	chromaIRange	(calculateNearestIJRange(coordFormat, chromaU));
2127 							const IVec2	chromaJRange	(calculateNearestIJRange(coordFormat, chromaV));
2128 
2129 							for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
2130 							for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
2131 							{
2132 								const Interval	srcColor[]	=
2133 								{
2134 									lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
2135 									gValue,
2136 									lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
2137 									aValue
2138 								};
2139 								Interval	dstColor[4];
2140 
2141 								convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2142 
2143 								for (size_t compNdx = 0; compNdx < 4; compNdx++)
2144 									bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2145 							}
2146 						}
2147 						else if (chromaFilter == vk::VK_FILTER_LINEAR)
2148 						{
2149 							const IVec2	chromaIRange	(calculateNearestIJRange(coordFormat, chromaU));
2150 							const IVec2	chromaJRange	(calculateNearestIJRange(coordFormat, chromaV));
2151 
2152 							for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
2153 							for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
2154 							{
2155 								const Interval	chromaA		(calculateAB(subTexelPrecisionBits, chromaU, chromaI));
2156 								const Interval	chromaB		(calculateAB(subTexelPrecisionBits, chromaV, chromaJ));
2157 
2158 								const Interval	rValue		(linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB));
2159 								const Interval	bValue		(linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB));
2160 
2161 								const Interval	srcColor[]	=
2162 								{
2163 									rValue,
2164 									gValue,
2165 									bValue,
2166 									aValue
2167 								};
2168 								Interval		dstColor[4];
2169 								convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2170 
2171 								for (size_t compNdx = 0; compNdx < 4; compNdx++)
2172 									bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2173 							}
2174 						}
2175 						else
2176 							DE_FATAL("Unknown chroma filter");
2177 					}
2178 				}
2179 				else
2180 				{
2181 					const Interval	chromaA		(lumaA);
2182 					const Interval	chromaB		(lumaB);
2183 					const Interval	rValue		(linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), chromaA, chromaB));
2184 					const Interval	bValue		(linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), chromaA, chromaB));
2185 					const Interval	srcColor[]	=
2186 					{
2187 						rValue,
2188 						gValue,
2189 						bValue,
2190 						aValue
2191 					};
2192 					Interval dstColor[4];
2193 
2194 					convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2195 
2196 					for (size_t compNdx = 0; compNdx < 4; compNdx++)
2197 						bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2198 				}
2199 			}
2200 		}
2201 		else
2202 			DE_FATAL("Unknown filter");
2203 
2204 		minBounds[ndx] = Vec4((float)bounds[0].lo(), (float)bounds[1].lo(), (float)bounds[2].lo(), (float)bounds[3].lo());
2205 		maxBounds[ndx] = Vec4((float)bounds[0].hi(), (float)bounds[1].hi(), (float)bounds[2].hi(), (float)bounds[3].hi());
2206 	}
2207 }
2208 
2209 
2210 } // ycbcr
2211 } // vkt
2212