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