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