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