1 #ifndef _VKTPROTECTEDMEMBUFFERVALIDATOR_HPP
2 #define _VKTPROTECTEDMEMBUFFERVALIDATOR_HPP
3 /*------------------------------------------------------------------------
4  * Vulkan Conformance Tests
5  * ------------------------
6  *
7  * Copyright (c) 2017 The Khronos Group 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 content buffer validator helper
25  *//*--------------------------------------------------------------------*/
26 
27 #include "tcuVector.hpp"
28 #include "vkDefs.hpp"
29 #include "vktTestCase.hpp"
30 #include "tcuVector.hpp"
31 #include "tcuTestLog.hpp"
32 
33 #include "vkBuilderUtil.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkObjUtil.hpp"
38 #include "vktTestCase.hpp"
39 #include "vktTestGroupUtil.hpp"
40 #include "tcuStringTemplate.hpp"
41 
42 #include "vktProtectedMemUtils.hpp"
43 #include "vktProtectedMemContext.hpp"
44 
45 namespace vkt
46 {
47 namespace ProtectedMem
48 {
49 
50 class ProtectedContext;
51 
52 template <typename T>
53 struct ValidationData
54 {
55     const tcu::IVec4 positions[4];
56     const T values[4];
57 };
58 
59 template <typename T>
60 struct ValidationDataStorage
61 {
62     T values;
63 };
64 
65 typedef ValidationData<tcu::UVec4> ValidationDataUVec4;
66 typedef ValidationData<tcu::IVec4> ValidationDataIVec4;
67 typedef ValidationData<tcu::Vec4> ValidationDataVec4;
68 
69 enum TestType
70 {
71     TYPE_UINT,
72     TYPE_INT,
73     TYPE_FLOAT,
74 };
75 
76 enum BufferType
77 {
78     SAMPLER_BUFFER,
79     STORAGE_BUFFER,
80 };
81 
82 void initBufferValidatorPrograms(vk::SourceCollections &programCollection, TestType testType, BufferType bufferType);
83 vk::VkDescriptorType getDescriptorType(BufferType bufferType);
84 
85 template <typename T>
86 class BufferValidator
87 {
88 public:
BufferValidator(const ValidationData<T> data,vk::VkFormat format)89     BufferValidator(const ValidationData<T> data, vk::VkFormat format)
90         : m_refData(data)
91         , m_refDataStorage(*reinterpret_cast<ValidationDataStorage<T> *>(
92               &std::vector<char>(sizeof(ValidationDataStorage<T>), '\0').front()))
93         , m_bufferType(SAMPLER_BUFFER)
94         , m_format(format)
95     {
96     }
97 
BufferValidator(const ValidationDataStorage<T> data,vk::VkFormat format)98     BufferValidator(const ValidationDataStorage<T> data, vk::VkFormat format)
99         : m_refData(*reinterpret_cast<ValidationData<T> *>(&std::vector<char>(sizeof(ValidationData<T>), '\0').front()))
100         , m_refDataStorage(data)
101         , m_bufferType(STORAGE_BUFFER)
102         , m_format(format)
103     {
104     }
105 
~BufferValidator()106     ~BufferValidator()
107     {
108     }
109     void initPrograms(vk::SourceCollections &programCollection) const;
110 
111     bool validateBuffer(ProtectedContext &ctx, const vk::VkBuffer buffer) const;
112 
113 private:
114     uint32_t getReferenceDataSize() const;
115     const void *getReferenceDataSrc() const;
116     void printReferenceInfo(ProtectedContext &ctx) const;
117 
118     const ValidationData<T> m_refData;
119     const ValidationDataStorage<T> m_refDataStorage;
120 
121     BufferType m_bufferType;
122     vk::VkFormat m_format;
123 };
124 
125 template <>
initPrograms(vk::SourceCollections & programCollection) const126 inline void BufferValidator<tcu::UVec4>::initPrograms(vk::SourceCollections &programCollection) const
127 {
128     initBufferValidatorPrograms(programCollection, TYPE_UINT, m_bufferType);
129 }
130 
131 template <>
initPrograms(vk::SourceCollections & programCollection) const132 inline void BufferValidator<tcu::IVec4>::initPrograms(vk::SourceCollections &programCollection) const
133 {
134     initBufferValidatorPrograms(programCollection, TYPE_INT, m_bufferType);
135 }
136 
137 template <>
initPrograms(vk::SourceCollections & programCollection) const138 inline void BufferValidator<tcu::Vec4>::initPrograms(vk::SourceCollections &programCollection) const
139 {
140     initBufferValidatorPrograms(programCollection, TYPE_FLOAT, m_bufferType);
141 }
142 
143 template <typename T>
getReferenceDataSize() const144 uint32_t BufferValidator<T>::getReferenceDataSize() const
145 {
146     return m_bufferType == SAMPLER_BUFFER ? (uint32_t)sizeof(m_refData) : (uint32_t)sizeof(m_refDataStorage);
147 }
148 
149 template <typename T>
getReferenceDataSrc() const150 const void *BufferValidator<T>::getReferenceDataSrc() const
151 {
152     return m_bufferType == SAMPLER_BUFFER ? (void *)&m_refData : (void *)&m_refDataStorage;
153 }
154 
155 template <typename T>
printReferenceInfo(ProtectedContext & ctx) const156 void BufferValidator<T>::printReferenceInfo(ProtectedContext &ctx) const
157 {
158     if (m_bufferType == SAMPLER_BUFFER)
159     {
160         ctx.getTestContext().getLog() << tcu::TestLog::Message << "Reference positions: \n"
161                                       << "1: " << m_refData.positions[0] << "\n"
162                                       << "2: " << m_refData.positions[1] << "\n"
163                                       << "3: " << m_refData.positions[2] << "\n"
164                                       << "4: " << m_refData.positions[3] << "\n"
165                                       << tcu::TestLog::EndMessage << tcu::TestLog::Message
166                                       << "Reference fill values: \n"
167                                       << "1: " << m_refData.values[0] << "\n"
168                                       << "2: " << m_refData.values[1] << "\n"
169                                       << "3: " << m_refData.values[2] << "\n"
170                                       << "4: " << m_refData.values[3] << "\n"
171                                       << tcu::TestLog::EndMessage;
172     }
173     else if (m_bufferType == STORAGE_BUFFER)
174     {
175         ctx.getTestContext().getLog() << tcu::TestLog::Message << "Reference values: \n"
176                                       << "1: " << m_refDataStorage.values << "\n"
177                                       << tcu::TestLog::EndMessage;
178     }
179 }
180 
181 template <typename T>
validateBuffer(ProtectedContext & ctx,const vk::VkBuffer buffer) const182 bool BufferValidator<T>::validateBuffer(ProtectedContext &ctx, const vk::VkBuffer buffer) const
183 {
184     // Log out a few reference info
185     printReferenceInfo(ctx);
186 
187     const uint64_t oneSec = 1000 * 1000 * 1000;
188 
189     const vk::DeviceInterface &vk   = ctx.getDeviceInterface();
190     const vk::VkDevice device       = ctx.getDevice();
191     const vk::VkQueue queue         = ctx.getQueue();
192     const uint32_t queueFamilyIndex = ctx.getQueueFamilyIndex();
193 
194     vk::Move<vk::VkBufferView> bufferView;
195 
196     const uint32_t refDataSize = getReferenceDataSize();
197     de::UniquePtr<vk::BufferWithMemory> refUniform(makeBuffer(ctx, PROTECTION_DISABLED, queueFamilyIndex, refDataSize,
198                                                               vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
199                                                               vk::MemoryRequirement::HostVisible));
200 
201     // Set the reference uniform data
202     {
203         deMemcpy(refUniform->getAllocation().getHostPtr(), getReferenceDataSrc(), refDataSize);
204         flushAlloc(vk, device, refUniform->getAllocation());
205     }
206 
207     const uint32_t helperBufferSize = (uint32_t)(2 * sizeof(uint32_t));
208     de::MovePtr<vk::BufferWithMemory> helperBuffer(makeBuffer(ctx, PROTECTION_ENABLED, queueFamilyIndex,
209                                                               helperBufferSize, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
210                                                               vk::MemoryRequirement::Protected));
211     vk::Unique<vk::VkShaderModule> resetSSBOShader(
212         vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("ResetSSBO"), 0));
213     vk::Unique<vk::VkShaderModule> validatorShader(
214         vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("BufferValidator"), 0));
215 
216     // Create descriptors
217     vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(
218         vk::DescriptorSetLayoutBuilder()
219             .addSingleBinding(getDescriptorType(m_bufferType), vk::VK_SHADER_STAGE_COMPUTE_BIT)
220             .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
221             .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
222             .build(vk, device));
223     vk::Unique<vk::VkDescriptorPool> descriptorPool(
224         vk::DescriptorPoolBuilder()
225             .addType(getDescriptorType(m_bufferType), 1u)
226             .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
227             .addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u)
228             .build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
229     vk::Unique<vk::VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
230 
231     // Update descriptor set information
232     {
233         vk::VkDescriptorBufferInfo descRefUniform = makeDescriptorBufferInfo(**refUniform, 0, refDataSize);
234         vk::VkDescriptorBufferInfo descBuffer     = makeDescriptorBufferInfo(**helperBuffer, 0, helperBufferSize);
235 
236         vk::DescriptorSetUpdateBuilder descriptorSetUpdateBuilder;
237         switch (m_bufferType)
238         {
239         case SAMPLER_BUFFER:
240         {
241             const vk::VkBufferViewCreateInfo viewParams = {
242                 vk::VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, // VkStructureType            sType
243                 DE_NULL,                                       // const void*                pNext
244                 0u,                                            // VkBufferViewCreateFlags    flags
245                 buffer,                                        // VkBuffer                    buffer
246                 m_format,                                      // VkFormat                    format
247                 0u,                                            // VkDeviceSize                offset
248                 VK_WHOLE_SIZE                                  // VkDeviceSize                range
249             };
250             bufferView = vk::Move<vk::VkBufferView>(vk::createBufferView(vk, device, &viewParams));
251             descriptorSetUpdateBuilder.writeSingle(*descriptorSet,
252                                                    vk::DescriptorSetUpdateBuilder::Location::binding(0u),
253                                                    vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, &bufferView.get());
254             break;
255         }
256         case STORAGE_BUFFER:
257         {
258             const uint32_t testBufferSize             = (uint32_t)(sizeof(ValidationDataStorage<T>));
259             vk::VkDescriptorBufferInfo descTestBuffer = makeDescriptorBufferInfo(buffer, 0, testBufferSize);
260             descriptorSetUpdateBuilder.writeSingle(*descriptorSet,
261                                                    vk::DescriptorSetUpdateBuilder::Location::binding(0u),
262                                                    vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descTestBuffer);
263             break;
264         }
265         }
266         descriptorSetUpdateBuilder
267             .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u),
268                          vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descBuffer)
269             .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u),
270                          vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descRefUniform)
271             .update(vk, device);
272     }
273 
274     // Build pipeline
275     vk::Unique<vk::VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
276 
277     vk::Unique<vk::VkCommandPool> cmdPool(makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
278 
279     // Reset helper SSBO
280     {
281         const vk::Unique<vk::VkFence> fence(vk::createFence(vk, device));
282         vk::Unique<vk::VkPipeline> resetSSBOPipeline(
283             makeComputePipeline(vk, device, *pipelineLayout, *resetSSBOShader));
284         vk::Unique<vk::VkCommandBuffer> resetCmdBuffer(
285             vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
286         beginCommandBuffer(vk, *resetCmdBuffer);
287 
288         vk.cmdBindPipeline(*resetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *resetSSBOPipeline);
289         vk.cmdBindDescriptorSets(*resetCmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u,
290                                  &*descriptorSet, 0u, DE_NULL);
291         vk.cmdDispatch(*resetCmdBuffer, 1u, 1u, 1u);
292 
293         endCommandBuffer(vk, *resetCmdBuffer);
294         VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *resetCmdBuffer, *fence, ~0ull));
295     }
296 
297     // Create validation compute commands & submit
298     vk::VkResult queueSubmitResult;
299     {
300         const vk::Unique<vk::VkFence> fence(vk::createFence(vk, device));
301         vk::Unique<vk::VkPipeline> validationPipeline(
302             makeComputePipeline(vk, device, *pipelineLayout, *validatorShader));
303         vk::Unique<vk::VkCommandBuffer> cmdBuffer(
304             vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
305 
306         beginCommandBuffer(vk, *cmdBuffer);
307 
308         vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *validationPipeline);
309         vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u,
310                                  &*descriptorSet, 0u, DE_NULL);
311         vk.cmdDispatch(*cmdBuffer, 1u, 1u, 1u);
312 
313         endCommandBuffer(vk, *cmdBuffer);
314 
315         queueSubmitResult = queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, oneSec);
316     }
317 
318     // \todo do we need to check the fence status?
319     if (queueSubmitResult == vk::VK_TIMEOUT)
320         return false;
321 
322     // at this point the submit result should be VK_TRUE
323     VK_CHECK(queueSubmitResult);
324     return true;
325 }
326 
327 } // namespace ProtectedMem
328 } // namespace vkt
329 
330 #endif // _VKTPROTECTEDMEMBUFFERVALIDATOR_HPP
331