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