1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2016 The Khronos Group Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Pipeline specialization constants tests
22 *//*--------------------------------------------------------------------*/
24 #include "vktPipelineSpecConstantTests.hpp"
25 #include "vktTestCase.hpp"
26 #include "vktPipelineSpecConstantUtil.hpp"
27 #include "vktPipelineMakeUtil.hpp"
29 #include "tcuTestLog.hpp"
30 #include "tcuTexture.hpp"
31 #include "tcuFormatUtil.hpp"
33 #include "gluShaderUtil.hpp"
35 #include "vkBuilderUtil.hpp"
36 #include "vkPrograms.hpp"
37 #include "vkRefUtil.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkImageUtil.hpp"
41 #include "deUniquePtr.hpp"
42 #include "deStringUtil.hpp"
54 static const char* const s_perVertexBlock = "gl_PerVertex {\n"
55 " vec4 gl_Position;\n"
58 //! Raw memory storage for values used in test cases.
59 //! We use it to simplify test case definitions where different types are expected in the result.
63 GenericValue (void) { clear(); }
65 //! Copy up to 'size' bytes of 'data'.
66 GenericValue (const void* data, const deUint32 size)
68 DE_ASSERT(size <= sizeof(m_data));
70 deMemcpy(&m_data, data, size);
76 void clear (void) { m_data = 0; }
79 inline GenericValue makeValueBool32 (const bool a) { return GenericValue(&a, sizeof(a)); }
80 inline GenericValue makeValueInt32 (const deInt32 a) { return GenericValue(&a, sizeof(a)); }
81 // \note deInt64 not tested
82 inline GenericValue makeValueUint32 (const deUint32 a) { return GenericValue(&a, sizeof(a)); }
83 // \note deUint64 not tested
84 inline GenericValue makeValueFloat32 (const float a) { return GenericValue(&a, sizeof(a)); }
85 inline GenericValue makeValueFloat64 (const double a) { return GenericValue(&a, sizeof(a)); }
89 deUint32 specID; //!< specialization constant ID
90 std::string declarationCode; //!< syntax to declare the constant, use ${ID} as an ID placeholder
91 deUint32 size; //!< data size on the host, 0 = no specialized value
92 GenericValue specValue; //!< specialized value passed by the API
94 SpecConstant (const deUint32 specID_, const std::string declarationCode_)
96 , declarationCode (declarationCode_)
102 SpecConstant (const deUint32 specID_, const std::string declarationCode_, const deUint32 size_, const GenericValue specValue_)
104 , declarationCode (declarationCode_)
106 , specValue (specValue_)
111 //! Useful when referring to a value in a buffer (i.e. check expected values in SSBO).
114 deUint32 size; //!< data size in the buffer (up to sizeof(value))
115 deUint32 offset; //!< offset into the buffer
116 GenericValue value; //!< value expected to be there
118 OffsetValue (const deUint32 size_, const deUint32 offset_, const GenericValue value_)
125 //! Get the integer value of 'size' bytes at 'memory' location.
126 deUint64 memoryAsInteger (const void* memory, const deUint32 size)
128 DE_ASSERT(size <= sizeof(deUint64));
130 deMemcpy(&value, memory, size);
134 inline std::string memoryAsHexString (const void* memory, const deUint32 size)
136 const deUint8* memoryBytePtr = static_cast<const deUint8*>(memory);
137 return de::toString(tcu::formatArray(tcu::Format::HexIterator<deUint8>(memoryBytePtr), tcu::Format::HexIterator<deUint8>(memoryBytePtr + size)));
140 void logValueMismatch (tcu::TestLog& log, const void* expected, const void* actual, const deUint32 offset, const deUint32 size)
142 const bool canDisplayValue = (size <= sizeof(deUint64));
143 log << tcu::TestLog::Message
144 << "Comparison failed for value at offset " << de::toString(offset) << ": expected "
145 << (canDisplayValue ? de::toString(memoryAsInteger(expected, size)) + " " : "") << memoryAsHexString(expected, size) << " but got "
146 << (canDisplayValue ? de::toString(memoryAsInteger(actual, size)) + " " : "") << memoryAsHexString(actual, size)
147 << tcu::TestLog::EndMessage;
150 //! Check if expected values exist in the memory.
151 bool verifyValues (tcu::TestLog& log, const void* memory, const std::vector<OffsetValue>& expectedValues)
154 log << tcu::TestLog::Section("compare", "Verify result values");
156 for (std::vector<OffsetValue>::const_iterator it = expectedValues.begin(); it < expectedValues.end(); ++it)
158 const char* const valuePtr = static_cast<const char*>(memory) + it->offset;
159 if (deMemCmp(valuePtr, &it->value, it->size) != 0)
162 logValueMismatch(log, &it->value, valuePtr, it->offset, it->size);
167 log << tcu::TestLog::Message << "All OK" << tcu::TestLog::EndMessage;
169 log << tcu::TestLog::EndSection;
173 //! Bundles together common test case parameters.
174 struct CaseDefinition
176 std::string name; //!< Test case name
177 std::vector<SpecConstant> specConstants; //!< list of specialization constants to declare
178 VkDeviceSize ssboSize; //!< required ssbo size in bytes
179 std::string ssboCode; //!< ssbo member definitions
180 std::string globalCode; //!< generic shader code outside the main function (e.g. declarations)
181 std::string mainCode; //!< generic shader code to execute in main (e.g. assignments)
182 std::vector<OffsetValue> expectedValues; //!< list of values to check inside the ssbo buffer
183 FeatureFlags requirements; //!< features the implementation must support to allow this test to run
186 //! Manages Vulkan structures to pass specialization data.
190 Specialization (const std::vector<SpecConstant>& specConstants);
192 //! Can return NULL if nothing is specialized
193 const VkSpecializationInfo* getSpecializationInfo (void) const { return m_entries.size() > 0 ? &m_specialization : DE_NULL; }
196 std::vector<GenericValue> m_data;
197 std::vector<VkSpecializationMapEntry> m_entries;
198 VkSpecializationInfo m_specialization;
201 Specialization::Specialization (const std::vector<SpecConstant>& specConstants)
203 m_data.reserve(specConstants.size());
204 m_entries.reserve(specConstants.size());
207 for (std::vector<SpecConstant>::const_iterator it = specConstants.begin(); it != specConstants.end(); ++it)
210 m_data.push_back(it->specValue);
211 m_entries.push_back(makeSpecializationMapEntry(it->specID, offset, it->size));
212 offset += (deUint32)sizeof(GenericValue);
215 if (m_entries.size() > 0)
217 m_specialization.mapEntryCount = static_cast<deUint32>(m_entries.size());
218 m_specialization.pMapEntries = &m_entries[0];
219 m_specialization.dataSize = sizeof(GenericValue) * m_data.size();
220 m_specialization.pData = &m_data[0];
223 deMemset(&m_specialization, 0, sizeof(m_specialization));
226 class SpecConstantTest : public TestCase
229 SpecConstantTest (tcu::TestContext& testCtx,
230 const VkShaderStageFlagBits stage, //!< which shader stage is tested
231 const CaseDefinition& caseDef);
233 void initPrograms (SourceCollections& programCollection) const;
234 TestInstance* createInstance (Context& context) const;
237 const VkShaderStageFlagBits m_stage;
238 const CaseDefinition m_caseDef;
241 SpecConstantTest::SpecConstantTest (tcu::TestContext& testCtx,
242 const VkShaderStageFlagBits stage,
243 const CaseDefinition& caseDef)
244 : TestCase (testCtx, caseDef.name, "")
246 , m_caseDef (caseDef)
250 //! Build a string that declares all specialization constants, replacing ${ID} with proper ID numbers.
251 std::string generateSpecConstantCode (const std::vector<SpecConstant>& specConstants)
253 std::ostringstream code;
254 for (std::vector<SpecConstant>::const_iterator it = specConstants.begin(); it != specConstants.end(); ++it)
256 std::string decl = it->declarationCode;
257 const std::string::size_type pos = decl.find("${ID}");
258 if (pos != std::string::npos)
259 decl.replace(pos, 5, de::toString(it->specID));
260 code << decl << "\n";
266 std::string generateSSBOCode (const std::string& memberDeclarations)
268 std::ostringstream code;
269 code << "layout (set = 0, binding = 0, std430) writeonly buffer Output {\n"
270 << memberDeclarations
276 void SpecConstantTest::initPrograms (SourceCollections& programCollection) const
278 // Always add vertex and fragment to graphics stages
279 VkShaderStageFlags requiredStages = m_stage;
281 if (requiredStages & VK_SHADER_STAGE_ALL_GRAPHICS)
282 requiredStages |= VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
284 if (requiredStages & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))
285 requiredStages |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
287 // Either graphics or compute must be defined, but not both
288 DE_ASSERT(((requiredStages & VK_SHADER_STAGE_ALL_GRAPHICS) != 0) != ((requiredStages & VK_SHADER_STAGE_COMPUTE_BIT) != 0));
290 if (requiredStages & VK_SHADER_STAGE_VERTEX_BIT)
292 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_VERTEX_BIT);
293 std::ostringstream src;
294 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
295 << "layout(location = 0) in highp vec4 position;\n"
297 << "out " << s_perVertexBlock << ";\n"
299 << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
300 << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
301 << (useSpecConst ? m_caseDef.globalCode + "\n" : "")
302 << "void main (void)\n"
304 << (useSpecConst ? m_caseDef.mainCode + "\n" : "")
305 << " gl_Position = position;\n"
308 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
311 if (requiredStages & VK_SHADER_STAGE_FRAGMENT_BIT)
313 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_FRAGMENT_BIT);
314 std::ostringstream src;
315 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
316 << "layout(location = 0) out highp vec4 fragColor;\n"
318 << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
319 << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
320 << (useSpecConst ? m_caseDef.globalCode + "\n" : "")
321 << "void main (void)\n"
323 << (useSpecConst ? m_caseDef.mainCode + "\n" : "")
324 << " fragColor = vec4(1.0, 1.0, 0.0, 1.0);\n"
327 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
330 if (requiredStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
332 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
333 std::ostringstream src;
334 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
335 << "layout(vertices = 3) out;\n"
337 << "in " << s_perVertexBlock << " gl_in[gl_MaxPatchVertices];\n"
339 << "out " << s_perVertexBlock << " gl_out[];\n"
341 << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
342 << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
343 << (useSpecConst ? m_caseDef.globalCode + "\n" : "")
344 << "void main (void)\n"
346 << (useSpecConst ? m_caseDef.mainCode + "\n" : "")
347 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
348 << " if (gl_InvocationID == 0)\n"
350 << " gl_TessLevelInner[0] = 3;\n"
351 << " gl_TessLevelOuter[0] = 2;\n"
352 << " gl_TessLevelOuter[1] = 2;\n"
353 << " gl_TessLevelOuter[2] = 2;\n"
357 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
360 if (requiredStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
362 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
363 std::ostringstream src;
364 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
365 << "layout(triangles, equal_spacing, ccw) in;\n"
367 << "in " << s_perVertexBlock << " gl_in[gl_MaxPatchVertices];\n"
369 << "out " << s_perVertexBlock << ";\n"
371 << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
372 << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
373 << (useSpecConst ? m_caseDef.globalCode + "\n" : "")
374 << "void main (void)\n"
376 << (useSpecConst ? m_caseDef.mainCode + "\n" : "")
377 << " vec3 p0 = gl_TessCoord.x * gl_in[0].gl_Position.xyz;\n"
378 << " vec3 p1 = gl_TessCoord.y * gl_in[1].gl_Position.xyz;\n"
379 << " vec3 p2 = gl_TessCoord.z * gl_in[2].gl_Position.xyz;\n"
380 << " gl_Position = vec4(p0 + p1 + p2, 1.0);\n"
383 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
386 if (requiredStages & VK_SHADER_STAGE_GEOMETRY_BIT)
388 const bool useSpecConst = (m_stage == VK_SHADER_STAGE_GEOMETRY_BIT);
389 std::ostringstream src;
390 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
391 << "layout(triangles) in;\n"
392 << "layout(triangle_strip, max_vertices = 3) out;\n"
394 << "in " << s_perVertexBlock << " gl_in[];\n"
396 << "out " << s_perVertexBlock << ";\n"
398 << (useSpecConst ? generateSpecConstantCode(m_caseDef.specConstants) : "")
399 << (useSpecConst ? generateSSBOCode(m_caseDef.ssboCode) : "")
400 << (useSpecConst ? m_caseDef.globalCode + "\n" : "")
401 << "void main (void)\n"
403 << (useSpecConst ? m_caseDef.mainCode + "\n" : "")
404 << " gl_Position = gl_in[0].gl_Position;\n"
405 << " EmitVertex();\n"
407 << " gl_Position = gl_in[1].gl_Position;\n"
408 << " EmitVertex();\n"
410 << " gl_Position = gl_in[2].gl_Position;\n"
411 << " EmitVertex();\n"
413 << " EndPrimitive();\n"
416 programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
419 if (requiredStages & VK_SHADER_STAGE_COMPUTE_BIT)
421 std::ostringstream src;
422 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
423 // Don't define work group size, use the default or specialization constants
425 << generateSpecConstantCode(m_caseDef.specConstants)
426 << generateSSBOCode(m_caseDef.ssboCode)
427 << m_caseDef.globalCode + "\n"
428 << "void main (void)\n"
430 << m_caseDef.mainCode
433 programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
437 class ComputeTestInstance : public TestInstance
440 ComputeTestInstance (Context& context,
441 const VkDeviceSize ssboSize,
442 const std::vector<SpecConstant>& specConstants,
443 const std::vector<OffsetValue>& expectedValues);
445 tcu::TestStatus iterate (void);
448 const VkDeviceSize m_ssboSize;
449 const std::vector<SpecConstant> m_specConstants;
450 const std::vector<OffsetValue> m_expectedValues;
453 ComputeTestInstance::ComputeTestInstance (Context& context,
454 const VkDeviceSize ssboSize,
455 const std::vector<SpecConstant>& specConstants,
456 const std::vector<OffsetValue>& expectedValues)
457 : TestInstance (context)
458 , m_ssboSize (ssboSize)
459 , m_specConstants (specConstants)
460 , m_expectedValues (expectedValues)
464 tcu::TestStatus ComputeTestInstance::iterate (void)
466 const DeviceInterface& vk = m_context.getDeviceInterface();
467 const VkDevice device = m_context.getDevice();
468 const VkQueue queue = m_context.getUniversalQueue();
469 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
470 Allocator& allocator = m_context.getDefaultAllocator();
474 const Buffer resultBuffer(vk, device, allocator, makeBufferCreateInfo(m_ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
476 const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
477 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
480 const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
481 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
482 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
484 const Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
485 const VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, m_ssboSize);
487 DescriptorSetUpdateBuilder()
488 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
493 const Specialization specialization (m_specConstants);
494 const VkSpecializationInfo* pSpecInfo = specialization.getSpecializationInfo();
498 const Unique<VkShaderModule> shaderModule (createShaderModule (vk, device, m_context.getBinaryCollection().get("comp"), 0));
499 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout (vk, device, *descriptorSetLayout));
500 const Unique<VkPipeline> pipeline (makeComputePipeline(vk, device, *pipelineLayout, *shaderModule, pSpecInfo));
501 const Unique<VkCommandPool> cmdPool (createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
502 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer (vk, device, *cmdPool));
504 beginCommandBuffer(vk, *cmdBuffer);
506 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
507 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
509 vk.cmdDispatch(*cmdBuffer, 1u, 1u, 1u);
512 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
513 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, m_ssboSize);
515 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
516 0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
519 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
520 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
524 const Allocation& resultAlloc = resultBuffer.getAllocation();
525 invalidateMappedMemoryRange(vk, device, resultAlloc.getMemory(), resultAlloc.getOffset(), m_ssboSize);
527 if (verifyValues(m_context.getTestContext().getLog(), resultAlloc.getHostPtr(), m_expectedValues))
528 return tcu::TestStatus::pass("Success");
530 return tcu::TestStatus::fail("Values did not match");
533 class GraphicsTestInstance : public TestInstance
536 GraphicsTestInstance (Context& context,
537 const VkDeviceSize ssboSize,
538 const std::vector<SpecConstant>& specConstants,
539 const std::vector<OffsetValue>& expectedValues,
540 const VkShaderStageFlagBits stage);
542 tcu::TestStatus iterate (void);
545 const VkDeviceSize m_ssboSize;
546 const std::vector<SpecConstant> m_specConstants;
547 const std::vector<OffsetValue> m_expectedValues;
548 const VkShaderStageFlagBits m_stage;
551 GraphicsTestInstance::GraphicsTestInstance (Context& context,
552 const VkDeviceSize ssboSize,
553 const std::vector<SpecConstant>& specConstants,
554 const std::vector<OffsetValue>& expectedValues,
555 const VkShaderStageFlagBits stage)
556 : TestInstance (context)
557 , m_ssboSize (ssboSize)
558 , m_specConstants (specConstants)
559 , m_expectedValues (expectedValues)
564 tcu::TestStatus GraphicsTestInstance::iterate (void)
566 const DeviceInterface& vk = m_context.getDeviceInterface();
567 const VkDevice device = m_context.getDevice();
568 const VkQueue queue = m_context.getUniversalQueue();
569 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
570 Allocator& allocator = m_context.getDefaultAllocator();
574 const tcu::IVec2 renderSize = tcu::IVec2(32, 32);
575 const VkFormat imageFormat = VK_FORMAT_R8G8B8A8_UNORM;
576 const Image colorImage (vk, device, allocator, makeImageCreateInfo(renderSize, imageFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT), MemoryRequirement::Any);
577 const Unique<VkImageView> colorImageView(makeImageView(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, imageFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)));
581 const deUint32 numVertices = 3;
582 const VkDeviceSize vertexBufferSizeBytes = sizeof(tcu::Vec4) * numVertices;
583 const Buffer vertexBuffer (vk, device, allocator, makeBufferCreateInfo(vertexBufferSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible);
586 const Allocation& alloc = vertexBuffer.getAllocation();
587 tcu::Vec4* pVertices = reinterpret_cast<tcu::Vec4*>(alloc.getHostPtr());
589 pVertices[0] = tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f);
590 pVertices[1] = tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f);
591 pVertices[2] = tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f);
593 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), vertexBufferSizeBytes);
594 // No barrier needed, flushed memory is automatically visible
599 const Buffer resultBuffer(vk, device, allocator, makeBufferCreateInfo(m_ssboSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
601 const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
602 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL_GRAPHICS)
605 const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
606 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
607 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
609 const Unique<VkDescriptorSet> descriptorSet (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
610 const VkDescriptorBufferInfo descriptorBufferInfo = makeDescriptorBufferInfo(resultBuffer.get(), 0ull, m_ssboSize);
612 DescriptorSetUpdateBuilder()
613 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorBufferInfo)
618 const Specialization specialization (m_specConstants);
619 const VkSpecializationInfo* pSpecInfo = specialization.getSpecializationInfo();
623 const Unique<VkRenderPass> renderPass (makeRenderPass (vk, device, imageFormat));
624 const Unique<VkFramebuffer> framebuffer (makeFramebuffer (vk, device, *renderPass, 1u, &colorImageView.get(), static_cast<deUint32>(renderSize.x()), static_cast<deUint32>(renderSize.y())));
625 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
626 const Unique<VkCommandPool> cmdPool (createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
627 const Unique<VkCommandBuffer> cmdBuffer (makeCommandBuffer (vk, device, *cmdPool));
629 GraphicsPipelineBuilder pipelineBuilder;
631 .setRenderSize(renderSize)
632 .setShader(vk, device, VK_SHADER_STAGE_VERTEX_BIT, m_context.getBinaryCollection().get("vert"), pSpecInfo)
633 .setShader(vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, m_context.getBinaryCollection().get("frag"), pSpecInfo);
635 if ((m_stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) || (m_stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))
637 .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, m_context.getBinaryCollection().get("tesc"), pSpecInfo)
638 .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get("tese"), pSpecInfo);
640 if (m_stage == VK_SHADER_STAGE_GEOMETRY_BIT)
642 .setShader(vk, device, VK_SHADER_STAGE_GEOMETRY_BIT, m_context.getBinaryCollection().get("geom"), pSpecInfo);
644 const Unique<VkPipeline> pipeline (pipelineBuilder.build(vk, device, *pipelineLayout, *renderPass));
648 const VkRect2D renderArea = {
650 makeExtent2D(renderSize.x(), renderSize.y()),
652 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f);
653 const VkDeviceSize vertexBufferOffset = 0ull;
655 beginCommandBuffer(vk, *cmdBuffer);
658 const VkImageSubresourceRange imageFullSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
659 const VkImageMemoryBarrier barrierColorAttachmentSetInitialLayout = makeImageMemoryBarrier(
660 0u, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
661 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
662 *colorImage, imageFullSubresourceRange);
664 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
665 0u, DE_NULL, 0u, DE_NULL, 1u, &barrierColorAttachmentSetInitialLayout);
668 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
670 vk.cmdBindPipeline (*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
671 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
672 vk.cmdBindVertexBuffers (*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
674 vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
675 vk.cmdEndRenderPass(*cmdBuffer);
678 const VkBufferMemoryBarrier shaderWriteBarrier = makeBufferMemoryBarrier(
679 VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *resultBuffer, 0ull, m_ssboSize);
681 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
682 0u, DE_NULL, 1u, &shaderWriteBarrier, 0u, DE_NULL);
685 VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
686 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
690 const Allocation& resultAlloc = resultBuffer.getAllocation();
691 invalidateMappedMemoryRange(vk, device, resultAlloc.getMemory(), resultAlloc.getOffset(), m_ssboSize);
693 if (verifyValues(m_context.getTestContext().getLog(), resultAlloc.getHostPtr(), m_expectedValues))
694 return tcu::TestStatus::pass("Success");
696 return tcu::TestStatus::fail("Values did not match");
699 FeatureFlags getShaderStageRequirements (const VkShaderStageFlags stageFlags)
701 FeatureFlags features = (FeatureFlags)0;
703 if (((stageFlags & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) || ((stageFlags & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0))
704 features |= FEATURE_TESSELLATION_SHADER;
706 if ((stageFlags & VK_SHADER_STAGE_GEOMETRY_BIT) != 0)
707 features |= FEATURE_GEOMETRY_SHADER;
709 // All tests use SSBO writes to read back results.
710 if ((stageFlags & VK_SHADER_STAGE_ALL_GRAPHICS) != 0)
712 if ((stageFlags & VK_SHADER_STAGE_FRAGMENT_BIT) != 0)
713 features |= FEATURE_FRAGMENT_STORES_AND_ATOMICS;
715 features |= FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS;
721 TestInstance* SpecConstantTest::createInstance (Context& context) const
723 requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), m_caseDef.requirements | getShaderStageRequirements(m_stage));
725 if (m_stage & VK_SHADER_STAGE_COMPUTE_BIT)
726 return new ComputeTestInstance(context, m_caseDef.ssboSize, m_caseDef.specConstants, m_caseDef.expectedValues);
728 return new GraphicsTestInstance(context, m_caseDef.ssboSize, m_caseDef.specConstants, m_caseDef.expectedValues, m_stage);
731 //! Declare specialization constants but use them with default values.
732 tcu::TestCaseGroup* createDefaultValueTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage)
734 de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "default_value", "use default constant value"));
736 const CaseDefinition defs[] =
740 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const bool sc0 = true;"),
741 SpecConstant(2u, "layout(constant_id = ${ID}) const bool sc1 = false;")),
746 " sb_out.r0 = sc0;\n"
747 " sb_out.r1 = sc1;\n",
748 makeVector(OffsetValue(4, 0, makeValueBool32(true)),
749 OffsetValue(4, 4, makeValueBool32(false))),
754 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = -3;"),
755 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 17;")),
760 " sb_out.r0 = sc0;\n"
761 " sb_out.r1 = sc1;\n",
762 makeVector(OffsetValue(4, 0, makeValueInt32(-3)),
763 OffsetValue(4, 4, makeValueInt32(17))),
768 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint sc0 = 42u;")),
772 " sb_out.r0 = sc0;\n",
773 makeVector(OffsetValue(4, 0, makeValueUint32(42u))),
778 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 7.5;")),
782 " sb_out.r0 = sc0;\n",
783 makeVector(OffsetValue(4, 0, makeValueFloat32(7.5f))),
788 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const double sc0 = 2.75LF;")),
792 " sb_out.r0 = sc0;\n",
793 makeVector(OffsetValue(8, 0, makeValueFloat64(2.75))),
794 FEATURE_SHADER_FLOAT_64,
798 for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
799 testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, defs[defNdx]));
801 return testGroup.release();
804 //! Declare specialization constants and specify their values through API.
805 tcu::TestCaseGroup* createBasicSpecializationTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage)
807 de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "basic", "specialize a constant"));
809 const CaseDefinition defs[] =
813 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const bool sc0 = true;", 4, makeValueBool32(true)),
814 SpecConstant(2u, "layout(constant_id = ${ID}) const bool sc1 = false;", 4, makeValueBool32(false)),
815 SpecConstant(3u, "layout(constant_id = ${ID}) const bool sc2 = true;", 4, makeValueBool32(false)),
816 SpecConstant(4u, "layout(constant_id = ${ID}) const bool sc3 = false;", 4, makeValueBool32(true))),
823 " sb_out.r0 = sc0;\n"
824 " sb_out.r1 = sc1;\n"
825 " sb_out.r2 = sc2;\n"
826 " sb_out.r3 = sc3;\n",
827 makeVector(OffsetValue(4, 0, makeValueBool32(true)),
828 OffsetValue(4, 4, makeValueBool32(false)),
829 OffsetValue(4, 8, makeValueBool32(false)),
830 OffsetValue(4, 12, makeValueBool32(true))),
835 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = -3;", 4, makeValueInt32(33)),
836 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 91;"),
837 SpecConstant(3u, "layout(constant_id = ${ID}) const int sc2 = 17;", 4, makeValueInt32(-15))),
843 " sb_out.r0 = sc0;\n"
844 " sb_out.r1 = sc1;\n"
845 " sb_out.r2 = sc2;\n",
846 makeVector(OffsetValue(4, 0, makeValueInt32(33)),
847 OffsetValue(4, 4, makeValueInt32(91)),
848 OffsetValue(4, 8, makeValueInt32(-15))),
853 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const uint sc0 = 42u;", 4, makeValueUint32(97u)),
854 SpecConstant(2u, "layout(constant_id = ${ID}) const uint sc1 = 7u;")),
859 " sb_out.r0 = sc0;\n"
860 " sb_out.r1 = sc1;\n",
861 makeVector(OffsetValue(4, 0, makeValueUint32(97u)),
862 OffsetValue(4, 4, makeValueUint32(7u))),
867 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 7.5;", 4, makeValueFloat32(15.75f)),
868 SpecConstant(2u, "layout(constant_id = ${ID}) const float sc1 = 1.125;")),
873 " sb_out.r0 = sc0;\n"
874 " sb_out.r1 = sc1;\n",
875 makeVector(OffsetValue(4, 0, makeValueFloat32(15.75f)),
876 OffsetValue(4, 4, makeValueFloat32(1.125f))),
881 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const double sc0 = 2.75LF;", 8, makeValueFloat64(22.5)),
882 SpecConstant(2u, "layout(constant_id = ${ID}) const double sc1 = 9.25LF;")),
887 " sb_out.r0 = sc0;\n"
888 " sb_out.r1 = sc1;\n",
889 makeVector(OffsetValue(8, 0, makeValueFloat64(22.5)),
890 OffsetValue(8, 8, makeValueFloat64(9.25))),
891 FEATURE_SHADER_FLOAT_64,
895 for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
896 testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, defs[defNdx]));
898 return testGroup.release();
901 //! Specify compute shader work group size through specialization constants.
902 tcu::TestCaseGroup* createWorkGroupSizeTests (tcu::TestContext& testCtx)
904 de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "local_size", "work group size specialization"));
906 const deUint32 ssboSize = 16;
907 const std::string ssboDecl =
908 " uvec3 workGroupSize;\n"
910 const std::string globalDecl = "shared uint count;\n";
911 const std::string mainCode =
914 " groupMemoryBarrier();\n"
917 " atomicAdd(count, 1u);\n"
919 " groupMemoryBarrier();\n"
922 " sb_out.workGroupSize = gl_WorkGroupSize;\n"
923 " sb_out.checksum = count;\n";
925 const CaseDefinition defs[] =
929 makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;", 4, makeValueUint32(7u))),
930 ssboSize, ssboDecl, globalDecl, mainCode,
931 makeVector(OffsetValue(4, 0, makeValueUint32(7u)),
932 OffsetValue(4, 4, makeValueUint32(1u)),
933 OffsetValue(4, 8, makeValueUint32(1u)),
934 OffsetValue(4, 12, makeValueUint32(7u))),
939 makeVector(SpecConstant(1u, "layout(local_size_y_id = ${ID}) in;", 4, makeValueUint32(5u))),
940 ssboSize, ssboDecl, globalDecl, mainCode,
941 makeVector(OffsetValue(4, 0, makeValueUint32(1u)),
942 OffsetValue(4, 4, makeValueUint32(5u)),
943 OffsetValue(4, 8, makeValueUint32(1u)),
944 OffsetValue(4, 12, makeValueUint32(5u))),
949 makeVector(SpecConstant(1u, "layout(local_size_z_id = ${ID}) in;", 4, makeValueUint32(3u))),
950 ssboSize, ssboDecl, globalDecl, mainCode,
951 makeVector(OffsetValue(4, 0, makeValueUint32(1u)),
952 OffsetValue(4, 4, makeValueUint32(1u)),
953 OffsetValue(4, 8, makeValueUint32(3u)),
954 OffsetValue(4, 12, makeValueUint32(3u))),
959 makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;", 4, makeValueUint32(6u)),
960 SpecConstant(2u, "layout(local_size_y_id = ${ID}) in;", 4, makeValueUint32(4u))),
961 ssboSize, ssboDecl, globalDecl, mainCode,
962 makeVector(OffsetValue(4, 0, makeValueUint32(6u)),
963 OffsetValue(4, 4, makeValueUint32(4u)),
964 OffsetValue(4, 8, makeValueUint32(1u)),
965 OffsetValue(4, 12, makeValueUint32(6u * 4u))),
970 makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;", 4, makeValueUint32(3u)),
971 SpecConstant(2u, "layout(local_size_z_id = ${ID}) in;", 4, makeValueUint32(9u))),
972 ssboSize, ssboDecl, globalDecl, mainCode,
973 makeVector(OffsetValue(4, 0, makeValueUint32(3u)),
974 OffsetValue(4, 4, makeValueUint32(1u)),
975 OffsetValue(4, 8, makeValueUint32(9u)),
976 OffsetValue(4, 12, makeValueUint32(3u * 9u))),
981 makeVector(SpecConstant(1u, "layout(local_size_y_id = ${ID}) in;", 4, makeValueUint32(2u)),
982 SpecConstant(2u, "layout(local_size_z_id = ${ID}) in;", 4, makeValueUint32(5u))),
983 ssboSize, ssboDecl, globalDecl, mainCode,
984 makeVector(OffsetValue(4, 0, makeValueUint32(1u)),
985 OffsetValue(4, 4, makeValueUint32(2u)),
986 OffsetValue(4, 8, makeValueUint32(5u)),
987 OffsetValue(4, 12, makeValueUint32(2u * 5u))),
992 makeVector(SpecConstant(1u, "layout(local_size_x_id = ${ID}) in;", 4, makeValueUint32(3u)),
993 SpecConstant(2u, "layout(local_size_y_id = ${ID}) in;", 4, makeValueUint32(5u)),
994 SpecConstant(3u, "layout(local_size_z_id = ${ID}) in;", 4, makeValueUint32(7u))),
995 ssboSize, ssboDecl, globalDecl, mainCode,
996 makeVector(OffsetValue(4, 0, makeValueUint32(3u)),
997 OffsetValue(4, 4, makeValueUint32(5u)),
998 OffsetValue(4, 8, makeValueUint32(7u)),
999 OffsetValue(4, 12, makeValueUint32(3u * 5u * 7u))),
1004 for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
1005 testGroup->addChild(new SpecConstantTest(testCtx, VK_SHADER_STAGE_COMPUTE_BIT, defs[defNdx]));
1007 return testGroup.release();
1010 //! Override a built-in variable with specialization constant value.
1011 tcu::TestCaseGroup* createBuiltInOverrideTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage)
1013 de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "builtin", "built-in override"));
1015 const CaseDefinition defs[] =
1019 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) gl_MaxImageUnits;")),
1023 " sb_out.ok = (gl_MaxImageUnits >= 8);\n", // implementation defined, 8 is the minimum
1024 makeVector(OffsetValue(4, 0, makeValueBool32(true))),
1029 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) gl_MaxImageUnits;", 4, makeValueInt32(12))),
1031 " int maxImageUnits;\n",
1033 " sb_out.maxImageUnits = gl_MaxImageUnits;\n",
1034 makeVector(OffsetValue(4, 0, makeValueInt32(12))),
1039 for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
1040 testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, defs[defNdx]));
1042 return testGroup.release();
1045 //! Specialization constants used in expressions.
1046 tcu::TestCaseGroup* createExpressionTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage)
1048 de::MovePtr<tcu::TestCaseGroup> testGroup (new tcu::TestCaseGroup(testCtx, "expression", "specialization constants usage in expressions"));
1050 const CaseDefinition defs[] =
1053 "spec_const_expression",
1054 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 2;"),
1055 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 3;", 4, makeValueInt32(5))),
1059 "const int expr0 = sc0 + 1;\n"
1060 "const int expr1 = sc0 + sc1;\n",
1062 " sb_out.result = expr0 + expr1;\n",
1063 makeVector(OffsetValue(4, 0, makeValueInt32(10))),
1068 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;"),
1069 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 2;", 4, makeValueInt32(3))),
1079 " for (int i = 0; i < sc0; ++i)\n"
1080 " a0[i] = sc0 - i;\n"
1081 " for (int i = 0; i < sc1; ++i)\n"
1082 " a1[i] = sc1 - i;\n"
1084 " sb_out.r0 = a0[0];\n"
1085 " for (int i = 0; i < sc1; ++i)\n"
1086 " sb_out.r1[i] = a1[i];\n",
1087 makeVector(OffsetValue(4, 0, makeValueInt32(1)),
1088 OffsetValue(4, 4, makeValueInt32(3)),
1089 OffsetValue(4, 8, makeValueInt32(2)),
1090 OffsetValue(4, 12, makeValueInt32(1))),
1094 "array_size_expression",
1095 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 3;"),
1096 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 5;", 4, makeValueInt32(7))),
1103 " int a0[sc0 + 3];\n"
1104 " int a1[sc0 + sc1];\n"
1106 " const int size0 = sc0 + 3;\n"
1107 " const int size1 = sc0 + sc1;\n"
1109 " for (int i = 0; i < size0; ++i)\n"
1111 " for (int i = 0; i < size1; ++i)\n"
1114 " sb_out.r0 = a0[size0 - 1];\n"
1115 " sb_out.r1 = a1[size1 - 1];\n",
1116 makeVector(OffsetValue(4, 0, makeValueInt32(-2)),
1117 OffsetValue(4, 4, makeValueInt32(-4))),
1121 "array_size_spec_const_expression",
1122 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 3;"),
1123 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 5;", 4, makeValueInt32(7))),
1130 " const int size0 = sc0 + 3;\n"
1131 " const int size1 = sc0 + sc1;\n"
1136 " for (int i = 0; i < size0; ++i)\n"
1138 " for (int i = 0; i < size1; ++i)\n"
1141 " sb_out.r0 = a0[size0 - 1];\n"
1142 " sb_out.r1 = a1[size1 - 1];\n",
1143 makeVector(OffsetValue(4, 0, makeValueInt32(-2)),
1144 OffsetValue(4, 4, makeValueInt32(-4))),
1148 "array_size_length",
1149 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;"),
1150 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 2;", 4, makeValueInt32(4))),
1160 " sb_out.r0 = a0.length();\n"
1161 " sb_out.r1 = a1.length();\n",
1162 makeVector(OffsetValue(4, 0, makeValueInt32(1)),
1163 OffsetValue(4, 4, makeValueInt32(4))),
1167 "array_size_pass_to_function",
1168 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 3;"),
1169 SpecConstant(2u, "layout(constant_id = ${ID}) const int sc1 = 1;", 4, makeValueInt32(3))),
1173 "int sumArrays (int a0[sc0], int a1[sc1])\n"
1176 " for (int i = 0; (i < sc0) && (i < sc1); ++i)\n"
1177 " sum += a0[i] + a1[i];\n"
1184 " for (int i = 0; i < sc0; ++i)\n"
1186 " for (int i = 0; i < sc1; ++i)\n"
1189 " sb_out.result = sumArrays(a0, a1);\n",
1190 makeVector(OffsetValue(4, 0, makeValueInt32(15))),
1195 for (int defNdx = 0; defNdx < DE_LENGTH_OF_ARRAY(defs); ++defNdx)
1196 testGroup->addChild(new SpecConstantTest(testCtx, shaderStage, defs[defNdx]));
1198 return testGroup.release();
1201 //! Helper functions internal to make*CompositeCaseDefinition functions.
1202 namespace composite_case_internal
1205 //! Generate a string like this: "1, 2, sc0, 4" or "true, true, sc0"
1206 //! castToType = true is useful when type requires more initializer values than we are providing, e.g.:
1207 //! vec2(1), vec2(sc0), vec(3)
1208 std::string generateInitializerListWithSpecConstant (const glu::DataType type,
1209 const bool castToType,
1212 const std::string& specConstName,
1213 const int specConstNdx)
1215 std::ostringstream str;
1217 for (int i = idxBegin; i < idxEnd; ++i)
1219 const std::string iVal = (i == specConstNdx ? specConstName : glu::getDataTypeScalarType(type) == glu::TYPE_BOOL ? "true" : de::toString(i + 1));
1220 str << (i != idxBegin ? ", " : "") << (castToType ? de::toString(glu::getDataTypeName(type)) + "(" + iVal + ")" : iVal);
1226 std::string generateArrayConstructorString (const glu::DataType elemType,
1229 const std::string& specConstName,
1230 const int specConstNdx)
1232 const bool isArrayOfArray = (size2 > 0);
1233 const bool doCast = (!isDataTypeScalar(elemType));
1235 std::ostringstream arrayCtorExpr;
1239 const std::string padding (36, ' ');
1243 for (int iterNdx = 0; iterNdx < size1; ++iterNdx)
1245 // Open sub-array ctor
1246 arrayCtorExpr << (iterNdx != 0 ? ",\n" + padding : "") << glu::getDataTypeName(elemType) << "[" << size2 << "](";
1248 // Sub-array constructor elements
1249 arrayCtorExpr << generateInitializerListWithSpecConstant(elemType, doCast, idxBegin, idxEnd, specConstName, specConstNdx);
1251 // Close sub-array ctor, move to next range
1252 arrayCtorExpr << ")";
1260 // Array constructor elements
1261 arrayCtorExpr << generateInitializerListWithSpecConstant(elemType, doCast, 0, size1, specConstName, specConstNdx);
1264 return arrayCtorExpr.str();
1267 inline GenericValue makeValue (const glu::DataType type, const int specValue)
1269 if (type == glu::TYPE_DOUBLE)
1270 return makeValueFloat64(static_cast<double>(specValue));
1271 else if (type == glu::TYPE_FLOAT)
1272 return makeValueFloat32(static_cast<float>(specValue));
1274 return makeValueInt32(specValue);
1277 deUint32 getDataTypeScalarSizeBytes (const glu::DataType dataType)
1279 switch (getDataTypeScalarType(dataType))
1281 case glu::TYPE_FLOAT:
1283 case glu::TYPE_UINT:
1284 case glu::TYPE_BOOL:
1287 case glu::TYPE_DOUBLE:
1296 //! This applies to matrices/vectors/array cases. dataType must be a basic type.
1297 std::vector<OffsetValue> computeExpectedValues (const int specValue, const glu::DataType dataType, const int numCombinations)
1299 DE_ASSERT(glu::isDataTypeScalar(dataType));
1301 std::vector<OffsetValue> expectedValues;
1303 for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1306 for (int i = 0; i < numCombinations; ++i)
1307 sum += (i == combNdx ? specValue : dataType == glu::TYPE_BOOL ? 1 : (i + 1));
1309 const int dataSize = getDataTypeScalarSizeBytes(dataType);
1310 expectedValues.push_back(OffsetValue(dataSize, dataSize * combNdx, makeValue(dataType, sum)));
1313 return expectedValues;
1316 inline std::string getFirstDataElementSubscriptString (const glu::DataType type)
1318 // Grab the first element of a matrix/vector, if dealing with non-basic types.
1319 return (isDataTypeMatrix(type) ? "[0][0]" : isDataTypeVector(type) ? "[0]" : "");
1322 //! This code will go into the main function.
1323 std::string generateShaderChecksumComputationCode (const glu::DataType elemType,
1324 const std::string& varName,
1325 const std::string& accumType,
1328 const int numCombinations)
1330 std::ostringstream mainCode;
1332 // Generate main code to calculate checksums for each array
1333 for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1334 mainCode << " "<< accumType << " sum_" << varName << combNdx << " = " << accumType << "(0);\n";
1339 << " for (int i = 0; i < " << size1 << "; ++i)\n"
1340 << " for (int j = 0; j < " << size2 << "; ++j)\n"
1343 for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1344 mainCode << " sum_" << varName << combNdx << " += " << accumType << "("
1345 << varName << combNdx << "[i][j]" << getFirstDataElementSubscriptString(elemType) << ");\n";
1350 << " for (int i = 0; i < " << size1 << "; ++i)\n"
1353 for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1354 mainCode << " sum_" << varName << combNdx << " += " << accumType << "("
1355 << varName << combNdx << "[i]" << getFirstDataElementSubscriptString(elemType) << ");\n";
1361 for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1362 mainCode << " sb_out.result[" << combNdx << "] = sum_" << varName << combNdx << ";\n";
1364 return mainCode.str();
1367 SpecConstant makeSpecConstant (const std::string specConstName, const deUint32 specConstId, const glu::DataType type, const int specValue)
1369 DE_ASSERT(glu::isDataTypeScalar(type));
1371 const std::string typeName(glu::getDataTypeName(type));
1373 return SpecConstant(
1375 "layout(constant_id = ${ID}) const " + typeName + " " + specConstName + " = " + typeName + "(1);",
1376 getDataTypeScalarSizeBytes(type), makeValue(type, specValue));
1379 } // composite_case_internal ns
1381 //! Generate a CaseDefinition for a composite test using a matrix or vector (a 1-column matrix)
1382 CaseDefinition makeMatrixVectorCompositeCaseDefinition (const glu::DataType type)
1384 using namespace composite_case_internal;
1386 DE_ASSERT(!glu::isDataTypeScalar(type));
1388 const std::string varName = (glu::isDataTypeMatrix(type) ? "m" : "v");
1389 const int numCombinations = getDataTypeScalarSize(type);
1390 const glu::DataType scalarType = glu::getDataTypeScalarType(type);
1391 const std::string typeName = glu::getDataTypeName(type);
1392 const bool isConst = (scalarType != glu::TYPE_FLOAT) && (scalarType != glu::TYPE_DOUBLE);
1394 std::ostringstream globalCode;
1396 // Build N matrices/vectors with specialization constant inserted at various locations in the constructor.
1397 for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1398 globalCode << ( isConst ? "const " : "" ) << typeName << " " << varName << combNdx << " = " << typeName << "("
1399 << generateInitializerListWithSpecConstant(type, false, 0, numCombinations, "sc0", combNdx) << ");\n";
1402 const bool isBoolElement = (scalarType == glu::TYPE_BOOL);
1403 const int specValue = (isBoolElement ? 0 : 42);
1404 const std::string accumType = glu::getDataTypeName(isBoolElement ? glu::TYPE_INT : scalarType);
1406 const int size1 = glu::isDataTypeMatrix(type) ? glu::getDataTypeMatrixNumColumns(type) : glu::getDataTypeNumComponents(type);
1407 const int size2 = glu::isDataTypeMatrix(type) ? glu::getDataTypeMatrixNumRows(type) : 0;
1409 const CaseDefinition def =
1412 makeVector(makeSpecConstant("sc0", 1u, scalarType, specValue)),
1413 static_cast<VkDeviceSize>(getDataTypeScalarSizeBytes(type) * numCombinations),
1414 " " + accumType + " result[" + de::toString(numCombinations) + "];\n",
1416 generateShaderChecksumComputationCode(scalarType, varName, accumType, size1, size2, numCombinations),
1417 computeExpectedValues(specValue, scalarType, numCombinations),
1418 (scalarType == glu::TYPE_DOUBLE ? (FeatureFlags)FEATURE_SHADER_FLOAT_64 : (FeatureFlags)0),
1423 //! Generate a CaseDefinition for a composite test using an array, or an array of array.
1424 //! If (size1, size2) = (N, 0) -> type array[N]
1425 //! = (N, M) -> type array[N][M]
1426 CaseDefinition makeArrayCompositeCaseDefinition (const glu::DataType elemType, const int size1, const int size2 = 0)
1428 using namespace composite_case_internal;
1430 DE_ASSERT(size1 > 0);
1432 const bool isArrayOfArray = (size2 > 0);
1433 const std::string varName = "a";
1434 const std::string arraySizeDecl = "[" + de::toString(size1) + "]" + (isArrayOfArray ? "[" + de::toString(size2) + "]" : "");
1435 const int numCombinations = (isArrayOfArray ? size1 * size2 : size1);
1436 const std::string elemTypeName (glu::getDataTypeName(elemType));
1438 std::ostringstream globalCode;
1440 // Create several arrays with specialization constant inserted in different positions.
1441 for (int combNdx = 0; combNdx < numCombinations; ++combNdx)
1442 globalCode << elemTypeName << " " << varName << combNdx << arraySizeDecl << " = "
1443 << elemTypeName << arraySizeDecl << "(" << generateArrayConstructorString(elemType, size1, size2, "sc0", combNdx) << ");\n";
1446 const glu::DataType scalarType = glu::getDataTypeScalarType(elemType);
1447 const bool isBoolData = (scalarType == glu::TYPE_BOOL);
1448 const int specValue = (isBoolData ? 0 : 19);
1449 const std::string caseName = (isArrayOfArray ? "array_" : "") + elemTypeName;
1450 const std::string accumType = (glu::getDataTypeName(isBoolData ? glu::TYPE_INT : scalarType));
1452 const CaseDefinition def =
1455 makeVector(makeSpecConstant("sc0", 1u, scalarType, specValue)),
1456 static_cast<VkDeviceSize>(getDataTypeScalarSizeBytes(elemType) * numCombinations),
1457 " " + accumType + " result[" + de::toString(numCombinations) + "];\n",
1459 generateShaderChecksumComputationCode(elemType, varName, accumType, size1, size2, numCombinations),
1460 computeExpectedValues(specValue, scalarType, numCombinations),
1461 (scalarType == glu::TYPE_DOUBLE ? (FeatureFlags)FEATURE_SHADER_FLOAT_64 : (FeatureFlags)0),
1466 //! A basic struct case, where one member is a specialization constant, or a specialization constant composite
1467 //! (a matrix/vector with a spec. const. element).
1468 CaseDefinition makeStructCompositeCaseDefinition (const glu::DataType memberType)
1470 using namespace composite_case_internal;
1472 std::ostringstream globalCode;
1474 globalCode << "struct Data {\n"
1478 << " " << glu::getDataTypeName(memberType) << " sc;\n"
1482 << "Data s0 = Data(3, 2.0, true, " << glu::getDataTypeName(memberType) << "(sc0), 8u);\n";
1485 const glu::DataType scalarType = glu::getDataTypeScalarType(memberType);
1486 const bool isBoolData = (scalarType == glu::TYPE_BOOL);
1487 const int specValue = (isBoolData ? 0 : 23);
1488 const int checksum = (3 + 2 + 1 + specValue + 8); // matches the shader code
1489 const glu::DataType accumType = (isBoolData ? glu::TYPE_INT : scalarType);
1490 const std::string accumTypeStr = glu::getDataTypeName(accumType);
1492 std::ostringstream mainCode;
1494 mainCode << " " << accumTypeStr << " sum_s0 = " << accumTypeStr << "(0);\n"
1496 << " sum_s0 += " << accumTypeStr << "(s0.i);\n"
1497 << " sum_s0 += " << accumTypeStr << "(s0.f);\n"
1498 << " sum_s0 += " << accumTypeStr << "(s0.b);\n"
1499 << " sum_s0 += " << accumTypeStr << "(s0.sc" << getFirstDataElementSubscriptString(memberType) << ");\n"
1500 << " sum_s0 += " << accumTypeStr << "(s0.ui);\n"
1502 << " sb_out.result = sum_s0;\n";
1505 const std::string caseName = glu::getDataTypeName(memberType);
1507 const CaseDefinition def =
1510 makeVector(makeSpecConstant("sc0", 1u, scalarType, specValue)),
1511 getDataTypeScalarSizeBytes(accumType),
1512 " " + accumTypeStr + " result;\n",
1515 makeVector(OffsetValue(getDataTypeScalarSizeBytes(memberType), 0, makeValue(scalarType, checksum))),
1516 (scalarType == glu::TYPE_DOUBLE ? (FeatureFlags)FEATURE_SHADER_FLOAT_64 : (FeatureFlags)0),
1521 //! Specialization constants used in composites.
1522 tcu::TestCaseGroup* createCompositeTests (tcu::TestContext& testCtx, const VkShaderStageFlagBits shaderStage)
1524 de::MovePtr<tcu::TestCaseGroup> compositeTests (new tcu::TestCaseGroup(testCtx, "composite", "specialization constants usage in composite types"));
1528 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "vector", ""));
1530 const glu::DataType types[] =
1532 glu::TYPE_FLOAT_VEC2,
1533 glu::TYPE_FLOAT_VEC3,
1534 glu::TYPE_FLOAT_VEC4,
1536 glu::TYPE_DOUBLE_VEC2,
1537 glu::TYPE_DOUBLE_VEC3,
1538 glu::TYPE_DOUBLE_VEC4,
1540 glu::TYPE_BOOL_VEC2,
1541 glu::TYPE_BOOL_VEC3,
1542 glu::TYPE_BOOL_VEC4,
1548 glu::TYPE_UINT_VEC2,
1549 glu::TYPE_UINT_VEC3,
1550 glu::TYPE_UINT_VEC4,
1552 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(types); ++typeNdx)
1553 group->addChild(new SpecConstantTest(testCtx, shaderStage, makeMatrixVectorCompositeCaseDefinition(types[typeNdx])));
1555 compositeTests->addChild(group.release());
1560 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "matrix", ""));
1562 const glu::DataType types[] =
1564 glu::TYPE_FLOAT_MAT2,
1565 glu::TYPE_FLOAT_MAT2X3,
1566 glu::TYPE_FLOAT_MAT2X4,
1567 glu::TYPE_FLOAT_MAT3X2,
1568 glu::TYPE_FLOAT_MAT3,
1569 glu::TYPE_FLOAT_MAT3X4,
1570 glu::TYPE_FLOAT_MAT4X2,
1571 glu::TYPE_FLOAT_MAT4X3,
1572 glu::TYPE_FLOAT_MAT4,
1574 glu::TYPE_DOUBLE_MAT2,
1575 glu::TYPE_DOUBLE_MAT2X3,
1576 glu::TYPE_DOUBLE_MAT2X4,
1577 glu::TYPE_DOUBLE_MAT3X2,
1578 glu::TYPE_DOUBLE_MAT3,
1579 glu::TYPE_DOUBLE_MAT3X4,
1580 glu::TYPE_DOUBLE_MAT4X2,
1581 glu::TYPE_DOUBLE_MAT4X3,
1582 glu::TYPE_DOUBLE_MAT4,
1584 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(types); ++typeNdx)
1585 group->addChild(new SpecConstantTest(testCtx, shaderStage, makeMatrixVectorCompositeCaseDefinition(types[typeNdx])));
1587 compositeTests->addChild(group.release());
1590 const glu::DataType allTypes[] =
1593 glu::TYPE_FLOAT_VEC2,
1594 glu::TYPE_FLOAT_VEC3,
1595 glu::TYPE_FLOAT_VEC4,
1596 glu::TYPE_FLOAT_MAT2,
1597 glu::TYPE_FLOAT_MAT2X3,
1598 glu::TYPE_FLOAT_MAT2X4,
1599 glu::TYPE_FLOAT_MAT3X2,
1600 glu::TYPE_FLOAT_MAT3,
1601 glu::TYPE_FLOAT_MAT3X4,
1602 glu::TYPE_FLOAT_MAT4X2,
1603 glu::TYPE_FLOAT_MAT4X3,
1604 glu::TYPE_FLOAT_MAT4,
1607 glu::TYPE_DOUBLE_VEC2,
1608 glu::TYPE_DOUBLE_VEC3,
1609 glu::TYPE_DOUBLE_VEC4,
1610 glu::TYPE_DOUBLE_MAT2,
1611 glu::TYPE_DOUBLE_MAT2X3,
1612 glu::TYPE_DOUBLE_MAT2X4,
1613 glu::TYPE_DOUBLE_MAT3X2,
1614 glu::TYPE_DOUBLE_MAT3,
1615 glu::TYPE_DOUBLE_MAT3X4,
1616 glu::TYPE_DOUBLE_MAT4X2,
1617 glu::TYPE_DOUBLE_MAT4X3,
1618 glu::TYPE_DOUBLE_MAT4,
1626 glu::TYPE_UINT_VEC2,
1627 glu::TYPE_UINT_VEC3,
1628 glu::TYPE_UINT_VEC4,
1631 glu::TYPE_BOOL_VEC2,
1632 glu::TYPE_BOOL_VEC3,
1633 glu::TYPE_BOOL_VEC4,
1638 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "array", ""));
1641 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(allTypes); ++typeNdx)
1642 group->addChild(new SpecConstantTest(testCtx, shaderStage, makeArrayCompositeCaseDefinition(allTypes[typeNdx], 3)));
1644 // Array of array of T
1645 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(allTypes); ++typeNdx)
1646 group->addChild(new SpecConstantTest(testCtx, shaderStage, makeArrayCompositeCaseDefinition(allTypes[typeNdx], 3, 2)));
1648 // Special case - array of struct
1650 const int checksum = (3 + 2 + 1) + (1 + 5 + 1) + (1 + 2 + 0);
1651 const CaseDefinition def =
1654 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;", 4, makeValueInt32 (3)),
1655 SpecConstant(2u, "layout(constant_id = ${ID}) const float sc1 = 1.0;", 4, makeValueFloat32(5.0f)),
1656 SpecConstant(3u, "layout(constant_id = ${ID}) const bool sc2 = true;", 4, makeValueBool32 (false))),
1666 "Data a0[3] = Data[3](Data(sc0, 2.0, true), Data(1, sc1, true), Data(1, 2.0, sc2));\n",
1668 " int sum_a0 = 0;\n"
1670 " for (int i = 0; i < 3; ++i)\n"
1671 " sum_a0 += int(a0[i].x) + int(a0[i].y) + int(a0[i].z);\n"
1673 " sb_out.result = sum_a0;\n",
1675 makeVector(OffsetValue(4, 0, makeValueInt32(checksum))),
1679 group->addChild(new SpecConstantTest(testCtx, shaderStage, def));
1682 compositeTests->addChild(group.release());
1687 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "struct", ""));
1689 // Struct with one member being a specialization constant (or spec. const. composite) of a given type
1690 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(allTypes); ++typeNdx)
1691 group->addChild(new SpecConstantTest(testCtx, shaderStage, makeStructCompositeCaseDefinition(allTypes[typeNdx])));
1693 // Special case - struct with array
1695 const int checksum = (1 + 2 + 31 + 4 + 0);
1696 const CaseDefinition def =
1699 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const float sc0 = 1.0;", 4, makeValueFloat32(31.0f))),
1709 "Data s0 = Data(1, vec3[3](vec3(2.0), vec3(sc0), vec3(4.0)), false);\n",
1711 " float sum_s0 = 0;\n"
1713 " sum_s0 += float(s0.i);\n"
1714 " sum_s0 += float(s0.sc[0][0]);\n"
1715 " sum_s0 += float(s0.sc[1][0]);\n"
1716 " sum_s0 += float(s0.sc[2][0]);\n"
1717 " sum_s0 += float(s0.b);\n"
1719 " sb_out.result = sum_s0;\n",
1721 makeVector(OffsetValue(4, 0, makeValueFloat32(static_cast<float>(checksum)))),
1725 group->addChild(new SpecConstantTest(testCtx, shaderStage, def));
1728 // Special case - struct of struct
1730 const int checksum = (1 + 2 + 11 + 4 + 1);
1731 const CaseDefinition def =
1734 makeVector(SpecConstant(1u, "layout(constant_id = ${ID}) const int sc0 = 1;", 4, makeValueInt32(11))),
1750 "Data s0 = Data(1u, Nested(vec2(2.0), sc0, 4.0), true);\n",
1752 " int sum_s0 = 0;\n"
1754 " sum_s0 += int(s0.ui);\n"
1755 " sum_s0 += int(s0.s.v[0]);\n"
1756 " sum_s0 += int(s0.s.sc);\n"
1757 " sum_s0 += int(s0.s.f);\n"
1758 " sum_s0 += int(s0.b);\n"
1760 " sb_out.result = sum_s0;\n",
1762 makeVector(OffsetValue(4, 0, makeValueInt32(checksum))),
1766 group->addChild(new SpecConstantTest(testCtx, shaderStage, def));
1769 compositeTests->addChild(group.release());
1772 return compositeTests.release();
1777 tcu::TestCaseGroup* createSpecConstantTests (tcu::TestContext& testCtx)
1779 de::MovePtr<tcu::TestCaseGroup> allTests (new tcu::TestCaseGroup(testCtx, "spec_constant", "Specialization constants tests"));
1780 de::MovePtr<tcu::TestCaseGroup> graphicsGroup (new tcu::TestCaseGroup(testCtx, "graphics", ""));
1784 tcu::TestCaseGroup* parentGroup;
1786 VkShaderStageFlagBits stage;
1789 const StageDef stages[] =
1791 { graphicsGroup.get(), "vertex", VK_SHADER_STAGE_VERTEX_BIT },
1792 { graphicsGroup.get(), "fragment", VK_SHADER_STAGE_FRAGMENT_BIT },
1793 { graphicsGroup.get(), "tess_control", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT },
1794 { graphicsGroup.get(), "tess_eval", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT },
1795 { graphicsGroup.get(), "geometry", VK_SHADER_STAGE_GEOMETRY_BIT },
1796 { allTests.get(), "compute", VK_SHADER_STAGE_COMPUTE_BIT },
1799 allTests->addChild(graphicsGroup.release());
1801 for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(stages); ++stageNdx)
1803 const StageDef& stage = stages[stageNdx];
1804 de::MovePtr<tcu::TestCaseGroup> stageGroup (new tcu::TestCaseGroup(testCtx, stage.name, ""));
1806 stageGroup->addChild(createDefaultValueTests (testCtx, stage.stage));
1807 stageGroup->addChild(createBasicSpecializationTests(testCtx, stage.stage));
1808 stageGroup->addChild(createBuiltInOverrideTests (testCtx, stage.stage));
1809 stageGroup->addChild(createExpressionTests (testCtx, stage.stage));
1810 stageGroup->addChild(createCompositeTests (testCtx, stage.stage));
1812 if (stage.stage == VK_SHADER_STAGE_COMPUTE_BIT)
1813 stageGroup->addChild(createWorkGroupSizeTests(testCtx));
1815 stage.parentGroup->addChild(stageGroup.release());
1818 return allTests.release();