1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 The Khronos Group Inc.
6  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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 Protected Memory image validator helper
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktProtectedMemImageValidator.hpp"
26 
27 #include "tcuTestLog.hpp"
28 #include "tcuStringTemplate.hpp"
29 
30 #include "vkBuilderUtil.hpp"
31 #include "vkPrograms.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkImageUtil.hpp"
34 #include "vktTestCase.hpp"
35 #include "vktTestGroupUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkObjUtil.hpp"
38 
39 #include "vktProtectedMemUtils.hpp"
40 #include "vktProtectedMemContext.hpp"
41 
42 namespace vkt
43 {
44 namespace ProtectedMem
45 {
46 
initPrograms(vk::SourceCollections & programCollection) const47 void ImageValidator::initPrograms(vk::SourceCollections &programCollection) const
48 {
49     // Layout:
50     //  set = 0, location = 0 -> uniform *sampler2D u_protectedImage
51     //  set = 0, location = 1 -> buffer ProtectedHelper (2 * uint)
52     //  set = 0, location = 2 -> uniform Data (2 * vec2 + 4 * vec4)
53     const char *validatorShader =
54         "#version 450\n"
55         "layout(local_size_x = 1) in;\n"
56         "\n"
57         "layout(set=0, binding=0) uniform ${SAMPLER_TYPE} u_protectedImage;\n"
58         "\n"
59         "layout(set=0, binding=1) buffer ProtectedHelper\n"
60         "{\n"
61         "    highp uint zero; // set to 0\n"
62         "    highp uint unusedOut;\n"
63         "} helper;\n"
64         "\n"
65         "layout(set=0, binding=2) uniform Data\n"
66         "{\n"
67         "    highp vec2 protectedImageCoord[4];\n"
68         "    highp vec4 protectedImageRef[4];\n"
69         "};\n"
70         "\n"
71         "void error ()\n"
72         "{\n"
73         "    for (uint x = 0; x < 10; x += helper.zero)\n"
74         "        atomicAdd(helper.unusedOut, 1u);\n"
75         "}\n"
76         "\n"
77         "bool compare (vec4 a, vec4 b, float threshold)\n"
78         "{\n"
79         "    return all(lessThanEqual(abs(a - b), vec4(threshold)));\n"
80         "}\n"
81         "\n"
82         "void main (void)\n"
83         "{\n"
84         "    float threshold = 0.1;\n"
85         "    for (uint i = 0; i < 4; i++)\n"
86         "    {\n"
87         "        if (!compare(texture(u_protectedImage, protectedImageCoord[i]), protectedImageRef[i], threshold))\n"
88         "            error();\n"
89         "    }\n"
90         "}\n";
91 
92     const char *resetSSBOShader = "#version 450\n"
93                                   "layout(local_size_x = 1) in;\n"
94                                   "\n"
95                                   "layout(set=0, binding=1) buffer ProtectedHelper\n"
96                                   "{\n"
97                                   "    highp uint zero; // set to 0\n"
98                                   "    highp uint unusedOut;\n"
99                                   "} helper;\n"
100                                   "\n"
101                                   "void main (void)\n"
102                                   "{\n"
103                                   "    helper.zero = 0;\n"
104                                   "}\n";
105 
106     programCollection.glslSources.add("ResetSSBO") << glu::ComputeSource(resetSSBOShader);
107 
108     std::map<std::string, std::string> validationParams;
109     validationParams["SAMPLER_TYPE"] = isIntFormat(m_imageFormat)  ? "isampler2D" :
110                                        isUintFormat(m_imageFormat) ? "usampler2D" :
111                                                                      "sampler2D";
112 
113     programCollection.glslSources.add("ImageValidator")
114         << glu::ComputeSource(tcu::StringTemplate(validatorShader).specialize(validationParams));
115 }
116 
validateImage(ProtectedContext & ctx,const ValidationData & refData,const vk::VkImage image,const vk::VkFormat imageFormat,const vk::VkImageLayout imageLayout) const117 bool ImageValidator::validateImage(ProtectedContext &ctx, const ValidationData &refData, const vk::VkImage image,
118                                    const vk::VkFormat imageFormat, const vk::VkImageLayout imageLayout) const
119 {
120     // Log out a few reference info
121     {
122         ctx.getTestContext().getLog() << tcu::TestLog::Message << "Reference coordinates: \n"
123                                       << "1: " << refData.coords[0] << "\n"
124                                       << "2: " << refData.coords[1] << "\n"
125                                       << "3: " << refData.coords[2] << "\n"
126                                       << "4: " << refData.coords[3] << "\n"
127                                       << tcu::TestLog::EndMessage << tcu::TestLog::Message
128                                       << "Reference color values: \n"
129                                       << "1: " << refData.values[0] << "\n"
130                                       << "2: " << refData.values[1] << "\n"
131                                       << "3: " << refData.values[2] << "\n"
132                                       << "4: " << refData.values[3] << "\n"
133                                       << tcu::TestLog::EndMessage;
134     }
135 
136     const uint64_t oneSec = 1000 * 1000 * 1000;
137 
138     const vk::DeviceInterface &vk   = ctx.getDeviceInterface();
139     const vk::VkDevice device       = ctx.getDevice();
140     const vk::VkQueue queue         = ctx.getQueue();
141     const uint32_t queueFamilyIndex = ctx.getQueueFamilyIndex();
142 
143     const uint32_t refUniformSize = sizeof(refData);
144     de::UniquePtr<vk::BufferWithMemory> refUniform(makeBuffer(ctx, PROTECTION_DISABLED, queueFamilyIndex,
145                                                               refUniformSize, vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
146                                                               vk::MemoryRequirement::HostVisible));
147     // Set the reference uniform data
148     {
149         deMemcpy(refUniform->getAllocation().getHostPtr(), &refData, refUniformSize);
150         flushAlloc(vk, device, refUniform->getAllocation());
151     }
152 
153     const uint32_t helperBufferSize = (uint32_t)(2 * sizeof(uint32_t));
154     de::MovePtr<vk::BufferWithMemory> helperBuffer(makeBuffer(ctx, PROTECTION_ENABLED, queueFamilyIndex,
155                                                               helperBufferSize, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
156                                                               vk::MemoryRequirement::Protected));
157     vk::Unique<vk::VkShaderModule> resetSSBOShader(
158         vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("ResetSSBO"), 0));
159     vk::Unique<vk::VkShaderModule> validatorShader(
160         vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("ImageValidator"), 0));
161 
162     vk::Unique<vk::VkSampler> sampler(makeSampler(vk, device));
163     const vk::VkImageViewCreateInfo viewParams = {
164         vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType
165         DE_NULL,                                      // pNext
166         0u,                                           // flags
167         image,                                        // image
168         vk::VK_IMAGE_VIEW_TYPE_2D,                    // viewType
169         imageFormat,                                  // format
170         vk::makeComponentMappingRGBA(),               // components
171         {
172             vk::VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
173             0u,                            // baseMipLevel
174             1u,                            // mipLeves
175             0u,                            // baseArraySlice
176             1u,                            // arraySize
177         }                                  // subresourceRange
178     };
179     vk::Unique<vk::VkImageView> imageView(vk::createImageView(vk, device, &viewParams));
180 
181     // Create descriptors
182     vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(
183         vk::DescriptorSetLayoutBuilder()
184             .addSingleSamplerBinding(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, vk::VK_SHADER_STAGE_COMPUTE_BIT,
185                                      DE_NULL)
186             .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
187             .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
188             .build(vk, device));
189     vk::Unique<vk::VkDescriptorPool> descriptorPool(
190         vk::DescriptorPoolBuilder()
191             .addType(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u)
192             .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
193             .addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u)
194             .build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
195     vk::Unique<vk::VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
196 
197     // Update descriptor set infirmation
198     {
199         vk::VkDescriptorBufferInfo descRefUniform = makeDescriptorBufferInfo(**refUniform, 0, refUniformSize);
200         vk::VkDescriptorBufferInfo descBuffer     = makeDescriptorBufferInfo(**helperBuffer, 0, helperBufferSize);
201         vk::VkDescriptorImageInfo descSampledImg  = makeDescriptorImageInfo(*sampler, *imageView, imageLayout);
202 
203         vk::DescriptorSetUpdateBuilder()
204             .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u),
205                          vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &descSampledImg)
206             .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u),
207                          vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descBuffer)
208             .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u),
209                          vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descRefUniform)
210             .update(vk, device);
211     }
212 
213     // Build pipeline
214     vk::Unique<vk::VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
215 
216     vk::Unique<vk::VkCommandPool> cmdPool(makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
217 
218     // Reset helper SSBO
219     {
220         const vk::Unique<vk::VkFence> fence(vk::createFence(vk, device));
221         vk::Unique<vk::VkPipeline> resetSSBOPipeline(
222             makeComputePipeline(vk, device, *pipelineLayout, *resetSSBOShader));
223         vk::Unique<vk::VkCommandBuffer> resetCmdBuffer(
224             vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
225         beginCommandBuffer(vk, *resetCmdBuffer);
226 
227         vk.cmdBindPipeline(*resetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *resetSSBOPipeline);
228         vk.cmdBindDescriptorSets(*resetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u,
229                                  &*descriptorSet, 0u, DE_NULL);
230         vk.cmdDispatch(*resetCmdBuffer, 1u, 1u, 1u);
231 
232         endCommandBuffer(vk, *resetCmdBuffer);
233         VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *resetCmdBuffer, *fence, ~0ull));
234     }
235 
236     // Create validation compute commands & submit
237     vk::VkResult queueSubmitResult;
238     {
239         const vk::Unique<vk::VkFence> fence(vk::createFence(vk, device));
240         vk::Unique<vk::VkPipeline> validationPipeline(
241             makeComputePipeline(vk, device, *pipelineLayout, *validatorShader));
242         vk::Unique<vk::VkCommandBuffer> cmdBuffer(
243             vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
244 
245         beginCommandBuffer(vk, *cmdBuffer);
246 
247         vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *validationPipeline);
248         vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u,
249                                  &*descriptorSet, 0u, DE_NULL);
250         vk.cmdDispatch(*cmdBuffer, 1u, 1u, 1u);
251 
252         endCommandBuffer(vk, *cmdBuffer);
253 
254         queueSubmitResult = queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, oneSec);
255     }
256 
257     // \todo do we need to check the fence status?
258     if (queueSubmitResult == vk::VK_TIMEOUT)
259         return false;
260 
261     // at this point the submit result should be VK_TRUE
262     VK_CHECK(queueSubmitResult);
263     return true;
264 }
265 
266 } // namespace ProtectedMem
267 } // namespace vkt
268