Test behaviour of color write enable with colorWriteMask
[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 #include "tcuFloat.hpp"
33
34 #include "gluShaderUtil.hpp"
35
36 #include "vkBuilderUtil.hpp"
37 #include "vkPrograms.hpp"
38 #include "vkRefUtil.hpp"
39 #include "vkTypeUtil.hpp"
40 #include "vkImageUtil.hpp"
41 #include "vkBarrierUtil.hpp"
42 #include "vkCmdUtil.hpp"
43 #include "vkObjUtil.hpp"
44
45 #include "deUniquePtr.hpp"
46 #include "deStringUtil.hpp"
47
48 #include <limits>
49
50 namespace vkt
51 {
52 namespace pipeline
53 {
54
55 using namespace vk;
56
57 namespace
58 {
59
60 static const char* const s_perVertexBlock =     "gl_PerVertex {\n"
61                                                                                         "    vec4 gl_Position;\n"
62                                                                                         "}";
63
64 //! Raw memory storage for values used in test cases.
65 //! We use it to simplify test case definitions where different types are expected in the result.
66 class GenericValue
67 {
68 public:
69         GenericValue (void) { clear(); }
70
71         //! Copy up to 'size' bytes of 'data'.
72         GenericValue (const void* data, const deUint32 size)
73         {
74                 DE_ASSERT(size <= sizeof(m_data));
75                 clear();
76                 deMemcpy(&m_data, data, size);
77         }
78
79 private:
80         deUint64 m_data;
81
82         void clear (void) { m_data = 0; }
83 };
84
85 inline GenericValue makeValueBool32      (const bool a)                 { return GenericValue(&a, sizeof(a)); }
86 inline GenericValue makeValueInt8    (const deInt8 a)           { return GenericValue(&a, sizeof(a)); }
87 inline GenericValue makeValueUint8   (const deUint8 a)          { return GenericValue(&a, sizeof(a)); }
88 inline GenericValue makeValueInt16   (const deInt16 a)          { return GenericValue(&a, sizeof(a)); }
89 inline GenericValue makeValueUint16  (const deUint16 a)         { return GenericValue(&a, sizeof(a)); }
90 inline GenericValue makeValueInt32       (const deInt32 a)              { return GenericValue(&a, sizeof(a)); }
91 inline GenericValue makeValueUint32      (const deUint32 a)             { return GenericValue(&a, sizeof(a)); }
92 inline GenericValue makeValueInt64   (const deInt64 a)          { return GenericValue(&a, sizeof(a)); }
93 inline GenericValue makeValueUint64  (const deUint64 a)         { return GenericValue(&a, sizeof(a)); }
94 inline GenericValue makeValueFloat16 (const tcu::Float16 a)     { return GenericValue(&a, sizeof(a)); }
95 inline GenericValue makeValueFloat32 (const float a)            { return GenericValue(&a, sizeof(a)); }
96 inline GenericValue makeValueFloat64 (const double a)           { return GenericValue(&a, sizeof(a)); }
97
98 struct SpecConstant
99 {
100         deUint32                        specID;                         //!< specialization constant ID
101         std::string                     declarationCode;        //!< syntax to declare the constant, use ${ID} as an ID placeholder
102         deUint32                        size;                           //!< data size on the host, 0 = no specialized value
103         GenericValue            specValue;                      //!< specialized value passed by the API
104
105         SpecConstant (const deUint32 specID_, const std::string declarationCode_)
106                 : specID                        (specID_)
107                 , declarationCode       (declarationCode_)
108                 , size                          (0)
109                 , specValue                     ()
110         {
111         }
112
113         SpecConstant (const deUint32 specID_, const std::string declarationCode_, const deUint32 size_, const GenericValue specValue_)
114                 : specID                        (specID_)
115                 , declarationCode       (declarationCode_)
116                 , size                          (size_)
117                 , specValue                     (specValue_)
118         {
119         }
120 };
121
122 //! Useful when referring to a value in a buffer (i.e. check expected values in SSBO).
123 struct OffsetValue
124 {
125         deUint32                size;           //!< data size in the buffer (up to sizeof(value))
126         deUint32                offset;         //!< offset into the buffer
127         GenericValue    value;          //!< value expected to be there
128
129         OffsetValue (const deUint32 size_, const deUint32 offset_, const GenericValue value_)
130                 : size          (size_)
131                 , offset        (offset_)
132                 , value         (value_)
133         {}
134 };
135
136 //! Get the integer value of 'size' bytes at 'memory' location.
137 deUint64 memoryAsInteger (const void* memory, const deUint32 size)
138 {
139         DE_ASSERT(size <= sizeof(deUint64));
140         deUint64 value = 0;
141         deMemcpy(&value, memory, size);
142         return value;
143 }
144
145 inline std::string memoryAsHexString (const void* memory, const deUint32 size)
146 {
147         const deUint8* memoryBytePtr = static_cast<const deUint8*>(memory);
148         return de::toString(tcu::formatArray(tcu::Format::HexIterator<deUint8>(memoryBytePtr), tcu::Format::HexIterator<deUint8>(memoryBytePtr + size)));
149 }
150
151 void logValueMismatch (tcu::TestLog& log, const void* expected, const void* actual, const deUint32 offset, const deUint32 size)
152 {
153         const bool canDisplayValue = (size <= sizeof(deUint64));
154         log << tcu::TestLog::Message
155                 << "Comparison failed for value at offset " << de::toString(offset) << ": expected "
156                 << (canDisplayValue ? de::toString(memoryAsInteger(expected, size)) + " " : "") << memoryAsHexString(expected, size) << " but got "
157                 << (canDisplayValue ? de::toString(memoryAsInteger(actual, size)) + " " : "") << memoryAsHexString(actual, size)
158                 << tcu::TestLog::EndMessage;
159 }
160
161 //! Check if expected values exist in the memory.
162 bool verifyValues (tcu::TestLog& log, const void* memory, const std::vector<OffsetValue>& expectedValues)
163 {
164         bool ok = true;
165         log << tcu::TestLog::Section("compare", "Verify result values");
166
167         for (std::vector<OffsetValue>::const_iterator it = expectedValues.begin(); it < expectedValues.end(); ++it)
168         {
169                 const char* const valuePtr = static_cast<const char*>(memory) + it->offset;
170                 if (deMemCmp(valuePtr, &it->value, it->size) != 0)
171                 {
172                         ok = false;
173                         logValueMismatch(log, &it->value, valuePtr, it->offset, it->size);
174                 }
175         }
176
177         if (ok)
178                 log << tcu::TestLog::Message << "All OK" << tcu::TestLog::EndMessage;
179
180         log << tcu::TestLog::EndSection;
181         return ok;
182 }
183
184 //! Bundles together common test case parameters.
185 struct CaseDefinition
186 {
187         std::string                                     name;                           //!< Test case name
188         std::vector<SpecConstant>       specConstants;          //!< list of specialization constants to declare
189         VkDeviceSize                            ssboSize;                       //!< required ssbo size in bytes
190         std::string                                     ssboCode;                       //!< ssbo member definitions
191         std::string                                     globalCode;                     //!< generic shader code outside the main function (e.g. declarations)
192         std::string                                     mainCode;                       //!< generic shader code to execute in main (e.g. assignments)
193         std::vector<OffsetValue>        expectedValues;         //!< list of values to check inside the ssbo buffer
194         FeatureFlags                            requirements;           //!< features the implementation must support to allow this test to run
195         bool                                            packData;                       //!< whether to tightly pack specialization constant data or not
196 };
197
198 //! Manages Vulkan structures to pass specialization data.
199 class Specialization
200 {
201 public:
202                                                                                         Specialization (const std::vector<SpecConstant>& specConstants, bool packData);
203
204         //! Can return NULL if nothing is specialized
205         const VkSpecializationInfo*                             getSpecializationInfo (void) const { return m_entries.size() > 0 ? &m_specialization : DE_NULL; }
206
207 private:
208         std::vector<deUint8>                                    m_data;
209         std::vector<VkSpecializationMapEntry>   m_entries;
210         VkSpecializationInfo                                    m_specialization;
211 };
212
213 Specialization::Specialization (const std::vector<SpecConstant>& specConstants, bool packData)
214 {
215         const auto kGenericValueSize = static_cast<deUint32>(sizeof(GenericValue));
216
217         // Reserve memory for the worst case in m_data.
218         m_data.resize(specConstants.size() * kGenericValueSize, std::numeric_limits<deUint8>::max());
219         m_entries.reserve(specConstants.size());
220
221         deUint32 offset = 0u;
222         for (const auto& sc : specConstants)
223         {
224                 if (sc.size != 0u)
225                 {
226                         deMemcpy(&m_data[offset], &sc.specValue, sc.size);
227                         m_entries.push_back(makeSpecializationMapEntry(sc.specID, offset, sc.size));
228                         offset += (packData ? sc.size : kGenericValueSize);
229                 }
230         }
231
232         if (m_entries.size() > 0)
233         {
234                 m_specialization.mapEntryCount = static_cast<deUint32>(m_entries.size());
235                 m_specialization.pMapEntries   = m_entries.data();
236                 m_specialization.dataSize          = static_cast<deUintptr>(offset);
237                 m_specialization.pData             = m_data.data();
238         }
239         else
240                 deMemset(&m_specialization, 0, sizeof(m_specialization));
241 }
242
243 class SpecConstantTest : public TestCase
244 {
245 public:
246                                                                 SpecConstantTest        (tcu::TestContext&                              testCtx,
247                                                                                                          const VkShaderStageFlagBits    stage,          //!< which shader stage is tested
248                                                                                                          const CaseDefinition&                  caseDef);
249
250         void                                            initPrograms            (SourceCollections&             programCollection) const;
251         TestInstance*                           createInstance          (Context&                               context) const;
252         virtual void                            checkSupport            (Context&                               context) const;
253
254 private:
255         const VkShaderStageFlagBits     m_stage;
256         const CaseDefinition            m_caseDef;
257 };
258
259 SpecConstantTest::SpecConstantTest (tcu::TestContext&                   testCtx,
260                                                                         const VkShaderStageFlagBits     stage,
261                                                                         const CaseDefinition&           caseDef)
262         : TestCase      (testCtx, caseDef.name, "")
263         , m_stage       (stage)
264         , m_caseDef     (caseDef)
265 {
266 }
267
268 //! Build a string that declares all specialization constants, replacing ${ID} with proper ID numbers.
269 std::string generateSpecConstantCode (const std::vector<SpecConstant>& specConstants)
270 {
271         std::ostringstream code;
272         for (std::vector<SpecConstant>::const_iterator it = specConstants.begin(); it != specConstants.end(); ++it)
273         {
274                 std::string decl = it->declarationCode;
275                 const std::string::size_type pos = decl.find("${ID}");
276                 if (pos != std::string::npos)
277                         decl.replace(pos, 5, de::toString(it->specID));
278                 code << decl << "\n";
279         }
280         code << "\n";
281         return code.str();
282 }
283
284 std::string generateSSBOCode (const std::string& memberDeclarations)
285 {
286         std::ostringstream code;
287         code << "layout (set = 0, binding = 0, std430) writeonly buffer Output {\n"
288                  << memberDeclarations
289                  << "} sb_out;\n"
290                  << "\n";
291         return code.str();
292 }
293
294 void SpecConstantTest::initPrograms (SourceCollections& programCollection) const
295 {
296         // Always add vertex and fragment to graphics stages
297         VkShaderStageFlags requiredStages = m_stage;
298
299         if (requiredStages & VK_SHADER_STAGE_ALL_GRAPHICS)
300                 requiredStages |= VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
301
302         if (requiredStages & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))
303                 requiredStages |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
304
305         // Either graphics or compute must be defined, but not both
306         DE_ASSERT(((requiredStages & VK_SHADER_STAGE_ALL_GRAPHICS) != 0) != ((requiredStages & VK_SHADER_STAGE_COMPUTE_BIT) != 0));
307
308         // Extensions needed for some tests.
309         std::ostringstream extStream;
310         if (m_caseDef.requirements & FEATURE_SHADER_INT_64)
311                 extStream << "#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require\n";
312         if (m_caseDef.requirements & FEATURE_SHADER_INT_16)
313                 extStream << "#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require\n";
314         if (m_caseDef.requirements & FEATURE_SHADER_INT_8)
315                 extStream << "#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require\n";
316         if (m_caseDef.requirements & FEATURE_SHADER_FLOAT_16)
317                 extStream << "#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require\n";
318         const std::string extensions = extStream.str();
319
320         // This makes glslang avoid the UniformAndStorage* capabilities.
321         const vk::ShaderBuildOptions buildOptions (programCollection.usedVulkanVersion, SPIRV_VERSION_1_3, 0u);
322
323         if (requiredStages & VK_SHADER_STAGE_VERTEX_BIT)
324         {
325                 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_VERTEX_BIT);
326                 std::ostringstream src;
327                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
328                         << extensions
329                         << "layout(location = 0) in highp vec4 position;\n"
330                         << "\n"
331                         << "out " << s_perVertexBlock << ";\n"
332                         << "\n"
333                         << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
334                         << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
335                         << (useSpecConst ? m_caseDef.globalCode + "\n" : "")
336                         << "void main (void)\n"
337                         << "{\n"
338                         << (useSpecConst ? m_caseDef.mainCode + "\n" : "")
339                         << "    gl_Position = position;\n"
340                         << "}\n";
341
342                 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()) << buildOptions;
343         }
344
345         if (requiredStages & VK_SHADER_STAGE_FRAGMENT_BIT)
346         {
347                 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_FRAGMENT_BIT);
348                 std::ostringstream src;
349                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
350                         << extensions
351                         << "layout(location = 0) out highp vec4 fragColor;\n"
352                         << "\n"
353                         << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
354                         << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
355                         << (useSpecConst ? m_caseDef.globalCode + "\n" : "")
356                         << "void main (void)\n"
357                         << "{\n"
358                         << (useSpecConst ? m_caseDef.mainCode + "\n" : "")
359                         << "    fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n"
360                         << "}\n";
361
362                 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()) << buildOptions;
363         }
364
365         if (requiredStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
366         {
367                 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
368                 std::ostringstream src;
369                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
370                         << extensions
371                         << "layout(vertices = 3) out;\n"
372                         << "\n"
373                         << "in " << s_perVertexBlock << " gl_in[gl_MaxPatchVertices];\n"
374                         << "\n"
375                         << "out " << s_perVertexBlock << " gl_out[];\n"
376                         << "\n"
377                         << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
378                         << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
379                         << (useSpecConst ? m_caseDef.globalCode + "\n" : "")
380                         << "void main (void)\n"
381                         << "{\n"
382                         << (useSpecConst ? m_caseDef.mainCode + "\n" : "")
383                         << "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
384                         << "    if (gl_InvocationID == 0)\n"
385                         << "    {\n"
386                         << "        gl_TessLevelInner[0] = 3;\n"
387                         << "        gl_TessLevelOuter[0] = 2;\n"
388                         << "        gl_TessLevelOuter[1] = 2;\n"
389                         << "        gl_TessLevelOuter[2] = 2;\n"
390                         << "    }\n"
391                         << "}\n";
392
393                 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str()) << buildOptions;
394         }
395
396         if (requiredStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
397         {
398                 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
399                 std::ostringstream src;
400                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
401                         << extensions
402                         << "layout(triangles, equal_spacing, ccw) in;\n"
403                         << "\n"
404                         << "in " << s_perVertexBlock << " gl_in[gl_MaxPatchVertices];\n"
405                         << "\n"
406                         << "out " << s_perVertexBlock << ";\n"
407                         << "\n"
408                         << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
409                         << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
410                         << (useSpecConst ? m_caseDef.globalCode + "\n" : "")
411                         << "void main (void)\n"
412                         << "{\n"
413                         << (useSpecConst ? m_caseDef.mainCode + "\n" : "")
414                         << "    vec3 p0 = gl_TessCoord.x * gl_in[0].gl_Position.xyz;\n"
415                         << "    vec3 p1 = gl_TessCoord.y * gl_in[1].gl_Position.xyz;\n"
416                         << "    vec3 p2 = gl_TessCoord.z * gl_in[2].gl_Position.xyz;\n"
417                         << "    gl_Position = vec4(p0 + p1 + p2, 1.0);\n"
418                         << "}\n";
419
420                 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str()) << buildOptions;
421         }
422
423         if (requiredStages & VK_SHADER_STAGE_GEOMETRY_BIT)
424         {
425                 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_GEOMETRY_BIT);
426                 std::ostringstream src;
427                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
428                         << extensions
429                         << "layout(triangles) in;\n"
430                         << "layout(triangle_strip, max_vertices = 3) out;\n"
431                         << "\n"
432                         << "in " << s_perVertexBlock << " gl_in[];\n"
433                         << "\n"
434                         << "out " << s_perVertexBlock << ";\n"
435                         << "\n"
436                         << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
437                         << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
438                         << (useSpecConst ? m_caseDef.globalCode + "\n" : "")
439                         << "void main (void)\n"
440                         << "{\n"
441                         << (useSpecConst ? m_caseDef.mainCode + "\n" : "")
442                         << "    gl_Position = gl_in[0].gl_Position;\n"
443                         << "    EmitVertex();\n"
444                         << "\n"
445                         << "    gl_Position = gl_in[1].gl_Position;\n"
446                         << "    EmitVertex();\n"
447                         << "\n"
448                         << "    gl_Position = gl_in[2].gl_Position;\n"
449                         << "    EmitVertex();\n"
450                         << "\n"
451                         << "    EndPrimitive();\n"
452                         << "}\n";
453
454                 programCollection.glslSources.add("geom") << glu::GeometrySource(src.str()) << buildOptions;
455         }
456
457         if (requiredStages & VK_SHADER_STAGE_COMPUTE_BIT)
458         {
459                 std::ostringstream src;
460                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
461                         << extensions
462                         // Don't define work group size, use the default or specialization constants
463                         << "\n"
464                         << generateSpecConstantCode(m_caseDef.specConstants)
465                         << generateSSBOCode(m_caseDef.ssboCode)
466                         << m_caseDef.globalCode + "\n"
467                         << "void main (void)\n"
468                         << "{\n"
469                         << m_caseDef.mainCode
470                         << "}\n";
471
472                 programCollection.glslSources.add("comp") << glu::ComputeSource(src.str()) << buildOptions;
473         }
474 }
475
476 class ComputeTestInstance : public TestInstance
477 {
478 public:
479                                                                         ComputeTestInstance     (Context&                                                       context,
480                                                                                                                  const VkDeviceSize                                     ssboSize,
481                                                                                                                  const std::vector<SpecConstant>&       specConstants,
482                                                                                                                  const std::vector<OffsetValue>&        expectedValues,
483                                                                                                                  bool                                                           packData);
484
485         tcu::TestStatus                                 iterate                         (void);
486
487 private:
488         const VkDeviceSize                              m_ssboSize;
489         const std::vector<SpecConstant> m_specConstants;
490         const std::vector<OffsetValue>  m_expectedValues;
491         const bool                                              m_packData;
492 };
493
494 ComputeTestInstance::ComputeTestInstance (Context&                                                      context,
495                                                                                   const VkDeviceSize                            ssboSize,
496                                                                                   const std::vector<SpecConstant>&      specConstants,
497                                                                                   const std::vector<OffsetValue>&       expectedValues,
498                                                                                   bool                                                          packData)
499         : TestInstance          (context)
500         , m_ssboSize            (ssboSize)
501         , m_specConstants       (specConstants)
502         , m_expectedValues      (expectedValues)
503         , m_packData            (packData)
504 {
505 }
506
507 tcu::TestStatus ComputeTestInstance::iterate (void)
508 {
509         const DeviceInterface&  vk                                      = m_context.getDeviceInterface();
510         const VkDevice                  device                          = m_context.getDevice();
511         const VkQueue                   queue                           = m_context.getUniversalQueue();
512         const deUint32                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
513         Allocator&                              allocator                       = m_context.getDefaultAllocator();
514
515         // Descriptors
516
517         const Buffer resultBuffer(vk, device, allocator, makeBufferCreateInfo(m_ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
518
519         const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
520                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
521                 .build(vk, device));
522
523         const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
524                 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
525                 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
526
527         const Unique<VkDescriptorSet> descriptorSet        (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
528         const VkDescriptorBufferInfo  descriptorBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, m_ssboSize);
529
530         DescriptorSetUpdateBuilder()
531                 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
532                 .update(vk, device);
533
534         // Specialization
535
536         const Specialization        specialization (m_specConstants, m_packData);
537         const VkSpecializationInfo* pSpecInfo      = specialization.getSpecializationInfo();
538
539         // Pipeline
540
541         const Unique<VkShaderModule>   shaderModule  (createShaderModule (vk, device, m_context.getBinaryCollection().get("comp"), 0));
542         const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout (vk, device, *descriptorSetLayout));
543         const Unique<VkPipeline>       pipeline      (makeComputePipeline(vk, device, *pipelineLayout, *shaderModule, pSpecInfo));
544         const Unique<VkCommandPool>    cmdPool       (createCommandPool  (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
545         const Unique<VkCommandBuffer>  cmdBuffer     (makeCommandBuffer  (vk, device, *cmdPool));
546
547         beginCommandBuffer(vk, *cmdBuffer);
548
549         vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
550         vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
551
552         vk.cmdDispatch(*cmdBuffer, 1u, 1u, 1u);
553
554         {
555                 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
556                         VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, m_ssboSize);
557
558                 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
559                         0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
560         }
561
562         endCommandBuffer(vk, *cmdBuffer);
563         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
564
565         // Verify results
566
567         const Allocation& resultAlloc = resultBuffer.getAllocation();
568         invalidateAlloc(vk, device, resultAlloc);
569
570         if (verifyValues(m_context.getTestContext().getLog(), resultAlloc.getHostPtr(), m_expectedValues))
571                 return tcu::TestStatus::pass("Success");
572         else
573                 return tcu::TestStatus::fail("Values did not match");
574 }
575
576 class GraphicsTestInstance : public TestInstance
577 {
578 public:
579                                                                         GraphicsTestInstance (Context&                                                  context,
580                                                                                                                   const VkDeviceSize                            ssboSize,
581                                                                                                                   const std::vector<SpecConstant>&      specConstants,
582                                                                                                                   const std::vector<OffsetValue>&       expectedValues,
583                                                                                                                   const VkShaderStageFlagBits           stage,
584                                                                                                                   bool                                                          packData);
585
586         tcu::TestStatus                                 iterate                          (void);
587
588 private:
589         const VkDeviceSize                              m_ssboSize;
590         const std::vector<SpecConstant> m_specConstants;
591         const std::vector<OffsetValue>  m_expectedValues;
592         const VkShaderStageFlagBits             m_stage;
593         const bool                                              m_packData;
594 };
595
596 GraphicsTestInstance::GraphicsTestInstance (Context&                                                    context,
597                                                                                         const VkDeviceSize                                      ssboSize,
598                                                                                         const std::vector<SpecConstant>&        specConstants,
599                                                                                         const std::vector<OffsetValue>&         expectedValues,
600                                                                                         const VkShaderStageFlagBits                     stage,
601                                                                                         bool                                                            packData)
602         : TestInstance          (context)
603         , m_ssboSize            (ssboSize)
604         , m_specConstants       (specConstants)
605         , m_expectedValues      (expectedValues)
606         , m_stage                       (stage)
607         , m_packData            (packData)
608 {
609 }
610
611 tcu::TestStatus GraphicsTestInstance::iterate (void)
612 {
613         const DeviceInterface&  vk                                      = m_context.getDeviceInterface();
614         const VkDevice                  device                          = m_context.getDevice();
615         const VkQueue                   queue                           = m_context.getUniversalQueue();
616         const deUint32                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
617         Allocator&                              allocator                       = m_context.getDefaultAllocator();
618
619         // Color attachment
620
621         const tcu::IVec2          renderSize    = tcu::IVec2(32, 32);
622         const VkFormat            imageFormat   = VK_FORMAT_R8G8B8A8_UNORM;
623         const Image               colorImage    (vk, device, allocator, makeImageCreateInfo(renderSize, imageFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), MemoryRequirement::Any);
624         const Unique<VkImageView> colorImageView(makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, imageFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)));
625
626         // Vertex buffer
627
628         const deUint32     numVertices           = 3;
629         const VkDeviceSize vertexBufferSizeBytes = sizeof(tcu::Vec4) * numVertices;
630         const Buffer       vertexBuffer          (vk, device, allocator, makeBufferCreateInfo(vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible);
631
632         {
633                 const Allocation& alloc = vertexBuffer.getAllocation();
634                 tcu::Vec4* pVertices = reinterpret_cast<tcu::Vec4*>(alloc.getHostPtr());
635
636                 pVertices[0] = tcu::Vec4(-1.0f, -1.0f,  0.0f,  1.0f);
637                 pVertices[1] = tcu::Vec4(-1.0f,  1.0f,  0.0f,  1.0f);
638                 pVertices[2] = tcu::Vec4( 1.0f, -1.0f,  0.0f,  1.0f);
639
640                 flushAlloc(vk, device, alloc);
641                 // No barrier needed, flushed memory is automatically visible
642         }
643
644         // Descriptors
645
646         const Buffer resultBuffer(vk, device, allocator, makeBufferCreateInfo(m_ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
647
648         const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
649                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL_GRAPHICS)
650                 .build(vk, device));
651
652         const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
653                 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
654                 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
655
656         const Unique<VkDescriptorSet> descriptorSet        (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
657         const VkDescriptorBufferInfo  descriptorBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, m_ssboSize);
658
659         DescriptorSetUpdateBuilder()
660                 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
661                 .update(vk, device);
662
663         // Specialization
664
665         const Specialization        specialization (m_specConstants, m_packData);
666         const VkSpecializationInfo* pSpecInfo      = specialization.getSpecializationInfo();
667
668         // Pipeline
669
670         const Unique<VkRenderPass>     renderPass    (makeRenderPass    (vk, device, imageFormat));
671         const Unique<VkFramebuffer>    framebuffer   (makeFramebuffer   (vk, device, *renderPass, colorImageView.get(), static_cast<deUint32>(renderSize.x()), static_cast<deUint32>(renderSize.y())));
672         const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
673         const Unique<VkCommandPool>    cmdPool       (createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
674         const Unique<VkCommandBuffer>  cmdBuffer     (makeCommandBuffer (vk, device, *cmdPool));
675
676         GraphicsPipelineBuilder pipelineBuilder;
677         pipelineBuilder
678                 .setRenderSize(renderSize)
679                 .setShader(vk, device, VK_SHADER_STAGE_VERTEX_BIT,   m_context.getBinaryCollection().get("vert"), pSpecInfo)
680                 .setShader(vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, m_context.getBinaryCollection().get("frag"), pSpecInfo);
681
682         if ((m_stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) || (m_stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))
683                 pipelineBuilder
684                         .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,    m_context.getBinaryCollection().get("tesc"), pSpecInfo)
685                         .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get("tese"), pSpecInfo);
686
687         if (m_stage == VK_SHADER_STAGE_GEOMETRY_BIT)
688                 pipelineBuilder
689                         .setShader(vk, device, VK_SHADER_STAGE_GEOMETRY_BIT, m_context.getBinaryCollection().get("geom"), pSpecInfo);
690
691         const Unique<VkPipeline> pipeline (pipelineBuilder.build(vk, device, *pipelineLayout, *renderPass));
692
693         // Draw commands
694
695         const VkRect2D          renderArea                      = makeRect2D(renderSize);
696         const tcu::Vec4         clearColor                      (0.0f, 0.0f, 0.0f, 1.0f);
697         const VkDeviceSize      vertexBufferOffset      = 0ull;
698
699         beginCommandBuffer(vk, *cmdBuffer);
700
701         {
702                 const VkImageSubresourceRange imageFullSubresourceRange              = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
703                 const VkImageMemoryBarrier    barrierColorAttachmentSetInitialLayout = makeImageMemoryBarrier(
704                         0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
705                         VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
706                         *colorImage, imageFullSubresourceRange);
707
708                 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
709                         0u, DE_NULL, 0u, DE_NULL, 1u, &barrierColorAttachmentSetInitialLayout);
710         }
711
712         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
713
714         vk.cmdBindPipeline      (*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
715         vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
716         vk.cmdBindVertexBuffers (*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
717
718         vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
719         endRenderPass(vk, *cmdBuffer);
720
721         {
722                 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
723                         VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, m_ssboSize);
724
725                 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
726                         0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
727         }
728
729         endCommandBuffer(vk, *cmdBuffer);
730         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
731
732         // Verify results
733
734         const Allocation& resultAlloc = resultBuffer.getAllocation();
735         invalidateAlloc(vk, device, resultAlloc);
736
737         if (verifyValues(m_context.getTestContext().getLog(), resultAlloc.getHostPtr(), m_expectedValues))
738                 return tcu::TestStatus::pass("Success");
739         else
740                 return tcu::TestStatus::fail("Values did not match");
741 }
742
743 FeatureFlags getShaderStageRequirements (const VkShaderStageFlags stageFlags)
744 {
745         FeatureFlags features = (FeatureFlags)0;
746
747         if (((stageFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) || ((stageFlags & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0))
748                 features |= FEATURE_TESSELLATION_SHADER;
749
750         if ((stageFlags & VK_SHADER_STAGE_GEOMETRY_BIT) != 0)
751                 features |= FEATURE_GEOMETRY_SHADER;
752
753         // All tests use SSBO writes to read back results.
754         if ((stageFlags & VK_SHADER_STAGE_ALL_GRAPHICS) != 0)
755         {
756                 if ((stageFlags & VK_SHADER_STAGE_FRAGMENT_BIT) != 0)
757                         features |= FEATURE_FRAGMENT_STORES_AND_ATOMICS;
758                 else
759                         features |= FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS;
760         }
761
762         return features;
763 }
764
765 void SpecConstantTest::checkSupport (Context& context) const
766 {
767         requireFeatures(context, m_caseDef.requirements | getShaderStageRequirements(m_stage));
768 }
769
770 TestInstance* SpecConstantTest::createInstance (Context& context) const
771 {
772         if (m_stage & VK_SHADER_STAGE_COMPUTE_BIT)
773                 return new ComputeTestInstance(context, m_caseDef.ssboSize, m_caseDef.specConstants, m_caseDef.expectedValues, m_caseDef.packData);
774         else
775                 return new GraphicsTestInstance(context, m_caseDef.ssboSize, m_caseDef.specConstants, m_caseDef.expectedValues, m_stage, m_caseDef.packData);
776 }
777
778 //! Declare specialization constants but use them with default values.
779 tcu::TestCaseGroup* createDefaultValueTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage)
780 {
781         de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "default_value", "use default constant value"));
782
783         CaseDefinition defs[] =
784         {
785                 {
786                         "bool",
787                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const bool sc0 = true;"),
788                                            SpecConstant(2u, "layout(constant_id = ${ID}) const bool sc1 = false;")),
789                         8,
790                         "    bool r0;\n"
791                         "    bool r1;\n",
792                         "",
793                         "    sb_out.r0 = sc0;\n"
794                         "    sb_out.r1 = sc1;\n",
795                         makeVector(OffsetValue(4, 0, makeValueBool32(true)),
796                                            OffsetValue(4, 4, makeValueBool32(false))),
797                         (FeatureFlags)0,
798                         false,
799                 },
800                 {
801                         "int8",
802                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int8_t sc0 = int8_t(1);"),
803                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int8_t sc1 = int8_t(-2);")),
804                         2,
805                         "    int8_t r0;\n"
806                         "    int8_t r1;\n",
807                         "",
808                         "    int8_t aux = sc0 + sc1;\n"
809                         "    sb_out.r0 = sc0;\n"
810                         "    sb_out.r1 = sc1;\n",
811                         makeVector(OffsetValue(1, 0, makeValueInt8(1)),
812                                            OffsetValue(1, 1, makeValueInt8(-2))),
813                         FEATURE_SHADER_INT_8,
814                         false,
815                 },
816                 {
817                         "uint8",
818                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint8_t sc0 = int8_t(15);"),
819                                            SpecConstant(2u, "layout(constant_id = ${ID}) const uint8_t sc1 = int8_t(43);")),
820                         2,
821                         "    uint8_t r0;\n"
822                         "    uint8_t r1;\n",
823                         "",
824                         "    uint8_t aux = sc0 + sc1;\n"
825                         "    sb_out.r0 = sc0;\n"
826                         "    sb_out.r1 = sc1;\n",
827                         makeVector(OffsetValue(1, 0, makeValueUint8(15)),
828                                            OffsetValue(1, 1, makeValueUint8(43))),
829                         FEATURE_SHADER_INT_8,
830                         false,
831                 },
832                 {
833                         "int16",
834                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int16_t sc0 = 20000s;", 2, makeValueInt16(32000)),
835                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int16_t sc1 = -20000s;")),
836                         4,
837                         "    int16_t r0;\n"
838                         "    int16_t r1;\n",
839                         "",
840                         "    int16_t aux = sc0 + sc1;\n"
841                         "    sb_out.r0 = sc0;\n"
842                         "    sb_out.r1 = sc1;\n",
843                         makeVector(OffsetValue(2, 0, makeValueInt16(32000)),
844                                            OffsetValue(2, 2, makeValueInt16(-20000))),
845                         FEATURE_SHADER_INT_16,
846                         false,
847                 },
848                 {
849                         "uint16",
850                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint16_t sc0 = 64000us;"),
851                                            SpecConstant(2u, "layout(constant_id = ${ID}) const uint16_t sc1 = 51829us;")),
852                         4,
853                         "    uint16_t r0;\n"
854                         "    uint16_t r1;\n",
855                         "",
856                         "    uint16_t aux = sc0 + sc1;\n"
857                         "    sb_out.r0 = sc0;\n"
858                         "    sb_out.r1 = sc1;\n",
859                         makeVector(OffsetValue(2, 0, makeValueUint16(64000)),
860                                            OffsetValue(2, 2, makeValueUint16(51829))),
861                         FEATURE_SHADER_INT_16,
862                         false,
863                 },
864                 {
865                         "int",
866                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = -3;"),
867                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 17;")),
868                         8,
869                         "    int r0;\n"
870                         "    int r1;\n",
871                         "",
872                         "    sb_out.r0 = sc0;\n"
873                         "    sb_out.r1 = sc1;\n",
874                         makeVector(OffsetValue(4, 0, makeValueInt32(-3)),
875                                            OffsetValue(4, 4, makeValueInt32(17))),
876                         (FeatureFlags)0,
877                         false,
878                 },
879                 {
880                         "uint",
881                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint sc0 = 42u;")),
882                         4,
883                         "    uint r0;\n",
884                         "",
885                         "    sb_out.r0 = sc0;\n",
886                         makeVector(OffsetValue(4, 0, makeValueUint32(42u))),
887                         (FeatureFlags)0,
888                         false,
889                 },
890                 {
891                         "int64",
892                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int64_t sc0 = 9141386509785772560l;"),
893                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int64_t sc1 = -9141386509785772560l;")),
894                         16,
895                         "    int64_t r0;\n"
896                         "    int64_t r1;\n",
897                         "",
898                         "    sb_out.r0 = sc0;\n"
899                         "    sb_out.r1 = sc1;\n",
900                         makeVector(OffsetValue(8, 0, makeValueInt64(9141386509785772560ll)),
901                                            OffsetValue(8, 8, makeValueInt64(-9141386509785772560ll))),
902                         FEATURE_SHADER_INT_64,
903                         false,
904                 },
905                 {
906                         "uint64",
907                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint64_t sc0 = 18364758544493064720ul;"),
908                                            SpecConstant(2u, "layout(constant_id = ${ID}) const uint64_t sc1 = 17298946664678735070ul;")),
909                         16,
910                         "    uint64_t r0;\n"
911                         "    uint64_t r1;\n",
912                         "",
913                         "    sb_out.r0 = sc0;\n"
914                         "    sb_out.r1 = sc1;\n",
915                         makeVector(OffsetValue(8, 0, makeValueUint64(18364758544493064720ull)),
916                                            OffsetValue(8, 8, makeValueUint64(17298946664678735070ull))),
917                         FEATURE_SHADER_INT_64,
918                         false,
919                 },
920                 {
921                         "float16",
922                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float16_t sc0 = 7.5hf;"),
923                                            SpecConstant(2u, "layout(constant_id = ${ID}) const float16_t sc1 = 1.125hf;")),
924                         4,
925                         "    float16_t r0;\n"
926                         "    float16_t r1;\n",
927                         "",
928                         "    float16_t aux = sc0 + sc1;\n"
929                         "    sb_out.r0 = sc0;\n"
930                         "    sb_out.r1 = sc1;\n",
931                         makeVector(OffsetValue(2, 0, makeValueFloat16(tcu::Float16(7.5))),
932                                            OffsetValue(2, 2, makeValueFloat16(tcu::Float16(1.125)))),
933                         FEATURE_SHADER_FLOAT_16,
934                         false,
935                 },
936                 {
937                         "float",
938                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 7.5;")),
939                         4,
940                         "    float r0;\n",
941                         "",
942                         "    sb_out.r0 = sc0;\n",
943                         makeVector(OffsetValue(4, 0, makeValueFloat32(7.5f))),
944                         (FeatureFlags)0,
945                         false,
946                 },
947                 {
948                         "double",
949                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const double sc0 = 2.75LF;")),
950                         8,
951                         "    double r0;\n",
952                         "",
953                         "    sb_out.r0 = sc0;\n",
954                         makeVector(OffsetValue(8, 0, makeValueFloat64(2.75))),
955                         FEATURE_SHADER_FLOAT_64,
956                         false,
957                 },
958         };
959
960         for (int i = 0; i < 2; ++i)
961         {
962                 const bool packData = (i > 0);
963                 for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
964                 {
965                         auto& def = defs[defNdx];
966                         def.packData = packData;
967                         if (packData)
968                                 def.name += "_packed";
969                         testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, def));
970                 }
971         }
972
973         return testGroup.release();
974 }
975
976 //! Declare specialization constants and specify their values through API.
977 tcu::TestCaseGroup* createBasicSpecializationTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage)
978 {
979         de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "basic", "specialize a constant"));
980
981         CaseDefinition defs[] =
982         {
983                 {
984                         "bool",
985                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const bool sc0 = true;",  4, makeValueBool32(true)),
986                                            SpecConstant(2u, "layout(constant_id = ${ID}) const bool sc1 = false;", 4, makeValueBool32(false)),
987                                            SpecConstant(3u, "layout(constant_id = ${ID}) const bool sc2 = true;",  4, makeValueBool32(false)),
988                                            SpecConstant(4u, "layout(constant_id = ${ID}) const bool sc3 = false;", 4, makeValueBool32(true))),
989                         16,
990                         "    bool r0;\n"
991                         "    bool r1;\n"
992                         "    bool r2;\n"
993                         "    bool r3;\n",
994                         "",
995                         "    sb_out.r0 = sc0;\n"
996                         "    sb_out.r1 = sc1;\n"
997                         "    sb_out.r2 = sc2;\n"
998                         "    sb_out.r3 = sc3;\n",
999                         makeVector(OffsetValue(4,  0, makeValueBool32(true)),
1000                                            OffsetValue(4,  4, makeValueBool32(false)),
1001                                            OffsetValue(4,  8, makeValueBool32(false)),
1002                                            OffsetValue(4, 12, makeValueBool32(true))),
1003                         (FeatureFlags)0,
1004                         false,
1005                 },
1006                 {
1007                         "int8",
1008                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int8_t sc0 = int8_t(1);", 1, makeValueInt8(127)),
1009                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int8_t sc1 = int8_t(-2);")),
1010                         2,
1011                         "    int8_t r0;\n"
1012                         "    int8_t r1;\n",
1013                         "",
1014                         "    int8_t aux = sc0 + sc1;\n"
1015                         "    sb_out.r0 = sc0;\n"
1016                         "    sb_out.r1 = sc1;\n",
1017                         makeVector(OffsetValue(1, 0, makeValueInt8(127)),
1018                                            OffsetValue(1, 1, makeValueInt8(-2))),
1019                         FEATURE_SHADER_INT_8,
1020                         false,
1021                 },
1022                 {
1023                         "int8_2",
1024                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int8_t sc0 = int8_t(123);", 1, makeValueInt8(65)),
1025                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int8_t sc1 = int8_t(-33);", 1, makeValueInt8(-128))),
1026                         2,
1027                         "    int8_t r0;\n"
1028                         "    int8_t r1;\n",
1029                         "",
1030                         "    int8_t aux = sc0 + sc1;\n"
1031                         "    sb_out.r0 = sc0;\n"
1032                         "    sb_out.r1 = sc1;\n",
1033                         makeVector(OffsetValue(1, 0, makeValueInt8(65)),
1034                                            OffsetValue(1, 1, makeValueInt8(-128))),
1035                         FEATURE_SHADER_INT_8,
1036                         false,
1037                 },
1038                 {
1039                         "uint8",
1040                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint8_t sc0 = int8_t(15);", 1, makeValueUint8(254)),
1041                                            SpecConstant(2u, "layout(constant_id = ${ID}) const uint8_t sc1 = int8_t(43);")),
1042                         2,
1043                         "    uint8_t r0;\n"
1044                         "    uint8_t r1;\n",
1045                         "",
1046                         "    uint8_t aux = sc0 + sc1;\n"
1047                         "    sb_out.r0 = sc0;\n"
1048                         "    sb_out.r1 = sc1;\n",
1049                         makeVector(OffsetValue(1, 0, makeValueUint8(254)),
1050                                            OffsetValue(1, 1, makeValueUint8(43))),
1051                         FEATURE_SHADER_INT_8,
1052                         false,
1053                 },
1054                 {
1055                         "uint8_2",
1056                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint8_t sc0 = int8_t(99);", 1, makeValueUint8(254)),
1057                                            SpecConstant(2u, "layout(constant_id = ${ID}) const uint8_t sc1 = int8_t(81);", 1, makeValueUint8(255))),
1058                         2,
1059                         "    uint8_t r0;\n"
1060                         "    uint8_t r1;\n",
1061                         "",
1062                         "    uint8_t aux = sc0 + sc1;\n"
1063                         "    sb_out.r0 = sc0;\n"
1064                         "    sb_out.r1 = sc1;\n",
1065                         makeVector(OffsetValue(1, 0, makeValueUint8(254)),
1066                                            OffsetValue(1, 1, makeValueUint8(255))),
1067                         FEATURE_SHADER_INT_8,
1068                         false,
1069                 },
1070                 {
1071                         "int16",
1072                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int16_t sc0 = 20000s;", 2, makeValueInt16(32000)),
1073                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int16_t sc1 = -20000s;")),
1074                         4,
1075                         "    int16_t r0;\n"
1076                         "    int16_t r1;\n",
1077                         "",
1078                         "    int16_t aux = sc0 + sc1;\n"
1079                         "    sb_out.r0 = sc0;\n"
1080                         "    sb_out.r1 = sc1;\n",
1081                         makeVector(OffsetValue(2, 0, makeValueInt16(32000)),
1082                                            OffsetValue(2, 2, makeValueInt16(-20000))),
1083                         FEATURE_SHADER_INT_16,
1084                         false,
1085                 },
1086                 {
1087                         "int16_2",
1088                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int16_t sc0 = 20000s;", 2, makeValueInt16(32000)),
1089                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int16_t sc1 = -20000s;", 2, makeValueInt16(-21000))),
1090                         4,
1091                         "    int16_t r0;\n"
1092                         "    int16_t r1;\n",
1093                         "",
1094                         "    int16_t aux = sc0 + sc1;\n"
1095                         "    sb_out.r0 = sc0;\n"
1096                         "    sb_out.r1 = sc1;\n",
1097                         makeVector(OffsetValue(2, 0, makeValueInt16(32000)),
1098                                            OffsetValue(2, 2, makeValueInt16(-21000))),
1099                         FEATURE_SHADER_INT_16,
1100                         false,
1101                 },
1102                 {
1103                         "uint16",
1104                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint16_t sc0 = 64000us;", 2, makeValueUint16(65000)),
1105                                            SpecConstant(2u, "layout(constant_id = ${ID}) const uint16_t sc1 = 51829us;")),
1106                         4,
1107                         "    uint16_t r0;\n"
1108                         "    uint16_t r1;\n",
1109                         "",
1110                         "    uint16_t aux = sc0 + sc1;\n"
1111                         "    sb_out.r0 = sc0;\n"
1112                         "    sb_out.r1 = sc1;\n",
1113                         makeVector(OffsetValue(2, 0, makeValueUint16(65000)),
1114                                            OffsetValue(2, 2, makeValueUint16(51829))),
1115                         FEATURE_SHADER_INT_16,
1116                         false,
1117                 },
1118                 {
1119                         "uint16_2",
1120                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint16_t sc0 = 64000us;", 2, makeValueUint16(65000)),
1121                                            SpecConstant(2u, "layout(constant_id = ${ID}) const uint16_t sc1 = 51829us;", 2, makeValueUint16(63000))),
1122                         4,
1123                         "    uint16_t r0;\n"
1124                         "    uint16_t r1;\n",
1125                         "",
1126                         "    uint16_t aux = sc0 + sc1;\n"
1127                         "    sb_out.r0 = sc0;\n"
1128                         "    sb_out.r1 = sc1;\n",
1129                         makeVector(OffsetValue(2, 0, makeValueUint16(65000)),
1130                                            OffsetValue(2, 2, makeValueUint16(63000))),
1131                         FEATURE_SHADER_INT_16,
1132                         false,
1133                 },
1134                 {
1135                         "int",
1136                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = -3;", 4, makeValueInt32(33)),
1137                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 91;"),
1138                                            SpecConstant(3u, "layout(constant_id = ${ID}) const int sc2 = 17;", 4, makeValueInt32(-15))),
1139                         12,
1140                         "    int r0;\n"
1141                         "    int r1;\n"
1142                         "    int r2;\n",
1143                         "",
1144                         "    sb_out.r0 = sc0;\n"
1145                         "    sb_out.r1 = sc1;\n"
1146                         "    sb_out.r2 = sc2;\n",
1147                         makeVector(OffsetValue(4, 0, makeValueInt32(33)),
1148                                            OffsetValue(4, 4, makeValueInt32(91)),
1149                                            OffsetValue(4, 8, makeValueInt32(-15))),
1150                         (FeatureFlags)0,
1151                         false,
1152                 },
1153                 {
1154                         "uint",
1155                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint sc0 = 42u;", 4, makeValueUint32(97u)),
1156                                            SpecConstant(2u, "layout(constant_id = ${ID}) const uint sc1 = 7u;")),
1157                         8,
1158                         "    uint r0;\n"
1159                         "    uint r1;\n",
1160                         "",
1161                         "    sb_out.r0 = sc0;\n"
1162                         "    sb_out.r1 = sc1;\n",
1163                         makeVector(OffsetValue(4, 0, makeValueUint32(97u)),
1164                                            OffsetValue(4, 4, makeValueUint32(7u))),
1165                         (FeatureFlags)0,
1166                         false,
1167                 },
1168                 {
1169                         "uint_2",
1170                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint sc0 = 305419896u;", 4, makeValueUint32(1985229328u)),
1171                                            SpecConstant(2u, "layout(constant_id = ${ID}) const uint sc1 = 591751049u;"),
1172                                            SpecConstant(3u, "layout(constant_id = ${ID}) const uint sc2 = 878082202u;", 4, makeValueUint32(1698898186u))),
1173                         12,
1174                         "    uint r0;\n"
1175                         "    uint r1;\n"
1176                         "    uint r2;\n",
1177                         "",
1178                         "    sb_out.r0 = sc0;\n"
1179                         "    sb_out.r1 = sc1;\n"
1180                         "    sb_out.r2 = sc2;\n",
1181                         makeVector(OffsetValue(4, 0, makeValueUint32(1985229328u)),
1182                                            OffsetValue(4, 4, makeValueUint32(591751049u)),
1183                                            OffsetValue(4, 8, makeValueUint32(1698898186u))),
1184                         (FeatureFlags)0,
1185                         false,
1186                 },
1187                 {
1188                         "int64",
1189                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int64_t sc0 = 9141386509785772560l;", 8, makeValueInt64(9137147825770275585ll)),
1190                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int64_t sc1 = -9141386509785772560l;")),
1191                         16,
1192                         "    int64_t r0;\n"
1193                         "    int64_t r1;\n",
1194                         "",
1195                         "    sb_out.r0 = sc0;\n"
1196                         "    sb_out.r1 = sc1;\n",
1197                         makeVector(OffsetValue(8, 0, makeValueInt64(9137147825770275585ll)),
1198                                            OffsetValue(8, 8, makeValueInt64(-9141386509785772560ll))),
1199                         FEATURE_SHADER_INT_64,
1200                         false,
1201                 },
1202                 {
1203                         "int64_2",
1204                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int64_t sc0 = 9141386509785772560l;", 8, makeValueInt64(9137147825770275585ll)),
1205                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int64_t sc1 = -9141386509785772560l;", 8, makeValueInt64(-9137164382869201665ll))),
1206                         16,
1207                         "    int64_t r0;\n"
1208                         "    int64_t r1;\n",
1209                         "",
1210                         "    sb_out.r0 = sc0;\n"
1211                         "    sb_out.r1 = sc1;\n",
1212                         makeVector(OffsetValue(8, 0, makeValueInt64(9137147825770275585ll)),
1213                                            OffsetValue(8, 8, makeValueInt64(-9137164382869201665ll))),
1214                         FEATURE_SHADER_INT_64,
1215                         false,
1216                 },
1217                 {
1218                         "uint64",
1219                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint64_t sc0 = 18364758544493064720ul;", 8, makeValueUint64(17279655951921914625ull)),
1220                                            SpecConstant(2u, "layout(constant_id = ${ID}) const uint64_t sc1 = 17298946664678735070ul;")),
1221                         16,
1222                         "    uint64_t r0;\n"
1223                         "    uint64_t r1;\n",
1224                         "",
1225                         "    sb_out.r0 = sc0;\n"
1226                         "    sb_out.r1 = sc1;\n",
1227                         makeVector(OffsetValue(8, 0, makeValueUint64(17279655951921914625ull)),
1228                                            OffsetValue(8, 8, makeValueUint64(17298946664678735070ull))),
1229                         FEATURE_SHADER_INT_64,
1230                         false,
1231                 },
1232                 {
1233                         "uint64_2",
1234                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint64_t sc0 = 18364758544493064720ul;", 8, makeValueUint64(17279655951921914625ull)),
1235                                            SpecConstant(2u, "layout(constant_id = ${ID}) const uint64_t sc1 = 17298946664678735070ul;", 8, makeValueUint64(17270123250533606145ull))),
1236                         16,
1237                         "    uint64_t r0;\n"
1238                         "    uint64_t r1;\n",
1239                         "",
1240                         "    sb_out.r0 = sc0;\n"
1241                         "    sb_out.r1 = sc1;\n",
1242                         makeVector(OffsetValue(8, 0, makeValueUint64(17279655951921914625ull)),
1243                                            OffsetValue(8, 8, makeValueUint64(17270123250533606145ull))),
1244                         FEATURE_SHADER_INT_64,
1245                         false,
1246                 },
1247                 // We create some floating point values below as unsigned integers to make sure all bytes are set to different values, avoiding special patterns and denormals.
1248                 {
1249                         "float16",
1250                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float16_t sc0 = 7.5hf;", 2, makeValueFloat16(tcu::Float16(15.75))),
1251                                            SpecConstant(2u, "layout(constant_id = ${ID}) const float16_t sc1 = 1.125hf;")),
1252                         4,
1253                         "    float16_t r0;\n"
1254                         "    float16_t r1;\n",
1255                         "",
1256                         "    float16_t aux = sc0 + sc1;\n"
1257                         "    sb_out.r0 = sc0;\n"
1258                         "    sb_out.r1 = sc1;\n",
1259                         makeVector(OffsetValue(2, 0, makeValueFloat16(tcu::Float16(15.75))),
1260                                            OffsetValue(2, 2, makeValueFloat16(tcu::Float16(1.125)))),
1261                         FEATURE_SHADER_FLOAT_16,
1262                         false,
1263                 },
1264                 {
1265                         "float16_2",
1266                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float16_t sc0 = 7.5hf;", 2, makeValueUint16(0x0123u)),
1267                                            SpecConstant(2u, "layout(constant_id = ${ID}) const float16_t sc1 = 1.125hf;"),
1268                                            SpecConstant(3u, "layout(constant_id = ${ID}) const float16_t sc2 = 1.125hf;", 2, makeValueUint16(0xFEDCu))),
1269                         6,
1270                         "    float16_t r0;\n"
1271                         "    float16_t r1;\n"
1272                         "    float16_t r2;\n",
1273                         "",
1274                         "    float16_t aux = sc0 + sc1;\n"
1275                         "    sb_out.r0 = sc0;\n"
1276                         "    sb_out.r1 = sc1;\n"
1277                         "    sb_out.r2 = sc2;\n",
1278                         makeVector(OffsetValue(2, 0, makeValueUint16(0x0123u)),
1279                                            OffsetValue(2, 2, makeValueFloat16(tcu::Float16(1.125))),
1280                                            OffsetValue(2, 4, makeValueUint16(0xFEDCu))),
1281                         FEATURE_SHADER_FLOAT_16,
1282                         false,
1283                 },
1284                 {
1285                         "float",
1286                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 7.5;", 4, makeValueFloat32(15.75f)),
1287                                            SpecConstant(2u, "layout(constant_id = ${ID}) const float sc1 = 1.125;")),
1288                         8,
1289                         "    float r0;\n"
1290                         "    float r1;\n",
1291                         "",
1292                         "    sb_out.r0 = sc0;\n"
1293                         "    sb_out.r1 = sc1;\n",
1294                         makeVector(OffsetValue(4, 0, makeValueFloat32(15.75f)),
1295                                            OffsetValue(4, 4, makeValueFloat32(1.125f))),
1296                         (FeatureFlags)0,
1297                         false,
1298                 },
1299                 {
1300                         "float_2",
1301                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 7.5;", 4, makeValueUint32(0x01234567u)),
1302                                            SpecConstant(2u, "layout(constant_id = ${ID}) const float sc1 = 1.125;"),
1303                                            SpecConstant(3u, "layout(constant_id = ${ID}) const float sc2 = 1.125;", 4, makeValueUint32(0xfedcba98u))),
1304                         12,
1305                         "    float r0;\n"
1306                         "    float r1;\n"
1307                         "    float r2;\n",
1308                         "",
1309                         "    sb_out.r0 = sc0;\n"
1310                         "    sb_out.r1 = sc1;\n"
1311                         "    sb_out.r2 = sc2;\n",
1312                         makeVector(OffsetValue(4, 0, makeValueUint32(0x01234567u)),
1313                                            OffsetValue(4, 4, makeValueFloat32(1.125f)),
1314                                            OffsetValue(4, 8, makeValueUint32(0xfedcba98u))),
1315                         (FeatureFlags)0,
1316                         false,
1317                 },
1318                 {
1319                         "double",
1320                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const double sc0 = 2.75LF;", 8, makeValueUint64(0xFEDCBA9876543210ull)),
1321                                            SpecConstant(2u, "layout(constant_id = ${ID}) const double sc1 = 9.25LF;")),
1322                         16,
1323                         "    double r0;\n"
1324                         "    double r1;\n",
1325                         "",
1326                         "    sb_out.r0 = sc0;\n"
1327                         "    sb_out.r1 = sc1;\n",
1328                         makeVector(OffsetValue(8, 0, makeValueUint64(0xFEDCBA9876543210ull)),
1329                                            OffsetValue(8, 8, makeValueFloat64(9.25))),
1330                         FEATURE_SHADER_FLOAT_64,
1331                         false,
1332                 },
1333                 {
1334                         "double_2",
1335                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const double sc0 = 2.75LF;", 8, makeValueUint64(0xFEDCBA9876543210ull)),
1336                                            SpecConstant(2u, "layout(constant_id = ${ID}) const double sc1 = 9.25LF;", 8, makeValueUint64(0xEFCDAB8967452301ull))),
1337                         16,
1338                         "    double r0;\n"
1339                         "    double r1;\n",
1340                         "",
1341                         "    sb_out.r0 = sc0;\n"
1342                         "    sb_out.r1 = sc1;\n",
1343                         makeVector(OffsetValue(8, 0, makeValueUint64(0xFEDCBA9876543210ull)),
1344                                            OffsetValue(8, 8, makeValueUint64(0xEFCDAB8967452301ull))),
1345                         FEATURE_SHADER_FLOAT_64,
1346                         false,
1347                 },
1348                 {
1349                         "mixed",
1350                         makeVector(
1351                                 SpecConstant(1u, "layout(constant_id = ${ID}) const uint8_t  sc0 = uint8_t  (0);", 1, makeValueUint8(0x98)),
1352                                 SpecConstant(2u, "layout(constant_id = ${ID}) const uint16_t sc1 = uint16_t (0);", 2, makeValueUint16(0x9876)),
1353                                 SpecConstant(3u, "layout(constant_id = ${ID}) const uint     sc2 = uint     (0);", 4, makeValueUint32(0xba987654u)),
1354                                 SpecConstant(4u, "layout(constant_id = ${ID}) const uint64_t sc3 = uint64_t (0);", 8, makeValueUint64(0xfedcba9876543210ull))),
1355                         8+4+2+1,
1356                         "    uint64_t r0;\n"
1357                         "    uint     r1;\n"
1358                         "    uint16_t r2;\n"
1359                         "    uint8_t  r3;\n",
1360                         "",
1361                         "    uint64_t i0 = sc3;\n"
1362                         "    uint     i1 = sc2;\n"
1363                         "    uint16_t i2 = sc1;\n"
1364                         "    uint8_t  i3 = sc0;\n"
1365                         "    sb_out.r0 = i0;\n"
1366                         "    sb_out.r1 = i1;\n"
1367                         "    sb_out.r2 = i2;\n"
1368                         "    sb_out.r3 = i3;\n",
1369                         makeVector(
1370                                 OffsetValue(8, 0, makeValueUint64(0xfedcba9876543210ull)),
1371                                 OffsetValue(4, 8, makeValueUint32(0xba987654u)),
1372                                 OffsetValue(2, 12, makeValueUint16(0x9876)),
1373                                 OffsetValue(1, 14, makeValueUint8(0x98))),
1374                         (FEATURE_SHADER_INT_8 | FEATURE_SHADER_INT_16 | FEATURE_SHADER_INT_64),
1375                         false,
1376                 },
1377                 {
1378                         "mixed_reversed",
1379                         makeVector(
1380                                 SpecConstant(1u, "layout(constant_id = ${ID}) const uint64_t sc3 = uint64_t (0);", 8, makeValueUint64(0xfedcba9876543210ull)),
1381                                 SpecConstant(2u, "layout(constant_id = ${ID}) const uint     sc2 = uint     (0);", 4, makeValueUint32(0xba987654u)),
1382                                 SpecConstant(3u, "layout(constant_id = ${ID}) const uint16_t sc1 = uint16_t (0);", 2, makeValueUint16(0x9876)),
1383                                 SpecConstant(4u, "layout(constant_id = ${ID}) const uint8_t  sc0 = uint8_t  (0);", 1, makeValueUint8(0x98))),
1384                         8+4+2+1,
1385                         "    uint64_t r0;\n"
1386                         "    uint     r1;\n"
1387                         "    uint16_t r2;\n"
1388                         "    uint8_t  r3;\n",
1389                         "",
1390                         "    uint64_t i0 = sc3;\n"
1391                         "    uint     i1 = sc2;\n"
1392                         "    uint16_t i2 = sc1;\n"
1393                         "    uint8_t  i3 = sc0;\n"
1394                         "    sb_out.r0 = i0;\n"
1395                         "    sb_out.r1 = i1;\n"
1396                         "    sb_out.r2 = i2;\n"
1397                         "    sb_out.r3 = i3;\n",
1398                         makeVector(
1399                                 OffsetValue(8, 0, makeValueUint64(0xfedcba9876543210ull)),
1400                                 OffsetValue(4, 8, makeValueUint32(0xba987654u)),
1401                                 OffsetValue(2, 12, makeValueUint16(0x9876)),
1402                                 OffsetValue(1, 14, makeValueUint8(0x98))),
1403                         (FEATURE_SHADER_INT_8 | FEATURE_SHADER_INT_16 | FEATURE_SHADER_INT_64),
1404                         false,
1405                 },
1406         };
1407
1408         for (int i = 0; i < 2; ++i)
1409         {
1410                 const bool packData = (i > 0);
1411                 for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
1412                 {
1413                         auto& def = defs[defNdx];
1414                         def.packData = packData;
1415                         if (packData)
1416                                 def.name += "_packed";
1417                         testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, def));
1418                 }
1419         }
1420
1421         return testGroup.release();
1422 }
1423
1424 //! Specify compute shader work group size through specialization constants.
1425 tcu::TestCaseGroup* createWorkGroupSizeTests (tcu::TestContext& testCtx)
1426 {
1427         de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "local_size", "work group size specialization"));
1428
1429         const deUint32 ssboSize = 16;
1430         const std::string ssboDecl =
1431                 "    uvec3 workGroupSize;\n"
1432                 "    uint  checksum;\n";
1433         const std::string globalDecl = "shared uint count;\n";
1434         const std::string mainCode =
1435                 "    count = 0u;\n"
1436                 "\n"
1437                 "    groupMemoryBarrier();\n"
1438                 "    barrier();\n"
1439                 "\n"
1440                 "    atomicAdd(count, 1u);\n"
1441                 "\n"
1442                 "    groupMemoryBarrier();\n"
1443                 "    barrier();\n"
1444                 "\n"
1445                 "    sb_out.workGroupSize = gl_WorkGroupSize;\n"
1446                 "    sb_out.checksum      = count;\n";
1447
1448         const CaseDefinition defs[] =
1449         {
1450                 {
1451                         "x",
1452                         makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;",  4, makeValueUint32(7u))),
1453                         ssboSize, ssboDecl, globalDecl, mainCode,
1454                         makeVector(OffsetValue(4,  0, makeValueUint32(7u)),
1455                                            OffsetValue(4,  4, makeValueUint32(1u)),
1456                                            OffsetValue(4,  8, makeValueUint32(1u)),
1457                                            OffsetValue(4, 12, makeValueUint32(7u))),
1458                         (FeatureFlags)0,
1459                         false,
1460                 },
1461                 {
1462                         "y",
1463                         makeVector(SpecConstant(1u, "layout(local_size_y_id = ${ID}) in;",  4, makeValueUint32(5u))),
1464                         ssboSize, ssboDecl, globalDecl, mainCode,
1465                         makeVector(OffsetValue(4,  0, makeValueUint32(1u)),
1466                                            OffsetValue(4,  4, makeValueUint32(5u)),
1467                                            OffsetValue(4,  8, makeValueUint32(1u)),
1468                                            OffsetValue(4, 12, makeValueUint32(5u))),
1469                         (FeatureFlags)0,
1470                         false,
1471                 },
1472                 {
1473                         "z",
1474                         makeVector(SpecConstant(1u, "layout(local_size_z_id = ${ID}) in;",  4, makeValueUint32(3u))),
1475                         ssboSize, ssboDecl, globalDecl, mainCode,
1476                         makeVector(OffsetValue(4,  0, makeValueUint32(1u)),
1477                                            OffsetValue(4,  4, makeValueUint32(1u)),
1478                                            OffsetValue(4,  8, makeValueUint32(3u)),
1479                                            OffsetValue(4, 12, makeValueUint32(3u))),
1480                         (FeatureFlags)0,
1481                         false,
1482                 },
1483                 {
1484                         "xy",
1485                         makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;",  4, makeValueUint32(6u)),
1486                                            SpecConstant(2u, "layout(local_size_y_id = ${ID}) in;",  4, makeValueUint32(4u))),
1487                         ssboSize, ssboDecl, globalDecl, mainCode,
1488                         makeVector(OffsetValue(4,  0, makeValueUint32(6u)),
1489                                            OffsetValue(4,  4, makeValueUint32(4u)),
1490                                            OffsetValue(4,  8, makeValueUint32(1u)),
1491                                            OffsetValue(4, 12, makeValueUint32(6u * 4u))),
1492                         (FeatureFlags)0,
1493                         false,
1494                 },
1495                 {
1496                         "xz",
1497                         makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;",  4, makeValueUint32(3u)),
1498                                            SpecConstant(2u, "layout(local_size_z_id = ${ID}) in;",  4, makeValueUint32(9u))),
1499                         ssboSize, ssboDecl, globalDecl, mainCode,
1500                         makeVector(OffsetValue(4,  0, makeValueUint32(3u)),
1501                                            OffsetValue(4,  4, makeValueUint32(1u)),
1502                                            OffsetValue(4,  8, makeValueUint32(9u)),
1503                                            OffsetValue(4, 12, makeValueUint32(3u * 9u))),
1504                         (FeatureFlags)0,
1505                         false,
1506                 },
1507                 {
1508                         "yz",
1509                         makeVector(SpecConstant(1u, "layout(local_size_y_id = ${ID}) in;",  4, makeValueUint32(2u)),
1510                                            SpecConstant(2u, "layout(local_size_z_id = ${ID}) in;",  4, makeValueUint32(5u))),
1511                         ssboSize, ssboDecl, globalDecl, mainCode,
1512                         makeVector(OffsetValue(4,  0, makeValueUint32(1u)),
1513                                            OffsetValue(4,  4, makeValueUint32(2u)),
1514                                            OffsetValue(4,  8, makeValueUint32(5u)),
1515                                            OffsetValue(4, 12, makeValueUint32(2u * 5u))),
1516                         (FeatureFlags)0,
1517                         false,
1518                 },
1519                 {
1520                         "xyz",
1521                         makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;",  4, makeValueUint32(3u)),
1522                                            SpecConstant(2u, "layout(local_size_y_id = ${ID}) in;",  4, makeValueUint32(5u)),
1523                                            SpecConstant(3u, "layout(local_size_z_id = ${ID}) in;",  4, makeValueUint32(7u))),
1524                         ssboSize, ssboDecl, globalDecl, mainCode,
1525                         makeVector(OffsetValue(4,  0, makeValueUint32(3u)),
1526                                            OffsetValue(4,  4, makeValueUint32(5u)),
1527                                            OffsetValue(4,  8, makeValueUint32(7u)),
1528                                            OffsetValue(4, 12, makeValueUint32(3u * 5u * 7u))),
1529                         (FeatureFlags)0,
1530                         false,
1531                 },
1532         };
1533
1534         for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
1535                 testGroup->addChild(new SpecConstantTest(testCtx, VK_SHADER_STAGE_COMPUTE_BIT, defs[defNdx]));
1536
1537         return testGroup.release();
1538 }
1539
1540 //! Override a built-in variable with specialization constant value.
1541 tcu::TestCaseGroup* createBuiltInOverrideTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage)
1542 {
1543         de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "builtin", "built-in override"));
1544
1545         const CaseDefinition defs[] =
1546         {
1547                 {
1548                         "default",
1549                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) gl_MaxImageUnits;")),
1550                         4,
1551                         "    bool ok;\n",
1552                         "",
1553                         "    sb_out.ok = (gl_MaxImageUnits >= 8);\n",   // implementation defined, 8 is the minimum
1554                         makeVector(OffsetValue(4,  0, makeValueBool32(true))),
1555                         (FeatureFlags)0,
1556                         false,
1557                 },
1558                 {
1559                         "specialized",
1560                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) gl_MaxImageUnits;", 4, makeValueInt32(12))),
1561                         4,
1562                         "    int maxImageUnits;\n",
1563                         "",
1564                         "    sb_out.maxImageUnits = gl_MaxImageUnits;\n",
1565                         makeVector(OffsetValue(4,  0, makeValueInt32(12))),
1566                         (FeatureFlags)0,
1567                         false,
1568                 },
1569         };
1570
1571         for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
1572                 testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, defs[defNdx]));
1573
1574         return testGroup.release();
1575 }
1576
1577 //! Specialization constants used in expressions.
1578 tcu::TestCaseGroup* createExpressionTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage)
1579 {
1580         de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "expression", "specialization constants usage in expressions"));
1581
1582         const CaseDefinition defs[] =
1583         {
1584                 {
1585                         "spec_const_expression",
1586                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 2;"),
1587                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 3;", 4, makeValueInt32(5))),
1588                         4,
1589                         "    int result;\n",
1590
1591                         "const int expr0 = sc0 + 1;\n"
1592                         "const int expr1 = sc0 + sc1;\n",
1593
1594                         "    sb_out.result = expr0 + expr1;\n",
1595                         makeVector(OffsetValue(4,  0, makeValueInt32(10))),
1596                         (FeatureFlags)0,
1597                         false,
1598                 },
1599                 {
1600                         "array_size",
1601                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;"),
1602                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 2;", 4, makeValueInt32(3))),
1603                         16,
1604                         "    int r0;\n"
1605                         "    int r1[3];\n",
1606
1607                         "",
1608
1609                         "    int a0[sc0];\n"
1610                         "    int a1[sc1];\n"
1611                         "\n"
1612                         "    for (int i = 0; i < sc0; ++i)\n"
1613                         "        a0[i] = sc0 - i;\n"
1614                         "    for (int i = 0; i < sc1; ++i)\n"
1615                         "        a1[i] = sc1 - i;\n"
1616                         "\n"
1617                         "    sb_out.r0 = a0[0];\n"
1618                         "    for (int i = 0; i < sc1; ++i)\n"
1619                         "            sb_out.r1[i] = a1[i];\n",
1620                         makeVector(OffsetValue(4,  0, makeValueInt32(1)),
1621                                            OffsetValue(4,  4, makeValueInt32(3)),
1622                                            OffsetValue(4,  8, makeValueInt32(2)),
1623                                            OffsetValue(4, 12, makeValueInt32(1))),
1624                         (FeatureFlags)0,
1625                         false,
1626                 },
1627                 {
1628                         "array_size_expression",
1629                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 3;"),
1630                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 5;", 4, makeValueInt32(7))),
1631                         8,
1632                         "    int r0;\n"
1633                         "    int r1;\n",
1634
1635                         "",
1636
1637                         "    int a0[sc0 + 3];\n"
1638                         "    int a1[sc0 + sc1];\n"
1639                         "\n"
1640                         "    const int size0 = sc0 + 3;\n"
1641                         "    const int size1 = sc0 + sc1;\n"
1642                         "\n"
1643                         "    for (int i = 0; i < size0; ++i)\n"
1644                         "        a0[i] = 3 - i;\n"
1645                         "    for (int i = 0; i < size1; ++i)\n"
1646                         "        a1[i] = 5 - i;\n"
1647                         "\n"
1648                         "    sb_out.r0 = a0[size0 - 1];\n"
1649                         "    sb_out.r1 = a1[size1 - 1];\n",
1650                         makeVector(OffsetValue(4,  0, makeValueInt32(-2)),
1651                                            OffsetValue(4,  4, makeValueInt32(-4))),
1652                         (FeatureFlags)0,
1653                         false,
1654                 },
1655                 {
1656                         "array_size_spec_const_expression",
1657                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 3;"),
1658                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 5;", 4, makeValueInt32(7))),
1659                         8,
1660                         "    int r0;\n"
1661                         "    int r1;\n",
1662
1663                         "",
1664
1665                         "    const int size0 = sc0 + 3;\n"
1666                         "    const int size1 = sc0 + sc1;\n"
1667                         "\n"
1668                         "    int a0[size0];\n"
1669                         "    int a1[size1];\n"
1670                         "\n"
1671                         "    for (int i = 0; i < size0; ++i)\n"
1672                         "        a0[i] = 3 - i;\n"
1673                         "    for (int i = 0; i < size1; ++i)\n"
1674                         "        a1[i] = 5 - i;\n"
1675                         "\n"
1676                         "    sb_out.r0 = a0[size0 - 1];\n"
1677                         "    sb_out.r1 = a1[size1 - 1];\n",
1678                         makeVector(OffsetValue(4,  0, makeValueInt32(-2)),
1679                                            OffsetValue(4,  4, makeValueInt32(-4))),
1680                         (FeatureFlags)0,
1681                         false,
1682                 },
1683                 {
1684                         "array_size_length",
1685                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;"),
1686                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 2;", 4, makeValueInt32(4))),
1687                         8,
1688                         "    int r0;\n"
1689                         "    int r1;\n",
1690
1691                         "",
1692
1693                         "    int a0[sc0];\n"
1694                         "    int a1[sc1];\n"
1695                         "\n"
1696                         "    sb_out.r0 = a0.length();\n"
1697                         "    sb_out.r1 = a1.length();\n",
1698                         makeVector(OffsetValue(4,  0, makeValueInt32(1)),
1699                                            OffsetValue(4,  4, makeValueInt32(4))),
1700                         (FeatureFlags)0,
1701                         false,
1702                 },
1703                 {
1704                         "array_size_pass_to_function",
1705                         makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 3;"),
1706                                            SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 1;", 4, makeValueInt32(3))),
1707                         4,
1708                         "    int result;\n",
1709
1710                         "int sumArrays (int a0[sc0], int a1[sc1])\n"
1711                         "{\n"
1712                         "    int sum = 0;\n"
1713                         "    for (int i = 0; (i < sc0) && (i < sc1); ++i)\n"
1714                         "        sum += a0[i] + a1[i];\n"
1715                         "    return sum;\n"
1716                         "}\n",
1717
1718                         "    int a0[sc0];\n"
1719                         "    int a1[sc1];\n"
1720                         "\n"
1721                         "    for (int i = 0; i < sc0; ++i)\n"
1722                         "        a0[i] = i + 1;\n"
1723                         "    for (int i = 0; i < sc1; ++i)\n"
1724                         "        a1[i] = i + 2;\n"
1725                         "\n"
1726                         "    sb_out.result = sumArrays(a0, a1);\n",
1727                         makeVector(OffsetValue(4,  0, makeValueInt32(15))),
1728                         (FeatureFlags)0,
1729                         false,
1730                 },
1731         };
1732
1733         for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
1734                 testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, defs[defNdx]));
1735
1736         return testGroup.release();
1737 }
1738
1739 //! Helper functions internal to make*CompositeCaseDefinition functions.
1740 namespace composite_case_internal
1741 {
1742
1743 //! Generate a string like this: "1, 2, sc0, 4" or "true, true, sc0"
1744 //! castToType = true is useful when type requires more initializer values than we are providing, e.g.:
1745 //!    vec2(1), vec2(sc0), vec(3)
1746 std::string generateInitializerListWithSpecConstant (const glu::DataType        type,
1747                                                                                                          const bool                             castToType,
1748                                                                                                          const int                              idxBegin,
1749                                                                                                          const int                              idxEnd,
1750                                                                                                          const std::string&             specConstName,
1751                                                                                                          const int                              specConstNdx)
1752 {
1753         std::ostringstream str;
1754
1755         for (int i = idxBegin; i < idxEnd; ++i)
1756         {
1757                 const std::string iVal = (i == specConstNdx ? specConstName : glu::getDataTypeScalarType(type) == glu::TYPE_BOOL ? "true" : de::toString(i + 1));
1758                 str << (i != idxBegin ? ", " : "") << (castToType ? de::toString(glu::getDataTypeName(type)) + "(" + iVal + ")" : iVal);
1759         }
1760
1761         return str.str();
1762 }
1763
1764 std::string generateArrayConstructorString (const glu::DataType elemType,
1765                                                                                         const int                       size1,
1766                                                                                         const int                       size2,
1767                                                                                         const std::string&      specConstName,
1768                                                                                         const int                       specConstNdx)
1769 {
1770         const bool isArrayOfArray = (size2 > 0);
1771         const bool doCast                 = (!isDataTypeScalar(elemType));
1772
1773         std::ostringstream arrayCtorExpr;
1774
1775         if (isArrayOfArray)
1776         {
1777                 const std::string padding  (36, ' ');
1778                 int               idxBegin = 0;
1779                 int               idxEnd   = size2;
1780
1781                 for (int iterNdx = 0; iterNdx < size1; ++iterNdx)
1782                 {
1783                         // Open sub-array ctor
1784                         arrayCtorExpr << (iterNdx != 0 ? ",\n" + padding : "") << glu::getDataTypeName(elemType) << "[" << size2 << "](";
1785
1786                         // Sub-array constructor elements
1787                         arrayCtorExpr << generateInitializerListWithSpecConstant(elemType, doCast, idxBegin, idxEnd, specConstName, specConstNdx);
1788
1789                         // Close sub-array ctor, move to next range
1790                         arrayCtorExpr << ")";
1791
1792                         idxBegin += size2;
1793                         idxEnd += size2;
1794                 }
1795         }
1796         else
1797         {
1798                 // Array constructor elements
1799                 arrayCtorExpr << generateInitializerListWithSpecConstant(elemType, doCast, 0, size1, specConstName, specConstNdx);
1800         }
1801
1802         return arrayCtorExpr.str();
1803 }
1804
1805 inline GenericValue makeValue (const glu::DataType type, const int specValue)
1806 {
1807         if (type == glu::TYPE_DOUBLE)
1808                 return makeValueFloat64(static_cast<double>(specValue));
1809         else if (type == glu::TYPE_FLOAT)
1810                 return makeValueFloat32(static_cast<float>(specValue));
1811         else
1812                 return makeValueInt32(specValue);
1813 }
1814
1815 deUint32 getDataTypeScalarSizeBytes (const glu::DataType dataType)
1816 {
1817         switch (getDataTypeScalarType(dataType))
1818         {
1819                 case glu::TYPE_FLOAT:
1820                 case glu::TYPE_INT:
1821                 case glu::TYPE_UINT:
1822                 case glu::TYPE_BOOL:
1823                         return 4;
1824
1825                 case glu::TYPE_DOUBLE:
1826                         return 8;
1827
1828                 default:
1829                         DE_ASSERT(false);
1830                         return 0;
1831         }
1832 }
1833
1834 //! This applies to matrices/vectors/array cases. dataType must be a basic type.
1835 std::vector<OffsetValue> computeExpectedValues (const int specValue, const glu::DataType dataType, const int numCombinations)
1836 {
1837         DE_ASSERT(glu::isDataTypeScalar(dataType));
1838
1839         std::vector<OffsetValue> expectedValues;
1840
1841         for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1842         {
1843                 int sum = 0;
1844                 for (int i = 0; i < numCombinations; ++i)
1845                         sum += (i == combNdx ? specValue : dataType == glu::TYPE_BOOL ? 1 : (i + 1));
1846
1847                 const int dataSize = getDataTypeScalarSizeBytes(dataType);
1848                 expectedValues.push_back(OffsetValue(dataSize, dataSize * combNdx, makeValue(dataType, sum)));
1849         }
1850
1851         return expectedValues;
1852 }
1853
1854 inline std::string getFirstDataElementSubscriptString (const glu::DataType type)
1855 {
1856         // Grab the first element of a matrix/vector, if dealing with non-basic types.
1857         return (isDataTypeMatrix(type) ? "[0][0]" : isDataTypeVector(type) ? "[0]" : "");
1858 }
1859
1860 //! This code will go into the main function.
1861 std::string generateShaderChecksumComputationCode (const glu::DataType  elemType,
1862                                                                                                    const std::string&   varName,
1863                                                                                                    const std::string&   accumType,
1864                                                                                                    const int                    size1,
1865                                                                                                    const int                    size2,
1866                                                                                                    const int                    numCombinations)
1867 {
1868         std::ostringstream mainCode;
1869
1870         // Generate main code to calculate checksums for each array
1871         for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1872                 mainCode << "    "<< accumType << " sum_" << varName << combNdx << " = " << accumType << "(0);\n";
1873
1874         if (size2 > 0)
1875         {
1876                 mainCode << "\n"
1877                                         << "    for (int i = 0; i < " << size1 << "; ++i)\n"
1878                                         << "    for (int j = 0; j < " << size2 << "; ++j)\n"
1879                                         << "    {\n";
1880
1881                 for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1882                         mainCode << "        sum_" << varName << combNdx << " += " << accumType << "("
1883                                          << varName << combNdx << "[i][j]" << getFirstDataElementSubscriptString(elemType) << ");\n";
1884         }
1885         else
1886         {
1887                 mainCode << "\n"
1888                                         << "    for (int i = 0; i < " << size1 << "; ++i)\n"
1889                                         << "    {\n";
1890
1891                 for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1892                         mainCode << "        sum_" << varName << combNdx << " += " << accumType << "("
1893                                          << varName << combNdx << "[i]" << getFirstDataElementSubscriptString(elemType) << ");\n";
1894         }
1895
1896         mainCode << "    }\n"
1897                                 << "\n";
1898
1899         for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1900                 mainCode << "    sb_out.result[" << combNdx << "] = sum_" << varName << combNdx << ";\n";
1901
1902         return mainCode.str();
1903 }
1904
1905 SpecConstant makeSpecConstant (const std::string specConstName, const deUint32 specConstId, const glu::DataType type, const int specValue)
1906 {
1907         DE_ASSERT(glu::isDataTypeScalar(type));
1908
1909         const std::string typeName(glu::getDataTypeName(type));
1910
1911         return SpecConstant(
1912                 specConstId,
1913                 "layout(constant_id = ${ID}) const " + typeName + " " + specConstName + " = " + typeName + "(1);",
1914                 getDataTypeScalarSizeBytes(type), makeValue(type, specValue));
1915 }
1916
1917 } // composite_case_internal ns
1918
1919 //! Generate a CaseDefinition for a composite test using a matrix or vector (a 1-column matrix)
1920 CaseDefinition makeMatrixVectorCompositeCaseDefinition (const glu::DataType type)
1921 {
1922         using namespace composite_case_internal;
1923
1924         DE_ASSERT(!glu::isDataTypeScalar(type));
1925
1926         const std::string   varName         = (glu::isDataTypeMatrix(type) ? "m" : "v");
1927         const int           numCombinations = getDataTypeScalarSize(type);
1928         const glu::DataType scalarType      = glu::getDataTypeScalarType(type);
1929         const std::string   typeName        = glu::getDataTypeName(type);
1930         const bool                      isConst         = (scalarType != glu::TYPE_FLOAT) && (scalarType != glu::TYPE_DOUBLE);
1931
1932         std::ostringstream globalCode;
1933         {
1934                 // Build N matrices/vectors with specialization constant inserted at various locations in the constructor.
1935                 for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1936                         globalCode << ( isConst ? "const " : "" ) << typeName << " " << varName << combNdx << " = " << typeName << "("
1937                                            << generateInitializerListWithSpecConstant(type, false, 0, numCombinations, "sc0", combNdx) << ");\n";
1938         }
1939
1940         const bool        isBoolElement = (scalarType == glu::TYPE_BOOL);
1941         const int         specValue     = (isBoolElement ? 0 : 42);
1942         const std::string accumType     = glu::getDataTypeName(isBoolElement ? glu::TYPE_INT : scalarType);
1943
1944         const int size1 = glu::isDataTypeMatrix(type) ? glu::getDataTypeMatrixNumColumns(type) : glu::getDataTypeNumComponents(type);
1945         const int size2 = glu::isDataTypeMatrix(type) ? glu::getDataTypeMatrixNumRows(type)    : 0;
1946
1947         const CaseDefinition def =
1948         {
1949                 typeName,
1950                 makeVector(makeSpecConstant("sc0", 1u, scalarType, specValue)),
1951                 static_cast<VkDeviceSize>(getDataTypeScalarSizeBytes(type) * numCombinations),
1952                 "    " + accumType + " result[" + de::toString(numCombinations) + "];\n",
1953                 globalCode.str(),
1954                 generateShaderChecksumComputationCode(scalarType, varName, accumType, size1, size2, numCombinations),
1955                 computeExpectedValues(specValue, scalarType, numCombinations),
1956                 (scalarType == glu::TYPE_DOUBLE ? (FeatureFlags)FEATURE_SHADER_FLOAT_64 : (FeatureFlags)0),
1957                 false,
1958         };
1959         return def;
1960 }
1961
1962 //! Generate a CaseDefinition for a composite test using an array, or an array of array.
1963 //! If (size1, size2) = (N, 0) -> type array[N]
1964 //!                   = (N, M) -> type array[N][M]
1965 CaseDefinition makeArrayCompositeCaseDefinition (const glu::DataType elemType, const int size1, const int size2 = 0)
1966 {
1967         using namespace composite_case_internal;
1968
1969         DE_ASSERT(size1 > 0);
1970
1971         const bool        isArrayOfArray  = (size2 > 0);
1972         const std::string varName                 = "a";
1973         const std::string arraySizeDecl   = "[" + de::toString(size1) + "]" + (isArrayOfArray ? "[" + de::toString(size2) + "]" : "");
1974         const int         numCombinations = (isArrayOfArray ? size1 * size2 : size1);
1975         const std::string elemTypeName    (glu::getDataTypeName(elemType));
1976
1977         std::ostringstream globalCode;
1978         {
1979                 // Create several arrays with specialization constant inserted in different positions.
1980                 for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1981                         globalCode << elemTypeName << " " << varName << combNdx << arraySizeDecl << " = "
1982                                            << elemTypeName << arraySizeDecl << "(" << generateArrayConstructorString(elemType, size1, size2, "sc0", combNdx) << ");\n";
1983         }
1984
1985         const glu::DataType scalarType = glu::getDataTypeScalarType(elemType);
1986         const bool          isBoolData = (scalarType == glu::TYPE_BOOL);
1987         const int           specValue  = (isBoolData ? 0 : 19);
1988         const std::string   caseName   = (isArrayOfArray ? "array_" : "") + elemTypeName;
1989         const std::string   accumType  = (glu::getDataTypeName(isBoolData ? glu::TYPE_INT : scalarType));
1990
1991         const CaseDefinition def =
1992         {
1993                 caseName,
1994                 makeVector(makeSpecConstant("sc0", 1u, scalarType, specValue)),
1995                 static_cast<VkDeviceSize>(getDataTypeScalarSizeBytes(elemType) * numCombinations),
1996                 "    " + accumType + " result[" + de::toString(numCombinations) + "];\n",
1997                 globalCode.str(),
1998                 generateShaderChecksumComputationCode(elemType, varName, accumType, size1, size2, numCombinations),
1999                 computeExpectedValues(specValue, scalarType, numCombinations),
2000                 (scalarType == glu::TYPE_DOUBLE ? (FeatureFlags)FEATURE_SHADER_FLOAT_64 : (FeatureFlags)0),
2001                 false,
2002         };
2003         return def;
2004 }
2005
2006 //! A basic struct case, where one member is a specialization constant, or a specialization constant composite
2007 //! (a matrix/vector with a spec. const. element).
2008 CaseDefinition makeStructCompositeCaseDefinition (const glu::DataType memberType)
2009 {
2010         using namespace composite_case_internal;
2011
2012         std::ostringstream globalCode;
2013         {
2014                 globalCode << "struct Data {\n"
2015                                    << "    int   i;\n"
2016                                    << "    float f;\n"
2017                                    << "    bool  b;\n"
2018                                    << "    " << glu::getDataTypeName(memberType) << " sc;\n"
2019                                    << "    uint  ui;\n"
2020                                    << "};\n"
2021                                    << "\n"
2022                                    << "Data s0 = Data(3, 2.0, true, " << glu::getDataTypeName(memberType) << "(sc0), 8u);\n";
2023         }
2024
2025         const glu::DataType scalarType   = glu::getDataTypeScalarType(memberType);
2026         const bool          isBoolData   = (scalarType == glu::TYPE_BOOL);
2027         const int           specValue    = (isBoolData ? 0 : 23);
2028         const int           checksum     = (3 + 2 + 1 + specValue + 8);  // matches the shader code
2029         const glu::DataType accumType    = (isBoolData ? glu::TYPE_INT : scalarType);
2030         const std::string   accumTypeStr = glu::getDataTypeName(accumType);
2031
2032         std::ostringstream mainCode;
2033         {
2034                 mainCode << "    " << accumTypeStr << " sum_s0 = " << accumTypeStr << "(0);\n"
2035                                  << "\n"
2036                                  << "    sum_s0 += " << accumTypeStr << "(s0.i);\n"
2037                                  << "    sum_s0 += " << accumTypeStr << "(s0.f);\n"
2038                                  << "    sum_s0 += " << accumTypeStr << "(s0.b);\n"
2039                                  << "    sum_s0 += " << accumTypeStr << "(s0.sc" << getFirstDataElementSubscriptString(memberType) << ");\n"
2040                                  << "    sum_s0 += " << accumTypeStr << "(s0.ui);\n"
2041                                  << "\n"
2042                                  << "    sb_out.result = sum_s0;\n";
2043         }
2044
2045         const std::string caseName = glu::getDataTypeName(memberType);
2046
2047         const CaseDefinition def =
2048         {
2049                 caseName,
2050                 makeVector(makeSpecConstant("sc0", 1u, scalarType, specValue)),
2051                 getDataTypeScalarSizeBytes(accumType),
2052                 "    " + accumTypeStr + " result;\n",
2053                 globalCode.str(),
2054                 mainCode.str(),
2055                 makeVector(OffsetValue(getDataTypeScalarSizeBytes(memberType), 0, makeValue(scalarType, checksum))),
2056                 (scalarType == glu::TYPE_DOUBLE ? (FeatureFlags)FEATURE_SHADER_FLOAT_64 : (FeatureFlags)0),
2057                 false,
2058         };
2059         return def;
2060 }
2061
2062 //! Specialization constants used in composites.
2063 tcu::TestCaseGroup* createCompositeTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage)
2064 {
2065         de::MovePtr<tcu::TestCaseGroup> compositeTests (new tcu::TestCaseGroup(testCtx, "composite", "specialization constants usage in composite types"));
2066
2067         // Vectors
2068         {
2069                 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "vector", ""));
2070
2071                 const glu::DataType types[] =
2072                 {
2073                         glu::TYPE_FLOAT_VEC2,
2074                         glu::TYPE_FLOAT_VEC3,
2075                         glu::TYPE_FLOAT_VEC4,
2076
2077                         glu::TYPE_DOUBLE_VEC2,
2078                         glu::TYPE_DOUBLE_VEC3,
2079                         glu::TYPE_DOUBLE_VEC4,
2080
2081                         glu::TYPE_BOOL_VEC2,
2082                         glu::TYPE_BOOL_VEC3,
2083                         glu::TYPE_BOOL_VEC4,
2084
2085                         glu::TYPE_INT_VEC2,
2086                         glu::TYPE_INT_VEC3,
2087                         glu::TYPE_INT_VEC4,
2088
2089                         glu::TYPE_UINT_VEC2,
2090                         glu::TYPE_UINT_VEC3,
2091                         glu::TYPE_UINT_VEC4,
2092                 };
2093                 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(types); ++typeNdx)
2094                         group->addChild(new SpecConstantTest(testCtx, shaderStage, makeMatrixVectorCompositeCaseDefinition(types[typeNdx])));
2095
2096                 compositeTests->addChild(group.release());
2097         }
2098
2099         // Matrices
2100         {
2101                 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "matrix", ""));
2102
2103                 const glu::DataType types[] =
2104                 {
2105                         glu::TYPE_FLOAT_MAT2,
2106                         glu::TYPE_FLOAT_MAT2X3,
2107                         glu::TYPE_FLOAT_MAT2X4,
2108                         glu::TYPE_FLOAT_MAT3X2,
2109                         glu::TYPE_FLOAT_MAT3,
2110                         glu::TYPE_FLOAT_MAT3X4,
2111                         glu::TYPE_FLOAT_MAT4X2,
2112                         glu::TYPE_FLOAT_MAT4X3,
2113                         glu::TYPE_FLOAT_MAT4,
2114
2115                         glu::TYPE_DOUBLE_MAT2,
2116                         glu::TYPE_DOUBLE_MAT2X3,
2117                         glu::TYPE_DOUBLE_MAT2X4,
2118                         glu::TYPE_DOUBLE_MAT3X2,
2119                         glu::TYPE_DOUBLE_MAT3,
2120                         glu::TYPE_DOUBLE_MAT3X4,
2121                         glu::TYPE_DOUBLE_MAT4X2,
2122                         glu::TYPE_DOUBLE_MAT4X3,
2123                         glu::TYPE_DOUBLE_MAT4,
2124                 };
2125                 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(types); ++typeNdx)
2126                         group->addChild(new SpecConstantTest(testCtx, shaderStage, makeMatrixVectorCompositeCaseDefinition(types[typeNdx])));
2127
2128                 compositeTests->addChild(group.release());
2129         }
2130
2131         const glu::DataType allTypes[] =
2132         {
2133                 glu::TYPE_FLOAT,
2134                 glu::TYPE_FLOAT_VEC2,
2135                 glu::TYPE_FLOAT_VEC3,
2136                 glu::TYPE_FLOAT_VEC4,
2137                 glu::TYPE_FLOAT_MAT2,
2138                 glu::TYPE_FLOAT_MAT2X3,
2139                 glu::TYPE_FLOAT_MAT2X4,
2140                 glu::TYPE_FLOAT_MAT3X2,
2141                 glu::TYPE_FLOAT_MAT3,
2142                 glu::TYPE_FLOAT_MAT3X4,
2143                 glu::TYPE_FLOAT_MAT4X2,
2144                 glu::TYPE_FLOAT_MAT4X3,
2145                 glu::TYPE_FLOAT_MAT4,
2146
2147                 glu::TYPE_DOUBLE,
2148                 glu::TYPE_DOUBLE_VEC2,
2149                 glu::TYPE_DOUBLE_VEC3,
2150                 glu::TYPE_DOUBLE_VEC4,
2151                 glu::TYPE_DOUBLE_MAT2,
2152                 glu::TYPE_DOUBLE_MAT2X3,
2153                 glu::TYPE_DOUBLE_MAT2X4,
2154                 glu::TYPE_DOUBLE_MAT3X2,
2155                 glu::TYPE_DOUBLE_MAT3,
2156                 glu::TYPE_DOUBLE_MAT3X4,
2157                 glu::TYPE_DOUBLE_MAT4X2,
2158                 glu::TYPE_DOUBLE_MAT4X3,
2159                 glu::TYPE_DOUBLE_MAT4,
2160
2161                 glu::TYPE_INT,
2162                 glu::TYPE_INT_VEC2,
2163                 glu::TYPE_INT_VEC3,
2164                 glu::TYPE_INT_VEC4,
2165
2166                 glu::TYPE_UINT,
2167                 glu::TYPE_UINT_VEC2,
2168                 glu::TYPE_UINT_VEC3,
2169                 glu::TYPE_UINT_VEC4,
2170
2171                 glu::TYPE_BOOL,
2172                 glu::TYPE_BOOL_VEC2,
2173                 glu::TYPE_BOOL_VEC3,
2174                 glu::TYPE_BOOL_VEC4,
2175         };
2176
2177         // Array cases
2178         {
2179                 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "array", ""));
2180
2181                 // Array of T
2182                 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(allTypes); ++typeNdx)
2183                         group->addChild(new SpecConstantTest(testCtx, shaderStage, makeArrayCompositeCaseDefinition(allTypes[typeNdx], 3)));
2184
2185                 // Array of array of T
2186                 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(allTypes); ++typeNdx)
2187                         group->addChild(new SpecConstantTest(testCtx, shaderStage, makeArrayCompositeCaseDefinition(allTypes[typeNdx], 3, 2)));
2188
2189                 // Special case - array of struct
2190                 {
2191                         const int checksum = (3 + 2 + 1) + (1 + 5 + 1) + (1 + 2 + 0);
2192                         const CaseDefinition def =
2193                         {
2194                                 "struct",
2195                                 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int   sc0 = 1;",    4, makeValueInt32  (3)),
2196                                                    SpecConstant(2u, "layout(constant_id = ${ID}) const float sc1 = 1.0;",  4, makeValueFloat32(5.0f)),
2197                                                    SpecConstant(3u, "layout(constant_id = ${ID}) const bool  sc2 = true;", 4, makeValueBool32 (false))),
2198                                 4,
2199                                 "    int result;\n",
2200
2201                                 "struct Data {\n"
2202                                 "    int   x;\n"
2203                                 "    float y;\n"
2204                                 "    bool  z;\n"
2205                                 "};\n"
2206                                 "\n"
2207                                 "Data a0[3] = Data[3](Data(sc0, 2.0, true), Data(1, sc1, true), Data(1, 2.0, sc2));\n",
2208
2209                                 "    int sum_a0 = 0;\n"
2210                                 "\n"
2211                                 "    for (int i = 0; i < 3; ++i)\n"
2212                                 "        sum_a0 += int(a0[i].x) + int(a0[i].y) + int(a0[i].z);\n"
2213                                 "\n"
2214                                 "    sb_out.result = sum_a0;\n",
2215
2216                                 makeVector(OffsetValue(4,  0, makeValueInt32(checksum))),
2217                                 (FeatureFlags)0,
2218                                 false,
2219                         };
2220
2221                         group->addChild(new SpecConstantTest(testCtx, shaderStage, def));
2222                 }
2223
2224                 compositeTests->addChild(group.release());
2225         }
2226
2227         // Struct cases
2228         {
2229                 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "struct", ""));
2230
2231                 // Struct with one member being a specialization constant (or spec. const. composite) of a given type
2232                 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(allTypes); ++typeNdx)
2233                         group->addChild(new SpecConstantTest(testCtx, shaderStage, makeStructCompositeCaseDefinition(allTypes[typeNdx])));
2234
2235                 // Special case - struct with array
2236                 {
2237                         const int checksum = (1 + 2 + 31 + 4 + 0);
2238                         const CaseDefinition def =
2239                         {
2240                                 "array",
2241                                 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 1.0;",  4, makeValueFloat32(31.0f))),
2242                                 4,
2243                                 "    float result;\n",
2244
2245                                 "struct Data {\n"
2246                                 "    int  i;\n"
2247                                 "    vec3 sc[3];\n"
2248                                 "    bool b;\n"
2249                                 "};\n"
2250                                 "\n"
2251                                 "Data s0 = Data(1, vec3[3](vec3(2.0), vec3(sc0), vec3(4.0)), false);\n",
2252
2253                                 "    float sum_s0 = 0;\n"
2254                                 "\n"
2255                                 "    sum_s0 += float(s0.i);\n"
2256                                 "    sum_s0 += float(s0.sc[0][0]);\n"
2257                                 "    sum_s0 += float(s0.sc[1][0]);\n"
2258                                 "    sum_s0 += float(s0.sc[2][0]);\n"
2259                                 "    sum_s0 += float(s0.b);\n"
2260                                 "\n"
2261                                 "    sb_out.result = sum_s0;\n",
2262
2263                                 makeVector(OffsetValue(4,  0, makeValueFloat32(static_cast<float>(checksum)))),
2264                                 (FeatureFlags)0,
2265                                 false,
2266                         };
2267
2268                         group->addChild(new SpecConstantTest(testCtx, shaderStage, def));
2269                 }
2270
2271                 // Special case - struct of struct
2272                 {
2273                         const int checksum = (1 + 2 + 11 + 4 + 1);
2274                         const CaseDefinition def =
2275                         {
2276                                 "struct",
2277                                 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;",  4, makeValueInt32(11))),
2278                                 4,
2279                                 "    int result;\n",
2280
2281                                 "struct Nested {\n"
2282                                 "    vec2  v;\n"
2283                                 "    int   sc;\n"
2284                                 "    float f;\n"
2285                                 "};\n"
2286                                 "\n"
2287                                 "struct Data {\n"
2288                                 "    uint   ui;\n"
2289                                 "    Nested s;\n"
2290                                 "    bool   b;\n"
2291                                 "};\n"
2292                                 "\n"
2293                                 "Data s0 = Data(1u, Nested(vec2(2.0), sc0, 4.0), true);\n",
2294
2295                                 "    int sum_s0 = 0;\n"
2296                                 "\n"
2297                                 "    sum_s0 += int(s0.ui);\n"
2298                                 "    sum_s0 += int(s0.s.v[0]);\n"
2299                                 "    sum_s0 += int(s0.s.sc);\n"
2300                                 "    sum_s0 += int(s0.s.f);\n"
2301                                 "    sum_s0 += int(s0.b);\n"
2302                                 "\n"
2303                                 "    sb_out.result = sum_s0;\n",
2304
2305                                 makeVector(OffsetValue(4,  0, makeValueInt32(checksum))),
2306                                 (FeatureFlags)0,
2307                                 false,
2308                         };
2309
2310                         group->addChild(new SpecConstantTest(testCtx, shaderStage, def));
2311                 }
2312
2313                 compositeTests->addChild(group.release());
2314         }
2315
2316         return compositeTests.release();
2317 }
2318
2319 } // anonymous ns
2320
2321 tcu::TestCaseGroup* createSpecConstantTests (tcu::TestContext& testCtx)
2322 {
2323         de::MovePtr<tcu::TestCaseGroup> allTests (new tcu::TestCaseGroup(testCtx, "spec_constant", "Specialization constants tests"));
2324         de::MovePtr<tcu::TestCaseGroup> graphicsGroup (new tcu::TestCaseGroup(testCtx, "graphics", ""));
2325
2326         struct StageDef
2327         {
2328                 tcu::TestCaseGroup*             parentGroup;
2329                 const char*                             name;
2330                 VkShaderStageFlagBits   stage;
2331         };
2332
2333         const StageDef stages[] =
2334         {
2335                 { graphicsGroup.get(),  "vertex",               VK_SHADER_STAGE_VERTEX_BIT                                      },
2336                 { graphicsGroup.get(),  "fragment",             VK_SHADER_STAGE_FRAGMENT_BIT                            },
2337                 { graphicsGroup.get(),  "tess_control", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT        },
2338                 { graphicsGroup.get(),  "tess_eval",    VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT     },
2339                 { graphicsGroup.get(),  "geometry",             VK_SHADER_STAGE_GEOMETRY_BIT                            },
2340                 { allTests.get(),               "compute",              VK_SHADER_STAGE_COMPUTE_BIT                                     },
2341         };
2342
2343         allTests->addChild(graphicsGroup.release());
2344
2345         for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(stages); ++stageNdx)
2346         {
2347                 const StageDef& stage = stages[stageNdx];
2348                 de::MovePtr<tcu::TestCaseGroup> stageGroup (new tcu::TestCaseGroup(testCtx, stage.name, ""));
2349
2350                 stageGroup->addChild(createDefaultValueTests       (testCtx, stage.stage));
2351                 stageGroup->addChild(createBasicSpecializationTests(testCtx, stage.stage));
2352                 stageGroup->addChild(createBuiltInOverrideTests    (testCtx, stage.stage));
2353                 stageGroup->addChild(createExpressionTests         (testCtx, stage.stage));
2354                 stageGroup->addChild(createCompositeTests          (testCtx, stage.stage));
2355
2356                 if (stage.stage == VK_SHADER_STAGE_COMPUTE_BIT)
2357                         stageGroup->addChild(createWorkGroupSizeTests(testCtx));
2358
2359                 stage.parentGroup->addChild(stageGroup.release());
2360         }
2361
2362         return allTests.release();
2363 }
2364
2365 } // pipeline
2366 } // vkt