• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group 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  vktSparseResourcesBufferSparseResidency.cpp
21  * \brief Sparse partially resident buffers tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktSparseResourcesBufferSparseResidency.hpp"
25 #include "vktSparseResourcesTestsUtil.hpp"
26 #include "vktSparseResourcesBase.hpp"
27 #include "vktTestCaseUtil.hpp"
28 
29 #include "vkDefs.hpp"
30 #include "vkRef.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkPrograms.hpp"
34 #include "vkRefUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkBarrierUtil.hpp"
37 #include "vkQueryUtil.hpp"
38 #include "vkBuilderUtil.hpp"
39 #include "vkTypeUtil.hpp"
40 #include "vkCmdUtil.hpp"
41 #include "vkObjUtil.hpp"
42 
43 #include "deStringUtil.hpp"
44 #include "deUniquePtr.hpp"
45 
46 #include <string>
47 #include <vector>
48 
49 using namespace vk;
50 
51 namespace vkt
52 {
53 namespace sparse
54 {
55 namespace
56 {
57 
58 enum ShaderParameters
59 {
60 	SIZE_OF_UINT_IN_SHADER = 4u,
61 };
62 
63 class BufferSparseResidencyCase : public TestCase
64 {
65 public:
66 					BufferSparseResidencyCase	(tcu::TestContext&		testCtx,
67 												 const std::string&		name,
68 												 const deUint32			bufferSize,
69 												 const glu::GLSLVersion	glslVersion,
70 												 const bool				useDeviceGroups);
71 
72 
73 	void			initPrograms				(SourceCollections&		sourceCollections) const;
74 	TestInstance*	createInstance				(Context&				context) const;
75 
76 private:
77 	const deUint32			m_bufferSize;
78 	const glu::GLSLVersion	m_glslVersion;
79 	const bool				m_useDeviceGroups;
80 
81 };
82 
BufferSparseResidencyCase(tcu::TestContext & testCtx,const std::string & name,const deUint32 bufferSize,const glu::GLSLVersion glslVersion,const bool useDeviceGroups)83 BufferSparseResidencyCase::BufferSparseResidencyCase (tcu::TestContext&			testCtx,
84 													  const std::string&		name,
85 													  const deUint32			bufferSize,
86 													  const glu::GLSLVersion	glslVersion,
87 													  const bool				useDeviceGroups)
88 
89 	: TestCase			(testCtx, name)
90 	, m_bufferSize		(bufferSize)
91 	, m_glslVersion		(glslVersion)
92 	, m_useDeviceGroups	(useDeviceGroups)
93 {
94 }
95 
initPrograms(SourceCollections & sourceCollections) const96 void BufferSparseResidencyCase::initPrograms (SourceCollections& sourceCollections) const
97 {
98 	const char* const	versionDecl		= glu::getGLSLVersionDeclaration(m_glslVersion);
99 	const deUint32		iterationsCount = m_bufferSize / SIZE_OF_UINT_IN_SHADER;
100 
101 	std::ostringstream src;
102 
103 	src << versionDecl << "\n"
104 		<< "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
105 		<< "layout(set = 0, binding = 0, std430) readonly buffer Input\n"
106 		<< "{\n"
107 		<< "	uint data[];\n"
108 		<< "} sb_in;\n"
109 		<< "\n"
110 		<< "layout(set = 0, binding = 1, std430) writeonly buffer Output\n"
111 		<< "{\n"
112 		<< "	uint result[];\n"
113 		<< "} sb_out;\n"
114 		<< "\n"
115 		<< "void main (void)\n"
116 		<< "{\n"
117 		<< "	for(int i=0; i<" << iterationsCount << "; ++i) \n"
118 		<< "	{\n"
119 		<< "		sb_out.result[i] = sb_in.data[i];"
120 		<< "	}\n"
121 		<< "}\n";
122 
123 	sourceCollections.glslSources.add("comp") << glu::ComputeSource(src.str());
124 }
125 
126 class BufferSparseResidencyInstance : public SparseResourcesBaseInstance
127 {
128 public:
129 					BufferSparseResidencyInstance	(Context&			context,
130 													 const deUint32		bufferSize,
131 													 const bool			useDeviceGroups);
132 
133 	tcu::TestStatus	iterate							(void);
134 
135 private:
136 	const deUint32	m_bufferSize;
137 };
138 
BufferSparseResidencyInstance(Context & context,const deUint32 bufferSize,const bool useDeviceGroups)139 BufferSparseResidencyInstance::BufferSparseResidencyInstance (Context&			context,
140 															  const deUint32	bufferSize,
141 															  const bool		useDeviceGroups)
142 	: SparseResourcesBaseInstance	(context, useDeviceGroups)
143 	, m_bufferSize					(bufferSize)
144 {
145 }
146 
iterate(void)147 tcu::TestStatus BufferSparseResidencyInstance::iterate (void)
148 {
149 	const InstanceInterface&		 instance					= m_context.getInstanceInterface();
150 	{
151 		// Create logical device supporting both sparse and compute operations
152 		QueueRequirementsVec queueRequirements;
153 		queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u));
154 		queueRequirements.push_back(QueueRequirements(VK_QUEUE_COMPUTE_BIT, 1u));
155 
156 		createDeviceSupportingQueues(queueRequirements);
157 	}
158 	const VkPhysicalDevice			 physicalDevice				= getPhysicalDevice();
159 	const VkPhysicalDeviceProperties physicalDeviceProperties	= getPhysicalDeviceProperties(instance, physicalDevice);
160 
161 	if (!getPhysicalDeviceFeatures(instance, physicalDevice).sparseResidencyBuffer)
162 		TCU_THROW(NotSupportedError, "Sparse partially resident buffers not supported");
163 
164 	const DeviceInterface&	deviceInterface	= getDeviceInterface();
165 	const Queue&			sparseQueue		= getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0);
166 	const Queue&			computeQueue	= getQueue(VK_QUEUE_COMPUTE_BIT, 0);
167 
168 	// Go through all physical devices
169 	for (deUint32 physDevID = 0; physDevID < m_numPhysicalDevices; physDevID++)
170 	{
171 		const deUint32	firstDeviceID	= physDevID;
172 		const deUint32	secondDeviceID	= (firstDeviceID + 1) % m_numPhysicalDevices;
173 
174 		VkBufferCreateInfo bufferCreateInfo =
175 		{
176 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
177 			DE_NULL,								// const void*			pNext;
178 			VK_BUFFER_CREATE_SPARSE_BINDING_BIT |
179 			VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT,	// VkBufferCreateFlags	flags;
180 			m_bufferSize,							// VkDeviceSize			size;
181 			VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
182 			VK_BUFFER_USAGE_TRANSFER_SRC_BIT,		// VkBufferUsageFlags	usage;
183 			VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
184 			0u,										// deUint32				queueFamilyIndexCount;
185 			DE_NULL									// const deUint32*		pQueueFamilyIndices;
186 		};
187 
188 		const deUint32 queueFamilyIndices[] = { sparseQueue.queueFamilyIndex, computeQueue.queueFamilyIndex };
189 
190 		if (sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex)
191 		{
192 			bufferCreateInfo.sharingMode			= VK_SHARING_MODE_CONCURRENT;
193 			bufferCreateInfo.queueFamilyIndexCount	= 2u;
194 			bufferCreateInfo.pQueueFamilyIndices	= queueFamilyIndices;
195 		}
196 
197 		// Create sparse buffer
198 		const Unique<VkBuffer> sparseBuffer(createBuffer(deviceInterface, getDevice(), &bufferCreateInfo));
199 
200 		// Create sparse buffer memory bind semaphore
201 		const Unique<VkSemaphore> bufferMemoryBindSemaphore(createSemaphore(deviceInterface, getDevice()));
202 
203 		const VkMemoryRequirements bufferMemRequirements = getBufferMemoryRequirements(deviceInterface, getDevice(), *sparseBuffer);
204 
205 		if (bufferMemRequirements.size > physicalDeviceProperties.limits.sparseAddressSpaceSize)
206 			TCU_THROW(NotSupportedError, "Required memory size for sparse resources exceeds device limits");
207 
208 		DE_ASSERT((bufferMemRequirements.size % bufferMemRequirements.alignment) == 0);
209 
210 		const deUint32				numSparseSlots = static_cast<deUint32>(bufferMemRequirements.size / bufferMemRequirements.alignment);
211 		std::vector<DeviceMemorySp>	deviceMemUniquePtrVec;
212 
213 		{
214 			std::vector<VkSparseMemoryBind>		sparseMemoryBinds;
215 			const deUint32						memoryType		= findMatchingMemoryType(instance, getPhysicalDevice(secondDeviceID), bufferMemRequirements, MemoryRequirement::Any);
216 
217 			if (memoryType == NO_MATCH_FOUND)
218 				return tcu::TestStatus::fail("No matching memory type found");
219 
220 			if (firstDeviceID != secondDeviceID)
221 			{
222 				VkPeerMemoryFeatureFlags	peerMemoryFeatureFlags = (VkPeerMemoryFeatureFlags)0;
223 				const deUint32				heapIndex = getHeapIndexForMemoryType(instance, getPhysicalDevice(secondDeviceID), memoryType);
224 				deviceInterface.getDeviceGroupPeerMemoryFeatures(getDevice(), heapIndex, firstDeviceID, secondDeviceID, &peerMemoryFeatureFlags);
225 
226 				if (((peerMemoryFeatureFlags & VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT)    == 0) ||
227 					((peerMemoryFeatureFlags & VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT) == 0))
228 				{
229 					TCU_THROW(NotSupportedError, "Peer memory does not support COPY_SRC and GENERIC_DST");
230 				}
231 			}
232 
233 			for (deUint32 sparseBindNdx = 0; sparseBindNdx < numSparseSlots; sparseBindNdx += 2)
234 			{
235 				const VkSparseMemoryBind sparseMemoryBind = makeSparseMemoryBind(deviceInterface, getDevice(), bufferMemRequirements.alignment, memoryType, bufferMemRequirements.alignment * sparseBindNdx);
236 
237 				deviceMemUniquePtrVec.push_back(makeVkSharedPtr(Move<VkDeviceMemory>(check<VkDeviceMemory>(sparseMemoryBind.memory), Deleter<VkDeviceMemory>(deviceInterface, getDevice(), DE_NULL))));
238 
239 				sparseMemoryBinds.push_back(sparseMemoryBind);
240 			}
241 
242 			const VkSparseBufferMemoryBindInfo sparseBufferBindInfo = makeSparseBufferMemoryBindInfo(*sparseBuffer, static_cast<deUint32>(sparseMemoryBinds.size()), &sparseMemoryBinds[0]);
243 
244 			const VkDeviceGroupBindSparseInfo devGroupBindSparseInfo =
245 			{
246 				VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO,		//VkStructureType							sType;
247 				DE_NULL,												//const void*								pNext;
248 				firstDeviceID,											//deUint32									resourceDeviceIndex;
249 				secondDeviceID,											//deUint32									memoryDeviceIndex;
250 			};
251 			const VkBindSparseInfo bindSparseInfo =
252 			{
253 				VK_STRUCTURE_TYPE_BIND_SPARSE_INFO,						//VkStructureType							sType;
254 				usingDeviceGroups() ? &devGroupBindSparseInfo : DE_NULL,//const void*								pNext;
255 				0u,														//deUint32									waitSemaphoreCount;
256 				DE_NULL,												//const VkSemaphore*						pWaitSemaphores;
257 				1u,														//deUint32									bufferBindCount;
258 				&sparseBufferBindInfo,									//const VkSparseBufferMemoryBindInfo*		pBufferBinds;
259 				0u,														//deUint32									imageOpaqueBindCount;
260 				DE_NULL,												//const VkSparseImageOpaqueMemoryBindInfo*	pImageOpaqueBinds;
261 				0u,														//deUint32									imageBindCount;
262 				DE_NULL,												//const VkSparseImageMemoryBindInfo*		pImageBinds;
263 				1u,														//deUint32									signalSemaphoreCount;
264 				&bufferMemoryBindSemaphore.get()						//const VkSemaphore*						pSignalSemaphores;
265 			};
266 
267 			VK_CHECK(deviceInterface.queueBindSparse(sparseQueue.queueHandle, 1u, &bindSparseInfo, DE_NULL));
268 		}
269 
270 		// Create input buffer
271 		const VkBufferCreateInfo		inputBufferCreateInfo	= makeBufferCreateInfo(m_bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
272 		const Unique<VkBuffer>			inputBuffer				(createBuffer(deviceInterface, getDevice(), &inputBufferCreateInfo));
273 		const de::UniquePtr<Allocation>	inputBufferAlloc		(bindBuffer(deviceInterface, getDevice(), getAllocator(), *inputBuffer, MemoryRequirement::HostVisible));
274 
275 
276 		std::vector<deUint8> referenceData;
277 		referenceData.resize(m_bufferSize);
278 
279 		for (deUint32 valueNdx = 0; valueNdx < m_bufferSize; ++valueNdx)
280 		{
281 			referenceData[valueNdx] = static_cast<deUint8>((valueNdx % bufferMemRequirements.alignment) + 1u);
282 		}
283 
284 		deMemcpy(inputBufferAlloc->getHostPtr(), &referenceData[0], m_bufferSize);
285 
286 		flushAlloc(deviceInterface, getDevice(), *inputBufferAlloc);
287 
288 		// Create output buffer
289 		const VkBufferCreateInfo		outputBufferCreateInfo	= makeBufferCreateInfo(m_bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
290 		const Unique<VkBuffer>			outputBuffer			(createBuffer(deviceInterface, getDevice(), &outputBufferCreateInfo));
291 		const de::UniquePtr<Allocation>	outputBufferAlloc		(bindBuffer(deviceInterface, getDevice(), getAllocator(), *outputBuffer, MemoryRequirement::HostVisible));
292 
293 		// Create command buffer for compute and data transfer operations
294 		const Unique<VkCommandPool>	  commandPool(makeCommandPool(deviceInterface, getDevice(), computeQueue.queueFamilyIndex));
295 		const Unique<VkCommandBuffer> commandBuffer(allocateCommandBuffer(deviceInterface, getDevice(), *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
296 
297 		// Start recording compute and transfer commands
298 		beginCommandBuffer(deviceInterface, *commandBuffer);
299 
300 		// Create descriptor set
301 		const Unique<VkDescriptorSetLayout> descriptorSetLayout(
302 			DescriptorSetLayoutBuilder()
303 			.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
304 			.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
305 			.build(deviceInterface, getDevice()));
306 
307 		// Create compute pipeline
308 		const Unique<VkShaderModule>	shaderModule(createShaderModule(deviceInterface, getDevice(), m_context.getBinaryCollection().get("comp"), DE_NULL));
309 		const Unique<VkPipelineLayout>	pipelineLayout(makePipelineLayout(deviceInterface, getDevice(), *descriptorSetLayout));
310 		const Unique<VkPipeline>		computePipeline(makeComputePipeline(deviceInterface, getDevice(), *pipelineLayout, *shaderModule));
311 
312 		deviceInterface.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline);
313 
314 		const Unique<VkDescriptorPool> descriptorPool(
315 			DescriptorPoolBuilder()
316 			.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u)
317 			.build(deviceInterface, getDevice(), VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
318 
319 		const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(deviceInterface, getDevice(), *descriptorPool, *descriptorSetLayout));
320 
321 		{
322 			const VkDescriptorBufferInfo inputBufferInfo = makeDescriptorBufferInfo(*inputBuffer, 0ull, m_bufferSize);
323 			const VkDescriptorBufferInfo sparseBufferInfo = makeDescriptorBufferInfo(*sparseBuffer, 0ull, m_bufferSize);
324 
325 			DescriptorSetUpdateBuilder()
326 				.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &inputBufferInfo)
327 				.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &sparseBufferInfo)
328 				.update(deviceInterface, getDevice());
329 		}
330 
331 		deviceInterface.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
332 
333 		{
334 			const VkBufferMemoryBarrier inputBufferBarrier
335 				= makeBufferMemoryBarrier(	VK_ACCESS_HOST_WRITE_BIT,
336 											VK_ACCESS_SHADER_READ_BIT,
337 											*inputBuffer,
338 											0ull,
339 											m_bufferSize);
340 
341 			deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u, 0u, DE_NULL, 1u, &inputBufferBarrier, 0u, DE_NULL);
342 		}
343 
344 		deviceInterface.cmdDispatch(*commandBuffer, 1u, 1u, 1u);
345 
346 		{
347 			const VkBufferMemoryBarrier sparseBufferBarrier
348 				= makeBufferMemoryBarrier(	VK_ACCESS_SHADER_WRITE_BIT,
349 											VK_ACCESS_TRANSFER_READ_BIT,
350 											*sparseBuffer,
351 											0ull,
352 											m_bufferSize);
353 
354 			deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 1u, &sparseBufferBarrier, 0u, DE_NULL);
355 		}
356 
357 		{
358 			const VkBufferCopy bufferCopy = makeBufferCopy(0u, 0u, m_bufferSize);
359 
360 			deviceInterface.cmdCopyBuffer(*commandBuffer, *sparseBuffer, *outputBuffer, 1u, &bufferCopy);
361 		}
362 
363 		{
364 			const VkBufferMemoryBarrier outputBufferBarrier
365 				= makeBufferMemoryBarrier(	VK_ACCESS_TRANSFER_WRITE_BIT,
366 											VK_ACCESS_HOST_READ_BIT,
367 											*outputBuffer,
368 											0ull,
369 											m_bufferSize);
370 
371 			deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &outputBufferBarrier, 0u, DE_NULL);
372 		}
373 
374 		// End recording compute and transfer commands
375 		endCommandBuffer(deviceInterface, *commandBuffer);
376 
377 		const VkPipelineStageFlags waitStageBits[] = { VK_PIPELINE_STAGE_TRANSFER_BIT };
378 
379 		// Submit transfer commands for execution and wait for completion
380 		submitCommandsAndWait(deviceInterface, getDevice(), computeQueue.queueHandle, *commandBuffer, 1u, &bufferMemoryBindSemaphore.get(),
381 			waitStageBits, 0, DE_NULL, usingDeviceGroups(), firstDeviceID);
382 
383 		// Retrieve data from output buffer to host memory
384 		invalidateAlloc(deviceInterface, getDevice(), *outputBufferAlloc);
385 
386 		const deUint8* outputData = static_cast<const deUint8*>(outputBufferAlloc->getHostPtr());
387 
388 		// Wait for sparse queue to become idle
389 		deviceInterface.queueWaitIdle(sparseQueue.queueHandle);
390 
391 		// Compare output data with reference data
392 		for (deUint32 sparseBindNdx = 0; sparseBindNdx < numSparseSlots; ++sparseBindNdx)
393 		{
394 			const deUint32 alignment = static_cast<deUint32>(bufferMemRequirements.alignment);
395 			const deUint32 offset	 = alignment * sparseBindNdx;
396 			const deUint32 size		 = sparseBindNdx == (numSparseSlots - 1) ? m_bufferSize % alignment : alignment;
397 
398 			if (sparseBindNdx % 2u == 0u)
399 			{
400 				if (deMemCmp(&referenceData[offset], outputData + offset, size) != 0)
401 					return tcu::TestStatus::fail("Failed");
402 			}
403 			else if (physicalDeviceProperties.sparseProperties.residencyNonResidentStrict)
404 			{
405 				deMemset(&referenceData[offset], 0u, size);
406 
407 				if (deMemCmp(&referenceData[offset], outputData + offset, size) != 0)
408 					return tcu::TestStatus::fail("Failed");
409 			}
410 		}
411 	}
412 
413 	return tcu::TestStatus::pass("Passed");
414 }
415 
createInstance(Context & context) const416 TestInstance* BufferSparseResidencyCase::createInstance (Context& context) const
417 {
418 	return new BufferSparseResidencyInstance(context, m_bufferSize, m_useDeviceGroups);
419 }
420 
421 } // anonymous ns
422 
addBufferSparseResidencyTests(tcu::TestCaseGroup * group,const bool useDeviceGroups)423 void addBufferSparseResidencyTests(tcu::TestCaseGroup* group, const bool useDeviceGroups)
424 {
425 	group->addChild(new BufferSparseResidencyCase(group->getTestContext(), "buffer_size_2_10", 1 << 10, glu::GLSL_VERSION_440, useDeviceGroups));
426 	group->addChild(new BufferSparseResidencyCase(group->getTestContext(), "buffer_size_2_12", 1 << 12, glu::GLSL_VERSION_440, useDeviceGroups));
427 	group->addChild(new BufferSparseResidencyCase(group->getTestContext(), "buffer_size_2_16", 1 << 16, glu::GLSL_VERSION_440, useDeviceGroups));
428 	group->addChild(new BufferSparseResidencyCase(group->getTestContext(), "buffer_size_2_17", 1 << 17, glu::GLSL_VERSION_440, useDeviceGroups));
429 	group->addChild(new BufferSparseResidencyCase(group->getTestContext(), "buffer_size_2_20", 1 << 20, glu::GLSL_VERSION_440, useDeviceGroups));
430 	group->addChild(new BufferSparseResidencyCase(group->getTestContext(), "buffer_size_2_24", 1 << 24, glu::GLSL_VERSION_440, useDeviceGroups));
431 }
432 
433 } // sparse
434 } // vkt
435