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 storage buffer tests 23 *//*--------------------------------------------------------------------*/ 24 25 #include "vktProtectedMemStorageBufferTests.hpp" 26 27 #include "deRandom.hpp" 28 #include "deStringUtil.hpp" 29 #include "tcuTestLog.hpp" 30 #include "tcuVector.hpp" 31 #include "tcuStringTemplate.hpp" 32 33 #include "vkPrograms.hpp" 34 #include "vktTestCase.hpp" 35 #include "vktTestGroupUtil.hpp" 36 #include "vkTypeUtil.hpp" 37 #include "vkBuilderUtil.hpp" 38 #include "vkCmdUtil.hpp" 39 40 #include "vktProtectedMemBufferValidator.hpp" 41 #include "vktProtectedMemUtils.hpp" 42 #include "vktProtectedMemContext.hpp" 43 44 namespace vkt 45 { 46 namespace ProtectedMem 47 { 48 49 namespace 50 { 51 52 enum { 53 RENDER_HEIGHT = 128, 54 RENDER_WIDTH = 128, 55 }; 56 57 enum { 58 RANDOM_TEST_COUNT = 10, 59 }; 60 61 enum SSBOTestType { 62 SSBO_READ, 63 SSBO_WRITE, 64 SSBO_ATOMIC 65 }; 66 67 enum SSBOAtomicType { 68 ATOMIC_ADD, 69 ATOMIC_MIN, 70 ATOMIC_MAX, 71 ATOMIC_AND, 72 ATOMIC_OR, 73 ATOMIC_XOR, 74 ATOMIC_EXCHANGE, 75 ATOMIC_COMPSWAP 76 }; 77 78 79 const char* getSSBOTestDescription (SSBOTestType type) 80 { 81 switch (type) { 82 case SSBO_READ: return "Test for read storage buffer on protected memory."; 83 case SSBO_WRITE: return "Test for write storage buffer on protected memory."; 84 case SSBO_ATOMIC: return "Test for atomic storage buffer on protected memory."; 85 default: DE_FATAL("Invalid SSBO test type"); return ""; 86 } 87 } 88 89 const char* getSSBOTypeString (SSBOTestType type) 90 { 91 switch (type) { 92 case SSBO_READ: return "read"; 93 case SSBO_WRITE: return "write"; 94 case SSBO_ATOMIC: return "atomic"; 95 default: DE_FATAL("Invalid SSBO test type"); return ""; 96 } 97 } 98 99 const char* getShaderTypeString (const glu::ShaderType shaderType) 100 { 101 switch (shaderType) { 102 case glu::SHADERTYPE_FRAGMENT: return "fragment"; 103 case glu::SHADERTYPE_COMPUTE: return "compute"; 104 default: DE_FATAL("Invalid shader type"); return ""; 105 } 106 } 107 108 const char* getSSBOAtomicTypeString (SSBOAtomicType type) 109 { 110 switch (type) 111 { 112 case ATOMIC_ADD: return "add"; 113 case ATOMIC_MIN: return "min"; 114 case ATOMIC_MAX: return "max"; 115 case ATOMIC_AND: return "and"; 116 case ATOMIC_OR: return "or"; 117 case ATOMIC_XOR: return "xor"; 118 case ATOMIC_EXCHANGE: return "exchange"; 119 case ATOMIC_COMPSWAP: return "compswap"; 120 default: DE_FATAL("Invalid SSBO atomic operation type"); return ""; 121 } 122 } 123 124 void static addBufferCopyCmd (const vk::DeviceInterface& vk, 125 vk::VkCommandBuffer cmdBuffer, 126 deUint32 queueFamilyIndex, 127 vk::VkBuffer srcBuffer, 128 vk::VkBuffer dstBuffer, 129 deUint32 copySize) 130 { 131 const vk::VkBufferMemoryBarrier dstWriteStartBarrier = 132 { 133 vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType 134 DE_NULL, // const void* pNext 135 0, // VkAccessFlags srcAccessMask 136 vk::VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags dstAccessMask 137 queueFamilyIndex, // uint32_t srcQueueFamilyIndex 138 queueFamilyIndex, // uint32_t dstQueueFamilyIndex 139 dstBuffer, // VkBuffer buffer 140 0u, // VkDeviceSize offset 141 VK_WHOLE_SIZE, // VkDeviceSize size 142 }; 143 144 vk.cmdPipelineBarrier(cmdBuffer, 145 vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // srcStageMask 146 vk::VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, // dstStageMask 147 (vk::VkDependencyFlags)0, 148 0, (const vk::VkMemoryBarrier*)DE_NULL, 149 1, &dstWriteStartBarrier, 150 0, (const vk::VkImageMemoryBarrier*)DE_NULL); 151 152 const vk::VkBufferCopy copyRegion = 153 { 154 0, // VkDeviceSize srcOffset 155 0, // VkDeviceSize dstOffset 156 copySize // VkDeviceSize size 157 }; 158 vk.cmdCopyBuffer(cmdBuffer, srcBuffer, dstBuffer, 1, ©Region); 159 160 const vk::VkBufferMemoryBarrier dstWriteEndBarrier = 161 { 162 vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType 163 DE_NULL, // const void* pNext 164 vk::VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags srcAccessMask 165 vk::VK_ACCESS_SHADER_READ_BIT, // VkAccessFlags dstAccessMask 166 queueFamilyIndex, // uint32_t srcQueueFamilyIndex 167 queueFamilyIndex, // uint32_t dstQueueFamilyIndex 168 dstBuffer, // VkBuffer buffer 169 0u, // VkDeviceSize offset 170 VK_WHOLE_SIZE, // VkDeviceSize size 171 }; 172 vk.cmdPipelineBarrier(cmdBuffer, 173 vk::VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, // srcStageMask 174 vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // dstStageMask 175 (vk::VkDependencyFlags)0, 176 0, (const vk::VkMemoryBarrier*)DE_NULL, 177 1, &dstWriteEndBarrier, 178 0, (const vk::VkImageMemoryBarrier*)DE_NULL); 179 180 } 181 182 template<typename T> 183 class StorageBufferTestInstance : public ProtectedTestInstance 184 { 185 public: 186 StorageBufferTestInstance (Context& ctx, 187 const SSBOTestType testType, 188 const glu::ShaderType shaderType, 189 const tcu::UVec4 testInput, 190 const BufferValidator<T>& validator); 191 virtual tcu::TestStatus iterate (void); 192 193 private: 194 tcu::TestStatus executeFragmentTest (void); 195 tcu::TestStatus executeComputeTest (void); 196 197 const SSBOTestType m_testType; 198 const glu::ShaderType m_shaderType; 199 const tcu::UVec4 m_testInput; 200 const BufferValidator<T>& m_validator; 201 const vk::VkFormat m_imageFormat; 202 }; 203 204 template<typename T> 205 class StorageBufferTestCase : public TestCase 206 { 207 public: 208 StorageBufferTestCase (tcu::TestContext& testctx, 209 const SSBOTestType testType, 210 const glu::ShaderType shaderType, 211 const char* name, 212 const tcu::UVec4 testInput, 213 ValidationDataStorage<T> validationData, 214 const std::string& extraShader = "") 215 : TestCase (testctx, name, getSSBOTestDescription(testType)) 216 , m_testType (testType) 217 , m_shaderType (shaderType) 218 , m_testInput (testInput) 219 , m_validator (validationData) 220 , m_extraShader (extraShader) 221 { 222 } 223 virtual TestInstance* createInstance (Context& ctx) const 224 { 225 return new StorageBufferTestInstance<T>(ctx, m_testType, m_shaderType, m_testInput, m_validator); 226 } 227 virtual void initPrograms (vk::SourceCollections& programCollection) const; 228 229 virtual ~StorageBufferTestCase (void) {} 230 231 private: 232 const SSBOTestType m_testType; 233 const glu::ShaderType m_shaderType; 234 const tcu::UVec4 m_testInput; 235 const BufferValidator<T> m_validator; 236 const std::string m_extraShader; 237 }; 238 239 template<typename T> 240 StorageBufferTestInstance<T>::StorageBufferTestInstance (Context& ctx, 241 const SSBOTestType testType, 242 const glu::ShaderType shaderType, 243 const tcu::UVec4 testInput, 244 const BufferValidator<T>& validator) 245 : ProtectedTestInstance (ctx) 246 , m_testType (testType) 247 , m_shaderType (shaderType) 248 , m_testInput (testInput) 249 , m_validator (validator) 250 , m_imageFormat (vk::VK_FORMAT_R8G8B8A8_UNORM) 251 { 252 } 253 254 template<typename T> 255 void StorageBufferTestCase<T>::initPrograms (vk::SourceCollections& programCollection) const 256 { 257 const char* vertexShader = 258 "#version 450\n" 259 "layout(location=0) out vec4 vIndex;\n" 260 "void main() {\n" 261 " vec2 pos[4] = vec2[4]( vec2(-0.7, 0.7), vec2(0.7, 0.7), vec2(0.0, -0.7), vec2(-0.7, -0.7) );\n" 262 " vIndex = vec4(gl_VertexIndex);\n" 263 " gl_PointSize = 1.0;\n" 264 " gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);\n" 265 "}"; 266 267 // set = 0, location = 0 -> buffer ProtectedTestBuffer (uvec4) 268 // set = 0, location = 2 -> buffer ProtectedTestBufferSource (uvec4) 269 const char* readShaderTemplateStr = 270 "#version 450\n" 271 "${INPUT_DECLARATION}\n" 272 "\n" 273 "layout(set=0, binding=0, std140) buffer ProtectedTestBuffer\n" 274 "{\n" 275 " highp uvec4 protectedTestResultBuffer;\n" 276 "};\n" 277 "\n" 278 "layout(set=0, binding=2, std140) buffer ProtectedTestBufferSource\n" 279 "{\n" 280 " highp uvec4 protectedTestBufferSource;\n" 281 "};\n" 282 "\n" 283 "void main (void)\n" 284 "{\n" 285 " protectedTestResultBuffer = protectedTestBufferSource;\n" 286 " ${FRAGMENT_OUTPUT}\n" 287 "}\n"; 288 289 // set = 0, location = 0 -> buffer ProtectedTestBuffer (uvec4) 290 // set = 0, location = 1 -> uniform Data (uvec4) 291 const char* writeShaderTemplateStr = 292 "#version 450\n" 293 "${INPUT_DECLARATION}\n" 294 "\n" 295 "layout(set=0, binding=0, std140) buffer ProtectedTestBuffer\n" 296 "{\n" 297 " highp uvec4 protectedTestResultBuffer;\n" 298 "};\n" 299 "\n" 300 "layout(set=0, binding=1, std140) uniform Data\n" 301 "{\n" 302 " highp uvec4 testInput;\n" 303 "};\n" 304 "\n" 305 "void main (void)\n" 306 "{\n" 307 " protectedTestResultBuffer = testInput;\n" 308 " ${FRAGMENT_OUTPUT}\n" 309 "}\n"; 310 311 // set = 0, location = 0 -> buffer ProtectedTestBuffer (uint [4]) 312 const char* atomicTestShaderTemplateStr = 313 "#version 450\n" 314 "${INPUT_DECLARATION}\n" 315 "\n" 316 "layout(set=0, binding=0, std430) buffer ProtectedTestBuffer\n" 317 "{\n" 318 " highp uint protectedTestResultBuffer[4];\n" 319 "};\n" 320 "\n" 321 "void main (void)\n" 322 "{\n" 323 " uint i = uint(${INVOCATION_ID});\n" 324 " ${ATOMIC_FUNCTION_CALL}\n" 325 " ${FRAGMENT_OUTPUT}\n" 326 "}\n"; 327 328 const char* shaderTemplateStr; 329 std::map<std::string, std::string> shaderParam; 330 switch (m_testType) { 331 case SSBO_READ: shaderTemplateStr = readShaderTemplateStr; break; 332 case SSBO_WRITE: shaderTemplateStr = writeShaderTemplateStr; break; 333 case SSBO_ATOMIC: { 334 shaderTemplateStr = atomicTestShaderTemplateStr; 335 shaderParam["ATOMIC_FUNCTION_CALL"] = m_extraShader; 336 break; 337 } 338 default: DE_FATAL("Incorrect SSBO test type"); return; 339 } 340 341 if (m_shaderType == glu::SHADERTYPE_FRAGMENT) 342 { 343 shaderParam["INPUT_DECLARATION"] = "layout(location=0) out mediump vec4 o_color;\n" 344 "layout(location=0) in vec4 vIndex;\n"; 345 shaderParam["FRAGMENT_OUTPUT"] = "o_color = vec4( 0.0, 0.4, 1.0, 1.0 );\n"; 346 shaderParam["INVOCATION_ID"] = "vIndex.x"; 347 348 programCollection.glslSources.add("vert") << glu::VertexSource(vertexShader); 349 programCollection.glslSources.add("TestShader") << glu::FragmentSource(tcu::StringTemplate(shaderTemplateStr).specialize(shaderParam)); 350 } 351 else if (m_shaderType == glu::SHADERTYPE_COMPUTE) 352 { 353 shaderParam["INPUT_DECLARATION"] = "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"; 354 shaderParam["FRAGMENT_OUTPUT"] = ""; 355 shaderParam["INVOCATION_ID"] = "gl_GlobalInvocationID.x"; 356 programCollection.glslSources.add("TestShader") << glu::ComputeSource(tcu::StringTemplate(shaderTemplateStr).specialize(shaderParam)); 357 } 358 else 359 DE_FATAL("Incorrect shader type"); 360 361 m_validator.initPrograms(programCollection); 362 } 363 364 template<typename T> 365 tcu::TestStatus StorageBufferTestInstance<T>::executeFragmentTest(void) 366 { 367 ProtectedContext& ctx (m_protectedContext); 368 const vk::DeviceInterface& vk = ctx.getDeviceInterface(); 369 const vk::VkDevice device = ctx.getDevice(); 370 const vk::VkQueue queue = ctx.getQueue(); 371 const deUint32 queueFamilyIndex = ctx.getQueueFamilyIndex(); 372 373 const deUint32 testUniformSize = sizeof(m_testInput); 374 de::UniquePtr<vk::BufferWithMemory> testUniform (makeBuffer(ctx, 375 PROTECTION_DISABLED, 376 queueFamilyIndex, 377 testUniformSize, 378 vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT 379 | vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 380 vk::MemoryRequirement::HostVisible)); 381 382 // Set the test input uniform data 383 { 384 deMemcpy(testUniform->getAllocation().getHostPtr(), &m_testInput, testUniformSize); 385 vk::flushMappedMemoryRange(vk, device, testUniform->getAllocation().getMemory(), testUniform->getAllocation().getOffset(), testUniformSize); 386 } 387 const deUint32 testBufferSize = sizeof(ValidationDataStorage<T>); 388 de::MovePtr<vk::BufferWithMemory> testBuffer (makeBuffer(ctx, 389 PROTECTION_ENABLED, 390 queueFamilyIndex, 391 testBufferSize, 392 vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT 393 | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT, 394 vk::MemoryRequirement::Protected)); 395 de::MovePtr<vk::BufferWithMemory> testBufferSource (makeBuffer(ctx, 396 PROTECTION_ENABLED, 397 queueFamilyIndex, 398 testBufferSize, 399 vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT 400 | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT, 401 vk::MemoryRequirement::Protected)); 402 403 vk::Move<vk::VkShaderModule> vertexShader (vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("vert"), 0)); 404 vk::Unique<vk::VkShaderModule> testShader (vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("TestShader"), 0)); 405 406 // Create descriptors 407 vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(vk::DescriptorSetLayoutBuilder() 408 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_ALL) 409 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_ALL) 410 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_ALL) 411 .build(vk, device)); 412 vk::Unique<vk::VkDescriptorPool> descriptorPool(vk::DescriptorPoolBuilder() 413 .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u) 414 .addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u) 415 .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u) 416 .build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u)); 417 vk::Unique<vk::VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout)); 418 419 // Update descriptor set information 420 { 421 vk::VkDescriptorBufferInfo descTestBuffer = makeDescriptorBufferInfo(**testBuffer, 0, testBufferSize); 422 vk::VkDescriptorBufferInfo descTestUniform = makeDescriptorBufferInfo(**testUniform, 0, testUniformSize); 423 vk::VkDescriptorBufferInfo descTestBufferSource = makeDescriptorBufferInfo(**testBufferSource, 0, testBufferSize); 424 425 vk::DescriptorSetUpdateBuilder() 426 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descTestBuffer) 427 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descTestUniform) 428 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descTestBufferSource) 429 .update(vk, device); 430 } 431 432 // Create output image 433 de::MovePtr<vk::ImageWithMemory> colorImage (createImage2D(ctx, PROTECTION_ENABLED, queueFamilyIndex, 434 RENDER_WIDTH, RENDER_HEIGHT, 435 m_imageFormat, 436 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|vk::VK_IMAGE_USAGE_SAMPLED_BIT)); 437 vk::Unique<vk::VkImageView> colorImageView (createImageView(ctx, **colorImage, m_imageFormat)); 438 vk::Unique<vk::VkRenderPass> renderPass (createRenderPass(ctx, m_imageFormat)); 439 vk::Unique<vk::VkFramebuffer> framebuffer (createFramebuffer(ctx, RENDER_WIDTH, RENDER_HEIGHT, *renderPass, *colorImageView)); 440 441 // Build pipeline 442 vk::Unique<vk::VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout)); 443 vk::Unique<vk::VkCommandPool> cmdPool (makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex)); 444 vk::Unique<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 445 446 // Create pipeline 447 vk::Unique<vk::VkPipeline> graphicsPipeline (makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, 448 *vertexShader, *testShader, 449 std::vector<vk::VkVertexInputBindingDescription>(), 450 std::vector<vk::VkVertexInputAttributeDescription>(), 451 tcu::UVec2(RENDER_WIDTH, RENDER_HEIGHT), 452 vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)); 453 454 beginCommandBuffer(vk, *cmdBuffer); 455 456 if (m_testType == SSBO_READ || m_testType == SSBO_ATOMIC) 457 { 458 vk::VkBuffer targetBuffer = (m_testType == SSBO_ATOMIC) ? **testBuffer : **testBufferSource; 459 addBufferCopyCmd(vk, *cmdBuffer, queueFamilyIndex, **testUniform, targetBuffer, testUniformSize); 460 } 461 462 // Start image barrier 463 { 464 const vk::VkImageMemoryBarrier startImgBarrier = 465 { 466 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType 467 DE_NULL, // pNext 468 0, // srcAccessMask 469 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // dstAccessMask 470 vk::VK_IMAGE_LAYOUT_UNDEFINED, // oldLayout 471 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout 472 queueFamilyIndex, // srcQueueFamilyIndex 473 queueFamilyIndex, // dstQueueFamilyIndex 474 **colorImage, // image 475 { 476 vk::VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask 477 0u, // baseMipLevel 478 1u, // mipLevels 479 0u, // baseArraySlice 480 1u, // subresourceRange 481 } 482 }; 483 484 vk.cmdPipelineBarrier(*cmdBuffer, 485 vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // srcStageMask 486 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // dstStageMask 487 (vk::VkDependencyFlags)0, 488 0, (const vk::VkMemoryBarrier*)DE_NULL, 489 0, (const vk::VkBufferMemoryBarrier*)DE_NULL, 490 1, &startImgBarrier); 491 } 492 493 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, vk::makeRect2D(0, 0, RENDER_WIDTH, RENDER_HEIGHT), tcu::Vec4(0.125f, 0.25f, 0.5f, 1.0f)); 494 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline); 495 vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL); 496 497 vk.cmdDraw(*cmdBuffer, 4u, 1u, 0u, 0u); 498 endRenderPass(vk, *cmdBuffer); 499 500 { 501 const vk::VkImageMemoryBarrier endImgBarrier = 502 { 503 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType 504 DE_NULL, // pNext 505 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // srcAccessMask 506 vk::VK_ACCESS_SHADER_READ_BIT, // dstAccessMask 507 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // oldLayout 508 vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // newLayout 509 queueFamilyIndex, // srcQueueFamilyIndex 510 queueFamilyIndex, // dstQueueFamilyIndex 511 **colorImage, // image 512 { 513 vk::VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask 514 0u, // baseMipLevel 515 1u, // mipLevels 516 0u, // baseArraySlice 517 1u, // subresourceRange 518 } 519 }; 520 vk.cmdPipelineBarrier(*cmdBuffer, 521 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // srcStageMask 522 vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, // dstStageMask 523 (vk::VkDependencyFlags)0, 524 0, (const vk::VkMemoryBarrier*)DE_NULL, 525 0, (const vk::VkBufferMemoryBarrier*)DE_NULL, 526 1, &endImgBarrier); 527 } 528 529 endCommandBuffer(vk, *cmdBuffer); 530 531 // Execute Draw 532 { 533 const vk::Unique<vk::VkFence> fence (vk::createFence(vk, device)); 534 VK_CHECK(vk.resetFences(device, 1, &fence.get())); 535 VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull)); 536 } 537 538 // Log inputs 539 ctx.getTestContext().getLog() 540 << tcu::TestLog::Message << "Input values: \n" 541 << "1: " << m_testInput << "\n" 542 << tcu::TestLog::EndMessage; 543 544 // Validate buffer 545 if (m_validator.validateBuffer(ctx, **testBuffer)) 546 return tcu::TestStatus::pass("Everything went OK"); 547 else 548 return tcu::TestStatus::fail("Something went really wrong"); 549 } 550 551 template<typename T> 552 tcu::TestStatus StorageBufferTestInstance<T>::executeComputeTest(void) 553 { 554 ProtectedContext& ctx (m_protectedContext); 555 const vk::DeviceInterface& vk = ctx.getDeviceInterface(); 556 const vk::VkDevice device = ctx.getDevice(); 557 const vk::VkQueue queue = ctx.getQueue(); 558 const deUint32 queueFamilyIndex = ctx.getQueueFamilyIndex(); 559 560 const deUint32 testUniformSize = sizeof(m_testInput); 561 de::UniquePtr<vk::BufferWithMemory> testUniform (makeBuffer(ctx, 562 PROTECTION_DISABLED, 563 queueFamilyIndex, 564 testUniformSize, 565 vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT 566 | vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 567 vk::MemoryRequirement::HostVisible)); 568 569 // Set the test input uniform data 570 { 571 deMemcpy(testUniform->getAllocation().getHostPtr(), &m_testInput, testUniformSize); 572 vk::flushMappedMemoryRange(vk, device, testUniform->getAllocation().getMemory(), testUniform->getAllocation().getOffset(), testUniformSize); 573 } 574 575 const deUint32 testBufferSize = sizeof(ValidationDataStorage<T>); 576 de::MovePtr<vk::BufferWithMemory> testBuffer (makeBuffer(ctx, 577 PROTECTION_ENABLED, 578 queueFamilyIndex, 579 testBufferSize, 580 vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT 581 | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT, 582 vk::MemoryRequirement::Protected)); 583 de::MovePtr<vk::BufferWithMemory> testBufferSource (makeBuffer(ctx, 584 PROTECTION_ENABLED, 585 queueFamilyIndex, 586 testBufferSize, 587 vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT 588 | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT, 589 vk::MemoryRequirement::Protected)); 590 591 vk::Unique<vk::VkShaderModule> testShader (vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("TestShader"), 0)); 592 593 // Create descriptors 594 vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(vk::DescriptorSetLayoutBuilder() 595 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT) 596 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT) 597 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT) 598 .build(vk, device)); 599 vk::Unique<vk::VkDescriptorPool> descriptorPool(vk::DescriptorPoolBuilder() 600 .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u) 601 .addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u) 602 .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u) 603 .build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u)); 604 vk::Unique<vk::VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout)); 605 606 // Update descriptor set information 607 { 608 vk::VkDescriptorBufferInfo descTestBuffer = makeDescriptorBufferInfo(**testBuffer, 0, testBufferSize); 609 vk::VkDescriptorBufferInfo descTestUniform = makeDescriptorBufferInfo(**testUniform, 0, testUniformSize); 610 vk::VkDescriptorBufferInfo descTestBufferSource = makeDescriptorBufferInfo(**testBufferSource, 0, testBufferSize); 611 612 vk::DescriptorSetUpdateBuilder() 613 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descTestBuffer) 614 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descTestUniform) 615 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descTestBufferSource) 616 .update(vk, device); 617 } 618 619 620 // Build and execute test 621 { 622 const vk::Unique<vk::VkFence> fence (vk::createFence(vk, device)); 623 vk::Unique<vk::VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout)); 624 vk::Unique<vk::VkPipeline> SSBOPipeline (makeComputePipeline(vk, device, *pipelineLayout, *testShader, DE_NULL)); 625 vk::Unique<vk::VkCommandPool> cmdPool (makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex)); 626 vk::Unique<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 627 deUint32 dispatchCount = (m_testType == SSBO_ATOMIC) ? 4u : 1u; 628 629 beginCommandBuffer(vk, *cmdBuffer); 630 631 if (m_testType == SSBO_READ || m_testType == SSBO_ATOMIC) 632 { 633 vk::VkBuffer targetBuffer = (m_testType == SSBO_ATOMIC) ? **testBuffer : **testBufferSource; 634 addBufferCopyCmd(vk, *cmdBuffer, queueFamilyIndex, **testUniform, targetBuffer, testUniformSize); 635 } 636 637 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *SSBOPipeline); 638 vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL); 639 640 vk.cmdDispatch(*cmdBuffer, dispatchCount, 1u, 1u); 641 642 endCommandBuffer(vk, *cmdBuffer); 643 VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull)); 644 } 645 646 ctx.getTestContext().getLog() 647 << tcu::TestLog::Message << "Input values: \n" 648 << "1: " << m_testInput << "\n" 649 << tcu::TestLog::EndMessage; 650 651 // Validate buffer 652 if (m_validator.validateBuffer(ctx, **testBuffer)) 653 return tcu::TestStatus::pass("Everything went OK"); 654 else 655 return tcu::TestStatus::fail("Something went really wrong"); 656 } 657 658 template<typename T> 659 tcu::TestStatus StorageBufferTestInstance<T>::iterate(void) 660 { 661 switch (m_shaderType) 662 { 663 case glu::SHADERTYPE_FRAGMENT: return executeFragmentTest(); 664 case glu::SHADERTYPE_COMPUTE: return executeComputeTest(); 665 default: 666 DE_FATAL("Incorrect shader type"); return tcu::TestStatus::fail(""); 667 } 668 } 669 670 tcu::TestCaseGroup* createSpecifiedStorageBufferTests (tcu::TestContext& testCtx, 671 const std::string groupName, 672 SSBOTestType testType, 673 const glu::ShaderType shaderType, 674 const ValidationDataStorage<tcu::UVec4> testData[], 675 size_t testCount) 676 { 677 const std::string testTypeStr = getSSBOTypeString(testType); 678 const std::string description = "Storage buffer " + testTypeStr + " tests"; 679 de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, groupName.c_str(), description.c_str())); 680 681 for (size_t ndx = 0; ndx < testCount; ++ndx) 682 { 683 const std::string name = testTypeStr + "_" + de::toString(ndx + 1); 684 testGroup->addChild(new StorageBufferTestCase<tcu::UVec4>(testCtx, testType, shaderType, name.c_str(), testData[ndx].values, testData[ndx])); 685 } 686 687 return testGroup.release(); 688 } 689 690 tcu::TestCaseGroup* createRandomizedBufferTests (tcu::TestContext& testCtx, SSBOTestType testType, const glu::ShaderType shaderType, size_t testCount) 691 { 692 de::Random rnd (testCtx.getCommandLine().getBaseSeed()); 693 std::vector<ValidationDataStorage<tcu::UVec4> > testData; 694 testData.resize(testCount); 695 696 for (size_t ndx = 0; ndx < testCount; ++ndx) 697 testData[ndx].values = tcu::UVec4(rnd.getUint32(), rnd.getUint32(), rnd.getUint32(), rnd.getUint32()); 698 699 return createSpecifiedStorageBufferTests(testCtx, "random", testType, shaderType, testData.data(), testData.size()); 700 } 701 702 tcu::TestCaseGroup* createRWStorageBufferTests (tcu::TestContext& testCtx, 703 const std::string groupName, 704 const std::string groupDescription, 705 SSBOTestType testType, 706 const ValidationDataStorage<tcu::UVec4> testData[], 707 size_t testCount) 708 { 709 de::MovePtr<tcu::TestCaseGroup> ssboRWTestGroup (new tcu::TestCaseGroup(testCtx, groupName.c_str(), groupDescription.c_str())); 710 711 glu::ShaderType shaderTypes[] = { 712 glu::SHADERTYPE_FRAGMENT, 713 glu::SHADERTYPE_COMPUTE 714 }; 715 716 for (int shaderNdx = 0; shaderNdx < DE_LENGTH_OF_ARRAY(shaderTypes); ++shaderNdx) 717 { 718 const glu::ShaderType shaderType = shaderTypes[shaderNdx]; 719 const std::string shaderName = getShaderTypeString(shaderType); 720 const std::string shaderGroupDesc = "Storage buffer tests for shader type: " + shaderName; 721 de::MovePtr<tcu::TestCaseGroup> testShaderGroup (new tcu::TestCaseGroup(testCtx, shaderName.c_str(), shaderGroupDesc.c_str())); 722 723 testShaderGroup->addChild(createSpecifiedStorageBufferTests(testCtx, "static", testType, shaderType, testData, testCount)); 724 testShaderGroup->addChild(createRandomizedBufferTests(testCtx, testType, shaderType, RANDOM_TEST_COUNT)); 725 ssboRWTestGroup->addChild(testShaderGroup.release()); 726 } 727 728 return ssboRWTestGroup.release(); 729 } 730 731 void calculateAtomicOpData (SSBOAtomicType type, 732 const tcu::UVec4& inputValue, 733 const deUint32 atomicArg, 734 std::string& atomicCall, 735 tcu::UVec4& refValue, 736 const deUint32 swapNdx = 0) 737 { 738 switch (type) 739 { 740 case ATOMIC_ADD: 741 { 742 refValue = inputValue + tcu::UVec4(atomicArg); 743 atomicCall = "atomicAdd(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);"; 744 break; 745 } 746 case ATOMIC_MIN: 747 { 748 refValue = tcu::UVec4(std::min(inputValue.x(), atomicArg), std::min(inputValue.y(), atomicArg), std::min(inputValue.z(), atomicArg), std::min(inputValue.w(), atomicArg)); 749 atomicCall = "atomicMin(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);"; 750 break; 751 } 752 case ATOMIC_MAX: 753 { 754 refValue = tcu::UVec4(std::max(inputValue.x(), atomicArg), std::max(inputValue.y(), atomicArg), std::max(inputValue.z(), atomicArg), std::max(inputValue.w(), atomicArg)); 755 atomicCall = "atomicMax(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);"; 756 break; 757 } 758 case ATOMIC_AND: 759 { 760 refValue = tcu::UVec4(inputValue.x() & atomicArg, inputValue.y() & atomicArg, inputValue.z() & atomicArg, inputValue.w() & atomicArg); 761 atomicCall = "atomicAnd(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);"; 762 break; 763 } 764 case ATOMIC_OR: 765 { 766 refValue = tcu::UVec4(inputValue.x() | atomicArg, inputValue.y() | atomicArg, inputValue.z() | atomicArg, inputValue.w() | atomicArg); 767 atomicCall = "atomicOr(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);"; 768 break; 769 } 770 case ATOMIC_XOR: 771 { 772 refValue = tcu::UVec4(inputValue.x() ^ atomicArg, inputValue.y() ^ atomicArg, inputValue.z() ^ atomicArg, inputValue.w() ^ atomicArg); 773 atomicCall = "atomicXor(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);"; 774 break; 775 } 776 case ATOMIC_EXCHANGE: 777 { 778 refValue = tcu::UVec4(atomicArg); 779 atomicCall = "atomicExchange(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);"; 780 break; 781 } 782 case ATOMIC_COMPSWAP: 783 { 784 int selectedNdx = swapNdx % 4; 785 deUint32 selectedChange = inputValue[selectedNdx]; 786 787 refValue = inputValue; 788 refValue[selectedNdx] = atomicArg; 789 atomicCall = "atomicCompSwap(protectedTestResultBuffer[i], " + de::toString(selectedChange) + "u, " + de::toString(atomicArg) + "u);"; 790 break; 791 } 792 default: DE_FATAL("Incorrect atomic function type"); break; 793 } 794 795 } 796 797 } // anonymous 798 799 tcu::TestCaseGroup* createReadStorageBufferTests (tcu::TestContext& testCtx) 800 { 801 const ValidationDataStorage<tcu::UVec4> testData[] = { 802 { tcu::UVec4(0u, 0u, 0u, 0u) }, { tcu::UVec4(1u, 0u, 0u, 0u) }, 803 { tcu::UVec4(0u, 1u, 0u, 0u) }, { tcu::UVec4(0u, 0u, 1u, 0u) }, 804 { tcu::UVec4(0u, 0u, 0u, 1u) }, { tcu::UVec4(1u, 1u, 1u, 1u) } 805 }; 806 807 return createRWStorageBufferTests(testCtx, "ssbo_read", "Storage Buffer Read Tests", SSBO_READ, testData, DE_LENGTH_OF_ARRAY(testData)); 808 } 809 810 tcu::TestCaseGroup* createWriteStorageBufferTests (tcu::TestContext& testCtx) 811 { 812 const ValidationDataStorage<tcu::UVec4> testData[] = { 813 { tcu::UVec4(0u, 0u, 0u, 0u) }, { tcu::UVec4(1u, 0u, 0u, 0u) }, 814 { tcu::UVec4(0u, 1u, 0u, 0u) }, { tcu::UVec4(0u, 0u, 1u, 0u) }, 815 { tcu::UVec4(0u, 0u, 0u, 1u) }, { tcu::UVec4(1u, 1u, 1u, 1u) } 816 }; 817 818 return createRWStorageBufferTests(testCtx, "ssbo_write", "Storage Buffer Write Tests", SSBO_WRITE, testData, DE_LENGTH_OF_ARRAY(testData)); 819 } 820 821 tcu::TestCaseGroup* createAtomicStorageBufferTests (tcu::TestContext& testctx) 822 { 823 struct { 824 const tcu::UVec4 input; 825 const deUint32 atomicArg; 826 const deUint32 swapNdx; 827 } testData[] = { 828 { tcu::UVec4(0u, 1u, 2u, 3u), 10u, 0u }, 829 { tcu::UVec4(10u, 20u, 30u, 40u), 3u, 2u }, 830 { tcu::UVec4(800u, 400u, 230u, 999u), 50u, 3u }, 831 { tcu::UVec4(100800u, 233400u, 22230u, 77999u), 800u, 1u }, 832 }; 833 834 SSBOAtomicType testTypes[] = { 835 ATOMIC_ADD, 836 ATOMIC_MIN, 837 ATOMIC_MAX, 838 ATOMIC_AND, 839 ATOMIC_OR, 840 ATOMIC_XOR, 841 ATOMIC_EXCHANGE, 842 ATOMIC_COMPSWAP 843 }; 844 845 glu::ShaderType shaderTypes[] = { 846 glu::SHADERTYPE_FRAGMENT, 847 glu::SHADERTYPE_COMPUTE 848 }; 849 850 de::Random rnd (testctx.getCommandLine().getBaseSeed()); 851 de::MovePtr<tcu::TestCaseGroup> ssboAtomicTests (new tcu::TestCaseGroup(testctx, "ssbo_atomic", "Storage Buffer Atomic Tests")); 852 853 for (int shaderNdx = 0; shaderNdx < DE_LENGTH_OF_ARRAY(shaderTypes); ++shaderNdx) 854 { 855 const glu::ShaderType shaderType = shaderTypes[shaderNdx]; 856 const std::string shaderName = getShaderTypeString(shaderType); 857 const std::string shaderDesc = "Storage Buffer Atomic Tests for shader type: " + shaderName; 858 de::MovePtr<tcu::TestCaseGroup> atomicShaderGroup (new tcu::TestCaseGroup(testctx, shaderName.c_str(), shaderDesc.c_str())); 859 860 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(testTypes); ++typeNdx) 861 { 862 SSBOAtomicType atomicType = testTypes[typeNdx]; 863 const std::string atomicTypeStr = getSSBOAtomicTypeString(atomicType); 864 const std::string atomicDesc = "Storage Buffer Atomic Tests: " + atomicTypeStr; 865 866 de::MovePtr<tcu::TestCaseGroup> staticTests (new tcu::TestCaseGroup(testctx, "static", (atomicDesc + " with static input").c_str())); 867 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(testData); ++ndx) 868 { 869 const std::string name = "atomic_" + atomicTypeStr + "_" + de::toString(ndx + 1); 870 const tcu::UVec4& inputValue = testData[ndx].input; 871 const deUint32& atomicArg = testData[ndx].atomicArg; 872 std::string atomicCall; 873 tcu::UVec4 refValue; 874 875 calculateAtomicOpData(atomicType, inputValue, atomicArg, atomicCall, refValue, testData[ndx].swapNdx); 876 877 ValidationDataStorage<tcu::UVec4> validationData = { refValue }; 878 staticTests->addChild(new StorageBufferTestCase<tcu::UVec4>(testctx, SSBO_ATOMIC, shaderType, name.c_str(), inputValue, validationData, atomicCall)); 879 } 880 881 de::MovePtr<tcu::TestCaseGroup> randomTests (new tcu::TestCaseGroup(testctx, "random", (atomicDesc + " with random input").c_str())); 882 for (int ndx = 0; ndx < RANDOM_TEST_COUNT; ndx++) 883 { 884 const std::string name = "atomic_" + atomicTypeStr + "_" + de::toString(ndx + 1); 885 deUint32 atomicArg = rnd.getUint16(); 886 tcu::UVec4 inputValue; 887 tcu::UVec4 refValue; 888 std::string atomicCall; 889 890 for (int i = 0; i < 4; i++) 891 inputValue[i] = rnd.getUint16(); 892 893 calculateAtomicOpData(atomicType, inputValue, atomicArg, atomicCall, refValue, ndx); 894 895 ValidationDataStorage<tcu::UVec4> validationData = { refValue }; 896 randomTests->addChild(new StorageBufferTestCase<tcu::UVec4>(testctx, SSBO_ATOMIC, shaderType, name.c_str(), inputValue, validationData, atomicCall)); 897 898 } 899 900 de::MovePtr<tcu::TestCaseGroup> atomicTests (new tcu::TestCaseGroup(testctx, atomicTypeStr.c_str(), atomicDesc.c_str())); 901 atomicTests->addChild(staticTests.release()); 902 atomicTests->addChild(randomTests.release()); 903 atomicShaderGroup->addChild(atomicTests.release()); 904 } 905 ssboAtomicTests->addChild(atomicShaderGroup.release()); 906 } 907 908 return ssboAtomicTests.release(); 909 } 910 911 } // ProtectedMem 912 } // vkt 913