1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2023 LunarG, Inc.
6  * Copyright (c) 2023 Nintendo
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 Shader Object Create Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktShaderObjectCreateTests.hpp"
26 #include "deUniquePtr.hpp"
27 #include "tcuTestCase.hpp"
28 #include "vktTestCase.hpp"
29 #include "vkQueryUtil.hpp"
30 #include "vktCustomInstancesDevices.hpp"
31 #include "tcuCommandLine.hpp"
32 #include "vkBufferWithMemory.hpp"
33 #include "vkRefUtil.hpp"
34 #include "deRandom.hpp"
35 #include "vktShaderObjectCreateUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 
38 namespace vkt
39 {
40 namespace ShaderObject
41 {
42 
43 namespace
44 {
45 
46 class ShaderObjectCreateInstance : public vkt::TestInstance
47 {
48 public:
ShaderObjectCreateInstance(Context & context,const bool useMeshShaders)49     ShaderObjectCreateInstance(Context &context, const bool useMeshShaders)
50         : vkt::TestInstance(context)
51         , m_useMeshShaders(useMeshShaders)
52     {
53     }
~ShaderObjectCreateInstance(void)54     virtual ~ShaderObjectCreateInstance(void)
55     {
56     }
57 
58     tcu::TestStatus iterate(void) override;
59 
60 private:
61     const bool m_useMeshShaders;
62 };
63 
iterate(void)64 tcu::TestStatus ShaderObjectCreateInstance::iterate(void)
65 {
66     const vk::VkInstance instance = m_context.getInstance();
67     const vk::InstanceDriver instanceDriver(m_context.getPlatformInterface(), instance);
68     const vk::DeviceInterface &vk    = m_context.getDeviceInterface();
69     const vk::VkDevice device        = m_context.getDevice();
70     tcu::TestLog &log                = m_context.getTestContext().getLog();
71     const bool tessellationSupported = m_context.getDeviceFeatures().tessellationShader;
72     const bool geometrySupported     = m_context.getDeviceFeatures().geometryShader;
73 
74     const auto &binaries = m_context.getBinaryCollection();
75     const auto &vert     = binaries.get("vert");
76     const auto &tesc     = binaries.get("tesc");
77     const auto &tese     = binaries.get("tese");
78     const auto &geom     = binaries.get("geom");
79     const auto &frag     = binaries.get("frag");
80     const auto &comp     = binaries.get("comp");
81 
82     const vk::VkDescriptorSetLayoutBinding layoutBinding = {
83         0u,                                    // uint32_t binding;
84         vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, // VkDescriptorType descriptorType;
85         1u,                                    // uint32_t arraySize;
86         vk::VK_SHADER_STAGE_COMPUTE_BIT,       // VkShaderStageFlags stageFlags;
87         DE_NULL                                // const VkSampler* pImmutableSamplers;
88     };
89 
90     const vk::VkDescriptorSetLayoutCreateInfo descriptorLayoutParams = {
91         vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType;
92         DE_NULL,                                                 // const void* pNext;
93         (vk::VkDescriptorSetLayoutCreateFlags)0,                 // VkDescriptorSetLayoutCreateFlags flags;
94         1u,                                                      // uint32_t count;
95         &layoutBinding                                           // const VkDescriptorSetLayoutBinding pBinding;
96     };
97 
98     const auto descriptorSetLayout = vk::createDescriptorSetLayout(vk, device, &descriptorLayoutParams);
99 
100     // Todo: remove const_cast if spec is updated
101     vk::VkDescriptorSetLayout *setLayout = const_cast<vk::VkDescriptorSetLayout *>(&descriptorSetLayout.get());
102 
103     std::vector<vk::VkShaderCreateInfoEXT> shaderCreateInfos = {
104         {
105             vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, // VkStructureType sType;
106             DE_NULL,                                      // const void* pNext;
107             0u,                                           // VkShaderCreateFlagsEXT flags;
108             vk::VK_SHADER_STAGE_VERTEX_BIT,               // VkShaderStageFlagBits stage;
109             vk::getShaderObjectNextStages(vk::VK_SHADER_STAGE_VERTEX_BIT, tessellationSupported,
110                                           geometrySupported), // VkShaderStageFlags nextStage;
111             vk::VK_SHADER_CODE_TYPE_SPIRV_EXT,                // VkShaderCodeTypeEXT codeType;
112             vert.getSize(),                                   // size_t codeSize;
113             vert.getBinary(),                                 // const void* pCode;
114             "main",                                           // const char* pName;
115             0u,                                               // uint32_t setLayoutCount;
116             DE_NULL,                                          // VkDescriptorSetLayout* pSetLayouts;
117             0u,                                               // uint32_t pushConstantRangeCount;
118             DE_NULL,                                          // const VkPushConstantRange* pPushConstantRanges;
119             DE_NULL,                                          // const VkSpecializationInfo* pSpecializationInfo;
120         },
121         {
122             vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, // VkStructureType sType;
123             DE_NULL,                                      // const void* pNext;
124             0u,                                           // VkShaderCreateFlagsEXT flags;
125             vk::VK_SHADER_STAGE_FRAGMENT_BIT,             // VkShaderStageFlagBits stage;
126             vk::getShaderObjectNextStages(vk::VK_SHADER_STAGE_FRAGMENT_BIT, tessellationSupported,
127                                           geometrySupported), // VkShaderStageFlags nextStage;
128             vk::VK_SHADER_CODE_TYPE_SPIRV_EXT,                // VkShaderCodeTypeEXT codeType;
129             frag.getSize(),                                   // size_t codeSize;
130             frag.getBinary(),                                 // const void* pCode;
131             "main",                                           // const char* pName;
132             0u,                                               // uint32_t setLayoutCount;
133             DE_NULL,                                          // VkDescriptorSetLayout* pSetLayouts;
134             0u,                                               // uint32_t pushConstantRangeCount;
135             DE_NULL,                                          // const VkPushConstantRange* pPushConstantRanges;
136             DE_NULL,                                          // const VkSpecializationInfo* pSpecializationInfo;
137         },
138         {
139             vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, // VkStructureType sType;
140             DE_NULL,                                      // const void* pNext;
141             0u,                                           // VkShaderCreateFlagsEXT flags;
142             vk::VK_SHADER_STAGE_COMPUTE_BIT,              // VkShaderStageFlagBits stage;
143             0u,                                           // VkShaderStageFlags nextStage;
144             vk::VK_SHADER_CODE_TYPE_SPIRV_EXT,            // VkShaderCodeTypeEXT codeType;
145             comp.getSize(),                               // size_t codeSize;
146             comp.getBinary(),                             // const void* pCode;
147             "main",                                       // const char* pName;
148             1u,                                           // uint32_t setLayoutCount;
149             setLayout,                                    // VkDescriptorSetLayout* pSetLayouts;
150             0u,                                           // uint32_t pushConstantRangeCount;
151             DE_NULL,                                      // const VkPushConstantRange* pPushConstantRanges;
152             DE_NULL,                                      // const VkSpecializationInfo* pSpecializationInfo;
153         },
154     };
155 
156     if (m_context.getDeviceFeatures().tessellationShader)
157     {
158         shaderCreateInfos.push_back({
159             vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, // VkStructureType sType;
160             DE_NULL,                                      // const void* pNext;
161             0u,                                           // VkShaderCreateFlagsEXT flags;
162             vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, // VkShaderStageFlagBits stage;
163             vk::getShaderObjectNextStages(vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, tessellationSupported,
164                                           geometrySupported), // VkShaderStageFlags nextStage;
165             vk::VK_SHADER_CODE_TYPE_SPIRV_EXT,                // VkShaderCodeTypeEXT codeType;
166             tesc.getSize(),                                   // size_t codeSize;
167             tesc.getBinary(),                                 // const void* pCode;
168             "main",                                           // const char* pName;
169             0u,                                               // uint32_t setLayoutCount;
170             DE_NULL,                                          // VkDescriptorSetLayout* pSetLayouts;
171             0u,                                               // uint32_t pushConstantRangeCount;
172             DE_NULL,                                          // const VkPushConstantRange* pPushConstantRanges;
173             DE_NULL,                                          // const VkSpecializationInfo* pSpecializationInfo;
174         });
175         shaderCreateInfos.push_back({
176             vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT,    // VkStructureType sType;
177             DE_NULL,                                         // const void* pNext;
178             0u,                                              // VkShaderCreateFlagsEXT flags;
179             vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, // VkShaderStageFlagBits stage;
180             vk::getShaderObjectNextStages(vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, tessellationSupported,
181                                           geometrySupported), // VkShaderStageFlags nextStage;
182             vk::VK_SHADER_CODE_TYPE_SPIRV_EXT,                // VkShaderCodeTypeEXT codeType;
183             tese.getSize(),                                   // size_t codeSize;
184             tese.getBinary(),                                 // const void* pCode;
185             "main",                                           // const char* pName;
186             0u,                                               // uint32_t setLayoutCount;
187             DE_NULL,                                          // VkDescriptorSetLayout* pSetLayouts;
188             0u,                                               // uint32_t pushConstantRangeCount;
189             DE_NULL,                                          // const VkPushConstantRange* pPushConstantRanges;
190             DE_NULL,                                          // const VkSpecializationInfo* pSpecializationInfo;
191         });
192     }
193 
194     if (m_context.getDeviceFeatures().geometryShader)
195     {
196         shaderCreateInfos.push_back({
197             vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, // VkStructureType sType;
198             DE_NULL,                                      // const void* pNext;
199             0u,                                           // VkShaderCreateFlagsEXT flags;
200             vk::VK_SHADER_STAGE_GEOMETRY_BIT,             // VkShaderStageFlagBits stage;
201             vk::getShaderObjectNextStages(vk::VK_SHADER_STAGE_GEOMETRY_BIT, tessellationSupported,
202                                           geometrySupported), // VkShaderStageFlags nextStage;
203             vk::VK_SHADER_CODE_TYPE_SPIRV_EXT,                // VkShaderCodeTypeEXT codeType;
204             geom.getSize(),                                   // size_t codeSize;
205             geom.getBinary(),                                 // const void* pCode;
206             "main",                                           // const char* pName;
207             0u,                                               // uint32_t setLayoutCount;
208             DE_NULL,                                          // VkDescriptorSetLayout* pSetLayouts;
209             0u,                                               // uint32_t pushConstantRangeCount;
210             DE_NULL,                                          // const VkPushConstantRange* pPushConstantRanges;
211             DE_NULL,                                          // const VkSpecializationInfo* pSpecializationInfo;
212         });
213     }
214 
215     if (m_useMeshShaders)
216     {
217         const auto &mesh = binaries.get("mesh");
218         const auto &task = binaries.get("task");
219         if (m_context.getMeshShaderFeaturesEXT().meshShader)
220         {
221             shaderCreateInfos.push_back({
222                 vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, // VkStructureType sType;
223                 DE_NULL,                                      // const void* pNext;
224                 0u,                                           // VkShaderCreateFlagsEXT flags;
225                 vk::VK_SHADER_STAGE_MESH_BIT_EXT,             // VkShaderStageFlagBits stage;
226                 0u,                                           // VkShaderStageFlags nextStage;
227                 vk::VK_SHADER_CODE_TYPE_SPIRV_EXT,            // VkShaderCodeTypeEXT codeType;
228                 mesh.getSize(),                               // size_t codeSize;
229                 mesh.getBinary(),                             // const void* pCode;
230                 "main",                                       // const char* pName;
231                 0u,                                           // uint32_t setLayoutCount;
232                 DE_NULL,                                      // VkDescriptorSetLayout* pSetLayouts;
233                 0u,                                           // uint32_t pushConstantRangeCount;
234                 DE_NULL,                                      // const VkPushConstantRange* pPushConstantRanges;
235                 DE_NULL,                                      // const VkSpecializationInfo* pSpecializationInfo;
236             });
237         }
238 
239         if (m_context.getMeshShaderFeaturesEXT().taskShader)
240         {
241             shaderCreateInfos.push_back({
242                 vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, // VkStructureType sType;
243                 DE_NULL,                                      // const void* pNext;
244                 0u,                                           // VkShaderCreateFlagsEXT flags;
245                 vk::VK_SHADER_STAGE_TASK_BIT_EXT,             // VkShaderStageFlagBits stage;
246                 0u,                                           // VkShaderStageFlags nextStage;
247                 vk::VK_SHADER_CODE_TYPE_SPIRV_EXT,            // VkShaderCodeTypeEXT codeType;
248                 task.getSize(),                               // size_t codeSize;
249                 task.getBinary(),                             // const void* pCode;
250                 "main",                                       // const char* pName;
251                 0u,                                           // uint32_t setLayoutCount;
252                 DE_NULL,                                      // VkDescriptorSetLayout* pSetLayouts;
253                 0u,                                           // uint32_t pushConstantRangeCount;
254                 DE_NULL,                                      // const VkPushConstantRange* pPushConstantRanges;
255                 DE_NULL,                                      // const VkSpecializationInfo* pSpecializationInfo;
256             });
257         }
258     }
259 
260     std::vector<vk::VkShaderEXT> shadersSeparate(shaderCreateInfos.size());
261     std::vector<vk::VkShaderEXT> shadersTogether(shaderCreateInfos.size());
262     for (uint32_t i = 0; i < (uint32_t)shaderCreateInfos.size(); ++i)
263     {
264         vk.createShadersEXT(device, 1, &shaderCreateInfos[i], DE_NULL, &shadersSeparate[i]);
265     }
266     vk.createShadersEXT(device, (uint32_t)shaderCreateInfos.size(), &shaderCreateInfos[0], DE_NULL,
267                         &shadersTogether[0]);
268 
269     bool match = true;
270     for (uint32_t i = 0; i < (uint32_t)shaderCreateInfos.size(); ++i)
271     {
272         size_t dataSizeSeparate = 0;
273         size_t dataSizeTogether = 0;
274         vk.getShaderBinaryDataEXT(device, shadersSeparate[i], &dataSizeSeparate, DE_NULL);
275         vk.getShaderBinaryDataEXT(device, shadersTogether[i], &dataSizeTogether, DE_NULL);
276         if (dataSizeSeparate != dataSizeTogether)
277         {
278             log << tcu::TestLog::Message << "Data size of shader created separately is " << dataSizeSeparate
279                 << ", but data size of shader created in the same call with others is " << dataSizeTogether
280                 << tcu::TestLog::EndMessage;
281             match = false;
282             break;
283         }
284         std::vector<uint8_t> dataSeparate(dataSizeSeparate);
285         std::vector<uint8_t> dataTogether(dataSizeTogether);
286         vk.getShaderBinaryDataEXT(device, shadersSeparate[i], &dataSizeSeparate, &dataSeparate[0]);
287         vk.getShaderBinaryDataEXT(device, shadersTogether[i], &dataSizeTogether, &dataTogether[0]);
288         for (uint32_t j = 0; j < dataSizeSeparate; ++j)
289         {
290             if (dataSeparate[j] != dataTogether[j])
291             {
292                 log << tcu::TestLog::Message
293                     << "Data of shader created separately and data of shader created in the same call with others does "
294                        "not match at index "
295                     << j << tcu::TestLog::EndMessage;
296                 match = false;
297                 break;
298             }
299         }
300         if (!match)
301             break;
302     }
303 
304     for (const auto &shader : shadersSeparate)
305         vk.destroyShaderEXT(device, shader, DE_NULL);
306     for (const auto &shader : shadersTogether)
307         vk.destroyShaderEXT(device, shader, DE_NULL);
308 
309     if (!match)
310         return tcu::TestStatus::fail("Fail");
311 
312     return tcu::TestStatus::pass("Pass");
313 }
314 
315 class ShaderObjectCreateCase : public vkt::TestCase
316 {
317 public:
ShaderObjectCreateCase(tcu::TestContext & testCtx,const std::string & name,const bool useMeshShaders)318     ShaderObjectCreateCase(tcu::TestContext &testCtx, const std::string &name, const bool useMeshShaders)
319         : vkt::TestCase(testCtx, name)
320         , m_useMeshShaders(useMeshShaders)
321     {
322     }
~ShaderObjectCreateCase(void)323     virtual ~ShaderObjectCreateCase(void)
324     {
325     }
326 
327     void checkSupport(vkt::Context &context) const override;
328     virtual void initPrograms(vk::SourceCollections &programCollection) const override;
createInstance(Context & context) const329     TestInstance *createInstance(Context &context) const override
330     {
331         return new ShaderObjectCreateInstance(context, m_useMeshShaders);
332     }
333 
334 private:
335     bool m_useMeshShaders;
336 };
337 
checkSupport(Context & context) const338 void ShaderObjectCreateCase::checkSupport(Context &context) const
339 {
340     context.requireDeviceFunctionality("VK_EXT_shader_object");
341 }
342 
initPrograms(vk::SourceCollections & programCollection) const343 void ShaderObjectCreateCase::initPrograms(vk::SourceCollections &programCollection) const
344 {
345     std::stringstream vert;
346     std::stringstream geom;
347     std::stringstream tesc;
348     std::stringstream tese;
349     std::stringstream frag;
350     std::stringstream comp;
351     std::stringstream mesh;
352     std::stringstream task;
353 
354     vert << "#version 450\n"
355          << "layout (location=0) in vec2 inPos;\n"
356          << "void main() {\n"
357          << "    vec2 pos = vec2(float(gl_VertexIndex & 1), float((gl_VertexIndex >> 1) & 1));\n"
358          << "    gl_Position = vec4(pos, 0.0f, 1.0f);\n"
359          << "}\n";
360 
361     tesc << "#version 450\n"
362          << "\n"
363          << "layout(vertices = 3) out;\n"
364          << "\n"
365          << "void main (void)\n"
366          << "{\n"
367          << "    gl_TessLevelInner[0] = 5.0;\n"
368          << "    gl_TessLevelInner[1] = 5.0;\n"
369          << "\n"
370          << "    gl_TessLevelOuter[0] = 5.0;\n"
371          << "    gl_TessLevelOuter[1] = 5.0;\n"
372          << "    gl_TessLevelOuter[2] = 5.0;\n"
373          << "    gl_TessLevelOuter[3] = 5.0;\n"
374          << "}\n";
375 
376     tese << "#version 450\n"
377          << "\n"
378          << "layout(quads) in;\n"
379          << "\n"
380          << "void main (void)\n"
381          << "{\n"
382          << "    highp float x = gl_TessCoord.x*2.0 - 1.0;\n"
383          << "    highp float y = gl_TessCoord.y*2.0 - 1.0;\n"
384          << "    gl_Position = vec4(x, y, 0.0, 1.0);\n"
385          << "}\n";
386 
387     geom << "#version 450\n"
388          << "layout(points) in;\n"
389          << "layout(points, max_vertices = 1) out;\n"
390          << "\n"
391          << "void main(void)\n"
392          << "{\n"
393          << "    gl_Position = gl_in[0].gl_Position;\n"
394          << "    EmitVertex();\n"
395          << "    EndPrimitive();\n"
396          << "}\n";
397 
398     frag << "#version 450\n"
399          << "layout (location=0) out vec4 outColor;\n"
400          << "void main() {\n"
401          << "    outColor = vec4(1.0f);\n"
402          << "}\n";
403 
404     comp << "#version 450\n"
405          << "layout(local_size_x=16, local_size_x=1, local_size_x=1) in;\n"
406          << "layout(binding = 0) buffer Output {\n"
407          << "    uint values[16];\n"
408          << "} buffer_out;\n\n"
409          << "void main() {\n"
410          << "    buffer_out.values[gl_LocalInvocationID.x] = gl_LocalInvocationID.x;\n"
411          << "}\n";
412 
413     mesh << "#version 460\n"
414          << "#extension GL_EXT_mesh_shader : require\n"
415          << "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
416          << "layout(max_vertices = 3) out;\n"
417          << "layout(max_primitives = 1) out;\n"
418          << "layout(triangles) out;\n"
419          << "void main() {\n"
420          << "      SetMeshOutputsEXT(3,1);\n"
421          << "      gl_MeshVerticesEXT[0].gl_Position = vec4(-1.0, -1.0, 0, 1);\n"
422          << "      gl_MeshVerticesEXT[1].gl_Position = vec4( 1.0, -1.0, 0, 1);\n"
423          << "      gl_MeshVerticesEXT[2].gl_Position = vec4( 0.0,  1.0, 0, 1);\n"
424          << "      gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0,1,2);\n"
425          << "}\n";
426 
427     task << "#version 450\n"
428          << "#extension GL_EXT_mesh_shader : enable\n"
429          << "layout (local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
430          << "struct TaskData {\n"
431          << "    int t;\n"
432          << "};\n"
433          << "taskPayloadSharedEXT TaskData td;\n"
434          << "void main ()\n"
435          << "{\n"
436          << "    td.t = 1;\n"
437          << "    EmitMeshTasksEXT(1u, 1u, 1u);\n"
438          << "}\n";
439 
440     programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
441     programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tesc.str());
442     programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(tese.str());
443     programCollection.glslSources.add("geom") << glu::GeometrySource(geom.str());
444     programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
445     programCollection.glslSources.add("comp") << glu::ComputeSource(comp.str());
446     if (m_useMeshShaders)
447     {
448         programCollection.glslSources.add("mesh")
449             << glu::MeshSource(mesh.str())
450             << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
451         programCollection.glslSources.add("task")
452             << glu::TaskSource(task.str())
453             << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
454     }
455 }
456 
457 class ShaderObjectStageInstance : public vkt::TestInstance
458 {
459 public:
ShaderObjectStageInstance(Context & context,const vk::VkShaderStageFlagBits stage,const bool fail,const bool useMeshShaders)460     ShaderObjectStageInstance(Context &context, const vk::VkShaderStageFlagBits stage, const bool fail,
461                               const bool useMeshShaders)
462         : vkt::TestInstance(context)
463         , m_stage(stage)
464         , m_fail(fail)
465         , m_useMeshShaders(useMeshShaders)
466     {
467     }
468 
~ShaderObjectStageInstance(void)469     virtual ~ShaderObjectStageInstance(void)
470     {
471     }
472 
473     tcu::TestStatus iterate(void) override;
474 
475 private:
476     const vk::VkShaderStageFlagBits m_stage;
477     const bool m_fail;
478     const bool m_useMeshShaders;
479 };
480 
iterate(void)481 tcu::TestStatus ShaderObjectStageInstance::iterate(void)
482 {
483     const vk::VkInstance instance = m_context.getInstance();
484     const vk::InstanceDriver instanceDriver(m_context.getPlatformInterface(), instance);
485     const vk::DeviceInterface &vk    = m_context.getDeviceInterface();
486     const vk::VkDevice device        = m_context.getDevice();
487     tcu::TestLog &log                = m_context.getTestContext().getLog();
488     const bool tessellationSupported = m_context.getDeviceFeatures().tessellationShader;
489     const bool geometrySupported     = m_context.getDeviceFeatures().geometryShader;
490 
491     const auto &binaries = m_context.getBinaryCollection();
492 
493     de::Random random(102030);
494     std::vector<vk::VkShaderStageFlagBits> stages = {
495         vk::VK_SHADER_STAGE_VERTEX_BIT,
496         vk::VK_SHADER_STAGE_FRAGMENT_BIT,
497         vk::VK_SHADER_STAGE_COMPUTE_BIT,
498     };
499     if (m_context.getDeviceFeatures().tessellationShader)
500     {
501         stages.push_back(vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
502         stages.push_back(vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
503     }
504     if (m_context.getDeviceFeatures().geometryShader)
505     {
506         stages.push_back(vk::VK_SHADER_STAGE_GEOMETRY_BIT);
507     }
508     if (m_useMeshShaders)
509     {
510         if (m_context.getMeshShaderFeaturesEXT().meshShader)
511             stages.push_back(vk::VK_SHADER_STAGE_MESH_BIT_EXT);
512         if (m_context.getMeshShaderFeaturesEXT().taskShader)
513             stages.push_back(vk::VK_SHADER_STAGE_TASK_BIT_EXT);
514     }
515 
516     const uint32_t count = m_stage == vk::VK_SHADER_STAGE_ALL ? 50 : 10;
517 
518     const vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(
519         vk::DescriptorSetLayoutBuilder()
520             .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
521             .build(vk, device));
522 
523     std::vector<vk::VkShaderCreateInfoEXT> shaderCreateInfos;
524 
525     for (uint32_t i = 0; i < count; ++i)
526     {
527         vk::VkShaderStageFlagBits stage;
528         if (m_stage == vk::VK_SHADER_STAGE_ALL)
529             stage = stages[random.getUint32() % stages.size()];
530         else
531             stage = m_stage;
532 
533         bool useLayout = stage == vk::VK_SHADER_STAGE_COMPUTE_BIT;
534 
535         const auto &src = binaries.get(getShaderName(stage) + std::to_string(i % 10));
536         shaderCreateInfos.push_back({
537             vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, // VkStructureType sType;
538             DE_NULL,                                      // const void* pNext;
539             0u,                                           // VkShaderCreateFlagsEXT flags;
540             stage,                                        // VkShaderStageFlagBits stage;
541             vk::getShaderObjectNextStages(stage, tessellationSupported,
542                                           geometrySupported), // VkShaderStageFlags nextStage;
543             vk::VK_SHADER_CODE_TYPE_SPIRV_EXT,                // VkShaderCodeTypeEXT codeType;
544             src.getSize(),                                    // size_t codeSize;
545             src.getBinary(),                                  // const void* pCode;
546             "main",                                           // const char* pName;
547             useLayout ? 1u : 0u,                              // uint32_t setLayoutCount;
548             useLayout ? &*descriptorSetLayout : DE_NULL,      // VkDescriptorSetLayout* pSetLayouts;
549             0u,                                               // uint32_t pushConstantRangeCount;
550             DE_NULL,                                          // const VkPushConstantRange* pPushConstantRanges;
551             DE_NULL,                                          // const VkSpecializationInfo* pSpecializationInfo;
552         });
553     }
554 
555     std::vector<vk::VkShaderEXT> shaders(count, VK_NULL_HANDLE);
556     vk::VkResult result;
557     result = vk.createShadersEXT(device, count, &shaderCreateInfos[0], DE_NULL, &shaders[0]);
558     if (result != vk::VK_SUCCESS)
559     {
560         log << tcu::TestLog::Message << "vkCreateShadersEXT returned " << result << tcu::TestLog::EndMessage;
561         return tcu::TestStatus::fail("Fail");
562     }
563 
564     std::vector<size_t> binarySizes(count);
565     std::vector<std::vector<uint8_t>> binaryData(count);
566     for (size_t i = 0; i < count; ++i)
567     {
568         vk.getShaderBinaryDataEXT(device, shaders[i], &binarySizes[i], DE_NULL);
569         binaryData[i].resize(binarySizes[i]);
570         vk.getShaderBinaryDataEXT(device, shaders[i], &binarySizes[i], (void *)&binaryData[i][0]);
571     }
572 
573     for (const auto &shader : shaders)
574         vk.destroyShaderEXT(device, shader, DE_NULL);
575 
576     const uint32_t failIndex = random.getUint32() % count;
577 
578     for (uint32_t i = 0; i < count; ++i)
579     {
580         shaderCreateInfos[i].codeType = vk::VK_SHADER_CODE_TYPE_BINARY_EXT;
581         if (m_fail && failIndex == i)
582             shaderCreateInfos[i].codeSize = 1;
583         else
584             shaderCreateInfos[i].codeSize = binarySizes[i];
585         shaderCreateInfos[i].pCode = &binaryData[i][0];
586     }
587 
588     uint32_t garbage = 1234u;
589     std::vector<vk::VkShaderEXT> binaryShaders(count, garbage); // Fill with garbage
590     result = vk.createShadersEXT(device, count, &shaderCreateInfos[0], DE_NULL, &binaryShaders[0]);
591 
592     if (m_fail)
593     {
594         if (result != vk::VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT)
595         {
596             log << tcu::TestLog::Message << "Shader at index " << failIndex
597                 << "was created with size 0, but vkCreateShadersEXT returned " << result << tcu::TestLog::EndMessage;
598             return tcu::TestStatus::fail("Fail");
599         }
600 
601         for (uint32_t i = 0; i < failIndex; ++i)
602         {
603             if (binaryShaders[i] == garbage)
604             {
605                 log << tcu::TestLog::Message
606                     << "vkCreateShadersEXT returned VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT and failed at index "
607                     << failIndex << ", but shader at index " << i << "was not created" << tcu::TestLog::EndMessage;
608                 return tcu::TestStatus::fail("Fail");
609             }
610             vk.destroyShaderEXT(device, binaryShaders[i], DE_NULL);
611         }
612         if (binaryShaders[failIndex] != VK_NULL_HANDLE)
613         {
614             log << tcu::TestLog::Message
615                 << "vkCreateShadersEXT returned VK_ERROR_INCOMPATIBLE_SHADER_BINARY_EXT, creating shader at index "
616                 << failIndex << " failed, but the shader is not VK_NULL_HANDLE" << tcu::TestLog::EndMessage;
617             return tcu::TestStatus::fail("Fail");
618         }
619     }
620     else
621     {
622         if (result != vk::VK_SUCCESS)
623         {
624             log << tcu::TestLog::Message << "vkCreateShadersEXT returned " << result << tcu::TestLog::EndMessage;
625             return tcu::TestStatus::fail("Fail");
626         }
627 
628         for (const auto &shader : binaryShaders)
629             vk.destroyShaderEXT(device, shader, DE_NULL);
630     }
631 
632     return tcu::TestStatus::pass("Pass");
633 }
634 
635 class ShaderObjectStageCase : public vkt::TestCase
636 {
637 public:
ShaderObjectStageCase(tcu::TestContext & testCtx,const std::string & name,const vk::VkShaderStageFlagBits stage,const bool fail,const bool useMeshShaders)638     ShaderObjectStageCase(tcu::TestContext &testCtx, const std::string &name, const vk::VkShaderStageFlagBits stage,
639                           const bool fail, const bool useMeshShaders)
640         : vkt::TestCase(testCtx, name)
641         , m_stage(stage)
642         , m_fail(fail)
643         , m_useMeshShaders(useMeshShaders)
644     {
645     }
~ShaderObjectStageCase(void)646     virtual ~ShaderObjectStageCase(void)
647     {
648     }
649 
650     void checkSupport(vkt::Context &context) const override;
651     virtual void initPrograms(vk::SourceCollections &programCollection) const override;
createInstance(Context & context) const652     TestInstance *createInstance(Context &context) const override
653     {
654         return new ShaderObjectStageInstance(context, m_stage, m_fail, m_useMeshShaders);
655     }
656 
657 private:
658     const vk::VkShaderStageFlagBits m_stage;
659     const bool m_fail;
660     const bool m_useMeshShaders;
661 };
662 
checkSupport(Context & context) const663 void ShaderObjectStageCase::checkSupport(Context &context) const
664 {
665     context.requireDeviceFunctionality("VK_EXT_shader_object");
666     if (m_useMeshShaders)
667         context.requireDeviceFunctionality("VK_EXT_mesh_shader");
668 
669     if (m_stage == vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
670         m_stage == vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
671         context.requireDeviceCoreFeature(vkt::DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
672     if (m_stage == vk::VK_SHADER_STAGE_GEOMETRY_BIT)
673         context.requireDeviceCoreFeature(vkt::DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
674     if (m_stage == vk::VK_SHADER_STAGE_TASK_BIT_EXT && context.getMeshShaderFeaturesEXT().taskShader == VK_FALSE)
675         TCU_THROW(NotSupportedError, "Task shaders not supported");
676     if (m_stage == vk::VK_SHADER_STAGE_MESH_BIT_EXT && context.getMeshShaderFeaturesEXT().meshShader == VK_FALSE)
677         TCU_THROW(NotSupportedError, "Mesh shaders not supported");
678 }
679 
initPrograms(vk::SourceCollections & programCollection) const680 void ShaderObjectStageCase::initPrograms(vk::SourceCollections &programCollection) const
681 {
682     for (uint32_t i = 0; i < 10; ++i)
683     {
684         std::stringstream vert;
685         std::stringstream geom;
686         std::stringstream tesc;
687         std::stringstream tese;
688         std::stringstream frag;
689         std::stringstream comp;
690         std::stringstream mesh;
691         std::stringstream task;
692 
693         vert << "#version 450\n"
694              << "layout (location=0) in vec2 inPos;\n"
695              << "void main() {\n"
696              << "    vec2 pos = vec2(float(gl_VertexIndex & 1), float((gl_VertexIndex >> 1) & 1));\n"
697              << "    gl_Position = vec4(pos * float(" << i << "), 0.0f, 1.0f);\n"
698              << "}\n";
699 
700         tesc << "#version 450\n"
701              << "\n"
702              << "layout(vertices = 3) out;\n"
703              << "\n"
704              << "void main (void)\n"
705              << "{\n"
706              << "    gl_TessLevelInner[0] = 5.0 + float(" << i << ");\n"
707              << "    gl_TessLevelInner[1] = 5.0 + float(" << i << ");\n"
708              << "\n"
709              << "    gl_TessLevelOuter[0] = 5.0;\n"
710              << "    gl_TessLevelOuter[1] = 5.0;\n"
711              << "    gl_TessLevelOuter[2] = 5.0;\n"
712              << "    gl_TessLevelOuter[3] = 5.0;\n"
713              << "}\n";
714 
715         tese << "#version 450\n"
716              << "\n"
717              << "layout(quads) in;\n"
718              << "\n"
719              << "void main (void)\n"
720              << "{\n"
721              << "    highp float x = gl_TessCoord.x * float(" << i << ") - 1.0;\n"
722              << "    highp float y = gl_TessCoord.y * float(" << i << ") - 1.0;\n"
723              << "    gl_Position = vec4(x, y, 0.0, 1.0);\n"
724              << "}\n";
725 
726         geom << "#version 450\n"
727              << "layout(points) in;\n"
728              << "layout(points, max_vertices = 1) out;\n"
729              << "\n"
730              << "void main(void)\n"
731              << "{\n"
732              << "    gl_Position = gl_in[0].gl_Position;\n"
733              << "    gl_Position.xy += vec2(float(" << i << "));\n"
734              << "    EmitVertex();\n"
735              << "    EndPrimitive();\n"
736              << "}\n";
737 
738         frag << "#version 450\n"
739              << "layout (location=0) out vec4 outColor;\n"
740              << "void main() {\n"
741              << "    outColor = vec4(1.0f / (1.0f + float(" << i << ")));\n"
742              << "}\n";
743 
744         comp << "#version 450\n"
745              << "layout(local_size_x=16, local_size_x=1, local_size_x=1) in;\n"
746              << "layout(binding = 0) buffer Output {\n"
747              << "    uint values[16];\n"
748              << "} buffer_out;\n\n"
749              << "void main() {\n"
750              << "    buffer_out.values[gl_LocalInvocationID.x] = gl_LocalInvocationID.x + " << i << ";\n"
751              << "}\n";
752 
753         mesh << "#version 460\n"
754              << "#extension GL_EXT_mesh_shader : require\n"
755              << "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
756              << "layout(max_vertices = 3) out;\n"
757              << "layout(max_primitives = 1) out;\n"
758              << "layout(triangles) out;\n"
759              << "void main() {\n"
760              << "      SetMeshOutputsEXT(3,1);\n"
761              << "      gl_MeshVerticesEXT[0].gl_Position = vec4(-1.0, -1.0, 0, 1);\n"
762              << "      gl_MeshVerticesEXT[1].gl_Position = vec4( 1.0, -1.0, 0, 1);\n"
763              << "      gl_MeshVerticesEXT[2].gl_Position = vec4( 0.0,  1.0, 0, 1);\n"
764              << "      gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0,1,2);\n"
765              << "}\n";
766 
767         task << "#version 450\n"
768              << "#extension GL_EXT_mesh_shader : enable\n"
769              << "layout (local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
770              << "struct TaskData {\n"
771              << "    int t;\n"
772              << "};\n"
773              << "taskPayloadSharedEXT TaskData td;\n"
774              << "void main ()\n"
775              << "{\n"
776              << "    td.t = 1;\n"
777              << "    EmitMeshTasksEXT(1u, 1u, 1u);\n"
778              << "}\n";
779 
780         programCollection.glslSources.add("vert" + std::to_string(i)) << glu::VertexSource(vert.str());
781         programCollection.glslSources.add("tesc" + std::to_string(i)) << glu::TessellationControlSource(tesc.str());
782         programCollection.glslSources.add("tese" + std::to_string(i)) << glu::TessellationEvaluationSource(tese.str());
783         programCollection.glslSources.add("geom" + std::to_string(i)) << glu::GeometrySource(geom.str());
784         programCollection.glslSources.add("frag" + std::to_string(i)) << glu::FragmentSource(frag.str());
785         programCollection.glslSources.add("comp" + std::to_string(i)) << glu::ComputeSource(comp.str());
786         if (m_useMeshShaders)
787         {
788             programCollection.glslSources.add("mesh" + std::to_string(i))
789                 << glu::MeshSource(mesh.str())
790                 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
791             programCollection.glslSources.add("task" + std::to_string(i))
792                 << glu::TaskSource(task.str())
793                 << vk::ShaderBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
794         }
795     }
796 }
797 
798 } // namespace
799 
createShaderObjectCreateTests(tcu::TestContext & testCtx)800 tcu::TestCaseGroup *createShaderObjectCreateTests(tcu::TestContext &testCtx)
801 {
802     de::MovePtr<tcu::TestCaseGroup> createGroup(new tcu::TestCaseGroup(testCtx, "create"));
803 
804     de::MovePtr<tcu::TestCaseGroup> multipleGroup(new tcu::TestCaseGroup(testCtx, "multiple"));
805 
806     multipleGroup->addChild(new ShaderObjectCreateCase(testCtx, "all", false));
807     multipleGroup->addChild(new ShaderObjectCreateCase(testCtx, "all_with_mesh", true));
808 
809     createGroup->addChild(multipleGroup.release());
810 
811     const struct
812     {
813         vk::VkShaderStageFlagBits stage;
814         const bool useMeshShaders;
815         const char *name;
816     } stageTests[] = {
817         {vk::VK_SHADER_STAGE_VERTEX_BIT, false, "vert"},
818         {vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, false, "tesc"},
819         {vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, false, "tese"},
820         {vk::VK_SHADER_STAGE_GEOMETRY_BIT, false, "geom"},
821         {vk::VK_SHADER_STAGE_FRAGMENT_BIT, false, "frag"},
822         {vk::VK_SHADER_STAGE_COMPUTE_BIT, false, "comp"},
823         {vk::VK_SHADER_STAGE_MESH_BIT_EXT, true, "mesh"},
824         {vk::VK_SHADER_STAGE_TASK_BIT_EXT, true, "task"},
825         {vk::VK_SHADER_STAGE_ALL, false, "all"},
826         {vk::VK_SHADER_STAGE_ALL, true, "all_with_mesh"},
827     };
828 
829     const struct
830     {
831         bool fail;
832         const char *name;
833     } failTests[] = {
834         {false, "succeed"},
835         {true, "fail"},
836     };
837 
838     for (const auto &stage : stageTests)
839     {
840         de::MovePtr<tcu::TestCaseGroup> stageGroup(new tcu::TestCaseGroup(testCtx, stage.name));
841         for (const auto &failTest : failTests)
842         {
843             stageGroup->addChild(
844                 new ShaderObjectStageCase(testCtx, failTest.name, stage.stage, failTest.fail, stage.useMeshShaders));
845         }
846         createGroup->addChild(stageGroup.release());
847     }
848 
849     return createGroup.release();
850 }
851 
852 } // namespace ShaderObject
853 } // namespace vkt
854