• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2018 The Khronos Group Inc.
6  * Copyright (c) 2018 Google Inc.
7  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Protected memory workgroup storage tests
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktProtectedMemWorkgroupStorageTests.hpp"
27 
28 #include "vktProtectedMemContext.hpp"
29 #include "vktProtectedMemUtils.hpp"
30 #include "vktProtectedMemImageValidator.hpp"
31 #include "vktTestCase.hpp"
32 #include "vktTestGroupUtil.hpp"
33 
34 #include "vkPrograms.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkCmdUtil.hpp"
39 #include "vkObjUtil.hpp"
40 
41 #include "tcuTestLog.hpp"
42 #include "tcuVector.hpp"
43 #include "tcuTextureUtil.hpp"
44 #include "tcuStringTemplate.hpp"
45 
46 #include "gluTextureTestUtil.hpp"
47 
48 #include "deRandom.hpp"
49 
50 namespace vkt
51 {
52 namespace ProtectedMem
53 {
54 
55 namespace
56 {
57 
58 struct Params
59 {
60 	deUint32			sharedMemorySize;
61 	deUint32			imageWidth;
62 	deUint32			imageHeight;
63 
Paramsvkt::ProtectedMem::__anoncfd66e4b0111::Params64 	Params (deUint32	sharedMemorySize_)
65 		: sharedMemorySize	(sharedMemorySize_)
66 	{
67 		// Find suitable image dimensions based on shared memory size
68 		imageWidth = 1;
69 		imageHeight = 1;
70 		bool increaseWidth = true;
71 		while (imageWidth * imageHeight < sharedMemorySize)
72 		{
73 			if (increaseWidth)
74 				imageWidth *= 2;
75 			else
76 				imageHeight *= 2;
77 
78 			increaseWidth = !increaseWidth;
79 		}
80 	}
81 };
82 
getSeedValue(const Params & params)83 deUint32 getSeedValue (const Params& params)
84 {
85 	return deInt32Hash(params.sharedMemorySize);
86 }
87 
88 class WorkgroupStorageTestInstance : public ProtectedTestInstance
89 {
90 public:
91 								WorkgroupStorageTestInstance	(Context&				ctx,
92 																 const ImageValidator&	validator,
93 																 const Params&			params);
94 	virtual tcu::TestStatus		iterate							(void);
95 
96 private:
97 	de::MovePtr<tcu::Texture2D>	createTestTexture2D				(void);
98 	tcu::TestStatus				validateResult					(vk::VkImage			image,
99 																 vk::VkImageLayout imageLayout,
100 																 const tcu::Texture2D&	texture2D,
101 																 const tcu::Sampler&	refSampler);
102 	void						calculateRef					(tcu::Texture2D&		texture2D);
103 
104 	const ImageValidator&		m_validator;
105 	const Params&				m_params;
106 };
107 
108 class WorkgroupStorageTestCase : public TestCase
109 {
110 public:
WorkgroupStorageTestCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const Params & params)111 								WorkgroupStorageTestCase	(tcu::TestContext&		testCtx,
112 															 const std::string&		name,
113 															 const std::string&		description,
114 															 const Params&			params)
115 									: TestCase		(testCtx, name, description)
116 									, m_validator	(vk::VK_FORMAT_R8G8B8A8_UNORM)
117 									, m_params		(params)
118 								{
119 								}
120 
~WorkgroupStorageTestCase(void)121 	virtual						~WorkgroupStorageTestCase	(void) {}
createInstance(Context & ctx) const122 	virtual TestInstance*		createInstance				(Context& ctx) const
123 								{
124 									return new WorkgroupStorageTestInstance(ctx, m_validator, m_params);
125 								}
126 	virtual void				initPrograms				(vk::SourceCollections& programCollection) const;
checkSupport(Context & context) const127 	virtual void				checkSupport				(Context& context) const
128 								{
129 									checkProtectedQueueSupport(context);
130 								}
131 
132 private:
133 	ImageValidator				m_validator;
134 	Params						m_params;
135 };
136 
initPrograms(vk::SourceCollections & programCollection) const137 void WorkgroupStorageTestCase::initPrograms (vk::SourceCollections& programCollection) const
138 {
139 	m_validator.initPrograms(programCollection);
140 
141 	// Fill shared data array with source image data. Output result color with results from
142 	// shared memory written by another invocation.
143 	std::string comp =
144 		std::string() +
145 		"#version 450\n"
146 		"layout(local_size_x = " + de::toString(m_params.imageWidth) + ", local_size_y = " + de::toString(m_params.imageHeight) + ", local_size_z = 1) in;\n"
147 		"layout(set = 0, binding = 0, rgba8) writeonly uniform highp image2D u_resultImage;\n"
148 		"layout(set = 0, binding = 1, rgba8) readonly uniform highp image2D u_srcImage;\n"
149 		"shared vec4 sharedData[" + de::toString(m_params.sharedMemorySize) + "];\n"
150 		"\n"
151 		"void main() {\n"
152 		"    int gx = int(gl_GlobalInvocationID.x);\n"
153 		"    int gy = int(gl_GlobalInvocationID.y);\n"
154 		"    int s = " + de::toString(m_params.sharedMemorySize) + ";\n"
155 		"    int idx0 = gy * " + de::toString(m_params.imageWidth) + " + gx;\n"
156 		"    int idx1 = (idx0 + 1) % s;\n"
157 		"    vec4 color = imageLoad(u_srcImage, ivec2(gx, gy));\n"
158 		"    if (idx0 < s)\n"
159 		"    {\n"
160 		"        sharedData[idx0] = color;\n"
161 		"    }\n"
162 		"    barrier();\n"
163 		"    vec4 outColor = sharedData[idx1];\n"
164 		"    imageStore(u_resultImage, ivec2(gx, gy), outColor);\n"
165 		"}\n";
166 
167 	programCollection.glslSources.add("comp") << glu::ComputeSource(comp);
168 }
169 
WorkgroupStorageTestInstance(Context & ctx,const ImageValidator & validator,const Params & params)170 WorkgroupStorageTestInstance::WorkgroupStorageTestInstance (Context&				ctx,
171 															const ImageValidator&	validator,
172 															const Params&			params)
173 	: ProtectedTestInstance	(ctx)
174 	, m_validator			(validator)
175 	, m_params				(params)
176 {
177 }
178 
createTestTexture2D(void)179 de::MovePtr<tcu::Texture2D> WorkgroupStorageTestInstance::createTestTexture2D (void)
180 {
181 	const tcu::TextureFormat		texFmt		= mapVkFormat(vk::VK_FORMAT_R8G8B8A8_UNORM);
182 	const tcu::TextureFormatInfo	fmtInfo		= tcu::getTextureFormatInfo(texFmt);
183 	de::MovePtr<tcu::Texture2D>		texture2D	(new tcu::Texture2D(texFmt, m_params.imageWidth, m_params.imageHeight));
184 
185 	texture2D->allocLevel(0);
186 
187 	const tcu::PixelBufferAccess&	level		= texture2D->getLevel(0);
188 
189 	fillWithRandomColorTiles(level, fmtInfo.valueMin, fmtInfo.valueMax, getSeedValue(m_params));
190 
191 	return texture2D;
192 }
193 
iterate(void)194 tcu::TestStatus WorkgroupStorageTestInstance::iterate (void)
195 {
196 	ProtectedContext&						ctx					(m_protectedContext);
197 	const vk::DeviceInterface&				vk					= ctx.getDeviceInterface();
198 	const vk::VkDevice						device				= ctx.getDevice();
199 	const vk::VkQueue						queue				= ctx.getQueue();
200 	const deUint32							queueFamilyIndex	= ctx.getQueueFamilyIndex();
201 	const vk::VkPhysicalDeviceProperties	properties			= vk::getPhysicalDeviceProperties(ctx.getInstanceDriver(), ctx.getPhysicalDevice());
202 
203 	vk::Unique<vk::VkCommandPool>			cmdPool				(makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
204 
205 	de::MovePtr<tcu::Texture2D>				texture2D			= createTestTexture2D();
206 	const tcu::Sampler						refSampler			= tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
207 																			   tcu::Sampler::NEAREST, tcu::Sampler::NEAREST,
208 																			   00.0f /* LOD threshold */, true /* normalized coords */, tcu::Sampler::COMPAREMODE_NONE,
209 																			   0 /* cmp channel */, tcu::Vec4(0.0f) /* border color */, true /* seamless cube map */);
210 
211 	vk::Unique<vk::VkShaderModule>			computeShader		(vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("comp"), 0));
212 
213 	de::MovePtr<vk::ImageWithMemory>		imageSrc;
214 	de::MovePtr<vk::ImageWithMemory>		imageDst;
215 	vk::Move<vk::VkSampler>					sampler;
216 	vk::Move<vk::VkImageView>				imageViewSrc;
217 	vk::Move<vk::VkImageView>				imageViewDst;
218 
219 	vk::Move<vk::VkDescriptorSetLayout>		descriptorSetLayout;
220 	vk::Move<vk::VkDescriptorPool>			descriptorPool;
221 	vk::Move<vk::VkDescriptorSet>			descriptorSet;
222 
223 	// Check there is enough shared memory supported
224 	if (properties.limits.maxComputeSharedMemorySize < m_params.sharedMemorySize * 4 * 4)
225 		throw tcu::NotSupportedError("Not enough shared memory supported.");
226 
227 	// Check the number of invocations supported
228 	if (properties.limits.maxComputeWorkGroupInvocations < m_params.imageWidth * m_params.imageHeight)
229 		throw tcu::NotSupportedError("Not enough compute workgroup invocations supported.");
230 
231 	// Create src and dst images
232 	{
233 		vk::VkImageUsageFlags imageUsageFlags = vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT	|
234 												vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT	|
235 												vk::VK_IMAGE_USAGE_SAMPLED_BIT		|
236 												vk::VK_IMAGE_USAGE_STORAGE_BIT;
237 
238 		imageSrc = createImage2D(ctx, PROTECTION_ENABLED, queueFamilyIndex,
239 								 m_params.imageWidth, m_params.imageHeight,
240 								 vk::VK_FORMAT_R8G8B8A8_UNORM,
241 								 imageUsageFlags);
242 
243 		imageDst = createImage2D(ctx, PROTECTION_ENABLED, queueFamilyIndex,
244 								 m_params.imageWidth, m_params.imageHeight,
245 								 vk::VK_FORMAT_R8G8B8A8_UNORM,
246 								 imageUsageFlags);
247 	}
248 
249 	// Upload source image
250 	{
251 		de::MovePtr<vk::ImageWithMemory>	unprotectedImage	= createImage2D(ctx, PROTECTION_DISABLED, queueFamilyIndex,
252 																				m_params.imageWidth, m_params.imageHeight,
253 																				vk::VK_FORMAT_R8G8B8A8_UNORM,
254 																				vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT);
255 
256 		// Upload data to an unprotected image
257 		uploadImage(m_protectedContext, **unprotectedImage, *texture2D);
258 
259 		// Copy unprotected image to protected image
260 		copyToProtectedImage(m_protectedContext, **unprotectedImage, **imageSrc, vk::VK_IMAGE_LAYOUT_GENERAL, m_params.imageWidth, m_params.imageHeight);
261 	}
262 
263 	// Clear dst image
264 	clearImage(m_protectedContext, **imageDst);
265 
266 	// Create descriptors
267 	{
268 		vk::DescriptorSetLayoutBuilder	layoutBuilder;
269 		vk::DescriptorPoolBuilder		poolBuilder;
270 
271 		layoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, vk::VK_SHADER_STAGE_COMPUTE_BIT);
272 		layoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, vk::VK_SHADER_STAGE_COMPUTE_BIT);
273 		poolBuilder.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 2u);
274 
275 		descriptorSetLayout		= layoutBuilder.build(vk, device);
276 		descriptorPool			= poolBuilder.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
277 		descriptorSet			= makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout);
278 	}
279 
280 	// Create pipeline layout
281 	vk::Unique<vk::VkPipelineLayout>	pipelineLayout		(makePipelineLayout(vk, device, *descriptorSetLayout));
282 
283 	// Create image views
284 	{
285 		imageViewSrc = createImageView(ctx, **imageSrc, vk::VK_FORMAT_R8G8B8A8_UNORM);
286 		imageViewDst = createImageView(ctx, **imageDst, vk::VK_FORMAT_R8G8B8A8_UNORM);
287 	}
288 
289 	// Update descriptor set information
290 	{
291 		vk::DescriptorSetUpdateBuilder	updateBuilder;
292 
293 		vk::VkDescriptorImageInfo		descStorageImgDst	= makeDescriptorImageInfo((vk::VkSampler)0, *imageViewDst, vk::VK_IMAGE_LAYOUT_GENERAL);
294 		vk::VkDescriptorImageInfo		descStorageImgSrc	= makeDescriptorImageInfo((vk::VkSampler)0, *imageViewSrc, vk::VK_IMAGE_LAYOUT_GENERAL);
295 
296 		updateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descStorageImgDst);
297 		updateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descStorageImgSrc);
298 
299 		updateBuilder.update(vk, device);
300 	}
301 
302 	// Create compute commands & submit
303 	{
304 		const vk::Unique<vk::VkFence>		fence		(vk::createFence(vk, device));
305 		vk::Unique<vk::VkPipeline>			pipeline	(makeComputePipeline(vk, device, *pipelineLayout, *computeShader));
306 		vk::Unique<vk::VkCommandBuffer>		cmdBuffer	(vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
307 
308 		beginCommandBuffer(vk, *cmdBuffer);
309 
310 		vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
311 		vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
312 		vk.cmdDispatch(*cmdBuffer, 1u, 1u, 1u);
313 		endCommandBuffer(vk, *cmdBuffer);
314 
315 		VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull));
316 	}
317 
318 	// Calculate reference image
319 	calculateRef(*texture2D);
320 
321 	// Validate result
322 	return validateResult(**imageDst, vk::VK_IMAGE_LAYOUT_GENERAL, *texture2D, refSampler);
323 }
324 
calculateRef(tcu::Texture2D & texture2D)325 void WorkgroupStorageTestInstance::calculateRef (tcu::Texture2D& texture2D)
326 {
327 	const tcu::PixelBufferAccess&	reference	= texture2D.getLevel(0);
328 
329 	std::vector<tcu::IVec4>	sharedData(m_params.sharedMemorySize);
330 	for (deUint32 dataIdx = 0; dataIdx < m_params.sharedMemorySize; ++dataIdx)
331 		sharedData[dataIdx] = reference.getPixelInt(dataIdx % reference.getWidth(), dataIdx / reference.getWidth());
332 
333 	for (int x = 0; x < reference.getWidth(); ++x)
334 	for (int y = 0; y < reference.getHeight(); ++y)
335 	{
336 		const int idx = (y * reference.getWidth() + x + 1) % m_params.sharedMemorySize;
337 
338 		reference.setPixel(sharedData[idx], x, y);
339 	}
340 }
341 
validateResult(vk::VkImage image,vk::VkImageLayout imageLayout,const tcu::Texture2D & texture2D,const tcu::Sampler & refSampler)342 tcu::TestStatus WorkgroupStorageTestInstance::validateResult (vk::VkImage image, vk::VkImageLayout imageLayout, const tcu::Texture2D& texture2D, const tcu::Sampler& refSampler)
343 {
344 	de::Random			rnd			(getSeedValue(m_params));
345 	ValidationData		refData;
346 
347 	for (int ndx = 0; ndx < 4; ++ndx)
348 	{
349 		const float		lod		= 0.0f;
350 		const float		cx		= rnd.getFloat(0.0f, 1.0f);
351 		const float		cy		= rnd.getFloat(0.0f, 1.0f);
352 
353 		refData.coords[ndx] = tcu::Vec4(cx, cy, 0.0f, 0.0f);
354 		refData.values[ndx] = texture2D.sample(refSampler, cx, cy, lod);
355 	}
356 
357 	if (!m_validator.validateImage(m_protectedContext, refData, image, vk::VK_FORMAT_R8G8B8A8_UNORM, imageLayout))
358 		return tcu::TestStatus::fail("Result validation failed");
359 	else
360 		return tcu::TestStatus::pass("Pass");
361 }
362 
363 } // anonymous
364 
createWorkgroupStorageTests(tcu::TestContext & testCtx)365 tcu::TestCaseGroup*	createWorkgroupStorageTests (tcu::TestContext& testCtx)
366 {
367 	de::MovePtr<tcu::TestCaseGroup> workgroupGroup (new tcu::TestCaseGroup(testCtx, "workgroupstorage", "Workgroup storage tests"));
368 
369 	static const deUint32 sharedMemSizes[] = { 1, 4, 5, 60, 101, 503 };
370 
371 	for (int sharedMemSizeIdx = 0; sharedMemSizeIdx < DE_LENGTH_OF_ARRAY(sharedMemSizes); ++sharedMemSizeIdx)
372 	{
373 		std::string testName = std::string("memsize_") + de::toString(sharedMemSizes[sharedMemSizeIdx]);
374 		workgroupGroup->addChild(new WorkgroupStorageTestCase(testCtx, testName, "", Params(sharedMemSizes[sharedMemSizeIdx])));
375 	}
376 
377 	return workgroupGroup.release();
378 }
379 
380 } // ProtectedMem
381 } // vkt
382