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