• 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 Testing compute shader writing to separate planes of a multiplanar format
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktYCbCrStorageImageWriteTests.hpp"
25 #include "vktTestCaseUtil.hpp"
26 #include "vktTestGroupUtil.hpp"
27 #include "vktYCbCrUtil.hpp"
28 #include "vkBuilderUtil.hpp"
29 #include "vkObjUtil.hpp"
30 #include "vkCmdUtil.hpp"
31 #include "vkBarrierUtil.hpp"
32 #include "vkImageUtil.hpp"
33 #include "tcuTexVerifierUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkRefUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "tcuTestLog.hpp"
38 #include <cstdio>
39 
40 namespace vkt
41 {
42 namespace ycbcr
43 {
44 namespace
45 {
46 
47 using namespace vk;
48 
49 struct TestParameters
50 {
51 	VkFormat			format;
52 	tcu::UVec3			size;
53 	VkImageCreateFlags	flags;
54 
TestParametersvkt::ycbcr::__anona09c7c7f0111::TestParameters55 	TestParameters (VkFormat			format_,
56 					const tcu::UVec3&	size_,
57 					VkImageCreateFlags	flags_)
58 		: format			(format_)
59 		, size				(size_)
60 		, flags				(flags_)
61 	{
62 	}
63 
TestParametersvkt::ycbcr::__anona09c7c7f0111::TestParameters64 	TestParameters (void)
65 		: format			(VK_FORMAT_UNDEFINED)
66 		, flags				(0u)
67 	{
68 	}
69 };
70 
getPlaneCompatibleFormatForWriting(const vk::PlanarFormatDescription & formatInfo,deUint32 planeNdx)71 vk::VkFormat getPlaneCompatibleFormatForWriting(const vk::PlanarFormatDescription& formatInfo, deUint32 planeNdx)
72 {
73 	DE_ASSERT(planeNdx < formatInfo.numPlanes);
74 	vk::VkFormat result = formatInfo.planes[planeNdx].planeCompatibleFormat;
75 
76 	// redirect result for some of the YCbCr image formats
77 	static const std::pair<vk::VkFormat, vk::VkFormat> ycbcrFormats[] =
78 	{
79 		{ VK_FORMAT_G8B8G8R8_422_UNORM,						VK_FORMAT_R8G8B8A8_UNORM		},
80 		{ VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16,	VK_FORMAT_R16G16B16A16_UNORM	},
81 		{ VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16,	VK_FORMAT_R16G16B16A16_UNORM	},
82 		{ VK_FORMAT_G16B16G16R16_422_UNORM,					VK_FORMAT_R16G16B16A16_UNORM	},
83 		{ VK_FORMAT_B8G8R8G8_422_UNORM,						VK_FORMAT_R8G8B8A8_UNORM		},
84 		{ VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16,	VK_FORMAT_R16G16B16A16_UNORM	},
85 		{ VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16,	VK_FORMAT_R16G16B16A16_UNORM	},
86 		{ VK_FORMAT_B16G16R16G16_422_UNORM,					VK_FORMAT_R16G16B16A16_UNORM	}
87 	};
88 	auto it = std::find_if(std::begin(ycbcrFormats), std::end(ycbcrFormats), [result](const std::pair<vk::VkFormat, vk::VkFormat>& p) { return p.first == result; });
89 	if (it != std::end(ycbcrFormats))
90 		result = it->second;
91 	return result;
92 }
93 
checkSupport(Context & context,const TestParameters params)94 void checkSupport (Context& context, const TestParameters params)
95 {
96 	const bool							disjoint = (params.flags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0;
97 	const auto&							instInt	(context.getInstanceInterface());
98 	std::vector<std::string>			reqExts;
99 
100 	if (disjoint)
101 	{
102 		if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_bind_memory2"))
103 			reqExts.push_back("VK_KHR_bind_memory2");
104 		if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_get_memory_requirements2"))
105 			reqExts.push_back("VK_KHR_get_memory_requirements2");
106 	}
107 
108 	for ( const auto& extIter : reqExts )
109 	{
110 		if (!context.isDeviceFunctionalitySupported(extIter))
111 			TCU_THROW(NotSupportedError, (extIter + " is not supported").c_str());
112 	}
113 
114 	{
115 		const VkPhysicalDeviceImageFormatInfo2			imageFormatInfo				=
116 		{
117 			VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,	// sType;
118 			DE_NULL,												// pNext;
119 			params.format,											// format;
120 			VK_IMAGE_TYPE_2D,										// type;
121 			VK_IMAGE_TILING_OPTIMAL,								// tiling;
122 			VK_IMAGE_USAGE_TRANSFER_DST_BIT |
123 			VK_IMAGE_USAGE_SAMPLED_BIT,								// usage;
124 			(VkImageCreateFlags)0u									// flags
125 		};
126 
127 		VkSamplerYcbcrConversionImageFormatProperties	samplerYcbcrConversionImage = {};
128 		samplerYcbcrConversionImage.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES;
129 		samplerYcbcrConversionImage.pNext = DE_NULL;
130 
131 		VkImageFormatProperties2						imageFormatProperties		= {};
132 		imageFormatProperties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
133 		imageFormatProperties.pNext = &samplerYcbcrConversionImage;
134 
135 		VkResult result = instInt.getPhysicalDeviceImageFormatProperties2(context.getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties);
136 		if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
137 			TCU_THROW(NotSupportedError, "Format not supported.");
138 		VK_CHECK(result);
139 
140 
141 		// Check for plane compatible format support when the disjoint flag is being used
142 		if (disjoint)
143 		{
144 			const PlanarFormatDescription				formatDescription		= getPlanarFormatDescription(params.format);
145 
146 			for (deUint32 channelNdx = 0; channelNdx < 4; ++channelNdx)
147 			{
148 				if (!formatDescription.hasChannelNdx(channelNdx))
149 					continue;
150 				deUint32					planeNdx					= formatDescription.channels[channelNdx].planeNdx;
151 				vk::VkFormat				planeCompatibleFormat		= getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
152 
153 				const VkPhysicalDeviceImageFormatInfo2			planeImageFormatInfo				=
154 				{
155 					VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,	// sType;
156 					DE_NULL,												// pNext;
157 					planeCompatibleFormat,									// format;
158 					VK_IMAGE_TYPE_2D,										// type;
159 					VK_IMAGE_TILING_OPTIMAL,								// tiling;
160 					VK_IMAGE_USAGE_TRANSFER_DST_BIT |
161 					VK_IMAGE_USAGE_SAMPLED_BIT,								// usage;
162 					(VkImageCreateFlags)0u									// flags
163 				};
164 
165 				VkResult planesResult = instInt.getPhysicalDeviceImageFormatProperties2(context.getPhysicalDevice(), &planeImageFormatInfo, &imageFormatProperties);
166 				if (planesResult == VK_ERROR_FORMAT_NOT_SUPPORTED)
167 					TCU_THROW(NotSupportedError, "Plane compatibile format not supported.");
168 				VK_CHECK(planesResult);
169 			}
170 		}
171 	}
172 
173 	{
174 		const VkFormatProperties	formatProperties = getPhysicalDeviceFormatProperties(context.getInstanceInterface(),
175 			context.getPhysicalDevice(),
176 			params.format);
177 
178 		const bool					transferByViews = disjoint && (getPlanarFormatDescription(params.format).numPlanes > 1);
179 
180 		if (!disjoint && (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0)
181 			TCU_THROW(NotSupportedError, "Storage images are not supported for this format");
182 
183 		if (disjoint && ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DISJOINT_BIT) == 0))
184 			TCU_THROW(NotSupportedError, "Disjoint planes are not supported for this format");
185 
186 		if (disjoint && transferByViews)
187 		{
188 			const PlanarFormatDescription	formatDescription				= getPlanarFormatDescription(params.format);
189 			for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
190 			{
191 				const VkFormat				planeCompatibleFormat			= getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
192 				const VkFormatProperties	planeCompatibleFormatProperties = getPhysicalDeviceFormatProperties(context.getInstanceInterface(),
193 					context.getPhysicalDevice(),
194 					planeCompatibleFormat);
195 
196 				if ((planeCompatibleFormatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) == 0)
197 					TCU_THROW(NotSupportedError, "Storage images are not supported for the plane compatible format");
198 			}
199 		}
200 	}
201 }
202 
203 template<typename T>
makeVkSharedPtr(vk::Move<T> vkMove)204 inline de::SharedPtr<vk::Unique<T> > makeVkSharedPtr(vk::Move<T> vkMove)
205 {
206 	return de::SharedPtr<vk::Unique<T> >(new vk::Unique<T>(vkMove));
207 }
208 
computeWorkGroupSize(const VkExtent3D & planeExtent)209 tcu::UVec3 computeWorkGroupSize(const VkExtent3D& planeExtent)
210 {
211 	const deUint32		maxComputeWorkGroupInvocations	= 128u;
212 	const tcu::UVec3	maxComputeWorkGroupSize			= tcu::UVec3(128u, 128u, 64u);
213 
214 	const deUint32		xWorkGroupSize					= std::min(std::min(planeExtent.width, maxComputeWorkGroupSize.x()), maxComputeWorkGroupInvocations);
215 	const deUint32		yWorkGroupSize					= std::min(std::min(planeExtent.height, maxComputeWorkGroupSize.y()), maxComputeWorkGroupInvocations / xWorkGroupSize);
216 	const deUint32		zWorkGroupSize					= std::min(std::min(planeExtent.depth, maxComputeWorkGroupSize.z()), maxComputeWorkGroupInvocations / (xWorkGroupSize*yWorkGroupSize));
217 
218 	return tcu::UVec3(xWorkGroupSize, yWorkGroupSize, zWorkGroupSize);
219 }
220 
testStorageImageWrite(Context & context,TestParameters params)221 tcu::TestStatus testStorageImageWrite (Context& context, TestParameters params)
222 {
223 	const DeviceInterface&						vkd						= context.getDeviceInterface();
224 	const VkDevice								device					= context.getDevice();
225 	const deUint32								queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
226 	const VkQueue								queue					= context.getUniversalQueue();
227 	const PlanarFormatDescription				formatDescription		= getPlanarFormatDescription(params.format);
228 	const bool									disjoint				= (params.flags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0;
229 	const bool									transferByViews			= disjoint && (formatDescription.numPlanes > 1);
230 
231 	VkImageCreateInfo							imageCreateInfo =
232 	{
233 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
234 		DE_NULL,
235 		params.flags,
236 		VK_IMAGE_TYPE_2D,
237 		params.format,
238 		makeExtent3D(params.size.x(), params.size.y(), params.size.z()),
239 		1u,			// mipLevels
240 		1u,			// arrayLayers
241 		VK_SAMPLE_COUNT_1_BIT,
242 		VK_IMAGE_TILING_OPTIMAL,
243 		VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
244 		VK_SHARING_MODE_EXCLUSIVE,
245 		0u,
246 		(const deUint32*)DE_NULL,
247 		VK_IMAGE_LAYOUT_UNDEFINED,
248 	};
249 
250 	// check if we need to create VkImageView with different VkFormat than VkImage format
251 	VkFormat planeCompatibleFormat0 = getPlaneCompatibleFormatForWriting(formatDescription, 0);
252 	if (planeCompatibleFormat0 != params.format)
253 	{
254 		imageCreateInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
255 	}
256 
257 	const Unique<VkImage>						image					(createImage(vkd, device, &imageCreateInfo));
258 	// allocate memory for the whole image, or for each separate plane ( if the params.flags include VK_IMAGE_CREATE_DISJOINT_BIT )
259 	const std::vector<AllocationSp>				allocations				(allocateAndBindImageMemory(vkd, device, context.getDefaultAllocator(), *image, params.format, params.flags, MemoryRequirement::Any));
260 
261 	// Create descriptor set layout
262 	const Unique<VkDescriptorSetLayout>			descriptorSetLayout		(DescriptorSetLayoutBuilder()
263 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
264 		.build(vkd, device));
265 	const Unique<VkPipelineLayout>				pipelineLayout			(makePipelineLayout(vkd, device, *descriptorSetLayout));
266 
267 	// Create descriptor sets
268 	const Unique<VkDescriptorPool>				descriptorPool			(DescriptorPoolBuilder()
269 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, vk::PlanarFormatDescription::MAX_PLANES)
270 		.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, vk::PlanarFormatDescription::MAX_PLANES));
271 
272 	// Create command buffer for compute and transfer operations
273 	const Unique<VkCommandPool>					commandPool				(makeCommandPool(vkd, device, queueFamilyIndex));
274 	const Unique<VkCommandBuffer>				commandBuffer			(allocateCommandBuffer(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
275 
276 	std::vector<de::SharedPtr<vk::Unique<vk::VkShaderModule>>>			shaderModules;
277 	std::vector<de::SharedPtr<vk::Unique<vk::VkPipeline>>>				computePipelines;
278 	std::vector<de::SharedPtr<vk::Unique<vk::VkDescriptorSet>>>			descriptorSets;
279 	std::vector<de::SharedPtr<vk::Unique<vk::VkImageView>>>				imageViews;
280 
281 	deUint32									imageSizeInBytes		= 0;
282 	deUint32									planeOffsets[PlanarFormatDescription::MAX_PLANES];
283 	deUint32									planeRowPitches[PlanarFormatDescription::MAX_PLANES];
284 	void*										planePointers[PlanarFormatDescription::MAX_PLANES];
285 
286 	{
287 		// Start recording commands
288 		beginCommandBuffer(vkd, *commandBuffer);
289 
290 		for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
291 		{
292 			const VkImageAspectFlags		aspect						= (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
293 			const VkImageSubresourceRange	subresourceRange			= makeImageSubresourceRange(aspect, 0u, 1u, 0u, 1u);
294 			VkFormat						planeCompatibleFormat		= getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
295 			vk::PlanarFormatDescription		compatibleFormatDescription = (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
296 			const tcu::UVec3				compatibleShaderGridSize	( params.size.x() / formatDescription.blockWidth, params.size.y() / formatDescription.blockHeight, params.size.z() / 1u);
297 			VkExtent3D						shaderExtent				= getPlaneExtent(compatibleFormatDescription, VkExtent3D{ compatibleShaderGridSize.x(), compatibleShaderGridSize.y(), compatibleShaderGridSize.z() }, planeNdx, 0u);
298 
299 			// Create and bind compute pipeline
300 			std::ostringstream shaderName;
301 			shaderName << "comp" << planeNdx;
302 			auto							shaderModule			= makeVkSharedPtr(createShaderModule(vkd, device, context.getBinaryCollection().get(shaderName.str()), DE_NULL));
303 			shaderModules.push_back(shaderModule);
304 			auto							computePipeline			= makeVkSharedPtr(makeComputePipeline(vkd, device, *pipelineLayout, (VkPipelineCreateFlags) 0u, nullptr, shaderModule->get(), (VkPipelineShaderStageCreateFlags) 0u, DE_NULL));
305 			computePipelines.push_back(computePipeline);
306 			vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline->get());
307 
308 			auto							descriptorSet			= makeVkSharedPtr(makeDescriptorSet(vkd, device, *descriptorPool, *descriptorSetLayout));
309 			descriptorSets.push_back(descriptorSet);
310 
311 			VkImageViewUsageCreateInfo imageViewUsageCreateInfo =
312 			{
313 				VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,		//VkStructureType		sType;
314 				DE_NULL,											//const void*			pNext;
315 				VK_IMAGE_USAGE_STORAGE_BIT,							//VkImageUsageFlags		usage;
316 			};
317 
318 			auto							imageView				= makeVkSharedPtr(makeImageView(vkd, device, *image, VK_IMAGE_VIEW_TYPE_2D, planeCompatibleFormat, subresourceRange, transferByViews ? &imageViewUsageCreateInfo : DE_NULL));
319 			imageViews.push_back(imageView);
320 			const VkDescriptorImageInfo		imageInfo				= makeDescriptorImageInfo(DE_NULL, imageView->get(), VK_IMAGE_LAYOUT_GENERAL);
321 
322 			DescriptorSetUpdateBuilder()
323 				.writeSingle(descriptorSet->get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &imageInfo)
324 				.update(vkd, device);
325 
326 			vkd.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet->get(), 0u, DE_NULL);
327 
328 			{
329 				const VkImageMemoryBarrier imageLayoutChangeBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, *image, subresourceRange, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED);
330 				vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageLayoutChangeBarrier);
331 			}
332 
333 			{
334 				const tcu::UVec3 workGroupSize = computeWorkGroupSize(shaderExtent);
335 
336 				const deUint32 xWorkGroupCount = shaderExtent.width / workGroupSize.x() + (shaderExtent.width % workGroupSize.x() ? 1u : 0u);
337 				const deUint32 yWorkGroupCount = shaderExtent.height / workGroupSize.y() + (shaderExtent.height % workGroupSize.y() ? 1u : 0u);
338 				const deUint32 zWorkGroupCount = shaderExtent.depth / workGroupSize.z() + (shaderExtent.depth % workGroupSize.z() ? 1u : 0u);
339 
340 				const tcu::UVec3 maxComputeWorkGroupCount = tcu::UVec3(65535u, 65535u, 65535u);
341 
342 				if (maxComputeWorkGroupCount.x() < xWorkGroupCount ||
343 					maxComputeWorkGroupCount.y() < yWorkGroupCount ||
344 					maxComputeWorkGroupCount.z() < zWorkGroupCount)
345 				{
346 					TCU_THROW(NotSupportedError, "Image size is not supported");
347 				}
348 
349 				vkd.cmdDispatch(*commandBuffer, xWorkGroupCount, yWorkGroupCount, zWorkGroupCount);
350 			}
351 
352 			{
353 				const VkImageMemoryBarrier imageTransferBarrier = makeImageMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *image, subresourceRange);
354 				vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageTransferBarrier);
355 			}
356 		}
357 
358 		for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
359 		{
360 			planeOffsets[planeNdx]		= imageSizeInBytes;
361 			const deUint32	planeW		= imageCreateInfo.extent.width / (formatDescription.blockWidth * formatDescription.planes[planeNdx].widthDivisor);
362 			planeRowPitches[planeNdx]	= formatDescription.planes[planeNdx].elementSizeBytes * planeW;
363 			imageSizeInBytes			+= getPlaneSizeInBytes(formatDescription, makeExtent3D( params.size.x(), params.size.y(), params.size.z()) , planeNdx, 0u, BUFFER_IMAGE_COPY_OFFSET_GRANULARITY);
364 		}
365 
366 		const VkBufferCreateInfo		outputBufferCreateInfo	= makeBufferCreateInfo(imageSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
367 		const Unique<VkBuffer>			outputBuffer			( createBuffer(vkd, device, &outputBufferCreateInfo) );
368 		const de::UniquePtr<Allocation>	outputBufferAlloc		( bindBuffer(vkd, device, context.getDefaultAllocator(), *outputBuffer, MemoryRequirement::HostVisible) );
369 		std::vector<VkBufferImageCopy>	bufferImageCopy			( formatDescription.numPlanes );
370 
371 		for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
372 		{
373 			const VkImageAspectFlags	aspect = (formatDescription.numPlanes > 1) ? getPlaneAspect(planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT;
374 
375 			bufferImageCopy[planeNdx] =
376 			{
377 				planeOffsets[planeNdx],																								//	VkDeviceSize				bufferOffset;
378 				0u,																													//	deUint32					bufferRowLength;
379 				0u,																													//	deUint32					bufferImageHeight;
380 				makeImageSubresourceLayers(aspect, 0u, 0u, 1u),																		//	VkImageSubresourceLayers	imageSubresource;
381 				makeOffset3D(0, 0, 0),																								//	VkOffset3D					imageOffset;
382 				getPlaneExtent(formatDescription, makeExtent3D(params.size.x(), params.size.y(), params.size.z()), planeNdx, 0u)	//	VkExtent3D					imageExtent;
383 			};
384 		}
385 		vkd.cmdCopyImageToBuffer(*commandBuffer, *image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *outputBuffer, static_cast<deUint32>(bufferImageCopy.size()), bufferImageCopy.data());
386 
387 		{
388 			const VkBufferMemoryBarrier outputBufferHostReadBarrier = makeBufferMemoryBarrier
389 			(
390 				VK_ACCESS_TRANSFER_WRITE_BIT,
391 				VK_ACCESS_HOST_READ_BIT,
392 				*outputBuffer,
393 				0u,
394 				imageSizeInBytes
395 			);
396 
397 			vkd.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &outputBufferHostReadBarrier, 0u, DE_NULL);
398 		}
399 
400 		// End recording commands
401 		endCommandBuffer(vkd, *commandBuffer);
402 
403 		// Submit commands for execution and wait for completion
404 		submitCommandsAndWait(vkd, device, queue, *commandBuffer);
405 
406 		// Retrieve data from buffer to host memory
407 		invalidateAlloc(vkd, device, *outputBufferAlloc);
408 		deUint8*					outputData = static_cast<deUint8*>(outputBufferAlloc->getHostPtr());
409 
410 		for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
411 			planePointers[planeNdx] = outputData + static_cast<size_t>(planeOffsets[planeNdx]);
412 
413 		// write result images to log file
414 		for (deUint32 channelNdx = 0; channelNdx < 4; ++channelNdx)
415 		{
416 			if (!formatDescription.hasChannelNdx(channelNdx))
417 				continue;
418 			deUint32					planeNdx					= formatDescription.channels[channelNdx].planeNdx;
419 			vk::VkFormat				planeCompatibleFormat		= getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
420 			vk::PlanarFormatDescription	compatibleFormatDescription	= (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
421 			const tcu::UVec3			compatibleShaderGridSize	( params.size.x() / formatDescription.blockWidth, params.size.y() / formatDescription.blockHeight, params.size.z() / 1u );
422 			tcu::ConstPixelBufferAccess	pixelBuffer					= vk::getChannelAccess(compatibleFormatDescription, compatibleShaderGridSize, planeRowPitches, (const void* const*)planePointers, channelNdx);
423 			std::ostringstream str;
424 			str << "image" << channelNdx;
425 			context.getTestContext().getLog() << tcu::LogImage(str.str(), str.str(), pixelBuffer);
426 		}
427 
428 		// verify data
429 		const float					epsilon = 1e-5f;
430 		for (deUint32 channelNdx = 0; channelNdx < 4; ++channelNdx)
431 		{
432 			if (!formatDescription.hasChannelNdx(channelNdx))
433 				continue;
434 
435 			deUint32							planeNdx					= formatDescription.channels[channelNdx].planeNdx;
436 			vk::VkFormat						planeCompatibleFormat		= getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
437 			vk::PlanarFormatDescription			compatibleFormatDescription	= (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
438 			const tcu::UVec3					compatibleShaderGridSize	( params.size.x() / formatDescription.blockWidth, params.size.y() / formatDescription.blockHeight, params.size.z() / 1u );
439 			VkExtent3D							compatibleImageSize			{ imageCreateInfo.extent.width / formatDescription.blockWidth, imageCreateInfo.extent.height / formatDescription.blockHeight, imageCreateInfo.extent.depth / 1u };
440 			tcu::ConstPixelBufferAccess			pixelBuffer					= vk::getChannelAccess(compatibleFormatDescription, compatibleShaderGridSize, planeRowPitches, (const void* const*)planePointers, channelNdx);
441 			VkExtent3D							planeExtent					= getPlaneExtent(compatibleFormatDescription, compatibleImageSize, planeNdx, 0u);
442 			tcu::IVec3							pixelDivider				= pixelBuffer.getDivider();
443 
444 			for (deUint32 offsetZ = 0u; offsetZ < planeExtent.depth; ++offsetZ)
445 			for (deUint32 offsetY = 0u; offsetY < planeExtent.height; ++offsetY)
446 			for (deUint32 offsetX = 0u; offsetX < planeExtent.width; ++offsetX)
447 			{
448 				deUint32	iReferenceValue;
449 				float		fReferenceValue;
450 				switch (channelNdx)
451 				{
452 					case 0:
453 						iReferenceValue = offsetX % 127u;
454 						fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
455 						break;
456 					case 1:
457 						iReferenceValue = offsetY % 127u;
458 						fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
459 						break;
460 					case 2:
461 						iReferenceValue = offsetZ % 127u;
462 						fReferenceValue = static_cast<float>(iReferenceValue) / 127.f;
463 						break;
464 					case 3:
465 						iReferenceValue = 1u;
466 						fReferenceValue = 1.f;
467 						break;
468 					default:	DE_FATAL("Unexpected channel index");	break;
469 				}
470 				float acceptableError = epsilon;
471 
472 				switch (formatDescription.channels[channelNdx].type)
473 				{
474 					case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
475 					case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
476 					{
477 						tcu::UVec4 outputValue = pixelBuffer.getPixelUint(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), 0);
478 
479 						if (outputValue.x() != iReferenceValue)
480 							return tcu::TestStatus::fail("Failed");
481 
482 						break;
483 					}
484 					case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
485 					case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
486 					{
487 						float fixedPointError = tcu::TexVerifierUtil::computeFixedPointError(formatDescription.channels[channelNdx].sizeBits);
488 						acceptableError += fixedPointError;
489 						tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), 0);
490 
491 						if (deAbs(outputValue.x() - fReferenceValue) > acceptableError)
492 							return tcu::TestStatus::fail("Failed");
493 
494 						break;
495 					}
496 					case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
497 					{
498 						const tcu::Vec4 outputValue = pixelBuffer.getPixel(offsetX * pixelDivider.x(), offsetY * pixelDivider.y(), 0);
499 
500 						if (deAbs( outputValue.x() - fReferenceValue) > acceptableError)
501 							return tcu::TestStatus::fail("Failed");
502 
503 						break;
504 					}
505 					default:	DE_FATAL("Unexpected channel type");	break;
506 				}
507 			}
508 		}
509 	}
510 	return tcu::TestStatus::pass("Passed");
511 }
512 
getShaderImageType(const vk::PlanarFormatDescription & description)513 std::string getShaderImageType (const vk::PlanarFormatDescription& description)
514 {
515 	std::string	formatPart;
516 
517 	// all PlanarFormatDescription types have at least one channel ( 0 ) and all channel types are the same :
518 	switch (description.channels[0].type)
519 	{
520 		case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
521 			formatPart = "i";
522 			break;
523 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
524 			formatPart = "u";
525 			break;
526 		case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
527 		case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
528 		case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
529 			break;
530 
531 		default:
532 			DE_FATAL("Unexpected channel type");
533 	}
534 
535 	return formatPart + "image2D";
536 }
537 
getShaderImageDataType(const vk::PlanarFormatDescription & description)538 std::string getShaderImageDataType (const vk::PlanarFormatDescription& description)
539 {
540 	switch (description.channels[0].type)
541 	{
542 	case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
543 		return "uvec4";
544 	case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
545 		return "ivec4";
546 	case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
547 	case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
548 	case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
549 		return "vec4";
550 	default:
551 		DE_FATAL("Unexpected channel type");
552 		return "";
553 	}
554 }
555 
getFormatValueString(const std::vector<std::pair<deUint32,deUint32>> & channelsOnPlane,const std::vector<std::string> & formatValueStrings)556 std::string getFormatValueString	(const std::vector<std::pair<deUint32, deUint32>>& channelsOnPlane,
557 									 const std::vector<std::string>& formatValueStrings)
558 {
559 	std::string result = "( ";
560 	deUint32 i;
561 	for (i=0; i<channelsOnPlane.size(); ++i)
562 	{
563 		result += formatValueStrings[channelsOnPlane[i].first];
564 		if (i < 3)
565 			result += ", ";
566 	}
567 	for (; i < 4; ++i)
568 	{
569 		result += "0";
570 		if (i < 3)
571 			result += ", ";
572 	}
573 	result += " )";
574 	return result;
575 }
576 
getShaderImageFormatQualifier(VkFormat format)577 std::string getShaderImageFormatQualifier (VkFormat format)
578 {
579 	switch (format)
580 	{
581 		case VK_FORMAT_R8_SINT:										return "r8i";
582 		case VK_FORMAT_R16_SINT:									return "r16i";
583 		case VK_FORMAT_R32_SINT:									return "r32i";
584 		case VK_FORMAT_R8_UINT:										return "r8ui";
585 		case VK_FORMAT_R16_UINT:									return "r16ui";
586 		case VK_FORMAT_R32_UINT:									return "r32ui";
587 		case VK_FORMAT_R8_SNORM:									return "r8_snorm";
588 		case VK_FORMAT_R16_SNORM:									return "r16_snorm";
589 		case VK_FORMAT_R8_UNORM:									return "r8";
590 		case VK_FORMAT_R16_UNORM:									return "r16";
591 
592 		case VK_FORMAT_R8G8_SINT:									return "rg8i";
593 		case VK_FORMAT_R16G16_SINT:									return "rg16i";
594 		case VK_FORMAT_R32G32_SINT:									return "rg32i";
595 		case VK_FORMAT_R8G8_UINT:									return "rg8ui";
596 		case VK_FORMAT_R16G16_UINT:									return "rg16ui";
597 		case VK_FORMAT_R32G32_UINT:									return "rg32ui";
598 		case VK_FORMAT_R8G8_SNORM:									return "rg8_snorm";
599 		case VK_FORMAT_R16G16_SNORM:								return "rg16_snorm";
600 		case VK_FORMAT_R8G8_UNORM:									return "rg8";
601 		case VK_FORMAT_R16G16_UNORM:								return "rg16";
602 
603 		case VK_FORMAT_R8G8B8A8_SINT:								return "rgba8i";
604 		case VK_FORMAT_R16G16B16A16_SINT:							return "rgba16i";
605 		case VK_FORMAT_R32G32B32A32_SINT:							return "rgba32i";
606 		case VK_FORMAT_R8G8B8A8_UINT:								return "rgba8ui";
607 		case VK_FORMAT_R16G16B16A16_UINT:							return "rgba16ui";
608 		case VK_FORMAT_R32G32B32A32_UINT:							return "rgba32ui";
609 		case VK_FORMAT_R8G8B8A8_SNORM:								return "rgba8_snorm";
610 		case VK_FORMAT_R16G16B16A16_SNORM:							return "rgba16_snorm";
611 		case VK_FORMAT_R8G8B8A8_UNORM:								return "rgba8";
612 		case VK_FORMAT_R16G16B16A16_UNORM:							return "rgba16";
613 
614 		case VK_FORMAT_G8B8G8R8_422_UNORM:							return "rgba8";
615 		case VK_FORMAT_B8G8R8G8_422_UNORM:							return "rgba8";
616 		case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:					return "rgba8";
617 		case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:					return "rgba8";
618 		case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:					return "rgba8";
619 		case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:					return "rgba8";
620 		case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:					return "rgba8";
621 		case VK_FORMAT_R10X6_UNORM_PACK16:							return "r16";
622 		case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:					return "rg16";
623 		case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:			return "rgba16";
624 		case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:		return "rgba16";
625 		case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:		return "rgba16";
626 		case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:	return "rgba16";
627 		case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:	return "rgba16";
628 		case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:	return "rgba16";
629 		case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:	return "rgba16";
630 		case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:	return "rgba16";
631 		case VK_FORMAT_R12X4_UNORM_PACK16:							return "r16";
632 		case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:					return "rg16";
633 		case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:			return "rgba16";
634 		case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:		return "rgba16";
635 		case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:		return "rgba16";
636 		case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:	return "rgba16";
637 		case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:	return "rgba16";
638 		case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:	return "rgba16";
639 		case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:	return "rgba16";
640 		case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:	return "rgba16";
641 		case VK_FORMAT_G16B16G16R16_422_UNORM:						return "rgba16";
642 		case VK_FORMAT_B16G16R16G16_422_UNORM:						return "rgba16";
643 		case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:				return "rgba16";
644 		case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:					return "rgba16";
645 		case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:				return "rgba16";
646 		case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:					return "rgba16";
647 		case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:				return "rgba16";
648 		case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT:				return "rgba8";
649 		case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT:return "rgba16";
650 		case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT:return "rgba16";
651 		case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT:				return "rgba16";
652 
653 		default:
654 			DE_FATAL("Unexpected texture format");
655 			return "error";
656 	}
657 }
658 
initPrograms(SourceCollections & sourceCollections,TestParameters params)659 void initPrograms (SourceCollections& sourceCollections, TestParameters params)
660 {
661 	// Create compute program
662 	const char* const				versionDecl			= glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440);
663 	const PlanarFormatDescription	formatDescription	= getPlanarFormatDescription(params.format);
664 	const std::string				imageTypeStr		= getShaderImageType(formatDescription);
665 	const std::string				formatDataStr		= getShaderImageDataType(formatDescription);
666 	const tcu::UVec3				shaderGridSize		( params.size.x(), params.size.y(), params.size.z() );
667 
668 	std::vector<std::string>		formatValueStrings;
669 	switch (formatDescription.channels[0].type)
670 	{
671 	case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
672 	case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
673 		formatValueStrings = {
674 			"int(gl_GlobalInvocationID.x) % 127",
675 			"int(gl_GlobalInvocationID.y) % 127",
676 			"int(gl_GlobalInvocationID.z) % 127",
677 			"1"
678 		};
679 		break;
680 	case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
681 	case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
682 	case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
683 		formatValueStrings = {
684 			"float(int(gl_GlobalInvocationID.x) % 127) / 127.0" ,
685 			"float(int(gl_GlobalInvocationID.y) % 127) / 127.0",
686 			"float(int(gl_GlobalInvocationID.z) % 127) / 127.0",
687 			"1.0"
688 		};
689 		break;
690 	default:	DE_ASSERT(false);	break;
691 	}
692 
693 	for (deUint32 planeNdx = 0; planeNdx < formatDescription.numPlanes; ++planeNdx)
694 	{
695 		VkFormat						planeCompatibleFormat		= getPlaneCompatibleFormatForWriting(formatDescription, planeNdx);
696 		vk::PlanarFormatDescription		compatibleFormatDescription	= (planeCompatibleFormat != getPlaneCompatibleFormat(formatDescription, planeNdx)) ? getPlanarFormatDescription(planeCompatibleFormat) : formatDescription;
697 		VkExtent3D						compatibleShaderGridSize	{ shaderGridSize.x() / formatDescription.blockWidth, shaderGridSize.y() / formatDescription.blockHeight, shaderGridSize.z() / 1u };
698 
699 		std::vector<std::pair<deUint32, deUint32>> channelsOnPlane;
700 		for (deUint32 channelNdx = 0; channelNdx < 4; ++channelNdx)
701 		{
702 			if (!formatDescription.hasChannelNdx(channelNdx))
703 				continue;
704 			if (formatDescription.channels[channelNdx].planeNdx != planeNdx)
705 				continue;
706 			channelsOnPlane.push_back({ channelNdx,formatDescription.channels[channelNdx].offsetBits });
707 		}
708 		// reorder channels for multi-planar images
709 		if (formatDescription.numPlanes > 1)
710 			std::sort(begin(channelsOnPlane), end(channelsOnPlane), [](const std::pair<deUint32, deUint32>& lhs, const std::pair<deUint32, deUint32>& rhs) { return lhs.second < rhs.second; });
711 		std::string			formatValueStr		= getFormatValueString(channelsOnPlane, formatValueStrings);
712 		VkExtent3D			shaderExtent		= getPlaneExtent(compatibleFormatDescription, compatibleShaderGridSize, planeNdx, 0);
713 		const std::string	formatQualifierStr	= getShaderImageFormatQualifier(formatDescription.planes[planeNdx].planeCompatibleFormat);
714 		const tcu::UVec3	workGroupSize		= computeWorkGroupSize(shaderExtent);
715 
716 		std::ostringstream src;
717 		src << versionDecl << "\n"
718 			<< "layout (local_size_x = " << workGroupSize.x() << ", local_size_y = " << workGroupSize.y() << ", local_size_z = " << workGroupSize.z() << ") in; \n"
719 			<< "layout (binding = 0, " << formatQualifierStr << ") writeonly uniform highp " << imageTypeStr << " u_image;\n"
720 			<< "void main (void)\n"
721 			<< "{\n"
722 			<< "	if( gl_GlobalInvocationID.x < " << shaderExtent.width << " ) \n"
723 			<< "	if( gl_GlobalInvocationID.y < " << shaderExtent.height << " ) \n"
724 			<< "	if( gl_GlobalInvocationID.z < " << shaderExtent.depth << " ) \n"
725 			<< "	{\n"
726 			<< "		imageStore(u_image, ivec2( gl_GlobalInvocationID.x, gl_GlobalInvocationID.y ) ,"
727 			<< formatDataStr << formatValueStr << ");\n"
728 			<< "	}\n"
729 			<< "}\n";
730 		std::ostringstream shaderName;
731 		shaderName << "comp" << planeNdx;
732 		sourceCollections.glslSources.add(shaderName.str()) << glu::ComputeSource(src.str());
733 	}
734 }
735 
populateStorageImageWriteFormatGroup(tcu::TestContext & testCtx,de::MovePtr<tcu::TestCaseGroup> testGroup)736 tcu::TestCaseGroup* populateStorageImageWriteFormatGroup (tcu::TestContext& testCtx, de::MovePtr<tcu::TestCaseGroup> testGroup)
737 {
738 	const std::vector<tcu::UVec3>	availableSizes{ tcu::UVec3(512u, 512u, 1u), tcu::UVec3(1024u, 128u, 1u), tcu::UVec3(66u, 32u, 1u) };
739 
740 	auto addTests = [&](int formatNdx)
741 	{
742 		const VkFormat					format				= (VkFormat)formatNdx;
743 		tcu::UVec3						imageSizeAlignment	= getImageSizeAlignment(format);
744 		std::string						formatName			= de::toLower(de::toString(format).substr(10));
745 		de::MovePtr<tcu::TestCaseGroup> formatGroup			( new tcu::TestCaseGroup(testCtx, formatName.c_str()));
746 
747 		for (size_t sizeNdx = 0; sizeNdx < availableSizes.size(); sizeNdx++)
748 		{
749 			const tcu::UVec3 imageSize = availableSizes[sizeNdx];
750 
751 			// skip test for images with odd sizes for some YCbCr formats
752 			if ((imageSize.x() % imageSizeAlignment.x()) != 0)
753 				continue;
754 			if ((imageSize.y() % imageSizeAlignment.y()) != 0)
755 				continue;
756 
757 			std::ostringstream stream;
758 			stream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
759 			de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, stream.str().c_str()));
760 
761 			addFunctionCaseWithPrograms(sizeGroup.get(), "joint", checkSupport, initPrograms, testStorageImageWrite, TestParameters(format, imageSize, 0u));
762 			addFunctionCaseWithPrograms(sizeGroup.get(), "disjoint", checkSupport, initPrograms, testStorageImageWrite, TestParameters(format, imageSize, (VkImageCreateFlags)(VK_IMAGE_CREATE_DISJOINT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT)));
763 
764 			formatGroup->addChild(sizeGroup.release());
765 		}
766 		testGroup->addChild(formatGroup.release());
767 	};
768 
769 	for (int formatNdx = VK_YCBCR_FORMAT_FIRST; formatNdx < VK_YCBCR_FORMAT_LAST; formatNdx++)
770 	{
771 		addTests(formatNdx);
772 	}
773 
774 	for (int formatNdx = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT; formatNdx <= VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT; formatNdx++)
775 	{
776 		addTests(formatNdx);
777 	}
778 
779 	return testGroup.release();
780 }
781 
782 } // namespace
783 
createStorageImageWriteTests(tcu::TestContext & testCtx)784 tcu::TestCaseGroup* createStorageImageWriteTests (tcu::TestContext& testCtx)
785 {
786 	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "storage_image_write"));
787 	return populateStorageImageWriteFormatGroup(testCtx, testGroup);
788 }
789 
790 } // ycbcr
791 } // vkt
792