Merge "Remove EGL gles1.rgb565_window from mustpass" am: 7bff163e7f am: 8d0d1e55f9
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / pipeline / vktPipelineSpecConstantTests.cpp
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Pipeline specialization constants tests
22  *//*--------------------------------------------------------------------*/
23
24 #include "vktPipelineSpecConstantTests.hpp"
25 #include "vktTestCase.hpp"
26 #include "vktPipelineSpecConstantUtil.hpp"
27 #include "vktPipelineMakeUtil.hpp"
28
29 #include "tcuTestLog.hpp"
30 #include "tcuTexture.hpp"
31 #include "tcuFormatUtil.hpp"
32
33 #include "gluShaderUtil.hpp"
34
35 #include "vkBuilderUtil.hpp"
36 #include "vkPrograms.hpp"
37 #include "vkRefUtil.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkImageUtil.hpp"
40
41 #include "deUniquePtr.hpp"
42 #include "deStringUtil.hpp"
43
44 namespace vkt
45 {
46 namespace pipeline
47 {
48
49 using namespace vk;
50
51 namespace
52 {
53
54 static const char* const s_perVertexBlock =     "gl_PerVertex {\n"
55                                                                                         "    vec4 gl_Position;\n"
56                                                                                         "}";
57
58 //! Raw memory storage for values used in test cases.
59 //! We use it to simplify test case definitions where different types are expected in the result.
60 class GenericValue
61 {
62 public:
63         GenericValue (void) { clear(); }
64
65         //! Copy up to 'size' bytes of 'data'.
66         GenericValue (const void* data, const deUint32 size)
67         {
68                 DE_ASSERT(size <= sizeof(m_data));
69                 clear();
70                 deMemcpy(&m_data, data, size);
71         }
72
73 private:
74         deUint64 m_data;
75
76         void clear (void) { m_data = 0; }
77 };
78
79 inline GenericValue makeValueBool32      (const bool a)         { return GenericValue(&a, sizeof(a)); }
80 inline GenericValue makeValueInt32       (const deInt32 a)      { return GenericValue(&a, sizeof(a)); }
81 // \note deInt64 not tested
82 inline GenericValue makeValueUint32      (const deUint32 a)     { return GenericValue(&a, sizeof(a)); }
83 // \note deUint64 not tested
84 inline GenericValue makeValueFloat32 (const float a)    { return GenericValue(&a, sizeof(a)); }
85 inline GenericValue makeValueFloat64 (const double a)   { return GenericValue(&a, sizeof(a)); }
86
87 struct SpecConstant
88 {
89         deUint32                        specID;                         //!< specialization constant ID
90         std::string                     declarationCode;        //!< syntax to declare the constant, use ${ID} as an ID placeholder
91         deUint32                        size;                           //!< data size on the host, 0 = no specialized value
92         GenericValue            specValue;                      //!< specialized value passed by the API
93
94         SpecConstant (const deUint32 specID_, const std::string declarationCode_)
95                 : specID                        (specID_)
96                 , declarationCode       (declarationCode_)
97                 , size                          (0)
98                 , specValue                     ()
99         {
100         }
101
102         SpecConstant (const deUint32 specID_, const std::string declarationCode_, const deUint32 size_, const GenericValue specValue_)
103                 : specID                        (specID_)
104                 , declarationCode       (declarationCode_)
105                 , size                          (size_)
106                 , specValue                     (specValue_)
107         {
108         }
109 };
110
111 //! Useful when referring to a value in a buffer (i.e. check expected values in SSBO).
112 struct OffsetValue
113 {
114         deUint32                size;           //!< data size in the buffer (up to sizeof(value))
115         deUint32                offset;         //!< offset into the buffer
116         GenericValue    value;          //!< value expected to be there
117
118         OffsetValue (const deUint32 size_, const deUint32 offset_, const GenericValue value_)
119                 : size          (size_)
120                 , offset        (offset_)
121                 , value         (value_)
122         {}
123 };
124
125 //! Get the integer value of 'size' bytes at 'memory' location.
126 deUint64 memoryAsInteger (const void* memory, const deUint32 size)
127 {
128         DE_ASSERT(size <= sizeof(deUint64));
129         deUint64 value = 0;
130         deMemcpy(&value, memory, size);
131         return value;
132 }
133
134 inline std::string memoryAsHexString (const void* memory, const deUint32 size)
135 {
136         const deUint8* memoryBytePtr = static_cast<const deUint8*>(memory);
137         return de::toString(tcu::formatArray(tcu::Format::HexIterator<deUint8>(memoryBytePtr), tcu::Format::HexIterator<deUint8>(memoryBytePtr + size)));
138 }
139
140 void logValueMismatch (tcu::TestLog& log, const void* expected, const void* actual, const deUint32 offset, const deUint32 size)
141 {
142         const bool canDisplayValue = (size <= sizeof(deUint64));
143         log << tcu::TestLog::Message
144                 << "Comparison failed for value at offset " << de::toString(offset) << ": expected "
145                 << (canDisplayValue ? de::toString(memoryAsInteger(expected, size)) + " " : "") << memoryAsHexString(expected, size) << " but got "
146                 << (canDisplayValue ? de::toString(memoryAsInteger(actual, size)) + " " : "") << memoryAsHexString(actual, size)
147                 << tcu::TestLog::EndMessage;
148 }
149
150 //! Check if expected values exist in the memory.
151 bool verifyValues (tcu::TestLog& log, const void* memory, const std::vector<OffsetValue>& expectedValues)
152 {
153         bool ok = true;
154         log << tcu::TestLog::Section("compare", "Verify result values");
155
156         for (std::vector<OffsetValue>::const_iterator it = expectedValues.begin(); it < expectedValues.end(); ++it)
157         {
158                 const char* const valuePtr = static_cast<const char*>(memory) + it->offset;
159                 if (deMemCmp(valuePtr, &it->value, it->size) != 0)
160                 {
161                         ok = false;
162                         logValueMismatch(log, &it->value, valuePtr, it->offset, it->size);
163                 }
164         }
165
166         if (ok)
167                 log << tcu::TestLog::Message << "All OK" << tcu::TestLog::EndMessage;
168
169         log << tcu::TestLog::EndSection;
170         return ok;
171 }
172
173 //! Bundles together common test case parameters.
174 struct CaseDefinition
175 {
176         std::string                                     name;                           //!< Test case name
177         std::vector<SpecConstant>       specConstants;          //!< list of specialization constants to declare
178         VkDeviceSize                            ssboSize;                       //!< required ssbo size in bytes
179         std::string                                     ssboCode;                       //!< ssbo member definitions
180         std::string                                     globalCode;                     //!< generic shader code outside the main function (e.g. declarations)
181         std::string                                     mainCode;                       //!< generic shader code to execute in main (e.g. assignments)
182         std::vector<OffsetValue>        expectedValues;         //!< list of values to check inside the ssbo buffer
183         FeatureFlags                            requirements;           //!< features the implementation must support to allow this test to run
184 };
185
186 //! Manages Vulkan structures to pass specialization data.
187 class Specialization
188 {
189 public:
190                                                                                         Specialization (const std::vector<SpecConstant>& specConstants);
191
192         //! Can return NULL if nothing is specialized
193         const VkSpecializationInfo*                             getSpecializationInfo (void) const { return m_entries.size() > 0 ? &m_specialization : DE_NULL; }
194
195 private:
196         std::vector<GenericValue>                               m_data;
197         std::vector<VkSpecializationMapEntry>   m_entries;
198         VkSpecializationInfo                                    m_specialization;
199 };
200
201 Specialization::Specialization (const std::vector<SpecConstant>& specConstants)
202 {
203         m_data.reserve(specConstants.size());
204         m_entries.reserve(specConstants.size());
205
206         deUint32 offset = 0;
207         for (std::vector<SpecConstant>::const_iterator it = specConstants.begin(); it != specConstants.end(); ++it)
208                 if (it->size != 0)
209                 {
210                         m_data.push_back(it->specValue);
211                         m_entries.push_back(makeSpecializationMapEntry(it->specID, offset, it->size));
212                         offset += (deUint32)sizeof(GenericValue);
213                 }
214
215         if (m_entries.size() > 0)
216         {
217                 m_specialization.mapEntryCount = static_cast<deUint32>(m_entries.size());
218                 m_specialization.pMapEntries   = &m_entries[0];
219                 m_specialization.dataSize          = sizeof(GenericValue) * m_data.size();
220                 m_specialization.pData             = &m_data[0];
221         }
222         else
223                 deMemset(&m_specialization, 0, sizeof(m_specialization));
224 }
225
226 class SpecConstantTest : public TestCase
227 {
228 public:
229                                                                 SpecConstantTest        (tcu::TestContext&                              testCtx,
230                                                                                                          const VkShaderStageFlagBits    stage,          //!< which shader stage is tested
231                                                                                                          const CaseDefinition&                  caseDef);
232
233         void                                            initPrograms            (SourceCollections&             programCollection) const;
234         TestInstance*                           createInstance          (Context&                               context) const;
235
236 private:
237         const VkShaderStageFlagBits     m_stage;
238         const CaseDefinition            m_caseDef;
239 };
240
241 SpecConstantTest::SpecConstantTest (tcu::TestContext&                   testCtx,
242                                                                         const VkShaderStageFlagBits     stage,
243                                                                         const CaseDefinition&           caseDef)
244         : TestCase      (testCtx, caseDef.name, "")
245         , m_stage       (stage)
246         , m_caseDef     (caseDef)
247 {
248 }
249
250 //! Build a string that declares all specialization constants, replacing ${ID} with proper ID numbers.
251 std::string generateSpecConstantCode (const std::vector<SpecConstant>& specConstants)
252 {
253         std::ostringstream code;
254         for (std::vector<SpecConstant>::const_iterator it = specConstants.begin(); it != specConstants.end(); ++it)
255         {
256                 std::string decl = it->declarationCode;
257                 const std::string::size_type pos = decl.find("${ID}");
258                 if (pos != std::string::npos)
259                         decl.replace(pos, 5, de::toString(it->specID));
260                 code << decl << "\n";
261         }
262         code << "\n";
263         return code.str();
264 }
265
266 std::string generateSSBOCode (const std::string& memberDeclarations)
267 {
268         std::ostringstream code;
269         code << "layout (set = 0, binding = 0, std430) writeonly buffer Output {\n"
270                  << memberDeclarations
271                  << "} sb_out;\n"
272                  << "\n";
273         return code.str();
274 }
275
276 void SpecConstantTest::initPrograms (SourceCollections& programCollection) const
277 {
278         // Always add vertex and fragment to graphics stages
279         VkShaderStageFlags requiredStages = m_stage;
280
281         if (requiredStages & VK_SHADER_STAGE_ALL_GRAPHICS)
282                 requiredStages |= VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
283
284         if (requiredStages & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))
285                 requiredStages |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
286
287         // Either graphics or compute must be defined, but not both
288         DE_ASSERT(((requiredStages & VK_SHADER_STAGE_ALL_GRAPHICS) != 0) != ((requiredStages & VK_SHADER_STAGE_COMPUTE_BIT) != 0));
289
290         if (requiredStages & VK_SHADER_STAGE_VERTEX_BIT)
291         {
292                 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_VERTEX_BIT);
293                 std::ostringstream src;
294                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
295                         << "layout(location = 0) in highp vec4 position;\n"
296                         << "\n"
297                         << "out " << s_perVertexBlock << ";\n"
298                         << "\n"
299                         << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
300                         << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
301                         << (useSpecConst ? m_caseDef.globalCode + "\n" : "")
302                         << "void main (void)\n"
303                         << "{\n"
304                         << (useSpecConst ? m_caseDef.mainCode + "\n" : "")
305                         << "    gl_Position = position;\n"
306                         << "}\n";
307
308                 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
309         }
310
311         if (requiredStages & VK_SHADER_STAGE_FRAGMENT_BIT)
312         {
313                 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_FRAGMENT_BIT);
314                 std::ostringstream src;
315                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
316                         << "layout(location = 0) out highp vec4 fragColor;\n"
317                         << "\n"
318                         << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
319                         << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
320                         << (useSpecConst ? m_caseDef.globalCode + "\n" : "")
321                         << "void main (void)\n"
322                         << "{\n"
323                         << (useSpecConst ? m_caseDef.mainCode + "\n" : "")
324                         << "    fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n"
325                         << "}\n";
326
327                 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
328         }
329
330         if (requiredStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
331         {
332                 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
333                 std::ostringstream src;
334                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
335                         << "layout(vertices = 3) out;\n"
336                         << "\n"
337                         << "in " << s_perVertexBlock << " gl_in[gl_MaxPatchVertices];\n"
338                         << "\n"
339                         << "out " << s_perVertexBlock << " gl_out[];\n"
340                         << "\n"
341                         << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
342                         << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
343                         << (useSpecConst ? m_caseDef.globalCode + "\n" : "")
344                         << "void main (void)\n"
345                         << "{\n"
346                         << (useSpecConst ? m_caseDef.mainCode + "\n" : "")
347                         << "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
348                         << "    if (gl_InvocationID == 0)\n"
349                         << "    {\n"
350                         << "        gl_TessLevelInner[0] = 3;\n"
351                         << "        gl_TessLevelOuter[0] = 2;\n"
352                         << "        gl_TessLevelOuter[1] = 2;\n"
353                         << "        gl_TessLevelOuter[2] = 2;\n"
354                         << "    }\n"
355                         << "}\n";
356
357                 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
358         }
359
360         if (requiredStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
361         {
362                 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
363                 std::ostringstream src;
364                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
365                         << "layout(triangles, equal_spacing, ccw) in;\n"
366                         << "\n"
367                         << "in " << s_perVertexBlock << " gl_in[gl_MaxPatchVertices];\n"
368                         << "\n"
369                         << "out " << s_perVertexBlock << ";\n"
370                         << "\n"
371                         << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
372                         << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
373                         << (useSpecConst ? m_caseDef.globalCode + "\n" : "")
374                         << "void main (void)\n"
375                         << "{\n"
376                         << (useSpecConst ? m_caseDef.mainCode + "\n" : "")
377                         << "    vec3 p0 = gl_TessCoord.x * gl_in[0].gl_Position.xyz;\n"
378                         << "    vec3 p1 = gl_TessCoord.y * gl_in[1].gl_Position.xyz;\n"
379                         << "    vec3 p2 = gl_TessCoord.z * gl_in[2].gl_Position.xyz;\n"
380                         << "    gl_Position = vec4(p0 + p1 + p2, 1.0);\n"
381                         << "}\n";
382
383                 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
384         }
385
386         if (requiredStages & VK_SHADER_STAGE_GEOMETRY_BIT)
387         {
388                 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_GEOMETRY_BIT);
389                 std::ostringstream src;
390                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
391                         << "layout(triangles) in;\n"
392                         << "layout(triangle_strip, max_vertices = 3) out;\n"
393                         << "\n"
394                         << "in " << s_perVertexBlock << " gl_in[];\n"
395                         << "\n"
396                         << "out " << s_perVertexBlock << ";\n"
397                         << "\n"
398                         << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
399                         << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
400                         << (useSpecConst ? m_caseDef.globalCode + "\n" : "")
401                         << "void main (void)\n"
402                         << "{\n"
403                         << (useSpecConst ? m_caseDef.mainCode + "\n" : "")
404                         << "    gl_Position = gl_in[0].gl_Position;\n"
405                         << "    EmitVertex();\n"
406                         << "\n"
407                         << "    gl_Position = gl_in[1].gl_Position;\n"
408                         << "    EmitVertex();\n"
409                         << "\n"
410                         << "    gl_Position = gl_in[2].gl_Position;\n"
411                         << "    EmitVertex();\n"
412                         << "\n"
413                         << "    EndPrimitive();\n"
414                         << "}\n";
415
416                 programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
417         }
418
419         if (requiredStages & VK_SHADER_STAGE_COMPUTE_BIT)
420         {
421                 std::ostringstream src;
422                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
423                         // Don't define work group size, use the default or specialization constants
424                         << "\n"
425                         << generateSpecConstantCode(m_caseDef.specConstants)
426                         << generateSSBOCode(m_caseDef.ssboCode)
427                         << m_caseDef.globalCode + "\n"
428                         << "void main (void)\n"
429                         << "{\n"
430                         << m_caseDef.mainCode
431                         << "}\n";
432
433                 programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
434         }
435 }
436
437 class ComputeTestInstance : public TestInstance
438 {
439 public:
440                                                                         ComputeTestInstance     (Context&                                                       context,
441                                                                                                                  const VkDeviceSize                                     ssboSize,
442                                                                                                                  const std::vector<SpecConstant>&       specConstants,
443                                                                                                                  const std::vector<OffsetValue>&        expectedValues);
444
445         tcu::TestStatus                                 iterate                         (void);
446
447 private:
448         const VkDeviceSize                              m_ssboSize;
449         const std::vector<SpecConstant> m_specConstants;
450         const std::vector<OffsetValue>  m_expectedValues;
451 };
452
453 ComputeTestInstance::ComputeTestInstance (Context&                                                      context,
454                                                                                   const VkDeviceSize                            ssboSize,
455                                                                                   const std::vector<SpecConstant>&      specConstants,
456                                                                                   const std::vector<OffsetValue>&       expectedValues)
457         : TestInstance          (context)
458         , m_ssboSize            (ssboSize)
459         , m_specConstants       (specConstants)
460         , m_expectedValues      (expectedValues)
461 {
462 }
463
464 tcu::TestStatus ComputeTestInstance::iterate (void)
465 {
466         const DeviceInterface&  vk                                      = m_context.getDeviceInterface();
467         const VkDevice                  device                          = m_context.getDevice();
468         const VkQueue                   queue                           = m_context.getUniversalQueue();
469         const deUint32                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
470         Allocator&                              allocator                       = m_context.getDefaultAllocator();
471
472         // Descriptors
473
474         const Buffer resultBuffer(vk, device, allocator, makeBufferCreateInfo(m_ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
475
476         const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
477                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
478                 .build(vk, device));
479
480         const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
481                 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
482                 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
483
484         const Unique<VkDescriptorSet> descriptorSet        (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
485         const VkDescriptorBufferInfo  descriptorBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, m_ssboSize);
486
487         DescriptorSetUpdateBuilder()
488                 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
489                 .update(vk, device);
490
491         // Specialization
492
493         const Specialization        specialization (m_specConstants);
494         const VkSpecializationInfo* pSpecInfo      = specialization.getSpecializationInfo();
495
496         // Pipeline
497
498         const Unique<VkShaderModule>   shaderModule  (createShaderModule (vk, device, m_context.getBinaryCollection().get("comp"), 0));
499         const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout (vk, device, *descriptorSetLayout));
500         const Unique<VkPipeline>       pipeline      (makeComputePipeline(vk, device, *pipelineLayout, *shaderModule, pSpecInfo));
501         const Unique<VkCommandPool>    cmdPool       (createCommandPool  (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
502         const Unique<VkCommandBuffer>  cmdBuffer     (makeCommandBuffer  (vk, device, *cmdPool));
503
504         beginCommandBuffer(vk, *cmdBuffer);
505
506         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
507         vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
508
509         vk.cmdDispatch(*cmdBuffer, 1u, 1u, 1u);
510
511         {
512                 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
513                         VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, m_ssboSize);
514
515                 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
516                         0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
517         }
518
519         VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
520         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
521
522         // Verify results
523
524         const Allocation& resultAlloc = resultBuffer.getAllocation();
525         invalidateMappedMemoryRange(vk, device, resultAlloc.getMemory(), resultAlloc.getOffset(), m_ssboSize);
526
527         if (verifyValues(m_context.getTestContext().getLog(), resultAlloc.getHostPtr(), m_expectedValues))
528                 return tcu::TestStatus::pass("Success");
529         else
530                 return tcu::TestStatus::fail("Values did not match");
531 }
532
533 class GraphicsTestInstance : public TestInstance
534 {
535 public:
536                                                                         GraphicsTestInstance (Context&                                                  context,
537                                                                                                                   const VkDeviceSize                            ssboSize,
538                                                                                                                   const std::vector<SpecConstant>&      specConstants,
539                                                                                                                   const std::vector<OffsetValue>&       expectedValues,
540                                                                                                                   const VkShaderStageFlagBits           stage);
541
542         tcu::TestStatus                                 iterate                          (void);
543
544 private:
545         const VkDeviceSize                              m_ssboSize;
546         const std::vector<SpecConstant> m_specConstants;
547         const std::vector<OffsetValue>  m_expectedValues;
548         const VkShaderStageFlagBits             m_stage;
549 };
550
551 GraphicsTestInstance::GraphicsTestInstance (Context&                                                    context,
552                                                                                         const VkDeviceSize                                      ssboSize,
553                                                                                         const std::vector<SpecConstant>&        specConstants,
554                                                                                         const std::vector<OffsetValue>&         expectedValues,
555                                                                                         const VkShaderStageFlagBits                     stage)
556         : TestInstance          (context)
557         , m_ssboSize            (ssboSize)
558         , m_specConstants       (specConstants)
559         , m_expectedValues      (expectedValues)
560         , m_stage                       (stage)
561 {
562 }
563
564 tcu::TestStatus GraphicsTestInstance::iterate (void)
565 {
566         const DeviceInterface&  vk                                      = m_context.getDeviceInterface();
567         const VkDevice                  device                          = m_context.getDevice();
568         const VkQueue                   queue                           = m_context.getUniversalQueue();
569         const deUint32                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
570         Allocator&                              allocator                       = m_context.getDefaultAllocator();
571
572         // Color attachment
573
574         const tcu::IVec2          renderSize    = tcu::IVec2(32, 32);
575         const VkFormat            imageFormat   = VK_FORMAT_R8G8B8A8_UNORM;
576         const Image               colorImage    (vk, device, allocator, makeImageCreateInfo(renderSize, imageFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), MemoryRequirement::Any);
577         const Unique<VkImageView> colorImageView(makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, imageFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)));
578
579         // Vertex buffer
580
581         const deUint32     numVertices           = 3;
582         const VkDeviceSize vertexBufferSizeBytes = sizeof(tcu::Vec4) * numVertices;
583         const Buffer       vertexBuffer          (vk, device, allocator, makeBufferCreateInfo(vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible);
584
585         {
586                 const Allocation& alloc = vertexBuffer.getAllocation();
587                 tcu::Vec4* pVertices = reinterpret_cast<tcu::Vec4*>(alloc.getHostPtr());
588
589                 pVertices[0] = tcu::Vec4(-1.0f, -1.0f,  0.0f,  1.0f);
590                 pVertices[1] = tcu::Vec4(-1.0f,  1.0f,  0.0f,  1.0f);
591                 pVertices[2] = tcu::Vec4( 1.0f, -1.0f,  0.0f,  1.0f);
592
593                 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), vertexBufferSizeBytes);
594                 // No barrier needed, flushed memory is automatically visible
595         }
596
597         // Descriptors
598
599         const Buffer resultBuffer(vk, device, allocator, makeBufferCreateInfo(m_ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
600
601         const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
602                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL_GRAPHICS)
603                 .build(vk, device));
604
605         const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
606                 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
607                 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
608
609         const Unique<VkDescriptorSet> descriptorSet        (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
610         const VkDescriptorBufferInfo  descriptorBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, m_ssboSize);
611
612         DescriptorSetUpdateBuilder()
613                 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
614                 .update(vk, device);
615
616         // Specialization
617
618         const Specialization        specialization (m_specConstants);
619         const VkSpecializationInfo* pSpecInfo      = specialization.getSpecializationInfo();
620
621         // Pipeline
622
623         const Unique<VkRenderPass>     renderPass    (makeRenderPass    (vk, device, imageFormat));
624         const Unique<VkFramebuffer>    framebuffer   (makeFramebuffer   (vk, device, *renderPass, 1u, &colorImageView.get(), static_cast<deUint32>(renderSize.x()), static_cast<deUint32>(renderSize.y())));
625         const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
626         const Unique<VkCommandPool>    cmdPool       (createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
627         const Unique<VkCommandBuffer>  cmdBuffer     (makeCommandBuffer (vk, device, *cmdPool));
628
629         GraphicsPipelineBuilder pipelineBuilder;
630         pipelineBuilder
631                 .setRenderSize(renderSize)
632                 .setShader(vk, device, VK_SHADER_STAGE_VERTEX_BIT,   m_context.getBinaryCollection().get("vert"), pSpecInfo)
633                 .setShader(vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, m_context.getBinaryCollection().get("frag"), pSpecInfo);
634
635         if ((m_stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) || (m_stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))
636                 pipelineBuilder
637                         .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,    m_context.getBinaryCollection().get("tesc"), pSpecInfo)
638                         .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get("tese"), pSpecInfo);
639
640         if (m_stage == VK_SHADER_STAGE_GEOMETRY_BIT)
641                 pipelineBuilder
642                         .setShader(vk, device, VK_SHADER_STAGE_GEOMETRY_BIT, m_context.getBinaryCollection().get("geom"), pSpecInfo);
643
644         const Unique<VkPipeline> pipeline (pipelineBuilder.build(vk, device, *pipelineLayout, *renderPass));
645
646         // Draw commands
647
648         const VkRect2D renderArea = {
649                 makeOffset2D(0, 0),
650                 makeExtent2D(renderSize.x(), renderSize.y()),
651         };
652         const tcu::Vec4    clearColor         (0.0f, 0.0f, 0.0f, 1.0f);
653         const VkDeviceSize vertexBufferOffset = 0ull;
654
655         beginCommandBuffer(vk, *cmdBuffer);
656
657         {
658                 const VkImageSubresourceRange imageFullSubresourceRange              = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
659                 const VkImageMemoryBarrier    barrierColorAttachmentSetInitialLayout = makeImageMemoryBarrier(
660                         0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
661                         VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
662                         *colorImage, imageFullSubresourceRange);
663
664                 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
665                         0u, DE_NULL, 0u, DE_NULL, 1u, &barrierColorAttachmentSetInitialLayout);
666         }
667
668         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
669
670         vk.cmdBindPipeline      (*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
671         vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
672         vk.cmdBindVertexBuffers (*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
673
674         vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
675         vk.cmdEndRenderPass(*cmdBuffer);
676
677         {
678                 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
679                         VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, m_ssboSize);
680
681                 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
682                         0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
683         }
684
685         VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
686         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
687
688         // Verify results
689
690         const Allocation& resultAlloc = resultBuffer.getAllocation();
691         invalidateMappedMemoryRange(vk, device, resultAlloc.getMemory(), resultAlloc.getOffset(), m_ssboSize);
692
693         if (verifyValues(m_context.getTestContext().getLog(), resultAlloc.getHostPtr(), m_expectedValues))
694                 return tcu::TestStatus::pass("Success");
695         else
696                 return tcu::TestStatus::fail("Values did not match");
697 }
698
699 FeatureFlags getShaderStageRequirements (const VkShaderStageFlags stageFlags)
700 {
701         FeatureFlags features = (FeatureFlags)0;
702
703         if (((stageFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) || ((stageFlags & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0))
704                 features |= FEATURE_TESSELLATION_SHADER;
705
706         if ((stageFlags & VK_SHADER_STAGE_GEOMETRY_BIT) != 0)
707                 features |= FEATURE_GEOMETRY_SHADER;
708
709         // All tests use SSBO writes to read back results.
710         if ((stageFlags & VK_SHADER_STAGE_ALL_GRAPHICS) != 0)
711         {
712                 if ((stageFlags & VK_SHADER_STAGE_FRAGMENT_BIT) != 0)
713                         features |= FEATURE_FRAGMENT_STORES_AND_ATOMICS;
714                 else
715                         features |= FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS;
716         }
717
718         return features;
719 }
720
721 TestInstance* SpecConstantTest::createInstance (Context& context) const
722 {
723         requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), m_caseDef.requirements | getShaderStageRequirements(m_stage));
724
725         if (m_stage & VK_SHADER_STAGE_COMPUTE_BIT)
726                 return new ComputeTestInstance(context, m_caseDef.ssboSize, m_caseDef.specConstants, m_caseDef.expectedValues);
727         else
728                 return new GraphicsTestInstance(context, m_caseDef.ssboSize, m_caseDef.specConstants, m_caseDef.expectedValues, m_stage);
729 }
730
731 //! Declare specialization constants but use them with default values.
732 tcu::TestCaseGroup* createDefaultValueTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage)
733 {
734         de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "default_value", "use default constant value"));
735
736         const CaseDefinition defs[] =
737         {
738                 {
739                         "bool",
740                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const bool sc0 = true;"),
741                                            SpecConstant(2u, "layout(constant_id = ${ID}) const bool sc1 = false;")),
742                         8,
743                         "    bool r0;\n"
744                         "    bool r1;\n",
745                         "",
746                         "    sb_out.r0 = sc0;\n"
747                         "    sb_out.r1 = sc1;\n",
748                         makeVector(OffsetValue(4, 0, makeValueBool32(true)),
749                                            OffsetValue(4, 4, makeValueBool32(false))),
750                         (FeatureFlags)0,
751                 },
752                 {
753                         "int",
754                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = -3;"),
755                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 17;")),
756                         8,
757                         "    int r0;\n"
758                         "    int r1;\n",
759                         "",
760                         "    sb_out.r0 = sc0;\n"
761                         "    sb_out.r1 = sc1;\n",
762                         makeVector(OffsetValue(4, 0, makeValueInt32(-3)),
763                                            OffsetValue(4, 4, makeValueInt32(17))),
764                         (FeatureFlags)0,
765                 },
766                 {
767                         "uint",
768                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint sc0 = 42u;")),
769                         4,
770                         "    uint r0;\n",
771                         "",
772                         "    sb_out.r0 = sc0;\n",
773                         makeVector(OffsetValue(4, 0, makeValueUint32(42u))),
774                         (FeatureFlags)0,
775                 },
776                 {
777                         "float",
778                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 7.5;")),
779                         4,
780                         "    float r0;\n",
781                         "",
782                         "    sb_out.r0 = sc0;\n",
783                         makeVector(OffsetValue(4, 0, makeValueFloat32(7.5f))),
784                         (FeatureFlags)0,
785                 },
786                 {
787                         "double",
788                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const double sc0 = 2.75LF;")),
789                         8,
790                         "    double r0;\n",
791                         "",
792                         "    sb_out.r0 = sc0;\n",
793                         makeVector(OffsetValue(8, 0, makeValueFloat64(2.75))),
794                         FEATURE_SHADER_FLOAT_64,
795                 },
796         };
797
798         for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
799                 testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, defs[defNdx]));
800
801         return testGroup.release();
802 }
803
804 //! Declare specialization constants and specify their values through API.
805 tcu::TestCaseGroup* createBasicSpecializationTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage)
806 {
807         de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "basic", "specialize a constant"));
808
809         const CaseDefinition defs[] =
810         {
811                 {
812                         "bool",
813                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const bool sc0 = true;",  4, makeValueBool32(true)),
814                                            SpecConstant(2u, "layout(constant_id = ${ID}) const bool sc1 = false;", 4, makeValueBool32(false)),
815                                            SpecConstant(3u, "layout(constant_id = ${ID}) const bool sc2 = true;",  4, makeValueBool32(false)),
816                                            SpecConstant(4u, "layout(constant_id = ${ID}) const bool sc3 = false;", 4, makeValueBool32(true))),
817                         16,
818                         "    bool r0;\n"
819                         "    bool r1;\n"
820                         "    bool r2;\n"
821                         "    bool r3;\n",
822                         "",
823                         "    sb_out.r0 = sc0;\n"
824                         "    sb_out.r1 = sc1;\n"
825                         "    sb_out.r2 = sc2;\n"
826                         "    sb_out.r3 = sc3;\n",
827                         makeVector(OffsetValue(4,  0, makeValueBool32(true)),
828                                            OffsetValue(4,  4, makeValueBool32(false)),
829                                            OffsetValue(4,  8, makeValueBool32(false)),
830                                            OffsetValue(4, 12, makeValueBool32(true))),
831                         (FeatureFlags)0,
832                 },
833                 {
834                         "int",
835                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = -3;", 4, makeValueInt32(33)),
836                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 91;"),
837                                            SpecConstant(3u, "layout(constant_id = ${ID}) const int sc2 = 17;", 4, makeValueInt32(-15))),
838                         12,
839                         "    int r0;\n"
840                         "    int r1;\n"
841                         "    int r2;\n",
842                         "",
843                         "    sb_out.r0 = sc0;\n"
844                         "    sb_out.r1 = sc1;\n"
845                         "    sb_out.r2 = sc2;\n",
846                         makeVector(OffsetValue(4, 0, makeValueInt32(33)),
847                                            OffsetValue(4, 4, makeValueInt32(91)),
848                                            OffsetValue(4, 8, makeValueInt32(-15))),
849                         (FeatureFlags)0,
850                 },
851                 {
852                         "uint",
853                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint sc0 = 42u;", 4, makeValueUint32(97u)),
854                                            SpecConstant(2u, "layout(constant_id = ${ID}) const uint sc1 = 7u;")),
855                         8,
856                         "    uint r0;\n"
857                         "    uint r1;\n",
858                         "",
859                         "    sb_out.r0 = sc0;\n"
860                         "    sb_out.r1 = sc1;\n",
861                         makeVector(OffsetValue(4, 0, makeValueUint32(97u)),
862                                            OffsetValue(4, 4, makeValueUint32(7u))),
863                         (FeatureFlags)0,
864                 },
865                 {
866                         "float",
867                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 7.5;", 4, makeValueFloat32(15.75f)),
868                                            SpecConstant(2u, "layout(constant_id = ${ID}) const float sc1 = 1.125;")),
869                         8,
870                         "    float r0;\n"
871                         "    float r1;\n",
872                         "",
873                         "    sb_out.r0 = sc0;\n"
874                         "    sb_out.r1 = sc1;\n",
875                         makeVector(OffsetValue(4, 0, makeValueFloat32(15.75f)),
876                                            OffsetValue(4, 4, makeValueFloat32(1.125f))),
877                         (FeatureFlags)0,
878                 },
879                 {
880                         "double",
881                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const double sc0 = 2.75LF;", 8, makeValueFloat64(22.5)),
882                                            SpecConstant(2u, "layout(constant_id = ${ID}) const double sc1 = 9.25LF;")),
883                         16,
884                         "    double r0;\n"
885                         "    double r1;\n",
886                         "",
887                         "    sb_out.r0 = sc0;\n"
888                         "    sb_out.r1 = sc1;\n",
889                         makeVector(OffsetValue(8, 0, makeValueFloat64(22.5)),
890                                            OffsetValue(8, 8, makeValueFloat64(9.25))),
891                         FEATURE_SHADER_FLOAT_64,
892                 },
893         };
894
895         for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
896                 testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, defs[defNdx]));
897
898         return testGroup.release();
899 }
900
901 //! Specify compute shader work group size through specialization constants.
902 tcu::TestCaseGroup* createWorkGroupSizeTests (tcu::TestContext& testCtx)
903 {
904         de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "local_size", "work group size specialization"));
905
906         const deUint32 ssboSize = 16;
907         const std::string ssboDecl =
908                 "    uvec3 workGroupSize;\n"
909                 "    uint  checksum;\n";
910         const std::string globalDecl = "shared uint count;\n";
911         const std::string mainCode =
912                 "    count = 0u;\n"
913                 "\n"
914                 "    groupMemoryBarrier();\n"
915                 "    barrier();\n"
916                 "\n"
917                 "    atomicAdd(count, 1u);\n"
918                 "\n"
919                 "    groupMemoryBarrier();\n"
920                 "    barrier();\n"
921                 "\n"
922                 "    sb_out.workGroupSize = gl_WorkGroupSize;\n"
923                 "    sb_out.checksum      = count;\n";
924
925         const CaseDefinition defs[] =
926         {
927                 {
928                         "x",
929                         makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;",  4, makeValueUint32(7u))),
930                         ssboSize, ssboDecl, globalDecl, mainCode,
931                         makeVector(OffsetValue(4,  0, makeValueUint32(7u)),
932                                            OffsetValue(4,  4, makeValueUint32(1u)),
933                                            OffsetValue(4,  8, makeValueUint32(1u)),
934                                            OffsetValue(4, 12, makeValueUint32(7u))),
935                         (FeatureFlags)0,
936                 },
937                 {
938                         "y",
939                         makeVector(SpecConstant(1u, "layout(local_size_y_id = ${ID}) in;",  4, makeValueUint32(5u))),
940                         ssboSize, ssboDecl, globalDecl, mainCode,
941                         makeVector(OffsetValue(4,  0, makeValueUint32(1u)),
942                                            OffsetValue(4,  4, makeValueUint32(5u)),
943                                            OffsetValue(4,  8, makeValueUint32(1u)),
944                                            OffsetValue(4, 12, makeValueUint32(5u))),
945                         (FeatureFlags)0,
946                 },
947                 {
948                         "z",
949                         makeVector(SpecConstant(1u, "layout(local_size_z_id = ${ID}) in;",  4, makeValueUint32(3u))),
950                         ssboSize, ssboDecl, globalDecl, mainCode,
951                         makeVector(OffsetValue(4,  0, makeValueUint32(1u)),
952                                            OffsetValue(4,  4, makeValueUint32(1u)),
953                                            OffsetValue(4,  8, makeValueUint32(3u)),
954                                            OffsetValue(4, 12, makeValueUint32(3u))),
955                         (FeatureFlags)0,
956                 },
957                 {
958                         "xy",
959                         makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;",  4, makeValueUint32(6u)),
960                                            SpecConstant(2u, "layout(local_size_y_id = ${ID}) in;",  4, makeValueUint32(4u))),
961                         ssboSize, ssboDecl, globalDecl, mainCode,
962                         makeVector(OffsetValue(4,  0, makeValueUint32(6u)),
963                                            OffsetValue(4,  4, makeValueUint32(4u)),
964                                            OffsetValue(4,  8, makeValueUint32(1u)),
965                                            OffsetValue(4, 12, makeValueUint32(6u * 4u))),
966                         (FeatureFlags)0,
967                 },
968                 {
969                         "xz",
970                         makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;",  4, makeValueUint32(3u)),
971                                            SpecConstant(2u, "layout(local_size_z_id = ${ID}) in;",  4, makeValueUint32(9u))),
972                         ssboSize, ssboDecl, globalDecl, mainCode,
973                         makeVector(OffsetValue(4,  0, makeValueUint32(3u)),
974                                            OffsetValue(4,  4, makeValueUint32(1u)),
975                                            OffsetValue(4,  8, makeValueUint32(9u)),
976                                            OffsetValue(4, 12, makeValueUint32(3u * 9u))),
977                         (FeatureFlags)0,
978                 },
979                 {
980                         "yz",
981                         makeVector(SpecConstant(1u, "layout(local_size_y_id = ${ID}) in;",  4, makeValueUint32(2u)),
982                                            SpecConstant(2u, "layout(local_size_z_id = ${ID}) in;",  4, makeValueUint32(5u))),
983                         ssboSize, ssboDecl, globalDecl, mainCode,
984                         makeVector(OffsetValue(4,  0, makeValueUint32(1u)),
985                                            OffsetValue(4,  4, makeValueUint32(2u)),
986                                            OffsetValue(4,  8, makeValueUint32(5u)),
987                                            OffsetValue(4, 12, makeValueUint32(2u * 5u))),
988                         (FeatureFlags)0,
989                 },
990                 {
991                         "xyz",
992                         makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;",  4, makeValueUint32(3u)),
993                                            SpecConstant(2u, "layout(local_size_y_id = ${ID}) in;",  4, makeValueUint32(5u)),
994                                            SpecConstant(3u, "layout(local_size_z_id = ${ID}) in;",  4, makeValueUint32(7u))),
995                         ssboSize, ssboDecl, globalDecl, mainCode,
996                         makeVector(OffsetValue(4,  0, makeValueUint32(3u)),
997                                            OffsetValue(4,  4, makeValueUint32(5u)),
998                                            OffsetValue(4,  8, makeValueUint32(7u)),
999                                            OffsetValue(4, 12, makeValueUint32(3u * 5u * 7u))),
1000                         (FeatureFlags)0,
1001                 },
1002         };
1003
1004         for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
1005                 testGroup->addChild(new SpecConstantTest(testCtx, VK_SHADER_STAGE_COMPUTE_BIT, defs[defNdx]));
1006
1007         return testGroup.release();
1008 }
1009
1010 //! Override a built-in variable with specialization constant value.
1011 tcu::TestCaseGroup* createBuiltInOverrideTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage)
1012 {
1013         de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "builtin", "built-in override"));
1014
1015         const CaseDefinition defs[] =
1016         {
1017                 {
1018                         "default",
1019                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) gl_MaxImageUnits;")),
1020                         4,
1021                         "    bool ok;\n",
1022                         "",
1023                         "    sb_out.ok = (gl_MaxImageUnits >= 8);\n",   // implementation defined, 8 is the minimum
1024                         makeVector(OffsetValue(4,  0, makeValueBool32(true))),
1025                         (FeatureFlags)0,
1026                 },
1027                 {
1028                         "specialized",
1029                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) gl_MaxImageUnits;", 4, makeValueInt32(12))),
1030                         4,
1031                         "    int maxImageUnits;\n",
1032                         "",
1033                         "    sb_out.maxImageUnits = gl_MaxImageUnits;\n",
1034                         makeVector(OffsetValue(4,  0, makeValueInt32(12))),
1035                         (FeatureFlags)0,
1036                 },
1037         };
1038
1039         for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
1040                 testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, defs[defNdx]));
1041
1042         return testGroup.release();
1043 }
1044
1045 //! Specialization constants used in expressions.
1046 tcu::TestCaseGroup* createExpressionTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage)
1047 {
1048         de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "expression", "specialization constants usage in expressions"));
1049
1050         const CaseDefinition defs[] =
1051         {
1052                 {
1053                         "spec_const_expression",
1054                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 2;"),
1055                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 3;", 4, makeValueInt32(5))),
1056                         4,
1057                         "    int result;\n",
1058
1059                         "const int expr0 = sc0 + 1;\n"
1060                         "const int expr1 = sc0 + sc1;\n",
1061
1062                         "    sb_out.result = expr0 + expr1;\n",
1063                         makeVector(OffsetValue(4,  0, makeValueInt32(10))),
1064                         (FeatureFlags)0,
1065                 },
1066                 {
1067                         "array_size",
1068                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;"),
1069                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 2;", 4, makeValueInt32(3))),
1070                         16,
1071                         "    int r0;\n"
1072                         "    int r1[3];\n",
1073
1074                         "",
1075
1076                         "    int a0[sc0];\n"
1077                         "    int a1[sc1];\n"
1078                         "\n"
1079                         "    for (int i = 0; i < sc0; ++i)\n"
1080                         "        a0[i] = sc0 - i;\n"
1081                         "    for (int i = 0; i < sc1; ++i)\n"
1082                         "        a1[i] = sc1 - i;\n"
1083                         "\n"
1084                         "    sb_out.r0 = a0[0];\n"
1085                         "    for (int i = 0; i < sc1; ++i)\n"
1086                         "            sb_out.r1[i] = a1[i];\n",
1087                         makeVector(OffsetValue(4,  0, makeValueInt32(1)),
1088                                            OffsetValue(4,  4, makeValueInt32(3)),
1089                                            OffsetValue(4,  8, makeValueInt32(2)),
1090                                            OffsetValue(4, 12, makeValueInt32(1))),
1091                         (FeatureFlags)0,
1092                 },
1093                 {
1094                         "array_size_expression",
1095                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 3;"),
1096                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 5;", 4, makeValueInt32(7))),
1097                         8,
1098                         "    int r0;\n"
1099                         "    int r1;\n",
1100
1101                         "",
1102
1103                         "    int a0[sc0 + 3];\n"
1104                         "    int a1[sc0 + sc1];\n"
1105                         "\n"
1106                         "    const int size0 = sc0 + 3;\n"
1107                         "    const int size1 = sc0 + sc1;\n"
1108                         "\n"
1109                         "    for (int i = 0; i < size0; ++i)\n"
1110                         "        a0[i] = 3 - i;\n"
1111                         "    for (int i = 0; i < size1; ++i)\n"
1112                         "        a1[i] = 5 - i;\n"
1113                         "\n"
1114                         "    sb_out.r0 = a0[size0 - 1];\n"
1115                         "    sb_out.r1 = a1[size1 - 1];\n",
1116                         makeVector(OffsetValue(4,  0, makeValueInt32(-2)),
1117                                            OffsetValue(4,  4, makeValueInt32(-4))),
1118                         (FeatureFlags)0,
1119                 },
1120                 {
1121                         "array_size_spec_const_expression",
1122                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 3;"),
1123                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 5;", 4, makeValueInt32(7))),
1124                         8,
1125                         "    int r0;\n"
1126                         "    int r1;\n",
1127
1128                         "",
1129
1130                         "    const int size0 = sc0 + 3;\n"
1131                         "    const int size1 = sc0 + sc1;\n"
1132                         "\n"
1133                         "    int a0[size0];\n"
1134                         "    int a1[size1];\n"
1135                         "\n"
1136                         "    for (int i = 0; i < size0; ++i)\n"
1137                         "        a0[i] = 3 - i;\n"
1138                         "    for (int i = 0; i < size1; ++i)\n"
1139                         "        a1[i] = 5 - i;\n"
1140                         "\n"
1141                         "    sb_out.r0 = a0[size0 - 1];\n"
1142                         "    sb_out.r1 = a1[size1 - 1];\n",
1143                         makeVector(OffsetValue(4,  0, makeValueInt32(-2)),
1144                                            OffsetValue(4,  4, makeValueInt32(-4))),
1145                         (FeatureFlags)0,
1146                 },
1147                 {
1148                         "array_size_length",
1149                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;"),
1150                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 2;", 4, makeValueInt32(4))),
1151                         8,
1152                         "    int r0;\n"
1153                         "    int r1;\n",
1154
1155                         "",
1156
1157                         "    int a0[sc0];\n"
1158                         "    int a1[sc1];\n"
1159                         "\n"
1160                         "    sb_out.r0 = a0.length();\n"
1161                         "    sb_out.r1 = a1.length();\n",
1162                         makeVector(OffsetValue(4,  0, makeValueInt32(1)),
1163                                            OffsetValue(4,  4, makeValueInt32(4))),
1164                         (FeatureFlags)0,
1165                 },
1166                 {
1167                         "array_size_pass_to_function",
1168                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 3;"),
1169                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 1;", 4, makeValueInt32(3))),
1170                         4,
1171                         "    int result;\n",
1172
1173                         "int sumArrays (int a0[sc0], int a1[sc1])\n"
1174                         "{\n"
1175                         "    int sum = 0;\n"
1176                         "    for (int i = 0; (i < sc0) && (i < sc1); ++i)\n"
1177                         "        sum += a0[i] + a1[i];\n"
1178                         "    return sum;\n"
1179                         "}\n",
1180
1181                         "    int a0[sc0];\n"
1182                         "    int a1[sc1];\n"
1183                         "\n"
1184                         "    for (int i = 0; i < sc0; ++i)\n"
1185                         "        a0[i] = i + 1;\n"
1186                         "    for (int i = 0; i < sc1; ++i)\n"
1187                         "        a1[i] = i + 2;\n"
1188                         "\n"
1189                         "    sb_out.result = sumArrays(a0, a1);\n",
1190                         makeVector(OffsetValue(4,  0, makeValueInt32(15))),
1191                         (FeatureFlags)0,
1192                 },
1193         };
1194
1195         for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
1196                 testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, defs[defNdx]));
1197
1198         return testGroup.release();
1199 }
1200
1201 //! Helper functions internal to make*CompositeCaseDefinition functions.
1202 namespace composite_case_internal
1203 {
1204
1205 //! Generate a string like this: "1, 2, sc0, 4" or "true, true, sc0"
1206 //! castToType = true is useful when type requires more initializer values than we are providing, e.g.:
1207 //!    vec2(1), vec2(sc0), vec(3)
1208 std::string generateInitializerListWithSpecConstant (const glu::DataType        type,
1209                                                                                                          const bool                             castToType,
1210                                                                                                          const int                              idxBegin,
1211                                                                                                          const int                              idxEnd,
1212                                                                                                          const std::string&             specConstName,
1213                                                                                                          const int                              specConstNdx)
1214 {
1215         std::ostringstream str;
1216
1217         for (int i = idxBegin; i < idxEnd; ++i)
1218         {
1219                 const std::string iVal = (i == specConstNdx ? specConstName : glu::getDataTypeScalarType(type) == glu::TYPE_BOOL ? "true" : de::toString(i + 1));
1220                 str << (i != idxBegin ? ", " : "") << (castToType ? de::toString(glu::getDataTypeName(type)) + "(" + iVal + ")" : iVal);
1221         }
1222
1223         return str.str();
1224 }
1225
1226 std::string generateArrayConstructorString (const glu::DataType elemType,
1227                                                                                         const int                       size1,
1228                                                                                         const int                       size2,
1229                                                                                         const std::string&      specConstName,
1230                                                                                         const int                       specConstNdx)
1231 {
1232         const bool isArrayOfArray = (size2 > 0);
1233         const bool doCast                 = (!isDataTypeScalar(elemType));
1234
1235         std::ostringstream arrayCtorExpr;
1236
1237         if (isArrayOfArray)
1238         {
1239                 const std::string padding  (36, ' ');
1240                 int               idxBegin = 0;
1241                 int               idxEnd   = size2;
1242
1243                 for (int iterNdx = 0; iterNdx < size1; ++iterNdx)
1244                 {
1245                         // Open sub-array ctor
1246                         arrayCtorExpr << (iterNdx != 0 ? ",\n" + padding : "") << glu::getDataTypeName(elemType) << "[" << size2 << "](";
1247
1248                         // Sub-array constructor elements
1249                         arrayCtorExpr << generateInitializerListWithSpecConstant(elemType, doCast, idxBegin, idxEnd, specConstName, specConstNdx);
1250
1251                         // Close sub-array ctor, move to next range
1252                         arrayCtorExpr << ")";
1253
1254                         idxBegin += size2;
1255                         idxEnd += size2;
1256                 }
1257         }
1258         else
1259         {
1260                 // Array constructor elements
1261                 arrayCtorExpr << generateInitializerListWithSpecConstant(elemType, doCast, 0, size1, specConstName, specConstNdx);
1262         }
1263
1264         return arrayCtorExpr.str();
1265 }
1266
1267 inline GenericValue makeValue (const glu::DataType type, const int specValue)
1268 {
1269         if (type == glu::TYPE_DOUBLE)
1270                 return makeValueFloat64(static_cast<double>(specValue));
1271         else if (type == glu::TYPE_FLOAT)
1272                 return makeValueFloat32(static_cast<float>(specValue));
1273         else
1274                 return makeValueInt32(specValue);
1275 }
1276
1277 deUint32 getDataTypeScalarSizeBytes (const glu::DataType dataType)
1278 {
1279         switch (getDataTypeScalarType(dataType))
1280         {
1281                 case glu::TYPE_FLOAT:
1282                 case glu::TYPE_INT:
1283                 case glu::TYPE_UINT:
1284                 case glu::TYPE_BOOL:
1285                         return 4;
1286
1287                 case glu::TYPE_DOUBLE:
1288                         return 8;
1289
1290                 default:
1291                         DE_ASSERT(false);
1292                         return 0;
1293         }
1294 }
1295
1296 //! This applies to matrices/vectors/array cases. dataType must be a basic type.
1297 std::vector<OffsetValue> computeExpectedValues (const int specValue, const glu::DataType dataType, const int numCombinations)
1298 {
1299         DE_ASSERT(glu::isDataTypeScalar(dataType));
1300
1301         std::vector<OffsetValue> expectedValues;
1302
1303         for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1304         {
1305                 int sum = 0;
1306                 for (int i = 0; i < numCombinations; ++i)
1307                         sum += (i == combNdx ? specValue : dataType == glu::TYPE_BOOL ? 1 : (i + 1));
1308
1309                 const int dataSize = getDataTypeScalarSizeBytes(dataType);
1310                 expectedValues.push_back(OffsetValue(dataSize, dataSize * combNdx, makeValue(dataType, sum)));
1311         }
1312
1313         return expectedValues;
1314 }
1315
1316 inline std::string getFirstDataElementSubscriptString (const glu::DataType type)
1317 {
1318         // Grab the first element of a matrix/vector, if dealing with non-basic types.
1319         return (isDataTypeMatrix(type) ? "[0][0]" : isDataTypeVector(type) ? "[0]" : "");
1320 }
1321
1322 //! This code will go into the main function.
1323 std::string generateShaderChecksumComputationCode (const glu::DataType  elemType,
1324                                                                                                    const std::string&   varName,
1325                                                                                                    const std::string&   accumType,
1326                                                                                                    const int                    size1,
1327                                                                                                    const int                    size2,
1328                                                                                                    const int                    numCombinations)
1329 {
1330         std::ostringstream mainCode;
1331
1332         // Generate main code to calculate checksums for each array
1333         for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1334                 mainCode << "    "<< accumType << " sum_" << varName << combNdx << " = " << accumType << "(0);\n";
1335
1336         if (size2 > 0)
1337         {
1338                 mainCode << "\n"
1339                                         << "    for (int i = 0; i < " << size1 << "; ++i)\n"
1340                                         << "    for (int j = 0; j < " << size2 << "; ++j)\n"
1341                                         << "    {\n";
1342
1343                 for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1344                         mainCode << "        sum_" << varName << combNdx << " += " << accumType << "("
1345                                          << varName << combNdx << "[i][j]" << getFirstDataElementSubscriptString(elemType) << ");\n";
1346         }
1347         else
1348         {
1349                 mainCode << "\n"
1350                                         << "    for (int i = 0; i < " << size1 << "; ++i)\n"
1351                                         << "    {\n";
1352
1353                 for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1354                         mainCode << "        sum_" << varName << combNdx << " += " << accumType << "("
1355                                          << varName << combNdx << "[i]" << getFirstDataElementSubscriptString(elemType) << ");\n";
1356         }
1357
1358         mainCode << "    }\n"
1359                                 << "\n";
1360
1361         for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1362                 mainCode << "    sb_out.result[" << combNdx << "] = sum_" << varName << combNdx << ";\n";
1363
1364         return mainCode.str();
1365 }
1366
1367 SpecConstant makeSpecConstant (const std::string specConstName, const deUint32 specConstId, const glu::DataType type, const int specValue)
1368 {
1369         DE_ASSERT(glu::isDataTypeScalar(type));
1370
1371         const std::string typeName(glu::getDataTypeName(type));
1372
1373         return SpecConstant(
1374                 specConstId,
1375                 "layout(constant_id = ${ID}) const " + typeName + " " + specConstName + " = " + typeName + "(1);",
1376                 getDataTypeScalarSizeBytes(type), makeValue(type, specValue));
1377 }
1378
1379 } // composite_case_internal ns
1380
1381 //! Generate a CaseDefinition for a composite test using a matrix or vector (a 1-column matrix)
1382 CaseDefinition makeMatrixVectorCompositeCaseDefinition (const glu::DataType type)
1383 {
1384         using namespace composite_case_internal;
1385
1386         DE_ASSERT(!glu::isDataTypeScalar(type));
1387
1388         const std::string   varName         = (glu::isDataTypeMatrix(type) ? "m" : "v");
1389         const int           numCombinations = getDataTypeScalarSize(type);
1390         const glu::DataType scalarType      = glu::getDataTypeScalarType(type);
1391         const std::string   typeName        = glu::getDataTypeName(type);
1392         const bool                      isConst         = (scalarType != glu::TYPE_FLOAT) && (scalarType != glu::TYPE_DOUBLE);
1393
1394         std::ostringstream globalCode;
1395         {
1396                 // Build N matrices/vectors with specialization constant inserted at various locations in the constructor.
1397                 for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1398                         globalCode << ( isConst ? "const " : "" ) << typeName << " " << varName << combNdx << " = " << typeName << "("
1399                                            << generateInitializerListWithSpecConstant(type, false, 0, numCombinations, "sc0", combNdx) << ");\n";
1400         }
1401
1402         const bool        isBoolElement = (scalarType == glu::TYPE_BOOL);
1403         const int         specValue     = (isBoolElement ? 0 : 42);
1404         const std::string accumType     = glu::getDataTypeName(isBoolElement ? glu::TYPE_INT : scalarType);
1405
1406         const int size1 = glu::isDataTypeMatrix(type) ? glu::getDataTypeMatrixNumColumns(type) : glu::getDataTypeNumComponents(type);
1407         const int size2 = glu::isDataTypeMatrix(type) ? glu::getDataTypeMatrixNumRows(type)    : 0;
1408
1409         const CaseDefinition def =
1410         {
1411                 typeName,
1412                 makeVector(makeSpecConstant("sc0", 1u, scalarType, specValue)),
1413                 static_cast<VkDeviceSize>(getDataTypeScalarSizeBytes(type) * numCombinations),
1414                 "    " + accumType + " result[" + de::toString(numCombinations) + "];\n",
1415                 globalCode.str(),
1416                 generateShaderChecksumComputationCode(scalarType, varName, accumType, size1, size2, numCombinations),
1417                 computeExpectedValues(specValue, scalarType, numCombinations),
1418                 (scalarType == glu::TYPE_DOUBLE ? (FeatureFlags)FEATURE_SHADER_FLOAT_64 : (FeatureFlags)0),
1419         };
1420         return def;
1421 }
1422
1423 //! Generate a CaseDefinition for a composite test using an array, or an array of array.
1424 //! If (size1, size2) = (N, 0) -> type array[N]
1425 //!                   = (N, M) -> type array[N][M]
1426 CaseDefinition makeArrayCompositeCaseDefinition (const glu::DataType elemType, const int size1, const int size2 = 0)
1427 {
1428         using namespace composite_case_internal;
1429
1430         DE_ASSERT(size1 > 0);
1431
1432         const bool        isArrayOfArray  = (size2 > 0);
1433         const std::string varName                 = "a";
1434         const std::string arraySizeDecl   = "[" + de::toString(size1) + "]" + (isArrayOfArray ? "[" + de::toString(size2) + "]" : "");
1435         const int         numCombinations = (isArrayOfArray ? size1 * size2 : size1);
1436         const std::string elemTypeName    (glu::getDataTypeName(elemType));
1437
1438         std::ostringstream globalCode;
1439         {
1440                 // Create several arrays with specialization constant inserted in different positions.
1441                 for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1442                         globalCode << elemTypeName << " " << varName << combNdx << arraySizeDecl << " = "
1443                                            << elemTypeName << arraySizeDecl << "(" << generateArrayConstructorString(elemType, size1, size2, "sc0", combNdx) << ");\n";
1444         }
1445
1446         const glu::DataType scalarType = glu::getDataTypeScalarType(elemType);
1447         const bool          isBoolData = (scalarType == glu::TYPE_BOOL);
1448         const int           specValue  = (isBoolData ? 0 : 19);
1449         const std::string   caseName   = (isArrayOfArray ? "array_" : "") + elemTypeName;
1450         const std::string   accumType  = (glu::getDataTypeName(isBoolData ? glu::TYPE_INT : scalarType));
1451
1452         const CaseDefinition def =
1453         {
1454                 caseName,
1455                 makeVector(makeSpecConstant("sc0", 1u, scalarType, specValue)),
1456                 static_cast<VkDeviceSize>(getDataTypeScalarSizeBytes(elemType) * numCombinations),
1457                 "    " + accumType + " result[" + de::toString(numCombinations) + "];\n",
1458                 globalCode.str(),
1459                 generateShaderChecksumComputationCode(elemType, varName, accumType, size1, size2, numCombinations),
1460                 computeExpectedValues(specValue, scalarType, numCombinations),
1461                 (scalarType == glu::TYPE_DOUBLE ? (FeatureFlags)FEATURE_SHADER_FLOAT_64 : (FeatureFlags)0),
1462         };
1463         return def;
1464 }
1465
1466 //! A basic struct case, where one member is a specialization constant, or a specialization constant composite
1467 //! (a matrix/vector with a spec. const. element).
1468 CaseDefinition makeStructCompositeCaseDefinition (const glu::DataType memberType)
1469 {
1470         using namespace composite_case_internal;
1471
1472         std::ostringstream globalCode;
1473         {
1474                 globalCode << "struct Data {\n"
1475                                    << "    int   i;\n"
1476                                    << "    float f;\n"
1477                                    << "    bool  b;\n"
1478                                    << "    " << glu::getDataTypeName(memberType) << " sc;\n"
1479                                    << "    uint  ui;\n"
1480                                    << "};\n"
1481                                    << "\n"
1482                                    << "Data s0 = Data(3, 2.0, true, " << glu::getDataTypeName(memberType) << "(sc0), 8u);\n";
1483         }
1484
1485         const glu::DataType scalarType   = glu::getDataTypeScalarType(memberType);
1486         const bool          isBoolData   = (scalarType == glu::TYPE_BOOL);
1487         const int           specValue    = (isBoolData ? 0 : 23);
1488         const int           checksum     = (3 + 2 + 1 + specValue + 8);  // matches the shader code
1489         const glu::DataType accumType    = (isBoolData ? glu::TYPE_INT : scalarType);
1490         const std::string   accumTypeStr = glu::getDataTypeName(accumType);
1491
1492         std::ostringstream mainCode;
1493         {
1494                 mainCode << "    " << accumTypeStr << " sum_s0 = " << accumTypeStr << "(0);\n"
1495                                  << "\n"
1496                                  << "    sum_s0 += " << accumTypeStr << "(s0.i);\n"
1497                                  << "    sum_s0 += " << accumTypeStr << "(s0.f);\n"
1498                                  << "    sum_s0 += " << accumTypeStr << "(s0.b);\n"
1499                                  << "    sum_s0 += " << accumTypeStr << "(s0.sc" << getFirstDataElementSubscriptString(memberType) << ");\n"
1500                                  << "    sum_s0 += " << accumTypeStr << "(s0.ui);\n"
1501                                  << "\n"
1502                                  << "    sb_out.result = sum_s0;\n";
1503         }
1504
1505         const std::string caseName = glu::getDataTypeName(memberType);
1506
1507         const CaseDefinition def =
1508         {
1509                 caseName,
1510                 makeVector(makeSpecConstant("sc0", 1u, scalarType, specValue)),
1511                 getDataTypeScalarSizeBytes(accumType),
1512                 "    " + accumTypeStr + " result;\n",
1513                 globalCode.str(),
1514                 mainCode.str(),
1515                 makeVector(OffsetValue(getDataTypeScalarSizeBytes(memberType), 0, makeValue(scalarType, checksum))),
1516                 (scalarType == glu::TYPE_DOUBLE ? (FeatureFlags)FEATURE_SHADER_FLOAT_64 : (FeatureFlags)0),
1517         };
1518         return def;
1519 }
1520
1521 //! Specialization constants used in composites.
1522 tcu::TestCaseGroup* createCompositeTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage)
1523 {
1524         de::MovePtr<tcu::TestCaseGroup> compositeTests (new tcu::TestCaseGroup(testCtx, "composite", "specialization constants usage in composite types"));
1525
1526         // Vectors
1527         {
1528                 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "vector", ""));
1529
1530                 const glu::DataType types[] =
1531                 {
1532                         glu::TYPE_FLOAT_VEC2,
1533                         glu::TYPE_FLOAT_VEC3,
1534                         glu::TYPE_FLOAT_VEC4,
1535
1536                         glu::TYPE_DOUBLE_VEC2,
1537                         glu::TYPE_DOUBLE_VEC3,
1538                         glu::TYPE_DOUBLE_VEC4,
1539
1540                         glu::TYPE_BOOL_VEC2,
1541                         glu::TYPE_BOOL_VEC3,
1542                         glu::TYPE_BOOL_VEC4,
1543
1544                         glu::TYPE_INT_VEC2,
1545                         glu::TYPE_INT_VEC3,
1546                         glu::TYPE_INT_VEC4,
1547
1548                         glu::TYPE_UINT_VEC2,
1549                         glu::TYPE_UINT_VEC3,
1550                         glu::TYPE_UINT_VEC4,
1551                 };
1552                 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(types); ++typeNdx)
1553                         group->addChild(new SpecConstantTest(testCtx, shaderStage, makeMatrixVectorCompositeCaseDefinition(types[typeNdx])));
1554
1555                 compositeTests->addChild(group.release());
1556         }
1557
1558         // Matrices
1559         {
1560                 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "matrix", ""));
1561
1562                 const glu::DataType types[] =
1563                 {
1564                         glu::TYPE_FLOAT_MAT2,
1565                         glu::TYPE_FLOAT_MAT2X3,
1566                         glu::TYPE_FLOAT_MAT2X4,
1567                         glu::TYPE_FLOAT_MAT3X2,
1568                         glu::TYPE_FLOAT_MAT3,
1569                         glu::TYPE_FLOAT_MAT3X4,
1570                         glu::TYPE_FLOAT_MAT4X2,
1571                         glu::TYPE_FLOAT_MAT4X3,
1572                         glu::TYPE_FLOAT_MAT4,
1573
1574                         glu::TYPE_DOUBLE_MAT2,
1575                         glu::TYPE_DOUBLE_MAT2X3,
1576                         glu::TYPE_DOUBLE_MAT2X4,
1577                         glu::TYPE_DOUBLE_MAT3X2,
1578                         glu::TYPE_DOUBLE_MAT3,
1579                         glu::TYPE_DOUBLE_MAT3X4,
1580                         glu::TYPE_DOUBLE_MAT4X2,
1581                         glu::TYPE_DOUBLE_MAT4X3,
1582                         glu::TYPE_DOUBLE_MAT4,
1583                 };
1584                 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(types); ++typeNdx)
1585                         group->addChild(new SpecConstantTest(testCtx, shaderStage, makeMatrixVectorCompositeCaseDefinition(types[typeNdx])));
1586
1587                 compositeTests->addChild(group.release());
1588         }
1589
1590         const glu::DataType allTypes[] =
1591         {
1592                 glu::TYPE_FLOAT,
1593                 glu::TYPE_FLOAT_VEC2,
1594                 glu::TYPE_FLOAT_VEC3,
1595                 glu::TYPE_FLOAT_VEC4,
1596                 glu::TYPE_FLOAT_MAT2,
1597                 glu::TYPE_FLOAT_MAT2X3,
1598                 glu::TYPE_FLOAT_MAT2X4,
1599                 glu::TYPE_FLOAT_MAT3X2,
1600                 glu::TYPE_FLOAT_MAT3,
1601                 glu::TYPE_FLOAT_MAT3X4,
1602                 glu::TYPE_FLOAT_MAT4X2,
1603                 glu::TYPE_FLOAT_MAT4X3,
1604                 glu::TYPE_FLOAT_MAT4,
1605
1606                 glu::TYPE_DOUBLE,
1607                 glu::TYPE_DOUBLE_VEC2,
1608                 glu::TYPE_DOUBLE_VEC3,
1609                 glu::TYPE_DOUBLE_VEC4,
1610                 glu::TYPE_DOUBLE_MAT2,
1611                 glu::TYPE_DOUBLE_MAT2X3,
1612                 glu::TYPE_DOUBLE_MAT2X4,
1613                 glu::TYPE_DOUBLE_MAT3X2,
1614                 glu::TYPE_DOUBLE_MAT3,
1615                 glu::TYPE_DOUBLE_MAT3X4,
1616                 glu::TYPE_DOUBLE_MAT4X2,
1617                 glu::TYPE_DOUBLE_MAT4X3,
1618                 glu::TYPE_DOUBLE_MAT4,
1619
1620                 glu::TYPE_INT,
1621                 glu::TYPE_INT_VEC2,
1622                 glu::TYPE_INT_VEC3,
1623                 glu::TYPE_INT_VEC4,
1624
1625                 glu::TYPE_UINT,
1626                 glu::TYPE_UINT_VEC2,
1627                 glu::TYPE_UINT_VEC3,
1628                 glu::TYPE_UINT_VEC4,
1629
1630                 glu::TYPE_BOOL,
1631                 glu::TYPE_BOOL_VEC2,
1632                 glu::TYPE_BOOL_VEC3,
1633                 glu::TYPE_BOOL_VEC4,
1634         };
1635
1636         // Array cases
1637         {
1638                 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "array", ""));
1639
1640                 // Array of T
1641                 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(allTypes); ++typeNdx)
1642                         group->addChild(new SpecConstantTest(testCtx, shaderStage, makeArrayCompositeCaseDefinition(allTypes[typeNdx], 3)));
1643
1644                 // Array of array of T
1645                 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(allTypes); ++typeNdx)
1646                         group->addChild(new SpecConstantTest(testCtx, shaderStage, makeArrayCompositeCaseDefinition(allTypes[typeNdx], 3, 2)));
1647
1648                 // Special case - array of struct
1649                 {
1650                         const int checksum = (3 + 2 + 1) + (1 + 5 + 1) + (1 + 2 + 0);
1651                         const CaseDefinition def =
1652                         {
1653                                 "struct",
1654                                 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int   sc0 = 1;",    4, makeValueInt32  (3)),
1655                                                    SpecConstant(2u, "layout(constant_id = ${ID}) const float sc1 = 1.0;",  4, makeValueFloat32(5.0f)),
1656                                                    SpecConstant(3u, "layout(constant_id = ${ID}) const bool  sc2 = true;", 4, makeValueBool32 (false))),
1657                                 4,
1658                                 "    int result;\n",
1659
1660                                 "struct Data {\n"
1661                                 "    int   x;\n"
1662                                 "    float y;\n"
1663                                 "    bool  z;\n"
1664                                 "};\n"
1665                                 "\n"
1666                                 "Data a0[3] = Data[3](Data(sc0, 2.0, true), Data(1, sc1, true), Data(1, 2.0, sc2));\n",
1667
1668                                 "    int sum_a0 = 0;\n"
1669                                 "\n"
1670                                 "    for (int i = 0; i < 3; ++i)\n"
1671                                 "        sum_a0 += int(a0[i].x) + int(a0[i].y) + int(a0[i].z);\n"
1672                                 "\n"
1673                                 "    sb_out.result = sum_a0;\n",
1674
1675                                 makeVector(OffsetValue(4,  0, makeValueInt32(checksum))),
1676                                 (FeatureFlags)0,
1677                         };
1678
1679                         group->addChild(new SpecConstantTest(testCtx, shaderStage, def));
1680                 }
1681
1682                 compositeTests->addChild(group.release());
1683         }
1684
1685         // Struct cases
1686         {
1687                 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "struct", ""));
1688
1689                 // Struct with one member being a specialization constant (or spec. const. composite) of a given type
1690                 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(allTypes); ++typeNdx)
1691                         group->addChild(new SpecConstantTest(testCtx, shaderStage, makeStructCompositeCaseDefinition(allTypes[typeNdx])));
1692
1693                 // Special case - struct with array
1694                 {
1695                         const int checksum = (1 + 2 + 31 + 4 + 0);
1696                         const CaseDefinition def =
1697                         {
1698                                 "array",
1699                                 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 1.0;",  4, makeValueFloat32(31.0f))),
1700                                 4,
1701                                 "    float result;\n",
1702
1703                                 "struct Data {\n"
1704                                 "    int  i;\n"
1705                                 "    vec3 sc[3];\n"
1706                                 "    bool b;\n"
1707                                 "};\n"
1708                                 "\n"
1709                                 "Data s0 = Data(1, vec3[3](vec3(2.0), vec3(sc0), vec3(4.0)), false);\n",
1710
1711                                 "    float sum_s0 = 0;\n"
1712                                 "\n"
1713                                 "    sum_s0 += float(s0.i);\n"
1714                                 "    sum_s0 += float(s0.sc[0][0]);\n"
1715                                 "    sum_s0 += float(s0.sc[1][0]);\n"
1716                                 "    sum_s0 += float(s0.sc[2][0]);\n"
1717                                 "    sum_s0 += float(s0.b);\n"
1718                                 "\n"
1719                                 "    sb_out.result = sum_s0;\n",
1720
1721                                 makeVector(OffsetValue(4,  0, makeValueFloat32(static_cast<float>(checksum)))),
1722                                 (FeatureFlags)0,
1723                         };
1724
1725                         group->addChild(new SpecConstantTest(testCtx, shaderStage, def));
1726                 }
1727
1728                 // Special case - struct of struct
1729                 {
1730                         const int checksum = (1 + 2 + 11 + 4 + 1);
1731                         const CaseDefinition def =
1732                         {
1733                                 "struct",
1734                                 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;",  4, makeValueInt32(11))),
1735                                 4,
1736                                 "    int result;\n",
1737
1738                                 "struct Nested {\n"
1739                                 "    vec2  v;\n"
1740                                 "    int   sc;\n"
1741                                 "    float f;\n"
1742                                 "};\n"
1743                                 "\n"
1744                                 "struct Data {\n"
1745                                 "    uint   ui;\n"
1746                                 "    Nested s;\n"
1747                                 "    bool   b;\n"
1748                                 "};\n"
1749                                 "\n"
1750                                 "Data s0 = Data(1u, Nested(vec2(2.0), sc0, 4.0), true);\n",
1751
1752                                 "    int sum_s0 = 0;\n"
1753                                 "\n"
1754                                 "    sum_s0 += int(s0.ui);\n"
1755                                 "    sum_s0 += int(s0.s.v[0]);\n"
1756                                 "    sum_s0 += int(s0.s.sc);\n"
1757                                 "    sum_s0 += int(s0.s.f);\n"
1758                                 "    sum_s0 += int(s0.b);\n"
1759                                 "\n"
1760                                 "    sb_out.result = sum_s0;\n",
1761
1762                                 makeVector(OffsetValue(4,  0, makeValueInt32(checksum))),
1763                                 (FeatureFlags)0,
1764                         };
1765
1766                         group->addChild(new SpecConstantTest(testCtx, shaderStage, def));
1767                 }
1768
1769                 compositeTests->addChild(group.release());
1770         }
1771
1772         return compositeTests.release();
1773 }
1774
1775 } // anonymous ns
1776
1777 tcu::TestCaseGroup* createSpecConstantTests (tcu::TestContext& testCtx)
1778 {
1779         de::MovePtr<tcu::TestCaseGroup> allTests (new tcu::TestCaseGroup(testCtx, "spec_constant", "Specialization constants tests"));
1780         de::MovePtr<tcu::TestCaseGroup> graphicsGroup (new tcu::TestCaseGroup(testCtx, "graphics", ""));
1781
1782         struct StageDef
1783         {
1784                 tcu::TestCaseGroup*             parentGroup;
1785                 const char*                             name;
1786                 VkShaderStageFlagBits   stage;
1787         };
1788
1789         const StageDef stages[] =
1790         {
1791                 { graphicsGroup.get(),  "vertex",               VK_SHADER_STAGE_VERTEX_BIT                                      },
1792                 { graphicsGroup.get(),  "fragment",             VK_SHADER_STAGE_FRAGMENT_BIT                            },
1793                 { graphicsGroup.get(),  "tess_control", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT        },
1794                 { graphicsGroup.get(),  "tess_eval",    VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT     },
1795                 { graphicsGroup.get(),  "geometry",             VK_SHADER_STAGE_GEOMETRY_BIT                            },
1796                 { allTests.get(),               "compute",              VK_SHADER_STAGE_COMPUTE_BIT                                     },
1797         };
1798
1799         allTests->addChild(graphicsGroup.release());
1800
1801         for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(stages); ++stageNdx)
1802         {
1803                 const StageDef& stage = stages[stageNdx];
1804                 de::MovePtr<tcu::TestCaseGroup> stageGroup (new tcu::TestCaseGroup(testCtx, stage.name, ""));
1805
1806                 stageGroup->addChild(createDefaultValueTests       (testCtx, stage.stage));
1807                 stageGroup->addChild(createBasicSpecializationTests(testCtx, stage.stage));
1808                 stageGroup->addChild(createBuiltInOverrideTests    (testCtx, stage.stage));
1809                 stageGroup->addChild(createExpressionTests         (testCtx, stage.stage));
1810                 stageGroup->addChild(createCompositeTests          (testCtx, stage.stage));
1811
1812                 if (stage.stage == VK_SHADER_STAGE_COMPUTE_BIT)
1813                         stageGroup->addChild(createWorkGroupSizeTests(testCtx));
1814
1815                 stage.parentGroup->addChild(stageGroup.release());
1816         }
1817
1818         return allTests.release();
1819 }
1820
1821 } // pipeline
1822 } // vkt