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
getSSBOTestDescription(SSBOTestType type)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
getSSBOTypeString(SSBOTestType type)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
getShaderTypeString(const glu::ShaderType shaderType)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
getSSBOAtomicTypeString(SSBOAtomicType type)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
addBufferCopyCmd(const vk::DeviceInterface & vk,vk::VkCommandBuffer cmdBuffer,deUint32 queueFamilyIndex,vk::VkBuffer srcBuffer,vk::VkBuffer dstBuffer,deUint32 copySize)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:
StorageBufferTestCase(tcu::TestContext & testctx,const SSBOTestType testType,const glu::ShaderType shaderType,const char * name,const tcu::UVec4 testInput,ValidationDataStorage<T> validationData,const std::string & extraShader="")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 }
createInstance(Context & ctx) const223 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
~StorageBufferTestCase(void)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>
StorageBufferTestInstance(Context & ctx,const SSBOTestType testType,const glu::ShaderType shaderType,const tcu::UVec4 testInput,const BufferValidator<T> & validator)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>
initPrograms(vk::SourceCollections & programCollection) const255 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>
executeFragmentTest(void)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>
executeComputeTest(void)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>
iterate(void)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
createSpecifiedStorageBufferTests(tcu::TestContext & testCtx,const std::string groupName,SSBOTestType testType,const glu::ShaderType shaderType,const ValidationDataStorage<tcu::UVec4> testData[],size_t testCount)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
createRandomizedBufferTests(tcu::TestContext & testCtx,SSBOTestType testType,const glu::ShaderType shaderType,size_t testCount)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
createRWStorageBufferTests(tcu::TestContext & testCtx,const std::string groupName,const std::string groupDescription,SSBOTestType testType,const ValidationDataStorage<tcu::UVec4> testData[],size_t testCount)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
calculateAtomicOpData(SSBOAtomicType type,const tcu::UVec4 & inputValue,const deUint32 atomicArg,std::string & atomicCall,tcu::UVec4 & refValue,const deUint32 swapNdx=0)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
createReadStorageBufferTests(tcu::TestContext & testCtx)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
createWriteStorageBufferTests(tcu::TestContext & testCtx)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
createAtomicStorageBufferTests(tcu::TestContext & testctx)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