1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2017 The Khronos Group Inc.
6 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * \brief Protected memory storage buffer tests
23 *//*--------------------------------------------------------------------*/
25 #include "vktProtectedMemStorageBufferTests.hpp"
27 #include "deRandom.hpp"
28 #include "deStringUtil.hpp"
29 #include "tcuTestLog.hpp"
30 #include "tcuVector.hpp"
31 #include "tcuStringTemplate.hpp"
33 #include "vkPrograms.hpp"
34 #include "vktTestCase.hpp"
35 #include "vktTestGroupUtil.hpp"
36 #include "vkTypeUtil.hpp"
37 #include "vkBuilderUtil.hpp"
38 #include "vkCmdUtil.hpp"
40 #include "vktProtectedMemBufferValidator.hpp"
41 #include "vktProtectedMemUtils.hpp"
42 #include "vktProtectedMemContext.hpp"
46 namespace ProtectedMem
58 RANDOM_TEST_COUNT = 10,
79 const char* getSSBOTestDescription (SSBOTestType 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 "";
89 const char* getSSBOTypeString (SSBOTestType 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 "";
99 const char* getSSBOAtomicTypeString (SSBOAtomicType type)
103 case ATOMIC_ADD: return "add";
104 case ATOMIC_MIN: return "min";
105 case ATOMIC_MAX: return "max";
106 case ATOMIC_AND: return "and";
107 case ATOMIC_OR: return "or";
108 case ATOMIC_XOR: return "xor";
109 case ATOMIC_EXCHANGE: return "exchange";
110 case ATOMIC_COMPSWAP: return "compswap";
111 default: DE_FATAL("Invalid SSBO atomic operation type"); return "";
115 void static addBufferCopyCmd (const vk::DeviceInterface& vk,
116 vk::VkCommandBuffer cmdBuffer,
117 deUint32 queueFamilyIndex,
118 vk::VkBuffer srcBuffer,
119 vk::VkBuffer dstBuffer,
122 const vk::VkBufferMemoryBarrier dstWriteStartBarrier =
124 vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType
125 DE_NULL, // const void* pNext
126 0, // VkAccessFlags srcAccessMask
127 vk::VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags dstAccessMask
128 queueFamilyIndex, // uint32_t srcQueueFamilyIndex
129 queueFamilyIndex, // uint32_t dstQueueFamilyIndex
130 dstBuffer, // VkBuffer buffer
131 0u, // VkDeviceSize offset
132 VK_WHOLE_SIZE, // VkDeviceSize size
135 vk.cmdPipelineBarrier(cmdBuffer,
136 vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // srcStageMask
137 vk::VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, // dstStageMask
138 (vk::VkDependencyFlags)0,
139 0, (const vk::VkMemoryBarrier*)DE_NULL,
140 1, &dstWriteStartBarrier,
141 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
143 const vk::VkBufferCopy copyRegion =
145 0, // VkDeviceSize srcOffset
146 0, // VkDeviceSize dstOffset
147 copySize // VkDeviceSize size
149 vk.cmdCopyBuffer(cmdBuffer, srcBuffer, dstBuffer, 1, ©Region);
151 const vk::VkBufferMemoryBarrier dstWriteEndBarrier =
153 vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType
154 DE_NULL, // const void* pNext
155 vk::VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags srcAccessMask
156 vk::VK_ACCESS_SHADER_READ_BIT, // VkAccessFlags dstAccessMask
157 queueFamilyIndex, // uint32_t srcQueueFamilyIndex
158 queueFamilyIndex, // uint32_t dstQueueFamilyIndex
159 dstBuffer, // VkBuffer buffer
160 0u, // VkDeviceSize offset
161 VK_WHOLE_SIZE, // VkDeviceSize size
163 vk.cmdPipelineBarrier(cmdBuffer,
164 vk::VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, // srcStageMask
165 vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // dstStageMask
166 (vk::VkDependencyFlags)0,
167 0, (const vk::VkMemoryBarrier*)DE_NULL,
168 1, &dstWriteEndBarrier,
169 0, (const vk::VkImageMemoryBarrier*)DE_NULL);
174 class StorageBufferTestInstance : public ProtectedTestInstance
177 StorageBufferTestInstance (Context& ctx,
178 const SSBOTestType testType,
179 const glu::ShaderType shaderType,
180 const tcu::UVec4 testInput,
181 const BufferValidator<T>& validator);
182 virtual tcu::TestStatus iterate (void);
185 tcu::TestStatus executeFragmentTest (void);
186 tcu::TestStatus executeComputeTest (void);
188 const SSBOTestType m_testType;
189 const glu::ShaderType m_shaderType;
190 const tcu::UVec4 m_testInput;
191 const BufferValidator<T>& m_validator;
192 const vk::VkFormat m_imageFormat;
196 class StorageBufferTestCase : public TestCase
199 StorageBufferTestCase (tcu::TestContext& testctx,
200 const SSBOTestType testType,
201 const glu::ShaderType shaderType,
203 const tcu::UVec4 testInput,
204 ValidationDataStorage<T> validationData,
206 const std::string& extraShader = "")
207 : TestCase (testctx, name, getSSBOTestDescription(testType))
208 , m_testType (testType)
209 , m_shaderType (shaderType)
210 , m_testInput (testInput)
211 , m_validator (validationData, format)
212 , m_extraShader (extraShader)
215 virtual TestInstance* createInstance (Context& ctx) const
217 return new StorageBufferTestInstance<T>(ctx, m_testType, m_shaderType, m_testInput, m_validator);
219 virtual void initPrograms (vk::SourceCollections& programCollection) const;
220 virtual void checkSupport (Context& context) const
222 checkProtectedQueueSupport(context);
225 virtual ~StorageBufferTestCase (void) {}
228 const SSBOTestType m_testType;
229 const glu::ShaderType m_shaderType;
230 const tcu::UVec4 m_testInput;
231 const BufferValidator<T> m_validator;
232 const std::string m_extraShader;
236 StorageBufferTestInstance<T>::StorageBufferTestInstance (Context& ctx,
237 const SSBOTestType testType,
238 const glu::ShaderType shaderType,
239 const tcu::UVec4 testInput,
240 const BufferValidator<T>& validator)
241 : ProtectedTestInstance (ctx)
242 , m_testType (testType)
243 , m_shaderType (shaderType)
244 , m_testInput (testInput)
245 , m_validator (validator)
246 , m_imageFormat (vk::VK_FORMAT_R8G8B8A8_UNORM)
251 void StorageBufferTestCase<T>::initPrograms (vk::SourceCollections& programCollection) const
253 const char* vertexShader =
255 "layout(location=0) out vec4 vIndex;\n"
257 " 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"
258 " vIndex = vec4(gl_VertexIndex);\n"
259 " gl_PointSize = 1.0;\n"
260 " gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);\n"
263 // set = 0, location = 0 -> buffer ProtectedTestBuffer (uvec4)
264 // set = 0, location = 2 -> buffer ProtectedTestBufferSource (uvec4)
265 const char* readShaderTemplateStr =
267 "${INPUT_DECLARATION}\n"
269 "layout(set=0, binding=0, std140) buffer ProtectedTestBuffer\n"
271 " highp uvec4 protectedTestResultBuffer;\n"
274 "layout(set=0, binding=2, std140) buffer ProtectedTestBufferSource\n"
276 " highp uvec4 protectedTestBufferSource;\n"
281 " protectedTestResultBuffer = protectedTestBufferSource;\n"
282 " ${FRAGMENT_OUTPUT}\n"
285 // set = 0, location = 0 -> buffer ProtectedTestBuffer (uvec4)
286 // set = 0, location = 1 -> uniform Data (uvec4)
287 const char* writeShaderTemplateStr =
289 "${INPUT_DECLARATION}\n"
291 "layout(set=0, binding=0, std140) buffer ProtectedTestBuffer\n"
293 " highp uvec4 protectedTestResultBuffer;\n"
296 "layout(set=0, binding=1, std140) uniform Data\n"
298 " highp uvec4 testInput;\n"
303 " protectedTestResultBuffer = testInput;\n"
304 " ${FRAGMENT_OUTPUT}\n"
307 // set = 0, location = 0 -> buffer ProtectedTestBuffer (uint [4])
308 const char* atomicTestShaderTemplateStr =
310 "${INPUT_DECLARATION}\n"
312 "layout(set=0, binding=0, std430) buffer ProtectedTestBuffer\n"
314 " highp uint protectedTestResultBuffer[4];\n"
319 " uint i = uint(${INVOCATION_ID});\n"
320 " ${ATOMIC_FUNCTION_CALL}\n"
321 " ${FRAGMENT_OUTPUT}\n"
324 const char* shaderTemplateStr;
325 std::map<std::string, std::string> shaderParam;
326 switch (m_testType) {
327 case SSBO_READ: shaderTemplateStr = readShaderTemplateStr; break;
328 case SSBO_WRITE: shaderTemplateStr = writeShaderTemplateStr; break;
330 shaderTemplateStr = atomicTestShaderTemplateStr;
331 shaderParam["ATOMIC_FUNCTION_CALL"] = m_extraShader;
334 default: DE_FATAL("Incorrect SSBO test type"); return;
337 if (m_shaderType == glu::SHADERTYPE_FRAGMENT)
339 shaderParam["INPUT_DECLARATION"] = "layout(location=0) out mediump vec4 o_color;\n"
340 "layout(location=0) in vec4 vIndex;\n";
341 shaderParam["FRAGMENT_OUTPUT"] = "o_color = vec4( 0.0, 0.4, 1.0, 1.0 );\n";
342 shaderParam["INVOCATION_ID"] = "vIndex.x";
344 programCollection.glslSources.add("vert") << glu::VertexSource(vertexShader);
345 programCollection.glslSources.add("TestShader") << glu::FragmentSource(tcu::StringTemplate(shaderTemplateStr).specialize(shaderParam));
347 else if (m_shaderType == glu::SHADERTYPE_COMPUTE)
349 shaderParam["INPUT_DECLARATION"] = "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n";
350 shaderParam["FRAGMENT_OUTPUT"] = "";
351 shaderParam["INVOCATION_ID"] = "gl_GlobalInvocationID.x";
352 programCollection.glslSources.add("TestShader") << glu::ComputeSource(tcu::StringTemplate(shaderTemplateStr).specialize(shaderParam));
355 DE_FATAL("Incorrect shader type");
357 m_validator.initPrograms(programCollection);
361 tcu::TestStatus StorageBufferTestInstance<T>::executeFragmentTest(void)
363 ProtectedContext& ctx (m_protectedContext);
364 const vk::DeviceInterface& vk = ctx.getDeviceInterface();
365 const vk::VkDevice device = ctx.getDevice();
366 const vk::VkQueue queue = ctx.getQueue();
367 const deUint32 queueFamilyIndex = ctx.getQueueFamilyIndex();
369 const deUint32 testUniformSize = sizeof(m_testInput);
370 de::UniquePtr<vk::BufferWithMemory> testUniform (makeBuffer(ctx,
374 vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
375 | vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
376 vk::MemoryRequirement::HostVisible));
378 // Set the test input uniform data
380 deMemcpy(testUniform->getAllocation().getHostPtr(), &m_testInput, testUniformSize);
381 vk::flushAlloc(vk, device, testUniform->getAllocation());
383 const deUint32 testBufferSize = sizeof(ValidationDataStorage<T>);
384 de::MovePtr<vk::BufferWithMemory> testBuffer (makeBuffer(ctx,
388 vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
389 | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT,
390 vk::MemoryRequirement::Protected));
391 de::MovePtr<vk::BufferWithMemory> testBufferSource (makeBuffer(ctx,
395 vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
396 | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT,
397 vk::MemoryRequirement::Protected));
399 vk::Move<vk::VkShaderModule> vertexShader (vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("vert"), 0));
400 vk::Unique<vk::VkShaderModule> testShader (vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("TestShader"), 0));
402 // Create descriptors
403 vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(vk::DescriptorSetLayoutBuilder()
404 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_ALL)
405 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_ALL)
406 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_ALL)
408 vk::Unique<vk::VkDescriptorPool> descriptorPool(vk::DescriptorPoolBuilder()
409 .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
410 .addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u)
411 .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
412 .build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
413 vk::Unique<vk::VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
415 // Update descriptor set information
417 vk::VkDescriptorBufferInfo descTestBuffer = makeDescriptorBufferInfo(**testBuffer, 0, testBufferSize);
418 vk::VkDescriptorBufferInfo descTestUniform = makeDescriptorBufferInfo(**testUniform, 0, testUniformSize);
419 vk::VkDescriptorBufferInfo descTestBufferSource = makeDescriptorBufferInfo(**testBufferSource, 0, testBufferSize);
421 vk::DescriptorSetUpdateBuilder()
422 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descTestBuffer)
423 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descTestUniform)
424 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descTestBufferSource)
428 // Create output image
429 de::MovePtr<vk::ImageWithMemory> colorImage (createImage2D(ctx, PROTECTION_ENABLED, queueFamilyIndex,
430 RENDER_WIDTH, RENDER_HEIGHT,
432 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|vk::VK_IMAGE_USAGE_SAMPLED_BIT));
433 vk::Unique<vk::VkImageView> colorImageView (createImageView(ctx, **colorImage, m_imageFormat));
434 vk::Unique<vk::VkRenderPass> renderPass (createRenderPass(ctx, m_imageFormat));
435 vk::Unique<vk::VkFramebuffer> framebuffer (createFramebuffer(ctx, RENDER_WIDTH, RENDER_HEIGHT, *renderPass, *colorImageView));
438 vk::Unique<vk::VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout));
439 vk::Unique<vk::VkCommandPool> cmdPool (makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
440 vk::Unique<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
443 vk::Unique<vk::VkPipeline> graphicsPipeline (makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass,
444 *vertexShader, *testShader,
445 std::vector<vk::VkVertexInputBindingDescription>(),
446 std::vector<vk::VkVertexInputAttributeDescription>(),
447 tcu::UVec2(RENDER_WIDTH, RENDER_HEIGHT),
448 vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST));
450 beginCommandBuffer(vk, *cmdBuffer);
452 if (m_testType == SSBO_READ || m_testType == SSBO_ATOMIC)
454 vk::VkBuffer targetBuffer = (m_testType == SSBO_ATOMIC) ? **testBuffer : **testBufferSource;
455 addBufferCopyCmd(vk, *cmdBuffer, queueFamilyIndex, **testUniform, targetBuffer, testUniformSize);
458 // Start image barrier
460 const vk::VkImageMemoryBarrier startImgBarrier =
462 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
465 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // dstAccessMask
466 vk::VK_IMAGE_LAYOUT_UNDEFINED, // oldLayout
467 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
468 queueFamilyIndex, // srcQueueFamilyIndex
469 queueFamilyIndex, // dstQueueFamilyIndex
470 **colorImage, // image
472 vk::VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
475 0u, // baseArraySlice
476 1u, // subresourceRange
480 vk.cmdPipelineBarrier(*cmdBuffer,
481 vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // srcStageMask
482 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // dstStageMask
483 (vk::VkDependencyFlags)0,
484 0, (const vk::VkMemoryBarrier*)DE_NULL,
485 0, (const vk::VkBufferMemoryBarrier*)DE_NULL,
486 1, &startImgBarrier);
489 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, vk::makeRect2D(0, 0, RENDER_WIDTH, RENDER_HEIGHT), tcu::Vec4(0.125f, 0.25f, 0.5f, 1.0f));
490 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
491 vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
493 vk.cmdDraw(*cmdBuffer, 4u, 1u, 0u, 0u);
494 endRenderPass(vk, *cmdBuffer);
497 const vk::VkImageMemoryBarrier endImgBarrier =
499 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
501 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // srcAccessMask
502 vk::VK_ACCESS_SHADER_READ_BIT, // dstAccessMask
503 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // oldLayout
504 vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // newLayout
505 queueFamilyIndex, // srcQueueFamilyIndex
506 queueFamilyIndex, // dstQueueFamilyIndex
507 **colorImage, // image
509 vk::VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
512 0u, // baseArraySlice
513 1u, // subresourceRange
516 vk.cmdPipelineBarrier(*cmdBuffer,
517 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // srcStageMask
518 vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, // dstStageMask
519 (vk::VkDependencyFlags)0,
520 0, (const vk::VkMemoryBarrier*)DE_NULL,
521 0, (const vk::VkBufferMemoryBarrier*)DE_NULL,
525 endCommandBuffer(vk, *cmdBuffer);
529 const vk::Unique<vk::VkFence> fence (vk::createFence(vk, device));
530 VK_CHECK(vk.resetFences(device, 1, &fence.get()));
531 VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull));
535 ctx.getTestContext().getLog()
536 << tcu::TestLog::Message << "Input values: \n"
537 << "1: " << m_testInput << "\n"
538 << tcu::TestLog::EndMessage;
541 if (m_validator.validateBuffer(ctx, **testBuffer))
542 return tcu::TestStatus::pass("Everything went OK");
544 return tcu::TestStatus::fail("Something went really wrong");
548 tcu::TestStatus StorageBufferTestInstance<T>::executeComputeTest(void)
550 ProtectedContext& ctx (m_protectedContext);
551 const vk::DeviceInterface& vk = ctx.getDeviceInterface();
552 const vk::VkDevice device = ctx.getDevice();
553 const vk::VkQueue queue = ctx.getQueue();
554 const deUint32 queueFamilyIndex = ctx.getQueueFamilyIndex();
556 const deUint32 testUniformSize = sizeof(m_testInput);
557 de::UniquePtr<vk::BufferWithMemory> testUniform (makeBuffer(ctx,
561 vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
562 | vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
563 vk::MemoryRequirement::HostVisible));
565 // Set the test input uniform data
567 deMemcpy(testUniform->getAllocation().getHostPtr(), &m_testInput, testUniformSize);
568 vk::flushAlloc(vk, device, testUniform->getAllocation());
571 const deUint32 testBufferSize = sizeof(ValidationDataStorage<T>);
572 de::MovePtr<vk::BufferWithMemory> testBuffer (makeBuffer(ctx,
576 vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
577 | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT,
578 vk::MemoryRequirement::Protected));
579 de::MovePtr<vk::BufferWithMemory> testBufferSource (makeBuffer(ctx,
583 vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
584 | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT,
585 vk::MemoryRequirement::Protected));
587 vk::Unique<vk::VkShaderModule> testShader (vk::createShaderModule(vk, device, ctx.getBinaryCollection().get("TestShader"), 0));
589 // Create descriptors
590 vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(vk::DescriptorSetLayoutBuilder()
591 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
592 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
593 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
595 vk::Unique<vk::VkDescriptorPool> descriptorPool(vk::DescriptorPoolBuilder()
596 .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
597 .addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u)
598 .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u)
599 .build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
600 vk::Unique<vk::VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
602 // Update descriptor set information
604 vk::VkDescriptorBufferInfo descTestBuffer = makeDescriptorBufferInfo(**testBuffer, 0, testBufferSize);
605 vk::VkDescriptorBufferInfo descTestUniform = makeDescriptorBufferInfo(**testUniform, 0, testUniformSize);
606 vk::VkDescriptorBufferInfo descTestBufferSource = makeDescriptorBufferInfo(**testBufferSource, 0, testBufferSize);
608 vk::DescriptorSetUpdateBuilder()
609 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descTestBuffer)
610 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &descTestUniform)
611 .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descTestBufferSource)
616 // Build and execute test
618 const vk::Unique<vk::VkFence> fence (vk::createFence(vk, device));
619 vk::Unique<vk::VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout));
620 vk::Unique<vk::VkPipeline> SSBOPipeline (makeComputePipeline(vk, device, *pipelineLayout, *testShader, DE_NULL));
621 vk::Unique<vk::VkCommandPool> cmdPool (makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex));
622 vk::Unique<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
623 deUint32 dispatchCount = (m_testType == SSBO_ATOMIC) ? 4u : 1u;
625 beginCommandBuffer(vk, *cmdBuffer);
627 if (m_testType == SSBO_READ || m_testType == SSBO_ATOMIC)
629 vk::VkBuffer targetBuffer = (m_testType == SSBO_ATOMIC) ? **testBuffer : **testBufferSource;
630 addBufferCopyCmd(vk, *cmdBuffer, queueFamilyIndex, **testUniform, targetBuffer, testUniformSize);
633 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *SSBOPipeline);
634 vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
636 vk.cmdDispatch(*cmdBuffer, dispatchCount, 1u, 1u);
638 endCommandBuffer(vk, *cmdBuffer);
639 VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull));
642 ctx.getTestContext().getLog()
643 << tcu::TestLog::Message << "Input values: \n"
644 << "1: " << m_testInput << "\n"
645 << tcu::TestLog::EndMessage;
648 if (m_validator.validateBuffer(ctx, **testBuffer))
649 return tcu::TestStatus::pass("Everything went OK");
651 return tcu::TestStatus::fail("Something went really wrong");
655 tcu::TestStatus StorageBufferTestInstance<T>::iterate(void)
657 switch (m_shaderType)
659 case glu::SHADERTYPE_FRAGMENT: return executeFragmentTest();
660 case glu::SHADERTYPE_COMPUTE: return executeComputeTest();
662 DE_FATAL("Incorrect shader type"); return tcu::TestStatus::fail("");
666 tcu::TestCaseGroup* createSpecifiedStorageBufferTests (tcu::TestContext& testCtx,
667 const std::string groupName,
668 SSBOTestType testType,
669 const glu::ShaderType shaderType,
670 const ValidationDataStorage<tcu::UVec4> testData[],
673 const std::string testTypeStr = getSSBOTypeString(testType);
674 const std::string description = "Storage buffer " + testTypeStr + " tests";
675 de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, groupName.c_str(), description.c_str()));
677 for (size_t ndx = 0; ndx < testCount; ++ndx)
679 const std::string name = testTypeStr + "_" + de::toString(ndx + 1);
680 testGroup->addChild(new StorageBufferTestCase<tcu::UVec4>(testCtx, testType, shaderType, name.c_str(), testData[ndx].values, testData[ndx], vk::VK_FORMAT_R32G32B32A32_UINT));
683 return testGroup.release();
686 tcu::TestCaseGroup* createRandomizedBufferTests (tcu::TestContext& testCtx, SSBOTestType testType, const glu::ShaderType shaderType, size_t testCount)
688 de::Random rnd (testCtx.getCommandLine().getBaseSeed());
689 std::vector<ValidationDataStorage<tcu::UVec4> > testData;
690 testData.resize(testCount);
692 for (size_t ndx = 0; ndx < testCount; ++ndx)
693 for (deUint32 compIdx = 0; compIdx < 4; ++compIdx)
694 testData[ndx].values[compIdx] = rnd.getUint32();
696 return createSpecifiedStorageBufferTests(testCtx, "random", testType, shaderType, testData.data(), testData.size());
699 tcu::TestCaseGroup* createRWStorageBufferTests (tcu::TestContext& testCtx,
700 const std::string groupName,
701 const std::string groupDescription,
702 SSBOTestType testType,
703 const ValidationDataStorage<tcu::UVec4> testData[],
706 de::MovePtr<tcu::TestCaseGroup> ssboRWTestGroup (new tcu::TestCaseGroup(testCtx, groupName.c_str(), groupDescription.c_str()));
708 glu::ShaderType shaderTypes[] = {
709 glu::SHADERTYPE_FRAGMENT,
710 glu::SHADERTYPE_COMPUTE
713 for (int shaderNdx = 0; shaderNdx < DE_LENGTH_OF_ARRAY(shaderTypes); ++shaderNdx)
715 const glu::ShaderType shaderType = shaderTypes[shaderNdx];
716 const std::string shaderName = glu::getShaderTypeName(shaderType);
717 const std::string shaderGroupDesc = "Storage buffer tests for shader type: " + shaderName;
718 de::MovePtr<tcu::TestCaseGroup> testShaderGroup (new tcu::TestCaseGroup(testCtx, shaderName.c_str(), shaderGroupDesc.c_str()));
720 testShaderGroup->addChild(createSpecifiedStorageBufferTests(testCtx, "static", testType, shaderType, testData, testCount));
721 testShaderGroup->addChild(createRandomizedBufferTests(testCtx, testType, shaderType, RANDOM_TEST_COUNT));
722 ssboRWTestGroup->addChild(testShaderGroup.release());
725 return ssboRWTestGroup.release();
728 void calculateAtomicOpData (SSBOAtomicType type,
729 const tcu::UVec4& inputValue,
730 const deUint32 atomicArg,
731 std::string& atomicCall,
732 tcu::UVec4& refValue,
733 const deUint32 swapNdx = 0)
739 refValue = inputValue + tcu::UVec4(atomicArg);
740 atomicCall = "atomicAdd(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);";
745 refValue = tcu::UVec4(std::min(inputValue.x(), atomicArg), std::min(inputValue.y(), atomicArg), std::min(inputValue.z(), atomicArg), std::min(inputValue.w(), atomicArg));
746 atomicCall = "atomicMin(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);";
751 refValue = tcu::UVec4(std::max(inputValue.x(), atomicArg), std::max(inputValue.y(), atomicArg), std::max(inputValue.z(), atomicArg), std::max(inputValue.w(), atomicArg));
752 atomicCall = "atomicMax(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);";
757 refValue = tcu::UVec4(inputValue.x() & atomicArg, inputValue.y() & atomicArg, inputValue.z() & atomicArg, inputValue.w() & atomicArg);
758 atomicCall = "atomicAnd(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);";
763 refValue = tcu::UVec4(inputValue.x() | atomicArg, inputValue.y() | atomicArg, inputValue.z() | atomicArg, inputValue.w() | atomicArg);
764 atomicCall = "atomicOr(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);";
769 refValue = tcu::UVec4(inputValue.x() ^ atomicArg, inputValue.y() ^ atomicArg, inputValue.z() ^ atomicArg, inputValue.w() ^ atomicArg);
770 atomicCall = "atomicXor(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);";
773 case ATOMIC_EXCHANGE:
775 refValue = tcu::UVec4(atomicArg);
776 atomicCall = "atomicExchange(protectedTestResultBuffer[i], " + de::toString(atomicArg) + "u);";
779 case ATOMIC_COMPSWAP:
781 int selectedNdx = swapNdx % 4;
782 deUint32 selectedChange = inputValue[selectedNdx];
784 refValue = inputValue;
785 refValue[selectedNdx] = atomicArg;
786 atomicCall = "atomicCompSwap(protectedTestResultBuffer[i], " + de::toString(selectedChange) + "u, " + de::toString(atomicArg) + "u);";
789 default: DE_FATAL("Incorrect atomic function type"); break;
796 tcu::TestCaseGroup* createReadStorageBufferTests (tcu::TestContext& testCtx)
798 const ValidationDataStorage<tcu::UVec4> testData[] = {
799 { tcu::UVec4(0u, 0u, 0u, 0u) }, { tcu::UVec4(1u, 0u, 0u, 0u) },
800 { tcu::UVec4(0u, 1u, 0u, 0u) }, { tcu::UVec4(0u, 0u, 1u, 0u) },
801 { tcu::UVec4(0u, 0u, 0u, 1u) }, { tcu::UVec4(1u, 1u, 1u, 1u) }
804 return createRWStorageBufferTests(testCtx, "ssbo_read", "Storage Buffer Read Tests", SSBO_READ, testData, DE_LENGTH_OF_ARRAY(testData));
807 tcu::TestCaseGroup* createWriteStorageBufferTests (tcu::TestContext& testCtx)
809 const ValidationDataStorage<tcu::UVec4> testData[] = {
810 { tcu::UVec4(0u, 0u, 0u, 0u) }, { tcu::UVec4(1u, 0u, 0u, 0u) },
811 { tcu::UVec4(0u, 1u, 0u, 0u) }, { tcu::UVec4(0u, 0u, 1u, 0u) },
812 { tcu::UVec4(0u, 0u, 0u, 1u) }, { tcu::UVec4(1u, 1u, 1u, 1u) }
815 return createRWStorageBufferTests(testCtx, "ssbo_write", "Storage Buffer Write Tests", SSBO_WRITE, testData, DE_LENGTH_OF_ARRAY(testData));
818 tcu::TestCaseGroup* createAtomicStorageBufferTests (tcu::TestContext& testctx)
821 const tcu::UVec4 input;
822 const deUint32 atomicArg;
823 const deUint32 swapNdx;
825 { tcu::UVec4(0u, 1u, 2u, 3u), 10u, 0u },
826 { tcu::UVec4(10u, 20u, 30u, 40u), 3u, 2u },
827 { tcu::UVec4(800u, 400u, 230u, 999u), 50u, 3u },
828 { tcu::UVec4(100800u, 233400u, 22230u, 77999u), 800u, 1u },
831 SSBOAtomicType testTypes[] = {
842 glu::ShaderType shaderTypes[] = {
843 glu::SHADERTYPE_FRAGMENT,
844 glu::SHADERTYPE_COMPUTE
847 de::Random rnd (testctx.getCommandLine().getBaseSeed());
848 de::MovePtr<tcu::TestCaseGroup> ssboAtomicTests (new tcu::TestCaseGroup(testctx, "ssbo_atomic", "Storage Buffer Atomic Tests"));
850 for (int shaderNdx = 0; shaderNdx < DE_LENGTH_OF_ARRAY(shaderTypes); ++shaderNdx)
852 const glu::ShaderType shaderType = shaderTypes[shaderNdx];
853 const std::string shaderName = glu::getShaderTypeName(shaderType);
854 const std::string shaderDesc = "Storage Buffer Atomic Tests for shader type: " + shaderName;
855 de::MovePtr<tcu::TestCaseGroup> atomicShaderGroup (new tcu::TestCaseGroup(testctx, shaderName.c_str(), shaderDesc.c_str()));
857 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(testTypes); ++typeNdx)
859 SSBOAtomicType atomicType = testTypes[typeNdx];
860 const std::string atomicTypeStr = getSSBOAtomicTypeString(atomicType);
861 const std::string atomicDesc = "Storage Buffer Atomic Tests: " + atomicTypeStr;
863 de::MovePtr<tcu::TestCaseGroup> staticTests (new tcu::TestCaseGroup(testctx, "static", (atomicDesc + " with static input").c_str()));
864 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(testData); ++ndx)
866 const std::string name = "atomic_" + atomicTypeStr + "_" + de::toString(ndx + 1);
867 const tcu::UVec4& inputValue = testData[ndx].input;
868 const deUint32& atomicArg = testData[ndx].atomicArg;
869 std::string atomicCall;
872 calculateAtomicOpData(atomicType, inputValue, atomicArg, atomicCall, refValue, testData[ndx].swapNdx);
874 ValidationDataStorage<tcu::UVec4> validationData = { refValue };
875 staticTests->addChild(new StorageBufferTestCase<tcu::UVec4>(testctx, SSBO_ATOMIC, shaderType, name.c_str(), inputValue, validationData, vk::VK_FORMAT_R32G32B32A32_UINT, atomicCall));
878 de::MovePtr<tcu::TestCaseGroup> randomTests (new tcu::TestCaseGroup(testctx, "random", (atomicDesc + " with random input").c_str()));
879 for (int ndx = 0; ndx < RANDOM_TEST_COUNT; ndx++)
881 const std::string name = "atomic_" + atomicTypeStr + "_" + de::toString(ndx + 1);
882 deUint32 atomicArg = rnd.getUint16();
883 tcu::UVec4 inputValue;
885 std::string atomicCall;
887 for (int i = 0; i < 4; i++)
888 inputValue[i] = rnd.getUint16();
890 calculateAtomicOpData(atomicType, inputValue, atomicArg, atomicCall, refValue, ndx);
892 ValidationDataStorage<tcu::UVec4> validationData = { refValue };
893 randomTests->addChild(new StorageBufferTestCase<tcu::UVec4>(testctx, SSBO_ATOMIC, shaderType, name.c_str(), inputValue, validationData, vk::VK_FORMAT_R32G32B32A32_UINT, atomicCall));
897 de::MovePtr<tcu::TestCaseGroup> atomicTests (new tcu::TestCaseGroup(testctx, atomicTypeStr.c_str(), atomicDesc.c_str()));
898 atomicTests->addChild(staticTests.release());
899 atomicTests->addChild(randomTests.release());
900 atomicShaderGroup->addChild(atomicTests.release());
902 ssboAtomicTests->addChild(atomicShaderGroup.release());
905 return ssboAtomicTests.release();