1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2016 The Android Open Source Project
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Image size Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktImageSizeTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktImageTestsUtil.hpp"
28 #include "vktImageTexture.hpp"
29 
30 #include "vkDefs.hpp"
31 #include "vkRef.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vkPlatform.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkBarrierUtil.hpp"
37 #include "vkBuilderUtil.hpp"
38 #include "vkImageUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkObjUtil.hpp"
41 #include "vkBufferWithMemory.hpp"
42 
43 #include "deUniquePtr.hpp"
44 #include "deStringUtil.hpp"
45 
46 #include <string>
47 
48 using namespace vk;
49 
50 namespace vkt
51 {
52 namespace image
53 {
54 namespace
55 {
56 
57 //! Get a texture based on image type and suggested size.
getTexture(const ImageType imageType, const tcu::IVec3& size)58 Texture getTexture (const ImageType imageType, const tcu::IVec3& size)
59 {
60 	switch (imageType)
61 	{
62 		case IMAGE_TYPE_1D:
63 		case IMAGE_TYPE_BUFFER:
64 			return Texture(imageType, tcu::IVec3(size.x(), 1, 1), 1);
65 
66 		case IMAGE_TYPE_1D_ARRAY:
67 			return Texture(imageType, tcu::IVec3(size.x(), 1, 1), size.y());
68 
69 		case IMAGE_TYPE_2D:
70 			return Texture(imageType, tcu::IVec3(size.x(), size.y(), 1), 1);
71 
72 		case IMAGE_TYPE_2D_ARRAY:
73 			return Texture(imageType, tcu::IVec3(size.x(), size.y(), 1), size.z());
74 
75 		case IMAGE_TYPE_CUBE:
76 			return Texture(imageType, tcu::IVec3(size.x(), size.x(), 1), 6);
77 
78 		case IMAGE_TYPE_CUBE_ARRAY:
79 			return Texture(imageType, tcu::IVec3(size.x(), size.x(), 1), 2*6);
80 
81 		case IMAGE_TYPE_3D:
82 			return Texture(imageType, size, 1);
83 
84 		default:
85 			DE_FATAL("Internal error");
86 			return Texture(IMAGE_TYPE_LAST, tcu::IVec3(), 0);
87 	}
88 }
89 
makeImageCreateInfo(const Texture& texture, const VkFormat format, const bool is2DViewOf3D)90 inline VkImageCreateInfo makeImageCreateInfo (const Texture& texture, const VkFormat format, const bool is2DViewOf3D)
91 {
92 	VkImageViewCreateFlags createFlags = 0u;
93 
94 	if (isCube(texture))
95 		createFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
96 #ifndef CTS_USES_VULKANSC
97 	else if (is2DViewOf3D)
98 		createFlags |= VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT;
99 #else
100 	DE_UNREF(is2DViewOf3D);
101 #endif // CTS_USES_VULKANSC
102 
103 	const VkImageCreateInfo imageParams =
104 	{
105 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,												// VkStructureType			sType;
106 		DE_NULL,																			// const void*				pNext;
107 		createFlags,																		// VkImageCreateFlags		flags;
108 		mapImageType(texture.type()),														// VkImageType				imageType;
109 		format,																				// VkFormat					format;
110 		makeExtent3D(texture.layerSize()),													// VkExtent3D				extent;
111 		1u,																					// deUint32					mipLevels;
112 		(deUint32)texture.numLayers(),														// deUint32					arrayLayers;
113 		VK_SAMPLE_COUNT_1_BIT,																// VkSampleCountFlagBits	samples;
114 		VK_IMAGE_TILING_OPTIMAL,															// VkImageTiling			tiling;
115 		VK_IMAGE_USAGE_STORAGE_BIT,															// VkImageUsageFlags		usage;
116 		VK_SHARING_MODE_EXCLUSIVE,															// VkSharingMode			sharingMode;
117 		0u,																					// deUint32					queueFamilyIndexCount;
118 		DE_NULL,																			// const deUint32*			pQueueFamilyIndices;
119 		VK_IMAGE_LAYOUT_UNDEFINED,															// VkImageLayout			initialLayout;
120 	};
121 	return imageParams;
122 }
123 
124 //! Interpret the memory as IVec3
readIVec3(const void* const data)125 inline tcu::IVec3 readIVec3 (const void* const data)
126 {
127 	const int* const p = reinterpret_cast<const int*>(data);
128 	return tcu::IVec3(p[0], p[1], p[2]);
129 }
130 
getExpectedImageSizeResult(const Texture& texture, const bool is2DViewOf3D)131 tcu::IVec3 getExpectedImageSizeResult (const Texture& texture, const bool is2DViewOf3D)
132 {
133 	// GLSL imageSize() function returns:
134 	// z = 0 for cubes
135 	// z = N for cube arrays, where N is the number of cubes
136 	// y or z = L where L is the number of layers for other array types (e.g. 1D array, 2D array)
137 	// z = D where D is the depth of 3d image
138 
139 	const tcu::IVec3 size = texture.size();
140 	const int numCubeFaces = 6;
141 
142 	switch (texture.type())
143 	{
144 		case IMAGE_TYPE_1D:
145 		case IMAGE_TYPE_BUFFER:
146 			return tcu::IVec3(size.x(), 0, 0);
147 
148 		case IMAGE_TYPE_1D_ARRAY:
149 		case IMAGE_TYPE_2D:
150 		case IMAGE_TYPE_CUBE:
151 			return tcu::IVec3(size.x(), size.y(), 0);
152 
153 		case IMAGE_TYPE_2D_ARRAY:
154 		case IMAGE_TYPE_3D:
155 			{
156 				if (is2DViewOf3D)
157 					return tcu::IVec3(size.x(), size.y(), 0);
158 				return size;
159 			}
160 
161 		case IMAGE_TYPE_CUBE_ARRAY:
162 			return tcu::IVec3(size.x(), size.y(), size.z() / numCubeFaces);
163 
164 		default:
165 			DE_FATAL("Internal error");
166 			return tcu::IVec3();
167 	}
168 }
169 
170 class SizeTest : public TestCase
171 {
172 public:
173 	enum TestFlags
174 	{
175 		FLAG_READONLY_IMAGE		= 1u << 0,
176 		FLAG_WRITEONLY_IMAGE	= 1u << 1,
177 	};
178 
179 						SizeTest			(tcu::TestContext&	testCtx,
180 											 const std::string&	name,
181 											 const Texture&		texture,
182 											 const VkFormat		format,
183 											 const deUint32		flags,
184 											 const bool			is2DViewOf3D);
185 
186 	void				initPrograms		(SourceCollections& programCollection) const;
187 	TestInstance*		createInstance		(Context&			context) const;
188 	virtual void		checkSupport		(Context&			context) const;
189 
190 private:
191 	const Texture		m_texture;
192 	const VkFormat		m_format;
193 	const bool			m_useReadonly;
194 	const bool			m_useWriteonly;
195 	const bool			m_2DViewOf3D;
196 };
197 
SizeTest(tcu::TestContext& testCtx, const std::string& name, const Texture& texture, const VkFormat format, const deUint32 flags, const bool is2DViewOf3D)198 SizeTest::SizeTest (tcu::TestContext&		testCtx,
199 					const std::string&		name,
200 					const Texture&			texture,
201 					const VkFormat			format,
202 					const deUint32			flags,
203 					const bool				is2DViewOf3D)
204 	: TestCase			(testCtx, name)
205 	, m_texture			(texture)
206 	, m_format			(format)
207 	, m_useReadonly		((flags & FLAG_READONLY_IMAGE) != 0)
208 	, m_useWriteonly	((flags & FLAG_WRITEONLY_IMAGE) != 0)
209 	, m_2DViewOf3D		(is2DViewOf3D)
210 {
211 	// We expect at least one flag to be set.
212 	DE_ASSERT(m_useReadonly || m_useWriteonly);
213 
214 	// For 2D views of 3D we need 3D images.
215 	DE_ASSERT(!m_2DViewOf3D || m_texture.type() == IMAGE_TYPE_3D);
216 }
217 
checkSupport(Context& context) const218 void SizeTest::checkSupport (Context& context) const
219 {
220 	const auto imgType = m_texture.type();
221 
222 	if (imgType == IMAGE_TYPE_CUBE_ARRAY)
223 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_IMAGE_CUBE_ARRAY);
224 
225 	if (imgType != IMAGE_TYPE_BUFFER)
226 	{
227 		const auto&				vki					= context.getInstanceInterface();
228 		const auto				physicalDevice		= context.getPhysicalDevice();
229 		const auto				createInfo			= makeImageCreateInfo(m_texture, m_format, m_2DViewOf3D);
230 		VkImageFormatProperties	formatProperties;
231 
232 		const auto result = vki.getPhysicalDeviceImageFormatProperties(physicalDevice, createInfo.format, createInfo.imageType, createInfo.tiling, createInfo.usage, createInfo.flags, &formatProperties);
233 
234 		if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
235 			TCU_THROW(NotSupportedError, "Format not supported for the specified usage");
236 	}
237 
238 	if (m_2DViewOf3D)
239 		context.requireDeviceFunctionality("VK_EXT_image_2d_view_of_3d");
240 }
241 
initPrograms(SourceCollections& programCollection) const242 void SizeTest::initPrograms (SourceCollections& programCollection) const
243 {
244 	const std::string	formatQualifierStr	= getShaderImageFormatQualifier(mapVkFormat(m_format));
245 	const std::string	imageTypeStr		= getShaderImageType(mapVkFormat(m_format), (m_2DViewOf3D ? IMAGE_TYPE_2D : m_texture.type()));
246 	const int			dimension			= m_texture.dimension();
247 
248 	std::ostringstream accessQualifier;
249 	if (m_useReadonly)
250 		accessQualifier << " readonly";
251 	if (m_useWriteonly)
252 		accessQualifier << " writeonly";
253 
254 	std::ostringstream src;
255 	src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
256 		<< "\n"
257 		<< "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
258 		<< "layout (binding = 0, " << formatQualifierStr << ")" << accessQualifier.str() << " uniform highp " << imageTypeStr << " u_image;\n"
259 		<< "layout (binding = 1) writeonly buffer Output {\n"
260 		<< "    ivec3 size;\n"
261 		<< "} sb_out;\n"
262 		<< "\n"
263 		<< "void main (void)\n"
264 		<< "{\n"
265 		<< (dimension == 1 ?
266 			"    sb_out.size = ivec3(imageSize(u_image), 0, 0);\n"
267 			: dimension == 2 || m_2DViewOf3D || m_texture.type() == IMAGE_TYPE_CUBE ?	// cubes return ivec2
268 			"    sb_out.size = ivec3(imageSize(u_image), 0);\n"
269 			: dimension == 3 ?															// cube arrays return ivec3
270 			"    sb_out.size = imageSize(u_image);\n"
271 			: "")
272 		<< "}\n";
273 
274 	programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
275 }
276 
277 //! Build a case name, e.g. "readonly_writeonly_32x32"
getCaseName(const Texture& texture, const deUint32 flags, const bool is2DViewOf3D)278 std::string getCaseName (const Texture& texture, const deUint32 flags, const bool is2DViewOf3D)
279 {
280 	std::ostringstream str;
281 	str << ((flags & SizeTest::FLAG_READONLY_IMAGE) != 0 ? "readonly_" : "")
282 		<< ((flags & SizeTest::FLAG_WRITEONLY_IMAGE) != 0 ? "writeonly_" : "");
283 
284 	if (is2DViewOf3D)
285 		str << "2d_view_";
286 
287 	const int numComponents = texture.dimension();
288 	for (int i = 0; i < numComponents; ++i)
289 		str << (i == 0 ? "" : "x") << texture.size()[i];
290 
291 	return str.str();
292 }
293 
294 //! Base test instance for image and buffer tests
295 class SizeTestInstance : public TestInstance
296 {
297 public:
298 									SizeTestInstance			(Context&				context,
299 																 const Texture&			texture,
300 																 const VkFormat			format,
301 																 const bool				is2DViewOf3D = false);
302 
303 	tcu::TestStatus                 iterate						(void);
~SizeTestInstance(void)304 	virtual							~SizeTestInstance			(void) {}
305 
306 protected:
307 	virtual VkDescriptorSetLayout	prepareDescriptors			(void) = 0;
308 	virtual VkDescriptorSet         getDescriptorSet			(void) const = 0;
309 	virtual void					commandBeforeCompute		(const VkCommandBuffer	cmdBuffer) = 0;
310 
311 	const Texture					m_texture;
312 	const VkFormat					m_format;
313 	const VkDeviceSize				m_resultBufferSizeBytes;
314 	const bool						m_2DViewOf3D;
315 	de::MovePtr<BufferWithMemory>	m_resultBuffer;				//!< Shader writes the output here.
316 };
317 
SizeTestInstance(Context& context, const Texture& texture, const VkFormat format, const bool is2DViewOf3D)318 SizeTestInstance::SizeTestInstance (Context& context, const Texture& texture, const VkFormat format, const bool is2DViewOf3D)
319 	: TestInstance				(context)
320 	, m_texture					(texture)
321 	, m_format					(format)
322 	, m_resultBufferSizeBytes	(3 * sizeof(deUint32))	// ivec3 in shader
323 	, m_2DViewOf3D				(is2DViewOf3D)
324 {
325 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
326 	const VkDevice			device		= m_context.getDevice();
327 	Allocator&				allocator	= m_context.getDefaultAllocator();
328 
329 	// Create an SSBO for shader output.
330 
331 	m_resultBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(
332 		vk, device, allocator,
333 		makeBufferCreateInfo(m_resultBufferSizeBytes, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),
334 		MemoryRequirement::HostVisible));
335 }
336 
iterate(void)337 tcu::TestStatus SizeTestInstance::iterate (void)
338 {
339 	const DeviceInterface&	vk					= m_context.getDeviceInterface();
340 	const VkDevice			device				= m_context.getDevice();
341 	const VkQueue			queue				= m_context.getUniversalQueue();
342 	const deUint32			queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
343 
344 	// Create memory barriers.
345 
346 	const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
347 		VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT,
348 		m_resultBuffer->get(), 0ull, m_resultBufferSizeBytes);
349 
350 	// Create the pipeline.
351 
352 	const Unique<VkShaderModule> shaderModule(createShaderModule(vk, device, m_context.getBinaryCollection().get("comp"), 0));
353 
354 	const VkDescriptorSetLayout descriptorSetLayout = prepareDescriptors();
355 	const VkDescriptorSet descriptorSet = getDescriptorSet();
356 
357 	const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, descriptorSetLayout));
358 	const Unique<VkPipeline> pipeline(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule));
359 
360 	const Unique<VkCommandPool> cmdPool(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
361 	const Unique<VkCommandBuffer> cmdBuffer(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
362 
363 	beginCommandBuffer(vk, *cmdBuffer);
364 
365 	vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
366 	vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet, 0u, DE_NULL);
367 
368 	commandBeforeCompute(*cmdBuffer);
369 	vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
370 	vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &shaderWriteBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL);
371 
372 	endCommandBuffer(vk, *cmdBuffer);
373 
374 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
375 
376 	// Compare the result.
377 
378 	const Allocation& bufferAlloc = m_resultBuffer->getAllocation();
379 	invalidateAlloc(vk, device, bufferAlloc);
380 
381 	const tcu::IVec3 resultSize = readIVec3(bufferAlloc.getHostPtr());
382 	const tcu::IVec3 expectedSize = getExpectedImageSizeResult(m_texture, m_2DViewOf3D);
383 
384 	if (resultSize != expectedSize)
385 		return tcu::TestStatus::fail("Incorrect imageSize(): expected " + de::toString(expectedSize) + " but got " + de::toString(resultSize));
386 	else
387 		return tcu::TestStatus::pass("Passed");
388 }
389 
390 class ImageSizeTestInstance : public SizeTestInstance
391 {
392 public:
393 									ImageSizeTestInstance		(Context&				context,
394 																 const Texture&			texture,
395 																 const VkFormat			format,
396 																 const bool				is2DViewOf3D);
397 
398 protected:
399 	VkDescriptorSetLayout			prepareDescriptors			(void);
400 	void							commandBeforeCompute		(const VkCommandBuffer	cmdBuffer);
401 
getDescriptorSet(void) const402 	VkDescriptorSet                 getDescriptorSet			(void) const { return *m_descriptorSet; }
403 
404 	de::MovePtr<Image>				m_image;
405 	Move<VkImageView>				m_imageView;
406 	Move<VkDescriptorSetLayout>		m_descriptorSetLayout;
407 	Move<VkDescriptorPool>			m_descriptorPool;
408 	Move<VkDescriptorSet>			m_descriptorSet;
409 };
410 
ImageSizeTestInstance(Context& context, const Texture& texture, const VkFormat format, const bool is2DViewOf3D)411 ImageSizeTestInstance::ImageSizeTestInstance (Context& context, const Texture& texture, const VkFormat format, const bool is2DViewOf3D)
412 	: SizeTestInstance	(context, texture, format, is2DViewOf3D)
413 {
414 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
415 	const VkDevice			device		= m_context.getDevice();
416 	Allocator&				allocator	= m_context.getDefaultAllocator();
417 
418 	// Create an image. Its data will be uninitialized, as we're not reading from it.
419 
420 	m_image = de::MovePtr<Image>(new Image(vk, device, allocator, makeImageCreateInfo(m_texture, m_format, m_2DViewOf3D), MemoryRequirement::Any));
421 
422 	const auto baseLayer		= (m_2DViewOf3D ? static_cast<uint32_t>(m_texture.size().z() / 2) : 0u);
423 	const auto viewType			= (m_2DViewOf3D ? VK_IMAGE_VIEW_TYPE_2D : mapImageViewType(m_texture.type()));
424 	const auto subresourceRange	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, baseLayer, m_texture.numLayers());
425 
426 	m_imageView = makeImageView(vk, device, m_image->get(), viewType, m_format, subresourceRange);
427 }
428 
prepareDescriptors(void)429 VkDescriptorSetLayout ImageSizeTestInstance::prepareDescriptors (void)
430 {
431 	const DeviceInterface&	vk		= m_context.getDeviceInterface();
432 	const VkDevice			device	= m_context.getDevice();
433 
434 	m_descriptorSetLayout = DescriptorSetLayoutBuilder()
435 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
436 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
437 		.build(vk, device);
438 
439 	m_descriptorPool = DescriptorPoolBuilder()
440 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
441 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
442 		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
443 
444 	m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
445 
446 	const VkDescriptorImageInfo descriptorImageInfo = makeDescriptorImageInfo(DE_NULL, *m_imageView, VK_IMAGE_LAYOUT_GENERAL);
447 	const VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(m_resultBuffer->get(), 0ull, m_resultBufferSizeBytes);
448 
449 	DescriptorSetUpdateBuilder()
450 		.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
451 		.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
452 		.update(vk, device);
453 
454 	return *m_descriptorSetLayout;
455 }
456 
commandBeforeCompute(const VkCommandBuffer cmdBuffer)457 void ImageSizeTestInstance::commandBeforeCompute (const VkCommandBuffer cmdBuffer)
458 {
459 	const DeviceInterface& vk = m_context.getDeviceInterface();
460 
461 	const VkImageSubresourceRange subresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_texture.numLayers());
462 	const VkImageMemoryBarrier barrierSetImageLayout = makeImageMemoryBarrier(
463 		0u, VK_ACCESS_SHADER_READ_BIT,
464 		VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL,
465 		m_image->get(), subresourceRange);
466 
467 	vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &barrierSetImageLayout);
468 }
469 
470 class BufferSizeTestInstance : public SizeTestInstance
471 {
472 public:
473 									BufferSizeTestInstance		(Context&				context,
474 																 const Texture&			texture,
475 																 const VkFormat			format);
476 
477 protected:
478 	VkDescriptorSetLayout			prepareDescriptors			(void);
479 
commandBeforeCompute(const VkCommandBuffer)480 	void							commandBeforeCompute		(const VkCommandBuffer) {}
getDescriptorSet(void) const481 	VkDescriptorSet					getDescriptorSet			(void) const { return *m_descriptorSet; }
482 
483 	de::MovePtr<BufferWithMemory>	m_imageBuffer;
484 	Move<VkBufferView>				m_bufferView;
485 	Move<VkDescriptorSetLayout>		m_descriptorSetLayout;
486 	Move<VkDescriptorPool>			m_descriptorPool;
487 	Move<VkDescriptorSet>			m_descriptorSet;
488 };
489 
BufferSizeTestInstance(Context& context, const Texture& texture, const VkFormat format)490 BufferSizeTestInstance::BufferSizeTestInstance (Context& context, const Texture& texture, const VkFormat format)
491 	: SizeTestInstance	(context, texture, format)
492 {
493 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
494 	const VkDevice			device		= m_context.getDevice();
495 	Allocator&				allocator	= m_context.getDefaultAllocator();
496 
497 	// Create a texel storage buffer. Its data be uninitialized, as we're not reading from it.
498 
499 	const VkDeviceSize imageSizeBytes = getImageSizeBytes(m_texture.size(), m_format);
500 	m_imageBuffer = de::MovePtr<BufferWithMemory>(new BufferWithMemory(vk, device, allocator,
501 		makeBufferCreateInfo(imageSizeBytes, VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT), MemoryRequirement::Any));
502 
503 	m_bufferView = makeBufferView(vk, device, m_imageBuffer->get(), m_format, 0ull, imageSizeBytes);
504 }
505 
prepareDescriptors(void)506 VkDescriptorSetLayout BufferSizeTestInstance::prepareDescriptors (void)
507 {
508 	const DeviceInterface&	vk		= m_context.getDeviceInterface();
509 	const VkDevice			device	= m_context.getDevice();
510 
511 	m_descriptorSetLayout = DescriptorSetLayoutBuilder()
512 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
513 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
514 		.build(vk, device);
515 
516 	m_descriptorPool = DescriptorPoolBuilder()
517 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)
518 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
519 		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
520 
521 	m_descriptorSet = makeDescriptorSet(vk, device, *m_descriptorPool, *m_descriptorSetLayout);
522 
523 	const VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(m_resultBuffer->get(), 0ull, m_resultBufferSizeBytes);
524 
525 	DescriptorSetUpdateBuilder()
526 		.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, &m_bufferView.get())
527 		.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
528 		.update(vk, device);
529 
530 	return *m_descriptorSetLayout;
531 }
532 
createInstance(Context& context) const533 TestInstance* SizeTest::createInstance (Context& context) const
534 {
535 	if (m_texture.type() == IMAGE_TYPE_BUFFER)
536 		return new BufferSizeTestInstance(context, m_texture, m_format);
537 	else
538 		return new ImageSizeTestInstance(context, m_texture, m_format, m_2DViewOf3D);
539 }
540 
541 } // anonymous ns
542 
createImageSizeTests(tcu::TestContext& testCtx)543 tcu::TestCaseGroup* createImageSizeTests (tcu::TestContext& testCtx)
544 {
545 	const ImageType s_imageTypes[] =
546 	{
547 		IMAGE_TYPE_1D,
548 		IMAGE_TYPE_1D_ARRAY,
549 		IMAGE_TYPE_2D,
550 		IMAGE_TYPE_2D_ARRAY,
551 		IMAGE_TYPE_3D,
552 		IMAGE_TYPE_CUBE,
553 		IMAGE_TYPE_CUBE_ARRAY,
554 		IMAGE_TYPE_BUFFER,
555 	};
556 
557 	//! Base sizes used to generate actual image/buffer sizes in the test.
558 	const tcu::IVec3 s_baseImageSizes[] =
559 	{
560 		tcu::IVec3(32, 32, 32),
561 		tcu::IVec3(12, 34, 56),
562 		tcu::IVec3(1,   1,  1),
563 		tcu::IVec3(7,   1,  1),
564 	};
565 
566 	const deUint32 s_flags[] =
567 	{
568 		SizeTest::FLAG_READONLY_IMAGE,
569 		SizeTest::FLAG_WRITEONLY_IMAGE,
570 		SizeTest::FLAG_READONLY_IMAGE | SizeTest::FLAG_WRITEONLY_IMAGE,
571 	};
572 
573 	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "image_size"));
574 
575 	const VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT;
576 
577 	for (const auto& imageType : s_imageTypes)
578 	{
579 		de::MovePtr<tcu::TestCaseGroup> imageGroup(new tcu::TestCaseGroup(testCtx, getImageTypeName(imageType).c_str()));
580 
581 		for (const auto& flags : s_flags)
582 			for (const auto& baseImageSize : s_baseImageSizes)
583 				for (int boolIdx = 0; boolIdx < 2; ++boolIdx)
584 				{
585 					const bool is2DViewOf3D = (boolIdx > 0);
586 
587 #ifdef CTS_USES_VULKANSC
588 					// VulkanSC doesn't have VK_EXT_image_2d_view_of_3d
589 					if (is2DViewOf3D)
590 						continue;
591 #endif // CTS_USES_VULKANSC
592 
593 					if (is2DViewOf3D && imageType != IMAGE_TYPE_3D)
594 						continue;
595 
596 					const Texture	texture		= getTexture(imageType, baseImageSize);
597 					const auto		caseName	= getCaseName(texture, flags, is2DViewOf3D);
598 
599 					imageGroup->addChild(new SizeTest(testCtx, caseName, texture, format, flags, is2DViewOf3D));
600 				}
601 
602 		testGroup->addChild(imageGroup.release());
603 	}
604 	return testGroup.release();
605 }
606 
607 } // image
608 } // vkt
609