Protected memory stack tests
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / protected_memory / vktProtectedMemStackTests.cpp
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
65         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
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         tcu::TestStatus                         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:
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
122         virtual                                         ~StackTestCase  (void) {}
123         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
134 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 several times (16) 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 < 16; 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
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
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
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
240         vk::Unique<vk::VkShaderModule>                  computeShader           (vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("comp"), 0));
241
242         de::MovePtr<vk::ImageWithMemory>                imageSrc;
243         de::MovePtr<vk::ImageWithMemory>                imageDst;
244         vk::Move<vk::VkSampler>                                 sampler;
245         vk::Move<vk::VkImageView>                               imageViewSrc;
246         vk::Move<vk::VkImageView>                               imageViewDst;
247
248         vk::Move<vk::VkDescriptorSetLayout>             descriptorSetLayout;
249         vk::Move<vk::VkDescriptorPool>                  descriptorPool;
250         vk::Move<vk::VkDescriptorSet>                   descriptorSet;
251
252         // Check the number of invocations supported
253         if (properties.limits.maxComputeWorkGroupInvocations < m_params.imageWidth * m_params.imageHeight)
254                 throw tcu::NotSupportedError("Not enough compute workgroup invocations supported.");
255
256         // Create src and dst images
257         {
258                 vk::VkImageUsageFlags imageUsageFlags = vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT     |
259                                                                                                 vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT     |
260                                                                                                 vk::VK_IMAGE_USAGE_SAMPLED_BIT          |
261                                                                                                 vk::VK_IMAGE_USAGE_STORAGE_BIT;
262
263                 imageSrc = createImage2D(ctx, PROTECTION_ENABLED, queueFamilyIndex,
264                                                                  m_params.imageWidth, m_params.imageHeight,
265                                                                  vk::VK_FORMAT_R8G8B8A8_UNORM,
266                                                                  imageUsageFlags);
267
268                 imageDst = createImage2D(ctx, PROTECTION_ENABLED, queueFamilyIndex,
269                                                                  m_params.imageWidth, m_params.imageHeight,
270                                                                  vk::VK_FORMAT_R8G8B8A8_UNORM,
271                                                                  imageUsageFlags);
272         }
273
274         // Upload source image
275         {
276                 de::MovePtr<vk::ImageWithMemory>        unprotectedImage        = createImage2D(ctx, PROTECTION_DISABLED, queueFamilyIndex,
277                                                                                                                                                                 m_params.imageWidth, m_params.imageHeight,
278                                                                                                                                                                 vk::VK_FORMAT_R8G8B8A8_UNORM,
279                                                                                                                                                                 vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT);
280
281                 // Upload data to an unprotected image
282                 uploadImage(m_protectedContext, **unprotectedImage, *texture2D);
283
284                 // Copy unprotected image to protected image
285                 copyToProtectedImage(m_protectedContext, **unprotectedImage, **imageSrc, vk::VK_IMAGE_LAYOUT_GENERAL, m_params.imageWidth, m_params.imageHeight);
286         }
287
288         // Clear dst image
289         clearImage(m_protectedContext, **imageDst);
290
291         // Create descriptors
292         {
293                 vk::DescriptorSetLayoutBuilder  layoutBuilder;
294                 vk::DescriptorPoolBuilder               poolBuilder;
295
296                 layoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, vk::VK_SHADER_STAGE_COMPUTE_BIT);
297                 layoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, vk::VK_SHADER_STAGE_COMPUTE_BIT);
298                 poolBuilder.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 2u);
299
300                 descriptorSetLayout             = layoutBuilder.build(vk, device);
301                 descriptorPool                  = poolBuilder.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
302                 descriptorSet                   = makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout);
303         }
304
305         // Create pipeline layout
306         vk::Unique<vk::VkPipelineLayout>        pipelineLayout          (makePipelineLayout(vk, device, *descriptorSetLayout));
307
308         // Create image views
309         {
310                 imageViewSrc = createImageView(ctx, **imageSrc, vk::VK_FORMAT_R8G8B8A8_UNORM);
311                 imageViewDst = createImageView(ctx, **imageDst, vk::VK_FORMAT_R8G8B8A8_UNORM);
312         }
313
314         // Update descriptor set information
315         {
316                 vk::DescriptorSetUpdateBuilder  updateBuilder;
317
318                 vk::VkDescriptorImageInfo               descStorageImgDst       = makeDescriptorImageInfo((vk::VkSampler)0, *imageViewDst, vk::VK_IMAGE_LAYOUT_GENERAL);
319                 vk::VkDescriptorImageInfo               descStorageImgSrc       = makeDescriptorImageInfo((vk::VkSampler)0, *imageViewSrc, vk::VK_IMAGE_LAYOUT_GENERAL);
320
321                 updateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descStorageImgDst);
322                 updateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descStorageImgSrc);
323
324                 updateBuilder.update(vk, device);
325         }
326
327         // Create compute commands & submit
328         {
329                 const vk::Unique<vk::VkFence>           fence           (vk::createFence(vk, device));
330                 vk::Unique<vk::VkPipeline>                      pipeline        (makeComputePipeline(vk, device, *pipelineLayout, *computeShader, DE_NULL));
331                 vk::Unique<vk::VkCommandBuffer>         cmdBuffer       (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
332
333                 beginCommandBuffer(vk, *cmdBuffer);
334
335                 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
336                 vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
337                 vk.cmdDispatch(*cmdBuffer, 1u, 1u, 1u);
338                 endCommandBuffer(vk, *cmdBuffer);
339
340                 VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull));
341         }
342
343         // Calculate reference image
344         calculateRef(*texture2D);
345
346         // Validate result
347         return validateResult(**imageDst, vk::VK_IMAGE_LAYOUT_GENERAL, *texture2D, refSampler);
348 }
349
350 void StackTestInstance::calculateRef (tcu::Texture2D& texture2D)
351 {
352         const tcu::PixelBufferAccess&   reference       = texture2D.getLevel(0);
353         const tcu::IVec4                                zero;
354
355         for (int x = 0; x < reference.getWidth(); ++x)
356         for (int y = 0; y < reference.getHeight(); ++y)
357                 reference.setPixel(zero, x, y);
358 }
359
360 tcu::TestStatus StackTestInstance::validateResult (vk::VkImage image, vk::VkImageLayout imageLayout, const tcu::Texture2D& texture2D, const tcu::Sampler& refSampler)
361 {
362         de::Random                      rnd                     (getSeedValue(m_params));
363         ValidationData          refData;
364
365         for (int ndx = 0; ndx < 4; ++ndx)
366         {
367                 const float     lod     = 0.0f;
368                 const float     cx      = rnd.getFloat(0.0f, 1.0f);
369                 const float     cy      = rnd.getFloat(0.0f, 1.0f);
370
371                 refData.coords[ndx] = tcu::Vec4(cx, cy, 0.0f, 0.0f);
372                 refData.values[ndx] = texture2D.sample(refSampler, cx, cy, lod);
373         }
374
375         if (!m_validator.validateImage(m_protectedContext, refData, image, vk::VK_FORMAT_R8G8B8A8_UNORM, imageLayout))
376                 return tcu::TestStatus::fail("Result validation failed");
377         else
378                 return tcu::TestStatus::pass("Pass");
379 }
380
381 } // anonymous
382
383 tcu::TestCaseGroup*     createStackTests (tcu::TestContext& testCtx)
384 {
385         de::MovePtr<tcu::TestCaseGroup> stackGroup (new tcu::TestCaseGroup(testCtx, "stack", "Protected memory stack tests"));
386
387         static const deUint32 stackMemSizes[] = { 32, 64, 128, 256, 512, 1024 };
388
389         for (int stackMemSizeIdx = 0; stackMemSizeIdx < DE_LENGTH_OF_ARRAY(stackMemSizes); ++stackMemSizeIdx)
390         {
391                 std::string testName = std::string("stacksize_") + de::toString(stackMemSizes[stackMemSizeIdx]);
392
393                 stackGroup->addChild(new StackTestCase(testCtx, testName, "", Params(stackMemSizes[stackMemSizeIdx])));
394         }
395
396         return stackGroup.release();
397 }
398
399 } // ProtectedMem
400 } // vkt