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