1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 Google 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 Graphics pipeline for SPIR-V assembly tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktSpvAsmGraphicsShaderTestUtil.hpp"
25 
26 #include "tcuFloat.hpp"
27 #include "tcuStringTemplate.hpp"
28 #include "tcuTextureUtil.hpp"
29 
30 #include "vkDefs.hpp"
31 #include "vkMemUtil.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkQueryUtil.hpp"
34 #include "vkRefUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkImageUtil.hpp"
37 #include "vkCmdUtil.hpp"
38 
39 #include "deRandom.hpp"
40 
41 namespace vkt
42 {
43 namespace SpirVAssembly
44 {
45 
46 using namespace vk;
47 using de::UniquePtr;
48 using std::map;
49 using std::string;
50 using std::vector;
51 using tcu::Float16;
52 using tcu::Float32;
53 using tcu::Float64;
54 using tcu::IVec3;
55 using tcu::IVec4;
56 using tcu::RGBA;
57 using tcu::StringTemplate;
58 using tcu::TestLog;
59 using tcu::TestStatus;
60 using tcu::Vec4;
61 
getElementNumBytes(void) const62 uint32_t IFDataType::getElementNumBytes(void) const
63 {
64     if (elementType < NUMBERTYPE_END32)
65         return 4;
66 
67     if (elementType < NUMBERTYPE_END16)
68         return 2;
69 
70     return 8;
71 }
72 
getVkFormat(void) const73 VkFormat IFDataType::getVkFormat(void) const
74 {
75     if (numElements == 1)
76     {
77         switch (elementType)
78         {
79         case NUMBERTYPE_FLOAT64:
80             return VK_FORMAT_R64_SFLOAT;
81         case NUMBERTYPE_FLOAT32:
82             return VK_FORMAT_R32_SFLOAT;
83         case NUMBERTYPE_INT32:
84             return VK_FORMAT_R32_SINT;
85         case NUMBERTYPE_UINT32:
86             return VK_FORMAT_R32_UINT;
87         case NUMBERTYPE_FLOAT16:
88             return VK_FORMAT_R16_SFLOAT;
89         case NUMBERTYPE_INT16:
90             return VK_FORMAT_R16_SINT;
91         case NUMBERTYPE_UINT16:
92             return VK_FORMAT_R16_UINT;
93         default:
94             break;
95         }
96     }
97     else if (numElements == 2)
98     {
99         switch (elementType)
100         {
101         case NUMBERTYPE_FLOAT64:
102             return VK_FORMAT_R64G64_SFLOAT;
103         case NUMBERTYPE_FLOAT32:
104             return VK_FORMAT_R32G32_SFLOAT;
105         case NUMBERTYPE_INT32:
106             return VK_FORMAT_R32G32_SINT;
107         case NUMBERTYPE_UINT32:
108             return VK_FORMAT_R32G32_UINT;
109         case NUMBERTYPE_FLOAT16:
110             return VK_FORMAT_R16G16_SFLOAT;
111         case NUMBERTYPE_INT16:
112             return VK_FORMAT_R16G16_SINT;
113         case NUMBERTYPE_UINT16:
114             return VK_FORMAT_R16G16_UINT;
115         default:
116             break;
117         }
118     }
119     else if (numElements == 3)
120     {
121         switch (elementType)
122         {
123         case NUMBERTYPE_FLOAT64:
124             return VK_FORMAT_R64G64B64_SFLOAT;
125         case NUMBERTYPE_FLOAT32:
126             return VK_FORMAT_R32G32B32_SFLOAT;
127         case NUMBERTYPE_INT32:
128             return VK_FORMAT_R32G32B32_SINT;
129         case NUMBERTYPE_UINT32:
130             return VK_FORMAT_R32G32B32_UINT;
131         case NUMBERTYPE_FLOAT16:
132             return VK_FORMAT_R16G16B16_SFLOAT;
133         case NUMBERTYPE_INT16:
134             return VK_FORMAT_R16G16B16_SINT;
135         case NUMBERTYPE_UINT16:
136             return VK_FORMAT_R16G16B16_UINT;
137         default:
138             break;
139         }
140     }
141     else if (numElements == 4)
142     {
143         switch (elementType)
144         {
145         case NUMBERTYPE_FLOAT64:
146             return VK_FORMAT_R64G64B64A64_SFLOAT;
147         case NUMBERTYPE_FLOAT32:
148             return VK_FORMAT_R32G32B32A32_SFLOAT;
149         case NUMBERTYPE_INT32:
150             return VK_FORMAT_R32G32B32A32_SINT;
151         case NUMBERTYPE_UINT32:
152             return VK_FORMAT_R32G32B32A32_UINT;
153         case NUMBERTYPE_FLOAT16:
154             return VK_FORMAT_R16G16B16A16_SFLOAT;
155         case NUMBERTYPE_INT16:
156             return VK_FORMAT_R16G16B16A16_SINT;
157         case NUMBERTYPE_UINT16:
158             return VK_FORMAT_R16G16B16A16_UINT;
159         default:
160             break;
161         }
162     }
163 
164     DE_ASSERT(false);
165     return VK_FORMAT_UNDEFINED;
166 }
167 
getTextureFormat(void) const168 tcu::TextureFormat IFDataType::getTextureFormat(void) const
169 {
170     tcu::TextureFormat::ChannelType ct  = tcu::TextureFormat::CHANNELTYPE_LAST;
171     tcu::TextureFormat::ChannelOrder co = tcu::TextureFormat::CHANNELORDER_LAST;
172 
173     switch (elementType)
174     {
175     case NUMBERTYPE_FLOAT64:
176         ct = tcu::TextureFormat::FLOAT64;
177         break;
178     case NUMBERTYPE_FLOAT32:
179         ct = tcu::TextureFormat::FLOAT;
180         break;
181     case NUMBERTYPE_INT32:
182         ct = tcu::TextureFormat::SIGNED_INT32;
183         break;
184     case NUMBERTYPE_UINT32:
185         ct = tcu::TextureFormat::UNSIGNED_INT32;
186         break;
187     case NUMBERTYPE_FLOAT16:
188         ct = tcu::TextureFormat::HALF_FLOAT;
189         break;
190     case NUMBERTYPE_INT16:
191         ct = tcu::TextureFormat::SIGNED_INT16;
192         break;
193     case NUMBERTYPE_UINT16:
194         ct = tcu::TextureFormat::UNSIGNED_INT16;
195         break;
196     default:
197         DE_ASSERT(false);
198     }
199 
200     switch (numElements)
201     {
202     case 1:
203         co = tcu::TextureFormat::R;
204         break;
205     case 2:
206         co = tcu::TextureFormat::RG;
207         break;
208     case 3:
209         co = tcu::TextureFormat::RGB;
210         break;
211     case 4:
212         co = tcu::TextureFormat::RGBA;
213         break;
214     default:
215         DE_ASSERT(false);
216     }
217 
218     return tcu::TextureFormat(co, ct);
219 }
220 
str(void) const221 string IFDataType::str(void) const
222 {
223     string ret;
224 
225     switch (elementType)
226     {
227     case NUMBERTYPE_FLOAT64:
228         ret = "f64";
229         break;
230     case NUMBERTYPE_FLOAT32:
231         ret = "f32";
232         break;
233     case NUMBERTYPE_INT32:
234         ret = "i32";
235         break;
236     case NUMBERTYPE_UINT32:
237         ret = "u32";
238         break;
239     case NUMBERTYPE_FLOAT16:
240         ret = "f16";
241         break;
242     case NUMBERTYPE_INT16:
243         ret = "i16";
244         break;
245     case NUMBERTYPE_UINT16:
246         ret = "u16";
247         break;
248     default:
249         DE_ASSERT(false);
250     }
251 
252     if (numElements == 1)
253         return ret;
254 
255     return string("v") + numberToString(numElements) + ret;
256 }
257 
getMatchingBufferUsageFlagBit(VkDescriptorType dType)258 VkBufferUsageFlagBits getMatchingBufferUsageFlagBit(VkDescriptorType dType)
259 {
260     switch (dType)
261     {
262     case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
263         return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
264     case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
265         return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
266     case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
267         return VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
268     case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
269         return VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
270     case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
271         return VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
272     default:
273         DE_ASSERT(0 && "not implemented");
274     }
275     return (VkBufferUsageFlagBits)0;
276 }
277 
getMatchingImageUsageFlags(VkDescriptorType dType)278 VkImageUsageFlags getMatchingImageUsageFlags(VkDescriptorType dType)
279 {
280     switch (dType)
281     {
282     case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
283         return VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
284     case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
285         return VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
286     case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
287         return VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
288     default:
289         DE_FATAL("Not implemented");
290     }
291     return (VkImageUsageFlags)0;
292 }
293 
requireFormatUsageSupport(const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkFormat format,VkImageTiling imageTiling,VkImageUsageFlags requiredUsageFlags)294 static void requireFormatUsageSupport(const InstanceInterface &vki, VkPhysicalDevice physicalDevice, VkFormat format,
295                                       VkImageTiling imageTiling, VkImageUsageFlags requiredUsageFlags)
296 {
297     VkFormatProperties properties;
298     VkFormatFeatureFlags tilingFeatures = 0;
299 
300     vki.getPhysicalDeviceFormatProperties(physicalDevice, format, &properties);
301 
302     switch (imageTiling)
303     {
304     case VK_IMAGE_TILING_LINEAR:
305         tilingFeatures = properties.linearTilingFeatures;
306         break;
307 
308     case VK_IMAGE_TILING_OPTIMAL:
309         tilingFeatures = properties.optimalTilingFeatures;
310         break;
311 
312     default:
313         DE_ASSERT(false);
314         break;
315     }
316 
317     if ((requiredUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0)
318     {
319         if ((tilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0)
320             TCU_THROW(NotSupportedError, "Image format cannot be used as color attachment");
321         requiredUsageFlags ^= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
322     }
323 
324     if ((requiredUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) != 0)
325     {
326         if ((tilingFeatures & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT) == 0)
327             TCU_THROW(NotSupportedError, "Image format cannot be used as transfer source");
328         requiredUsageFlags ^= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
329     }
330 
331     DE_ASSERT(!requiredUsageFlags && "checking other image usage bits not supported yet");
332 }
333 
InstanceContext(const RGBA (& inputs)[4],const RGBA (& outputs)[4],const map<string,string> & testCodeFragments_,const StageToSpecConstantMap & specConstants_,const PushConstants & pushConsants_,const GraphicsResources & resources_,const GraphicsInterfaces & interfaces_,const vector<string> & extensions_,VulkanFeatures vulkanFeatures_,VkShaderStageFlags customizedStages_)334 InstanceContext::InstanceContext(const RGBA (&inputs)[4], const RGBA (&outputs)[4],
335                                  const map<string, string> &testCodeFragments_,
336                                  const StageToSpecConstantMap &specConstants_, const PushConstants &pushConsants_,
337                                  const GraphicsResources &resources_, const GraphicsInterfaces &interfaces_,
338                                  const vector<string> &extensions_, VulkanFeatures vulkanFeatures_,
339                                  VkShaderStageFlags customizedStages_)
340     : testCodeFragments(testCodeFragments_)
341     , specConstants(specConstants_)
342     , hasTessellation(false)
343     , requiredStages(static_cast<VkShaderStageFlagBits>(0))
344     , requiredDeviceExtensions(extensions_)
345     , requestedFeatures(vulkanFeatures_)
346     , pushConstants(pushConsants_)
347     , customizedStages(customizedStages_)
348     , resources(resources_)
349     , interfaces(interfaces_)
350     , failResult(QP_TEST_RESULT_FAIL)
351     , failMessageTemplate("${reason}")
352     , renderFullSquare(false)
353     , splitRenderArea(false)
354 {
355     inputColors[0] = inputs[0];
356     inputColors[1] = inputs[1];
357     inputColors[2] = inputs[2];
358     inputColors[3] = inputs[3];
359 
360     outputColors[0] = outputs[0];
361     outputColors[1] = outputs[1];
362     outputColors[2] = outputs[2];
363     outputColors[3] = outputs[3];
364 }
365 
InstanceContext(const InstanceContext & other)366 InstanceContext::InstanceContext(const InstanceContext &other)
367     : moduleMap(other.moduleMap)
368     , testCodeFragments(other.testCodeFragments)
369     , specConstants(other.specConstants)
370     , hasTessellation(other.hasTessellation)
371     , requiredStages(other.requiredStages)
372     , requiredDeviceExtensions(other.requiredDeviceExtensions)
373     , requestedFeatures(other.requestedFeatures)
374     , pushConstants(other.pushConstants)
375     , customizedStages(other.customizedStages)
376     , resources(other.resources)
377     , interfaces(other.interfaces)
378     , failResult(other.failResult)
379     , failMessageTemplate(other.failMessageTemplate)
380     , renderFullSquare(other.renderFullSquare)
381     , splitRenderArea(other.splitRenderArea)
382 {
383     inputColors[0] = other.inputColors[0];
384     inputColors[1] = other.inputColors[1];
385     inputColors[2] = other.inputColors[2];
386     inputColors[3] = other.inputColors[3];
387 
388     outputColors[0] = other.outputColors[0];
389     outputColors[1] = other.outputColors[1];
390     outputColors[2] = other.outputColors[2];
391     outputColors[3] = other.outputColors[3];
392 }
393 
getSpecializedFailMessage(const string & failureReason)394 string InstanceContext::getSpecializedFailMessage(const string &failureReason)
395 {
396     map<string, string> parameters;
397     parameters["reason"] = failureReason;
398     return StringTemplate(failMessageTemplate).specialize(parameters);
399 }
400 
createInstanceContext(const std::vector<ShaderElement> & elements,const tcu::RGBA (& inputColors)[4],const tcu::RGBA (& outputColors)[4],const std::map<std::string,std::string> & testCodeFragments,const StageToSpecConstantMap & specConstants,const PushConstants & pushConstants,const GraphicsResources & resources,const GraphicsInterfaces & interfaces,const std::vector<std::string> & extensions,VulkanFeatures vulkanFeatures,VkShaderStageFlags customizedStages,const qpTestResult failResult,const std::string & failMessageTemplate)401 InstanceContext createInstanceContext(const std::vector<ShaderElement> &elements, const tcu::RGBA (&inputColors)[4],
402                                       const tcu::RGBA (&outputColors)[4],
403                                       const std::map<std::string, std::string> &testCodeFragments,
404                                       const StageToSpecConstantMap &specConstants, const PushConstants &pushConstants,
405                                       const GraphicsResources &resources, const GraphicsInterfaces &interfaces,
406                                       const std::vector<std::string> &extensions, VulkanFeatures vulkanFeatures,
407                                       VkShaderStageFlags customizedStages, const qpTestResult failResult,
408                                       const std::string &failMessageTemplate)
409 {
410     InstanceContext ctx(inputColors, outputColors, testCodeFragments, specConstants, pushConstants, resources,
411                         interfaces, extensions, vulkanFeatures, customizedStages);
412     for (size_t i = 0; i < elements.size(); ++i)
413     {
414         ctx.moduleMap[elements[i].moduleName].push_back(std::make_pair(elements[i].entryName, elements[i].stage));
415         ctx.requiredStages = static_cast<VkShaderStageFlagBits>(ctx.requiredStages | elements[i].stage);
416     }
417     ctx.failResult = failResult;
418     if (!failMessageTemplate.empty())
419         ctx.failMessageTemplate = failMessageTemplate;
420     return ctx;
421 }
422 
createInstanceContext(const std::vector<ShaderElement> & elements,tcu::RGBA (& inputColors)[4],const tcu::RGBA (& outputColors)[4],const std::map<std::string,std::string> & testCodeFragments)423 InstanceContext createInstanceContext(const std::vector<ShaderElement> &elements, tcu::RGBA (&inputColors)[4],
424                                       const tcu::RGBA (&outputColors)[4],
425                                       const std::map<std::string, std::string> &testCodeFragments)
426 {
427     return createInstanceContext(elements, inputColors, outputColors, testCodeFragments, StageToSpecConstantMap(),
428                                  PushConstants(), GraphicsResources(), GraphicsInterfaces(), std::vector<std::string>(),
429                                  VulkanFeatures(), vk::VK_SHADER_STAGE_ALL);
430 }
431 
createInstanceContext(const std::vector<ShaderElement> & elements,const std::map<std::string,std::string> & testCodeFragments)432 InstanceContext createInstanceContext(const std::vector<ShaderElement> &elements,
433                                       const std::map<std::string, std::string> &testCodeFragments)
434 {
435     tcu::RGBA defaultColors[4];
436     getDefaultColors(defaultColors);
437     return createInstanceContext(elements, defaultColors, defaultColors, testCodeFragments);
438 }
439 
createUnusedVariableContext(const ShaderTaskArray & shaderTasks,const VariableLocation & location)440 UnusedVariableContext createUnusedVariableContext(const ShaderTaskArray &shaderTasks, const VariableLocation &location)
441 {
442     for (size_t i = 0; i < DE_LENGTH_OF_ARRAY(shaderTasks); ++i)
443     {
444         DE_ASSERT(shaderTasks[i] >= 0 && shaderTasks[i] < SHADER_TASK_LAST);
445     }
446 
447     std::vector<ShaderElement> elements;
448 
449     DE_ASSERT(shaderTasks[SHADER_TASK_INDEX_VERTEX] != SHADER_TASK_NONE);
450     DE_ASSERT(shaderTasks[SHADER_TASK_INDEX_FRAGMENT] != SHADER_TASK_NONE);
451     elements.push_back(ShaderElement("vert", "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
452     elements.push_back(ShaderElement("frag", "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
453 
454     if (shaderTasks[SHADER_TASK_INDEX_GEOMETRY] != SHADER_TASK_NONE)
455         elements.push_back(ShaderElement("geom", "main", vk::VK_SHADER_STAGE_GEOMETRY_BIT));
456 
457     if (shaderTasks[SHADER_TASK_INDEX_TESS_CONTROL] != SHADER_TASK_NONE)
458         elements.push_back(ShaderElement("tessc", "main", vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT));
459 
460     if (shaderTasks[SHADER_TASK_INDEX_TESS_EVAL] != SHADER_TASK_NONE)
461         elements.push_back(ShaderElement("tesse", "main", vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT));
462 
463     return UnusedVariableContext(createInstanceContext(elements, map<string, string>()), shaderTasks, location);
464 }
465 
ShaderElement(const string & moduleName_,const string & entryPoint_,VkShaderStageFlagBits shaderStage_)466 ShaderElement::ShaderElement(const string &moduleName_, const string &entryPoint_, VkShaderStageFlagBits shaderStage_)
467     : moduleName(moduleName_)
468     , entryName(entryPoint_)
469     , stage(shaderStage_)
470 {
471 }
472 
getDefaultColors(RGBA (& colors)[4])473 void getDefaultColors(RGBA (&colors)[4])
474 {
475     colors[0] = RGBA::white();
476     colors[1] = RGBA::red();
477     colors[2] = RGBA::green();
478     colors[3] = RGBA::blue();
479 }
480 
getHalfColorsFullAlpha(RGBA (& colors)[4])481 void getHalfColorsFullAlpha(RGBA (&colors)[4])
482 {
483     colors[0] = RGBA(127, 127, 127, 255);
484     colors[1] = RGBA(127, 0, 0, 255);
485     colors[2] = RGBA(0, 127, 0, 255);
486     colors[3] = RGBA(0, 0, 127, 255);
487 }
488 
getInvertedDefaultColors(RGBA (& colors)[4])489 void getInvertedDefaultColors(RGBA (&colors)[4])
490 {
491     colors[0] = RGBA(0, 0, 0, 255);
492     colors[1] = RGBA(0, 255, 255, 255);
493     colors[2] = RGBA(255, 0, 255, 255);
494     colors[3] = RGBA(255, 255, 0, 255);
495 }
496 
497 // For the current InstanceContext, constructs the required modules and shader stage create infos.
createPipelineShaderStages(const DeviceInterface & vk,const VkDevice vkDevice,InstanceContext & instance,Context & context,vector<ModuleHandleSp> & modules,vector<VkPipelineShaderStageCreateInfo> & createInfos)498 void createPipelineShaderStages(const DeviceInterface &vk, const VkDevice vkDevice, InstanceContext &instance,
499                                 Context &context, vector<ModuleHandleSp> &modules,
500                                 vector<VkPipelineShaderStageCreateInfo> &createInfos)
501 {
502     for (ModuleMap::const_iterator moduleNdx = instance.moduleMap.begin(); moduleNdx != instance.moduleMap.end();
503          ++moduleNdx)
504     {
505         const ModuleHandleSp mod(new Unique<VkShaderModule>(
506             createShaderModule(vk, vkDevice, context.getBinaryCollection().get(moduleNdx->first), 0)));
507         modules.push_back(ModuleHandleSp(mod));
508         for (vector<EntryToStage>::const_iterator shaderNdx = moduleNdx->second.begin();
509              shaderNdx != moduleNdx->second.end(); ++shaderNdx)
510         {
511             const EntryToStage &stage                         = *shaderNdx;
512             const VkPipelineShaderStageCreateInfo shaderParam = {
513                 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
514                 DE_NULL,                                             // const void* pNext;
515                 (VkPipelineShaderStageCreateFlags)0,
516                 stage.second,        // VkShaderStageFlagBits stage;
517                 **modules.back(),    // VkShaderModule module;
518                 stage.first.c_str(), // const char* pName;
519                 (const VkSpecializationInfo *)DE_NULL,
520             };
521             createInfos.push_back(shaderParam);
522         }
523     }
524 }
525 
526 // Creates vertex-shader assembly by specializing a boilerplate StringTemplate
527 // on fragments, which must (at least) map "testfun" to an OpFunction definition
528 // for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
529 // with "BP_" to avoid collisions with fragments.
530 //
531 // It corresponds roughly to this GLSL:
532 //;
533 // layout(location = 0) in vec4 position;
534 // layout(location = 1) in vec4 color;
535 // layout(location = 1) out highp vec4 vtxColor;
536 // void main (void) { gl_Position = position; vtxColor = test_func(color); }
makeVertexShaderAssembly(const map<string,string> & fragments)537 string makeVertexShaderAssembly(const map<string, string> &fragments)
538 {
539     static const char vertexShaderBoilerplate[] =
540         "OpCapability Shader\n"
541         "${capability:opt}\n"
542         "${extension:opt}\n"
543         "OpMemoryModel Logical GLSL450\n"
544         "OpEntryPoint Vertex %BP_main \"main\" %BP_stream %BP_position %BP_vtx_color %BP_color %BP_gl_VertexIndex "
545         "%BP_gl_InstanceIndex ${IF_entrypoint:opt} \n"
546         "${execution_mode:opt}\n"
547         "${debug:opt}\n"
548         "${moduleprocessed:opt}\n"
549         "OpMemberDecorate %BP_gl_PerVertex 0 BuiltIn Position\n"
550         "OpMemberDecorate %BP_gl_PerVertex 1 BuiltIn PointSize\n"
551         "OpMemberDecorate %BP_gl_PerVertex 2 BuiltIn ClipDistance\n"
552         "OpMemberDecorate %BP_gl_PerVertex 3 BuiltIn CullDistance\n"
553         "OpDecorate %BP_gl_PerVertex Block\n"
554         "OpDecorate %BP_position Location 0\n"
555         "OpDecorate %BP_vtx_color Location 1\n"
556         "OpDecorate %BP_color Location 1\n"
557         "OpDecorate %BP_gl_VertexIndex BuiltIn VertexIndex\n"
558         "OpDecorate %BP_gl_InstanceIndex BuiltIn InstanceIndex\n"
559         "${IF_decoration:opt}\n"
560         "${decoration:opt}\n" SPIRV_ASSEMBLY_TYPES SPIRV_ASSEMBLY_CONSTANTS SPIRV_ASSEMBLY_ARRAYS
561         "%BP_gl_PerVertex = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
562         "%BP_op_gl_PerVertex = OpTypePointer Output %BP_gl_PerVertex\n"
563         "%BP_stream = OpVariable %BP_op_gl_PerVertex Output\n"
564         "%BP_position = OpVariable %ip_v4f32 Input\n"
565         "%BP_vtx_color = OpVariable %op_v4f32 Output\n"
566         "%BP_color = OpVariable %ip_v4f32 Input\n"
567         "%BP_gl_VertexIndex = OpVariable %ip_i32 Input\n"
568         "%BP_gl_InstanceIndex = OpVariable %ip_i32 Input\n"
569         "${pre_main:opt}\n"
570         "${IF_variable:opt}\n"
571         "%BP_main = OpFunction %void None %voidf\n"
572         "%BP_label = OpLabel\n"
573         "${IF_carryforward:opt}\n"
574         "${post_interface_op_vert:opt}\n"
575         "%BP_pos = OpLoad %v4f32 %BP_position\n"
576         "%BP_gl_pos = OpAccessChain %op_v4f32 %BP_stream %c_i32_0\n"
577         "OpStore %BP_gl_pos %BP_pos\n"
578         "%BP_col = OpLoad %v4f32 %BP_color\n"
579         "%BP_col_transformed = OpFunctionCall %v4f32 %test_code %BP_col\n"
580         "OpStore %BP_vtx_color %BP_col_transformed\n"
581         "OpReturn\n"
582         "OpFunctionEnd\n"
583         "${interface_op_func:opt}\n"
584 
585         "%isUniqueIdZero = OpFunction %bool None %bool_function\n"
586         "%getId_label = OpLabel\n"
587         "%vert_id = OpLoad %i32 %BP_gl_VertexIndex\n"
588         "%is_id_0 = OpIEqual %bool %vert_id %c_i32_0\n"
589         "OpReturnValue %is_id_0\n"
590         "OpFunctionEnd\n"
591 
592         "${testfun}\n";
593     return tcu::StringTemplate(vertexShaderBoilerplate).specialize(fragments);
594 }
595 
596 // Creates tess-control-shader assembly by specializing a boilerplate
597 // StringTemplate on fragments, which must (at least) map "testfun" to an
598 // OpFunction definition for %test_code that takes and returns a %v4f32.
599 // Boilerplate IDs are prefixed with "BP_" to avoid collisions with fragments.
600 //
601 // It roughly corresponds to the following GLSL.
602 //
603 // #version 450
604 // layout(vertices = 3) out;
605 // layout(location = 1) in vec4 in_color[];
606 // layout(location = 1) out vec4 out_color[];
607 //
608 // void main() {
609 //   out_color[gl_InvocationID] = testfun(in_color[gl_InvocationID]);
610 //   gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
611 //   if (gl_InvocationID == 0) {
612 //     gl_TessLevelOuter[0] = 1.0;
613 //     gl_TessLevelOuter[1] = 1.0;
614 //     gl_TessLevelOuter[2] = 1.0;
615 //     gl_TessLevelInner[0] = 1.0;
616 //   }
617 // }
makeTessControlShaderAssembly(const map<string,string> & fragments)618 string makeTessControlShaderAssembly(const map<string, string> &fragments)
619 {
620     static const char tessControlShaderBoilerplate[] =
621         "OpCapability Tessellation\n"
622         "${capability:opt}\n"
623         "${extension:opt}\n"
624         "OpMemoryModel Logical GLSL450\n"
625         "OpEntryPoint TessellationControl %BP_main \"main\" %BP_out_color %BP_gl_InvocationID %BP_gl_PrimitiveID "
626         "%BP_in_color %BP_gl_out %BP_gl_in %BP_gl_TessLevelOuter %BP_gl_TessLevelInner ${IF_entrypoint:opt} \n"
627         "OpExecutionMode %BP_main OutputVertices 3\n"
628         "${execution_mode:opt}\n"
629         "${debug:opt}\n"
630         "${moduleprocessed:opt}\n"
631         "OpDecorate %BP_out_color Location 1\n"
632         "OpDecorate %BP_gl_InvocationID BuiltIn InvocationId\n"
633         "OpDecorate %BP_gl_PrimitiveID BuiltIn PrimitiveId\n"
634         "OpDecorate %BP_in_color Location 1\n"
635         "OpMemberDecorate %BP_gl_PerVertex 0 BuiltIn Position\n"
636         "OpMemberDecorate %BP_gl_PerVertex 1 BuiltIn PointSize\n"
637         "OpMemberDecorate %BP_gl_PerVertex 2 BuiltIn ClipDistance\n"
638         "OpMemberDecorate %BP_gl_PerVertex 3 BuiltIn CullDistance\n"
639         "OpDecorate %BP_gl_PerVertex Block\n"
640         "OpMemberDecorate %BP_gl_PVOut 0 BuiltIn Position\n"
641         "OpMemberDecorate %BP_gl_PVOut 1 BuiltIn PointSize\n"
642         "OpMemberDecorate %BP_gl_PVOut 2 BuiltIn ClipDistance\n"
643         "OpMemberDecorate %BP_gl_PVOut 3 BuiltIn CullDistance\n"
644         "OpDecorate %BP_gl_PVOut Block\n"
645         "OpDecorate %BP_gl_TessLevelOuter Patch\n"
646         "OpDecorate %BP_gl_TessLevelOuter BuiltIn TessLevelOuter\n"
647         "OpDecorate %BP_gl_TessLevelInner Patch\n"
648         "OpDecorate %BP_gl_TessLevelInner BuiltIn TessLevelInner\n"
649         "${IF_decoration:opt}\n"
650         "${decoration:opt}\n"
651         "${decoration_tessc:opt}\n" SPIRV_ASSEMBLY_TYPES SPIRV_ASSEMBLY_CONSTANTS SPIRV_ASSEMBLY_ARRAYS
652         "%BP_out_color = OpVariable %op_a3v4f32 Output\n"
653         "%BP_gl_InvocationID = OpVariable %ip_i32 Input\n"
654         "%BP_gl_PrimitiveID = OpVariable %ip_i32 Input\n"
655         "%BP_in_color = OpVariable %ip_a32v4f32 Input\n"
656         "%BP_gl_PerVertex = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
657         "%BP_a3_gl_PerVertex = OpTypeArray %BP_gl_PerVertex %c_u32_3\n"
658         "%BP_op_a3_gl_PerVertex = OpTypePointer Output %BP_a3_gl_PerVertex\n"
659         "%BP_gl_out = OpVariable %BP_op_a3_gl_PerVertex Output\n"
660         "%BP_gl_PVOut = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
661         "%BP_a32_gl_PVOut = OpTypeArray %BP_gl_PVOut %c_u32_32\n"
662         "%BP_ip_a32_gl_PVOut = OpTypePointer Input %BP_a32_gl_PVOut\n"
663         "%BP_gl_in = OpVariable %BP_ip_a32_gl_PVOut Input\n"
664         "%BP_gl_TessLevelOuter = OpVariable %op_a4f32 Output\n"
665         "%BP_gl_TessLevelInner = OpVariable %op_a2f32 Output\n"
666         "${pre_main:opt}\n"
667         "${IF_variable:opt}\n"
668 
669         "%BP_main = OpFunction %void None %voidf\n"
670         "%BP_label = OpLabel\n"
671         "%BP_gl_Invoc = OpLoad %i32 %BP_gl_InvocationID\n"
672         "${IF_carryforward:opt}\n"
673         "${post_interface_op_tessc:opt}\n"
674         "%BP_in_col_loc = OpAccessChain %ip_v4f32 %BP_in_color %BP_gl_Invoc\n"
675         "%BP_out_col_loc = OpAccessChain %op_v4f32 %BP_out_color %BP_gl_Invoc\n"
676         "%BP_in_col_val = OpLoad %v4f32 %BP_in_col_loc\n"
677         "%BP_clr_transformed = OpFunctionCall %v4f32 %test_code %BP_in_col_val\n"
678         "OpStore %BP_out_col_loc %BP_clr_transformed\n"
679 
680         "%BP_in_pos_loc = OpAccessChain %ip_v4f32 %BP_gl_in %BP_gl_Invoc %c_i32_0\n"
681         "%BP_out_pos_loc = OpAccessChain %op_v4f32 %BP_gl_out %BP_gl_Invoc %c_i32_0\n"
682         "%BP_in_pos_val = OpLoad %v4f32 %BP_in_pos_loc\n"
683         "OpStore %BP_out_pos_loc %BP_in_pos_val\n"
684 
685         "%BP_cmp = OpIEqual %bool %BP_gl_Invoc %c_i32_0\n"
686         "OpSelectionMerge %BP_merge_label None\n"
687         "OpBranchConditional %BP_cmp %BP_if_label %BP_merge_label\n"
688         "%BP_if_label = OpLabel\n"
689         "%BP_gl_TessLevelOuterPos_0 = OpAccessChain %op_f32 %BP_gl_TessLevelOuter %c_i32_0\n"
690         "%BP_gl_TessLevelOuterPos_1 = OpAccessChain %op_f32 %BP_gl_TessLevelOuter %c_i32_1\n"
691         "%BP_gl_TessLevelOuterPos_2 = OpAccessChain %op_f32 %BP_gl_TessLevelOuter %c_i32_2\n"
692         "%BP_gl_TessLevelInnerPos_0 = OpAccessChain %op_f32 %BP_gl_TessLevelInner %c_i32_0\n"
693         "OpStore %BP_gl_TessLevelOuterPos_0 %c_f32_1\n"
694         "OpStore %BP_gl_TessLevelOuterPos_1 %c_f32_1\n"
695         "OpStore %BP_gl_TessLevelOuterPos_2 %c_f32_1\n"
696         "OpStore %BP_gl_TessLevelInnerPos_0 %c_f32_1\n"
697         "OpBranch %BP_merge_label\n"
698         "%BP_merge_label = OpLabel\n"
699         "OpReturn\n"
700         "OpFunctionEnd\n"
701         "${interface_op_func:opt}\n"
702 
703         "%isUniqueIdZero = OpFunction %bool None %bool_function\n"
704         "%getId_label = OpLabel\n"
705         "%invocation_id = OpLoad %i32 %BP_gl_InvocationID\n"
706         "%primitive_id = OpLoad %i32 %BP_gl_PrimitiveID\n"
707         "%is_invocation_0 = OpIEqual %bool %invocation_id %c_i32_0\n"
708         "%is_primitive_0 = OpIEqual %bool %primitive_id %c_i32_0\n"
709         "%is_id_0 = OpLogicalAnd %bool %is_invocation_0 %is_primitive_0\n"
710         "OpReturnValue %is_id_0\n"
711         "OpFunctionEnd\n"
712 
713         "${testfun}\n";
714     return tcu::StringTemplate(tessControlShaderBoilerplate).specialize(fragments);
715 }
716 
717 // Creates tess-evaluation-shader assembly by specializing a boilerplate
718 // StringTemplate on fragments, which must (at least) map "testfun" to an
719 // OpFunction definition for %test_code that takes and returns a %v4f32.
720 // Boilerplate IDs are prefixed with "BP_" to avoid collisions with fragments.
721 //
722 // It roughly corresponds to the following glsl.
723 //
724 // #version 450
725 //
726 // layout(triangles, equal_spacing, ccw) in;
727 // layout(location = 1) in vec4 in_color[];
728 // layout(location = 1) out vec4 out_color;
729 //
730 // #define interpolate(val)
731 //   vec4(gl_TessCoord.x) * val[0] + vec4(gl_TessCoord.y) * val[1] +
732 //          vec4(gl_TessCoord.z) * val[2]
733 //
734 // void main() {
735 //   gl_Position = vec4(gl_TessCoord.x) * gl_in[0].gl_Position +
736 //                  vec4(gl_TessCoord.y) * gl_in[1].gl_Position +
737 //                  vec4(gl_TessCoord.z) * gl_in[2].gl_Position;
738 //   out_color = testfun(interpolate(in_color));
739 // }
makeTessEvalShaderAssembly(const map<string,string> & fragments)740 string makeTessEvalShaderAssembly(const map<string, string> &fragments)
741 {
742     static const char tessEvalBoilerplate[] =
743         "OpCapability Tessellation\n"
744         "${capability:opt}\n"
745         "${extension:opt}\n"
746         "OpMemoryModel Logical GLSL450\n"
747         "OpEntryPoint TessellationEvaluation %BP_main \"main\" %BP_stream %BP_gl_TessCoord %BP_gl_PrimitiveID "
748         "%BP_gl_in %BP_out_color %BP_in_color ${IF_entrypoint:opt} \n"
749         "OpExecutionMode %BP_main Triangles\n"
750         "OpExecutionMode %BP_main SpacingEqual\n"
751         "OpExecutionMode %BP_main VertexOrderCcw\n"
752         "${execution_mode:opt}\n"
753         "${debug:opt}\n"
754         "${moduleprocessed:opt}\n"
755         "OpMemberDecorate %BP_gl_PerVertexOut 0 BuiltIn Position\n"
756         "OpMemberDecorate %BP_gl_PerVertexOut 1 BuiltIn PointSize\n"
757         "OpMemberDecorate %BP_gl_PerVertexOut 2 BuiltIn ClipDistance\n"
758         "OpMemberDecorate %BP_gl_PerVertexOut 3 BuiltIn CullDistance\n"
759         "OpDecorate %BP_gl_PerVertexOut Block\n"
760         "OpDecorate %BP_gl_PrimitiveID BuiltIn PrimitiveId\n"
761         "OpDecorate %BP_gl_TessCoord BuiltIn TessCoord\n"
762         "OpMemberDecorate %BP_gl_PerVertexIn 0 BuiltIn Position\n"
763         "OpMemberDecorate %BP_gl_PerVertexIn 1 BuiltIn PointSize\n"
764         "OpMemberDecorate %BP_gl_PerVertexIn 2 BuiltIn ClipDistance\n"
765         "OpMemberDecorate %BP_gl_PerVertexIn 3 BuiltIn CullDistance\n"
766         "OpDecorate %BP_gl_PerVertexIn Block\n"
767         "OpDecorate %BP_out_color Location 1\n"
768         "OpDecorate %BP_in_color Location 1\n"
769         "${IF_decoration:opt}\n"
770         "${decoration:opt}\n" SPIRV_ASSEMBLY_TYPES SPIRV_ASSEMBLY_CONSTANTS SPIRV_ASSEMBLY_ARRAYS
771         "%BP_gl_PerVertexOut = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
772         "%BP_op_gl_PerVertexOut = OpTypePointer Output %BP_gl_PerVertexOut\n"
773         "%BP_stream = OpVariable %BP_op_gl_PerVertexOut Output\n"
774         "%BP_gl_TessCoord = OpVariable %ip_v3f32 Input\n"
775         "%BP_gl_PrimitiveID = OpVariable %ip_i32 Input\n"
776         "%BP_gl_PerVertexIn = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
777         "%BP_a32_gl_PerVertexIn = OpTypeArray %BP_gl_PerVertexIn %c_u32_32\n"
778         "%BP_ip_a32_gl_PerVertexIn = OpTypePointer Input %BP_a32_gl_PerVertexIn\n"
779         "%BP_gl_in = OpVariable %BP_ip_a32_gl_PerVertexIn Input\n"
780         "%BP_out_color = OpVariable %op_v4f32 Output\n"
781         "%BP_in_color = OpVariable %ip_a32v4f32 Input\n"
782         "${pre_main:opt}\n"
783         "${IF_variable:opt}\n"
784         "%BP_main = OpFunction %void None %voidf\n"
785         "%BP_label = OpLabel\n"
786         "${IF_carryforward:opt}\n"
787         "${post_interface_op_tesse:opt}\n"
788         "%BP_gl_TC_0 = OpAccessChain %ip_f32 %BP_gl_TessCoord %c_u32_0\n"
789         "%BP_gl_TC_1 = OpAccessChain %ip_f32 %BP_gl_TessCoord %c_u32_1\n"
790         "%BP_gl_TC_2 = OpAccessChain %ip_f32 %BP_gl_TessCoord %c_u32_2\n"
791         "%BP_gl_in_gl_Pos_0 = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_0 %c_i32_0\n"
792         "%BP_gl_in_gl_Pos_1 = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_1 %c_i32_0\n"
793         "%BP_gl_in_gl_Pos_2 = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_2 %c_i32_0\n"
794 
795         "%BP_gl_OPos = OpAccessChain %op_v4f32 %BP_stream %c_i32_0\n"
796         "%BP_in_color_0 = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_0\n"
797         "%BP_in_color_1 = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_1\n"
798         "%BP_in_color_2 = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_2\n"
799 
800         "%BP_TC_W_0 = OpLoad %f32 %BP_gl_TC_0\n"
801         "%BP_TC_W_1 = OpLoad %f32 %BP_gl_TC_1\n"
802         "%BP_TC_W_2 = OpLoad %f32 %BP_gl_TC_2\n"
803         "%BP_v4f32_TC_0 = OpCompositeConstruct %v4f32 %BP_TC_W_0 %BP_TC_W_0 %BP_TC_W_0 %BP_TC_W_0\n"
804         "%BP_v4f32_TC_1 = OpCompositeConstruct %v4f32 %BP_TC_W_1 %BP_TC_W_1 %BP_TC_W_1 %BP_TC_W_1\n"
805         "%BP_v4f32_TC_2 = OpCompositeConstruct %v4f32 %BP_TC_W_2 %BP_TC_W_2 %BP_TC_W_2 %BP_TC_W_2\n"
806 
807         "%BP_gl_IP_0 = OpLoad %v4f32 %BP_gl_in_gl_Pos_0\n"
808         "%BP_gl_IP_1 = OpLoad %v4f32 %BP_gl_in_gl_Pos_1\n"
809         "%BP_gl_IP_2 = OpLoad %v4f32 %BP_gl_in_gl_Pos_2\n"
810 
811         "%BP_IP_W_0 = OpFMul %v4f32 %BP_v4f32_TC_0 %BP_gl_IP_0\n"
812         "%BP_IP_W_1 = OpFMul %v4f32 %BP_v4f32_TC_1 %BP_gl_IP_1\n"
813         "%BP_IP_W_2 = OpFMul %v4f32 %BP_v4f32_TC_2 %BP_gl_IP_2\n"
814 
815         "%BP_pos_sum_0 = OpFAdd %v4f32 %BP_IP_W_0 %BP_IP_W_1\n"
816         "%BP_pos_sum_1 = OpFAdd %v4f32 %BP_pos_sum_0 %BP_IP_W_2\n"
817 
818         "OpStore %BP_gl_OPos %BP_pos_sum_1\n"
819 
820         "%BP_IC_0 = OpLoad %v4f32 %BP_in_color_0\n"
821         "%BP_IC_1 = OpLoad %v4f32 %BP_in_color_1\n"
822         "%BP_IC_2 = OpLoad %v4f32 %BP_in_color_2\n"
823 
824         "%BP_IC_W_0 = OpFMul %v4f32 %BP_v4f32_TC_0 %BP_IC_0\n"
825         "%BP_IC_W_1 = OpFMul %v4f32 %BP_v4f32_TC_1 %BP_IC_1\n"
826         "%BP_IC_W_2 = OpFMul %v4f32 %BP_v4f32_TC_2 %BP_IC_2\n"
827 
828         "%BP_col_sum_0 = OpFAdd %v4f32 %BP_IC_W_0 %BP_IC_W_1\n"
829         "%BP_col_sum_1 = OpFAdd %v4f32 %BP_col_sum_0 %BP_IC_W_2\n"
830 
831         "%BP_clr_transformed = OpFunctionCall %v4f32 %test_code %BP_col_sum_1\n"
832 
833         "OpStore %BP_out_color %BP_clr_transformed\n"
834         "OpReturn\n"
835         "OpFunctionEnd\n"
836         "${interface_op_func:opt}\n"
837 
838         "%isUniqueIdZero = OpFunction %bool None %bool_function\n"
839         "%getId_label = OpLabel\n"
840         "%primitive_id = OpLoad %i32 %BP_gl_PrimitiveID\n"
841         "%is_primitive_0 = OpIEqual %bool %primitive_id %c_i32_0\n"
842         "%TC_0_loc = OpAccessChain %ip_f32 %BP_gl_TessCoord %c_u32_0\n"
843         "%TC_1_loc = OpAccessChain %ip_f32 %BP_gl_TessCoord %c_u32_1\n"
844         "%TC_2_loc = OpAccessChain %ip_f32 %BP_gl_TessCoord %c_u32_2\n"
845         "%TC_W_0 = OpLoad %f32 %TC_0_loc\n"
846         "%TC_W_1 = OpLoad %f32 %TC_1_loc\n"
847         "%TC_W_2 = OpLoad %f32 %TC_2_loc\n"
848         "%is_W_0_1 = OpFOrdEqual %bool %TC_W_0 %c_f32_1\n"
849         "%is_W_1_0 = OpFOrdEqual %bool %TC_W_1 %c_f32_0\n"
850         "%is_W_2_0 = OpFOrdEqual %bool %TC_W_2 %c_f32_0\n"
851         "%is_tessCoord_1_0 = OpLogicalAnd %bool %is_W_0_1 %is_W_1_0\n"
852         "%is_tessCoord_1_0_0 = OpLogicalAnd %bool %is_tessCoord_1_0 %is_W_2_0\n"
853         "%is_unique_id_0 = OpLogicalAnd %bool %is_tessCoord_1_0_0 %is_primitive_0\n"
854         "OpReturnValue %is_unique_id_0\n"
855         "OpFunctionEnd\n"
856 
857         "${testfun}\n";
858     return tcu::StringTemplate(tessEvalBoilerplate).specialize(fragments);
859 }
860 
861 // Creates geometry-shader assembly by specializing a boilerplate StringTemplate
862 // on fragments, which must (at least) map "testfun" to an OpFunction definition
863 // for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
864 // with "BP_" to avoid collisions with fragments.
865 //
866 // Derived from this GLSL:
867 //
868 // #version 450
869 // layout(triangles) in;
870 // layout(triangle_strip, max_vertices = 3) out;
871 //
872 // layout(location = 1) in vec4 in_color[];
873 // layout(location = 1) out vec4 out_color;
874 //
875 // void main() {
876 //   gl_Position = gl_in[0].gl_Position;
877 //   out_color = test_fun(in_color[0]);
878 //   EmitVertex();
879 //   gl_Position = gl_in[1].gl_Position;
880 //   out_color = test_fun(in_color[1]);
881 //   EmitVertex();
882 //   gl_Position = gl_in[2].gl_Position;
883 //   out_color = test_fun(in_color[2]);
884 //   EmitVertex();
885 //   EndPrimitive();
886 // }
makeGeometryShaderAssembly(const map<string,string> & fragments)887 string makeGeometryShaderAssembly(const map<string, string> &fragments)
888 {
889     static const char geometryShaderBoilerplate[] =
890         "OpCapability Geometry\n"
891         "${capability:opt}\n"
892         "${extension:opt}\n"
893         "OpMemoryModel Logical GLSL450\n"
894         "OpEntryPoint Geometry %BP_main \"main\" %BP_out_gl_position %BP_gl_PrimitiveID %BP_gl_in %BP_out_color "
895         "%BP_in_color ${IF_entrypoint:opt} ${GL_entrypoint:opt} \n"
896         "OpExecutionMode %BP_main Triangles\n"
897         "OpExecutionMode %BP_main Invocations 1\n"
898         "OpExecutionMode %BP_main OutputTriangleStrip\n"
899         "OpExecutionMode %BP_main OutputVertices 3\n"
900         "${execution_mode:opt}\n"
901         "${debug:opt}\n"
902         "${moduleprocessed:opt}\n"
903         "OpDecorate %BP_gl_PrimitiveID BuiltIn PrimitiveId\n"
904         "OpDecorate %BP_out_gl_position BuiltIn Position\n"
905         "OpMemberDecorate %BP_per_vertex_in 0 BuiltIn Position\n"
906         "OpMemberDecorate %BP_per_vertex_in 1 BuiltIn PointSize\n"
907         "OpMemberDecorate %BP_per_vertex_in 2 BuiltIn ClipDistance\n"
908         "OpMemberDecorate %BP_per_vertex_in 3 BuiltIn CullDistance\n"
909         "OpDecorate %BP_per_vertex_in Block\n"
910         "OpDecorate %BP_out_color Location 1\n"
911         "OpDecorate %BP_in_color Location 1\n"
912         "${IF_decoration:opt}\n"
913         "${decoration:opt}\n" SPIRV_ASSEMBLY_TYPES SPIRV_ASSEMBLY_CONSTANTS SPIRV_ASSEMBLY_ARRAYS
914         "%BP_per_vertex_in = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
915         "%BP_a3_per_vertex_in = OpTypeArray %BP_per_vertex_in %c_u32_3\n"
916         "%BP_ip_a3_per_vertex_in = OpTypePointer Input %BP_a3_per_vertex_in\n"
917         "%BP_pp_i32 = OpTypePointer Private %i32\n"
918         "%BP_pp_v4i32 = OpTypePointer Private %v4i32\n"
919 
920         "%BP_gl_in = OpVariable %BP_ip_a3_per_vertex_in Input\n"
921         "%BP_out_color = OpVariable %op_v4f32 Output\n"
922         "%BP_in_color = OpVariable %ip_a3v4f32 Input\n"
923         "%BP_gl_PrimitiveID = OpVariable %ip_i32 Input\n"
924         "%BP_out_gl_position = OpVariable %op_v4f32 Output\n"
925         "%BP_vertexIdInCurrentPatch = OpVariable %BP_pp_v4i32 Private\n"
926         "${pre_main:opt}\n"
927         "${IF_variable:opt}\n"
928 
929         "%BP_main = OpFunction %void None %voidf\n"
930         "%BP_label = OpLabel\n"
931 
932         "${IF_carryforward:opt}\n"
933         "${post_interface_op_geom:opt}\n"
934 
935         "%BP_primitiveId = OpLoad %i32 %BP_gl_PrimitiveID\n"
936         "%BP_addr_vertexIdInCurrentPatch = OpAccessChain %BP_pp_i32 %BP_vertexIdInCurrentPatch %BP_primitiveId\n"
937 
938         "%BP_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_0 %c_i32_0\n"
939         "%BP_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_1 %c_i32_0\n"
940         "%BP_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %BP_gl_in %c_i32_2 %c_i32_0\n"
941 
942         "%BP_in_position_0 = OpLoad %v4f32 %BP_gl_in_0_gl_position\n"
943         "%BP_in_position_1 = OpLoad %v4f32 %BP_gl_in_1_gl_position\n"
944         "%BP_in_position_2 = OpLoad %v4f32 %BP_gl_in_2_gl_position \n"
945 
946         "%BP_in_color_0_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_0\n"
947         "%BP_in_color_1_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_1\n"
948         "%BP_in_color_2_ptr = OpAccessChain %ip_v4f32 %BP_in_color %c_i32_2\n"
949 
950         "%BP_in_color_0 = OpLoad %v4f32 %BP_in_color_0_ptr\n"
951         "%BP_in_color_1 = OpLoad %v4f32 %BP_in_color_1_ptr\n"
952         "%BP_in_color_2 = OpLoad %v4f32 %BP_in_color_2_ptr\n"
953 
954         "OpStore %BP_addr_vertexIdInCurrentPatch %c_i32_0\n"
955         "%BP_transformed_in_color_0 = OpFunctionCall %v4f32 %test_code %BP_in_color_0\n"
956         "OpStore %BP_addr_vertexIdInCurrentPatch %c_i32_1\n"
957         "%BP_transformed_in_color_1 = OpFunctionCall %v4f32 %test_code %BP_in_color_1\n"
958         "OpStore %BP_addr_vertexIdInCurrentPatch %c_i32_2\n"
959         "%BP_transformed_in_color_2 = OpFunctionCall %v4f32 %test_code %BP_in_color_2\n"
960 
961         "OpStore %BP_out_gl_position %BP_in_position_0\n"
962         "OpStore %BP_out_color %BP_transformed_in_color_0\n"
963         "OpEmitVertex\n"
964 
965         "OpStore %BP_out_gl_position %BP_in_position_1\n"
966         "OpStore %BP_out_color %BP_transformed_in_color_1\n"
967         "OpEmitVertex\n"
968 
969         "OpStore %BP_out_gl_position %BP_in_position_2\n"
970         "OpStore %BP_out_color %BP_transformed_in_color_2\n"
971         "OpEmitVertex\n"
972 
973         "OpEndPrimitive\n"
974         "OpReturn\n"
975         "OpFunctionEnd\n"
976         "${interface_op_func:opt}\n"
977 
978         "%isUniqueIdZero = OpFunction %bool None %bool_function\n"
979         "%getId_label = OpLabel\n"
980         "%primitive_id = OpLoad %i32 %BP_gl_PrimitiveID\n"
981         "%addr_vertexIdInCurrentPatch = OpAccessChain %BP_pp_i32 %BP_vertexIdInCurrentPatch %primitive_id\n"
982         "%vertexIdInCurrentPatch = OpLoad %i32 %addr_vertexIdInCurrentPatch\n"
983         "%is_primitive_0 = OpIEqual %bool %primitive_id %c_i32_0\n"
984         "%is_vertex_0 = OpIEqual %bool %vertexIdInCurrentPatch %c_i32_0\n"
985         "%is_unique_id_0 = OpLogicalAnd %bool %is_primitive_0 %is_vertex_0\n"
986         "OpReturnValue %is_unique_id_0\n"
987         "OpFunctionEnd\n"
988 
989         "${testfun}\n";
990     return tcu::StringTemplate(geometryShaderBoilerplate).specialize(fragments);
991 }
992 
993 // Creates fragment-shader assembly by specializing a boilerplate StringTemplate
994 // on fragments, which must (at least) map "testfun" to an OpFunction definition
995 // for %test_code that takes and returns a %v4f32.  Boilerplate IDs are prefixed
996 // with "BP_" to avoid collisions with fragments.
997 //
998 // Derived from this GLSL:
999 //
1000 // layout(location = 1) in highp vec4 vtxColor;
1001 // layout(location = 0) out highp vec4 fragColor;
1002 // highp vec4 testfun(highp vec4 x) { return x; }
1003 // void main(void) { fragColor = testfun(vtxColor); }
1004 //
1005 // with modifications including passing vtxColor by value and ripping out
1006 // testfun() definition.
makeFragmentShaderAssembly(const map<string,string> & fragments)1007 string makeFragmentShaderAssembly(const map<string, string> &fragments)
1008 {
1009     static const char fragmentShaderBoilerplate[] =
1010         "OpCapability Shader\n"
1011         "${capability:opt}\n"
1012         "${extension:opt}\n"
1013         "OpMemoryModel Logical GLSL450\n"
1014         "OpEntryPoint Fragment %BP_main \"main\" %BP_vtxColor %BP_fragColor %BP_gl_FragCoord ${IF_entrypoint:opt} \n"
1015         "OpExecutionMode %BP_main OriginUpperLeft\n"
1016         "${execution_mode:opt}\n"
1017         "${debug:opt}\n"
1018         "${moduleprocessed:opt}\n"
1019         "OpDecorate %BP_fragColor Location 0\n"
1020         "OpDecorate %BP_vtxColor Location 1\n"
1021         "OpDecorate %BP_gl_FragCoord BuiltIn FragCoord\n"
1022         "${IF_decoration:opt}\n"
1023         "${decoration:opt}\n" SPIRV_ASSEMBLY_TYPES SPIRV_ASSEMBLY_CONSTANTS SPIRV_ASSEMBLY_ARRAYS
1024         "%BP_gl_FragCoord = OpVariable %ip_v4f32 Input\n"
1025         "%BP_fragColor = OpVariable %op_v4f32 Output\n"
1026         "%BP_vtxColor = OpVariable %ip_v4f32 Input\n"
1027         "${pre_main:opt}\n"
1028         "${IF_variable:opt}\n"
1029         "%BP_main = OpFunction %void None %voidf\n"
1030         "%BP_label_main = OpLabel\n"
1031         "${IF_carryforward:opt}\n"
1032         "${post_interface_op_frag:opt}\n"
1033         "%BP_tmp1 = OpLoad %v4f32 %BP_vtxColor\n"
1034         "%BP_tmp2 = OpFunctionCall %v4f32 %test_code %BP_tmp1\n"
1035         "OpStore %BP_fragColor %BP_tmp2\n"
1036         "OpReturn\n"
1037         "OpFunctionEnd\n"
1038         "${interface_op_func:opt}\n"
1039 
1040         "%isUniqueIdZero = OpFunction %bool None %bool_function\n"
1041         "%getId_label = OpLabel\n"
1042         "%loc_x_coord = OpAccessChain %ip_f32 %BP_gl_FragCoord %c_i32_0\n"
1043         "%loc_y_coord = OpAccessChain %ip_f32 %BP_gl_FragCoord %c_i32_1\n"
1044         "%x_coord = OpLoad %f32 %loc_x_coord\n"
1045         "%y_coord = OpLoad %f32 %loc_y_coord\n"
1046         "%is_x_idx0 = OpFOrdEqual %bool %x_coord %c_f32_0_5\n"
1047         "%is_y_idx0 = OpFOrdEqual %bool %y_coord %c_f32_0_5\n"
1048         "%is_frag_0 = OpLogicalAnd %bool %is_x_idx0 %is_y_idx0\n"
1049         "OpReturnValue %is_frag_0\n"
1050         "OpFunctionEnd\n"
1051 
1052         "${testfun}\n";
1053     return tcu::StringTemplate(fragmentShaderBoilerplate).specialize(fragments);
1054 }
1055 
1056 // Creates mappings from placeholders to pass-through shader code which copies
1057 // the input to the output faithfully.
passthruInterface(const IFDataType & data_type)1058 map<string, string> passthruInterface(const IFDataType &data_type)
1059 {
1060     const string var_type         = data_type.str();
1061     map<string, string> fragments = passthruFragments();
1062     const string functype         = string("%") + var_type + "_" + var_type + "_function";
1063 
1064     fragments["interface_op_call"] = "OpCopyObject %" + var_type;
1065     fragments["interface_op_func"] = "";
1066     fragments["input_type"]        = var_type;
1067     fragments["output_type"]       = var_type;
1068     fragments["pre_main"]          = "";
1069 
1070     if (!data_type.elementIs32bit())
1071     {
1072         if (data_type.elementType == NUMBERTYPE_FLOAT64)
1073         {
1074             fragments["capability"] = "OpCapability Float64\n\n";
1075             fragments["pre_main"] += "%f64 = OpTypeFloat 64\n";
1076         }
1077         else if (data_type.elementType == NUMBERTYPE_FLOAT16)
1078         {
1079             fragments["capability"] = "OpCapability StorageInputOutput16\n";
1080             fragments["extension"]  = "OpExtension \"SPV_KHR_16bit_storage\"\n";
1081             fragments["pre_main"] += "%f16 = OpTypeFloat 16\n";
1082         }
1083         else if (data_type.elementType == NUMBERTYPE_INT16)
1084         {
1085             fragments["capability"] = "OpCapability StorageInputOutput16\n";
1086             fragments["extension"]  = "OpExtension \"SPV_KHR_16bit_storage\"\n";
1087             fragments["pre_main"] += "%i16 = OpTypeInt 16 1\n";
1088         }
1089         else if (data_type.elementType == NUMBERTYPE_UINT16)
1090         {
1091             fragments["capability"] = "OpCapability StorageInputOutput16\n";
1092             fragments["extension"]  = "OpExtension \"SPV_KHR_16bit_storage\"\n";
1093             fragments["pre_main"] += "%u16 = OpTypeInt 16 0\n";
1094         }
1095         else
1096         {
1097             DE_ASSERT(0 && "unhandled type");
1098         }
1099 
1100         if (data_type.isVector())
1101         {
1102             fragments["pre_main"] += "%" + var_type + " = OpTypeVector %" + IFDataType(1, data_type.elementType).str() +
1103                                      " " + numberToString(data_type.numElements) + "\n";
1104         }
1105 
1106         fragments["pre_main"] += "%ip_" + var_type + " = OpTypePointer Input %" + var_type +
1107                                  "\n"
1108                                  "%op_" +
1109                                  var_type + " = OpTypePointer Output %" + var_type + "\n";
1110     }
1111 
1112     if (strcmp(var_type.c_str(), "v4f32") != 0)
1113         fragments["pre_main"] += functype + " = OpTypeFunction %" + var_type + " %" + var_type +
1114                                  "\n"
1115                                  "%a3" +
1116                                  var_type + " = OpTypeArray %" + var_type +
1117                                  " %c_i32_3\n"
1118                                  "%ip_a3" +
1119                                  var_type + " = OpTypePointer Input %a3" + var_type +
1120                                  "\n"
1121                                  "%op_a3" +
1122                                  var_type + " = OpTypePointer Output %a3" + var_type + "\n";
1123 
1124     return fragments;
1125 }
1126 
1127 // Returns mappings from interface placeholders to their concrete values.
1128 //
1129 // The concrete values should be specialized again to provide ${input_type}
1130 // and ${output_type}.
1131 //
1132 // %ip_${input_type} and %op_${output_type} should also be defined in the final code.
fillInterfacePlaceholderVert(void)1133 map<string, string> fillInterfacePlaceholderVert(void)
1134 {
1135     map<string, string> fragments;
1136 
1137     fragments["IF_entrypoint"]   = "%IF_input %IF_output";
1138     fragments["IF_variable"]     = " %IF_input = OpVariable %ip_${input_type} Input\n"
1139                                    "%IF_output = OpVariable %op_${output_type} Output\n";
1140     fragments["IF_decoration"]   = "OpDecorate  %IF_input Location 2\n"
1141                                    "OpDecorate %IF_output Location 2\n";
1142     fragments["IF_carryforward"] = "%IF_input_val = OpLoad %${input_type} %IF_input\n"
1143                                    "   %IF_result = ${interface_op_call} %IF_input_val\n"
1144                                    "                OpStore %IF_output %IF_result\n";
1145 
1146     // Make sure the rest still need to be instantialized.
1147     fragments["capability"]             = "${capability:opt}";
1148     fragments["extension"]              = "${extension:opt}";
1149     fragments["execution_mode"]         = "${execution_mode:opt}";
1150     fragments["debug"]                  = "${debug:opt}";
1151     fragments["decoration"]             = "${decoration:opt}";
1152     fragments["pre_main"]               = "${pre_main:opt}";
1153     fragments["testfun"]                = "${testfun}";
1154     fragments["interface_op_call"]      = "${interface_op_call}";
1155     fragments["interface_op_func"]      = "${interface_op_func}";
1156     fragments["post_interface_op_vert"] = "${post_interface_op_vert:opt}";
1157 
1158     return fragments;
1159 }
1160 
1161 // Returns mappings from interface placeholders to their concrete values.
1162 //
1163 // The concrete values should be specialized again to provide ${input_type}
1164 // and ${output_type}.
1165 //
1166 // %ip_${input_type} and %op_${output_type} should also be defined in the final code.
fillInterfacePlaceholderFrag(void)1167 map<string, string> fillInterfacePlaceholderFrag(void)
1168 {
1169     map<string, string> fragments;
1170 
1171     fragments["IF_entrypoint"]   = "%IF_input %IF_output";
1172     fragments["IF_variable"]     = " %IF_input = OpVariable %ip_${input_type} Input\n"
1173                                    "%IF_output = OpVariable %op_${output_type} Output\n";
1174     fragments["IF_decoration"]   = "OpDecorate %IF_input Flat\n"
1175                                    "OpDecorate %IF_input Location 2\n"
1176                                    "OpDecorate %IF_output Location 1\n"; // Fragment shader should write to location #1.
1177     fragments["IF_carryforward"] = "%IF_input_val = OpLoad %${input_type} %IF_input\n"
1178                                    "   %IF_result = ${interface_op_call} %IF_input_val\n"
1179                                    "                OpStore %IF_output %IF_result\n";
1180 
1181     // Make sure the rest still need to be instantialized.
1182     fragments["capability"]             = "${capability:opt}";
1183     fragments["extension"]              = "${extension:opt}";
1184     fragments["execution_mode"]         = "${execution_mode:opt}";
1185     fragments["debug"]                  = "${debug:opt}";
1186     fragments["decoration"]             = "${decoration:opt}";
1187     fragments["pre_main"]               = "${pre_main:opt}";
1188     fragments["testfun"]                = "${testfun}";
1189     fragments["interface_op_call"]      = "${interface_op_call}";
1190     fragments["interface_op_func"]      = "${interface_op_func}";
1191     fragments["post_interface_op_frag"] = "${post_interface_op_frag:opt}";
1192 
1193     return fragments;
1194 }
1195 
1196 // Returns mappings from interface placeholders to their concrete values.
1197 //
1198 // The concrete values should be specialized again to provide ${input_type}
1199 // and ${output_type}.
1200 //
1201 // %ip_${input_type}, %op_${output_type}, %ip_a3${input_type}, and $op_a3${output_type}
1202 // should also be defined in the final code.
fillInterfacePlaceholderTessCtrl(void)1203 map<string, string> fillInterfacePlaceholderTessCtrl(void)
1204 {
1205     map<string, string> fragments;
1206 
1207     fragments["IF_entrypoint"]   = "%IF_input %IF_output";
1208     fragments["IF_variable"]     = " %IF_input = OpVariable %ip_a3${input_type} Input\n"
1209                                    "%IF_output = OpVariable %op_a3${output_type} Output\n";
1210     fragments["IF_decoration"]   = "OpDecorate  %IF_input Location 2\n"
1211                                    "OpDecorate %IF_output Location 2\n";
1212     fragments["IF_carryforward"] = " %IF_input_ptr0 = OpAccessChain %ip_${input_type} %IF_input %c_i32_0\n"
1213                                    " %IF_input_ptr1 = OpAccessChain %ip_${input_type} %IF_input %c_i32_1\n"
1214                                    " %IF_input_ptr2 = OpAccessChain %ip_${input_type} %IF_input %c_i32_2\n"
1215                                    "%IF_output_ptr0 = OpAccessChain %op_${output_type} %IF_output %c_i32_0\n"
1216                                    "%IF_output_ptr1 = OpAccessChain %op_${output_type} %IF_output %c_i32_1\n"
1217                                    "%IF_output_ptr2 = OpAccessChain %op_${output_type} %IF_output %c_i32_2\n"
1218                                    "%IF_input_val0 = OpLoad %${input_type} %IF_input_ptr0\n"
1219                                    "%IF_input_val1 = OpLoad %${input_type} %IF_input_ptr1\n"
1220                                    "%IF_input_val2 = OpLoad %${input_type} %IF_input_ptr2\n"
1221                                    "%IF_input_res0 = ${interface_op_call} %IF_input_val0\n"
1222                                    "%IF_input_res1 = ${interface_op_call} %IF_input_val1\n"
1223                                    "%IF_input_res2 = ${interface_op_call} %IF_input_val2\n"
1224                                    "OpStore %IF_output_ptr0 %IF_input_res0\n"
1225                                    "OpStore %IF_output_ptr1 %IF_input_res1\n"
1226                                    "OpStore %IF_output_ptr2 %IF_input_res2\n";
1227 
1228     // Make sure the rest still need to be instantialized.
1229     fragments["capability"]              = "${capability:opt}";
1230     fragments["extension"]               = "${extension:opt}";
1231     fragments["execution_mode"]          = "${execution_mode:opt}";
1232     fragments["debug"]                   = "${debug:opt}";
1233     fragments["decoration"]              = "${decoration:opt}";
1234     fragments["decoration_tessc"]        = "${decoration_tessc:opt}";
1235     fragments["pre_main"]                = "${pre_main:opt}";
1236     fragments["testfun"]                 = "${testfun}";
1237     fragments["interface_op_call"]       = "${interface_op_call}";
1238     fragments["interface_op_func"]       = "${interface_op_func}";
1239     fragments["post_interface_op_tessc"] = "${post_interface_op_tessc:opt}";
1240 
1241     return fragments;
1242 }
1243 
1244 // Returns mappings from interface placeholders to their concrete values.
1245 //
1246 // The concrete values should be specialized again to provide ${input_type}
1247 // and ${output_type}.
1248 //
1249 // %ip_${input_type}, %op_${output_type}, %ip_a3${input_type}, and $op_a3${output_type}
1250 // should also be defined in the final code.
fillInterfacePlaceholderTessEvalGeom(void)1251 map<string, string> fillInterfacePlaceholderTessEvalGeom(void)
1252 {
1253     map<string, string> fragments;
1254 
1255     fragments["IF_entrypoint"] = "%IF_input %IF_output";
1256     fragments["IF_variable"]   = " %IF_input = OpVariable %ip_a3${input_type} Input\n"
1257                                  "%IF_output = OpVariable %op_${output_type} Output\n";
1258     fragments["IF_decoration"] = "OpDecorate  %IF_input Location 2\n"
1259                                  "OpDecorate %IF_output Location 2\n";
1260     fragments["IF_carryforward"] =
1261         // Only get the first value since all three values are the same anyway.
1262         " %IF_input_ptr0 = OpAccessChain %ip_${input_type} %IF_input %c_i32_0\n"
1263         " %IF_input_val0 = OpLoad %${input_type} %IF_input_ptr0\n"
1264         " %IF_input_res0 = ${interface_op_call} %IF_input_val0\n"
1265         "OpStore %IF_output %IF_input_res0\n";
1266 
1267     // Make sure the rest still need to be instantialized.
1268     fragments["capability"]              = "${capability:opt}";
1269     fragments["extension"]               = "${extension:opt}";
1270     fragments["execution_mode"]          = "${execution_mode:opt}";
1271     fragments["debug"]                   = "${debug:opt}";
1272     fragments["decoration"]              = "${decoration:opt}";
1273     fragments["pre_main"]                = "${pre_main:opt}";
1274     fragments["testfun"]                 = "${testfun}";
1275     fragments["interface_op_call"]       = "${interface_op_call}";
1276     fragments["interface_op_func"]       = "${interface_op_func}";
1277     fragments["post_interface_op_tesse"] = "${post_interface_op_tesse:opt}";
1278     fragments["post_interface_op_geom"]  = "${post_interface_op_geom:opt}";
1279 
1280     return fragments;
1281 }
1282 
passthruFragments(void)1283 map<string, string> passthruFragments(void)
1284 {
1285     map<string, string> fragments;
1286     fragments["testfun"] =
1287         // A %test_code function that returns its argument unchanged.
1288         "%test_code = OpFunction %v4f32 None %v4f32_v4f32_function\n"
1289         "%param1 = OpFunctionParameter %v4f32\n"
1290         "%label_testfun = OpLabel\n"
1291         "OpReturnValue %param1\n"
1292         "OpFunctionEnd\n";
1293     return fragments;
1294 }
1295 
1296 // Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
1297 // Vertex shader gets custom code from context, the rest are pass-through.
addShaderCodeCustomVertex(vk::SourceCollections & dst,InstanceContext & context,const SpirVAsmBuildOptions * spirVAsmBuildOptions)1298 void addShaderCodeCustomVertex(vk::SourceCollections &dst, InstanceContext &context,
1299                                const SpirVAsmBuildOptions *spirVAsmBuildOptions)
1300 {
1301     const uint32_t vulkanVersion = dst.usedVulkanVersion;
1302     SpirvVersion targetSpirvVersion;
1303 
1304     if (spirVAsmBuildOptions == DE_NULL)
1305         targetSpirvVersion = context.resources.spirvVersion;
1306     else
1307         targetSpirvVersion = spirVAsmBuildOptions->targetVersion;
1308 
1309     if (!context.interfaces.empty())
1310     {
1311         // Inject boilerplate code to wire up additional input/output variables between stages.
1312         // Just copy the contents in input variable to output variable in all stages except
1313         // the customized stage.
1314         dst.spirvAsmSources.add("vert", spirVAsmBuildOptions)
1315             << StringTemplate(makeVertexShaderAssembly(fillInterfacePlaceholderVert()))
1316                    .specialize(context.testCodeFragments)
1317             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1318         dst.spirvAsmSources.add("frag", spirVAsmBuildOptions)
1319             << StringTemplate(makeFragmentShaderAssembly(fillInterfacePlaceholderFrag()))
1320                    .specialize(passthruInterface(context.interfaces.getOutputType()))
1321             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1322     }
1323     else
1324     {
1325         map<string, string> passthru = passthruFragments();
1326 
1327         dst.spirvAsmSources.add("vert", spirVAsmBuildOptions)
1328             << makeVertexShaderAssembly(context.testCodeFragments)
1329             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1330         dst.spirvAsmSources.add("frag", spirVAsmBuildOptions)
1331             << makeFragmentShaderAssembly(passthru) << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1332     }
1333 }
1334 
addShaderCodeCustomVertex(vk::SourceCollections & dst,InstanceContext context)1335 void addShaderCodeCustomVertex(vk::SourceCollections &dst, InstanceContext context)
1336 {
1337     addShaderCodeCustomVertex(dst, context, DE_NULL);
1338 }
1339 
1340 // Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
1341 // Tessellation control shader gets custom code from context, the rest are
1342 // pass-through.
addShaderCodeCustomTessControl(vk::SourceCollections & dst,InstanceContext & context,const SpirVAsmBuildOptions * spirVAsmBuildOptions)1343 void addShaderCodeCustomTessControl(vk::SourceCollections &dst, InstanceContext &context,
1344                                     const SpirVAsmBuildOptions *spirVAsmBuildOptions)
1345 {
1346     const uint32_t vulkanVersion = dst.usedVulkanVersion;
1347     SpirvVersion targetSpirvVersion;
1348 
1349     if (spirVAsmBuildOptions == DE_NULL)
1350         targetSpirvVersion = context.resources.spirvVersion;
1351     else
1352         targetSpirvVersion = spirVAsmBuildOptions->targetVersion;
1353 
1354     if (!context.interfaces.empty())
1355     {
1356         // Inject boilerplate code to wire up additional input/output variables between stages.
1357         // Just copy the contents in input variable to output variable in all stages except
1358         // the customized stage.
1359         dst.spirvAsmSources.add("vert", spirVAsmBuildOptions)
1360             << StringTemplate(makeVertexShaderAssembly(fillInterfacePlaceholderVert()))
1361                    .specialize(passthruInterface(context.interfaces.getInputType()))
1362             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1363         dst.spirvAsmSources.add("tessc", spirVAsmBuildOptions)
1364             << StringTemplate(makeTessControlShaderAssembly(fillInterfacePlaceholderTessCtrl()))
1365                    .specialize(context.testCodeFragments)
1366             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1367         dst.spirvAsmSources.add("tesse", spirVAsmBuildOptions)
1368             << StringTemplate(makeTessEvalShaderAssembly(fillInterfacePlaceholderTessEvalGeom()))
1369                    .specialize(passthruInterface(context.interfaces.getOutputType()))
1370             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1371         dst.spirvAsmSources.add("frag", spirVAsmBuildOptions)
1372             << StringTemplate(makeFragmentShaderAssembly(fillInterfacePlaceholderFrag()))
1373                    .specialize(passthruInterface(context.interfaces.getOutputType()))
1374             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1375     }
1376     else
1377     {
1378         map<string, string> passthru = passthruFragments();
1379 
1380         dst.spirvAsmSources.add("vert", spirVAsmBuildOptions)
1381             << makeVertexShaderAssembly(passthru) << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1382         dst.spirvAsmSources.add("tessc", spirVAsmBuildOptions)
1383             << makeTessControlShaderAssembly(context.testCodeFragments)
1384             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1385         dst.spirvAsmSources.add("tesse", spirVAsmBuildOptions)
1386             << makeTessEvalShaderAssembly(passthru) << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1387         dst.spirvAsmSources.add("frag", spirVAsmBuildOptions)
1388             << makeFragmentShaderAssembly(passthru) << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1389     }
1390 }
1391 
addShaderCodeCustomTessControl(vk::SourceCollections & dst,InstanceContext context)1392 void addShaderCodeCustomTessControl(vk::SourceCollections &dst, InstanceContext context)
1393 {
1394     addShaderCodeCustomTessControl(dst, context, DE_NULL);
1395 }
1396 
1397 // Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
1398 // Tessellation evaluation shader gets custom code from context, the rest are
1399 // pass-through.
addShaderCodeCustomTessEval(vk::SourceCollections & dst,InstanceContext & context,const SpirVAsmBuildOptions * spirVAsmBuildOptions)1400 void addShaderCodeCustomTessEval(vk::SourceCollections &dst, InstanceContext &context,
1401                                  const SpirVAsmBuildOptions *spirVAsmBuildOptions)
1402 {
1403     const uint32_t vulkanVersion = dst.usedVulkanVersion;
1404     SpirvVersion targetSpirvVersion;
1405 
1406     if (spirVAsmBuildOptions == DE_NULL)
1407         targetSpirvVersion = context.resources.spirvVersion;
1408     else
1409         targetSpirvVersion = spirVAsmBuildOptions->targetVersion;
1410 
1411     if (!context.interfaces.empty())
1412     {
1413         // Inject boilerplate code to wire up additional input/output variables between stages.
1414         // Just copy the contents in input variable to output variable in all stages except
1415         // the customized stage.
1416         dst.spirvAsmSources.add("vert", spirVAsmBuildOptions)
1417             << StringTemplate(makeVertexShaderAssembly(fillInterfacePlaceholderVert()))
1418                    .specialize(passthruInterface(context.interfaces.getInputType()))
1419             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1420         dst.spirvAsmSources.add("tessc", spirVAsmBuildOptions)
1421             << StringTemplate(makeTessControlShaderAssembly(fillInterfacePlaceholderTessCtrl()))
1422                    .specialize(passthruInterface(context.interfaces.getInputType()))
1423             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1424         dst.spirvAsmSources.add("tesse", spirVAsmBuildOptions)
1425             << StringTemplate(makeTessEvalShaderAssembly(fillInterfacePlaceholderTessEvalGeom()))
1426                    .specialize(context.testCodeFragments)
1427             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1428         dst.spirvAsmSources.add("frag", spirVAsmBuildOptions)
1429             << StringTemplate(makeFragmentShaderAssembly(fillInterfacePlaceholderFrag()))
1430                    .specialize(passthruInterface(context.interfaces.getOutputType()))
1431             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1432     }
1433     else
1434     {
1435         map<string, string> passthru = passthruFragments();
1436         dst.spirvAsmSources.add("vert", spirVAsmBuildOptions)
1437             << makeVertexShaderAssembly(passthru) << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1438         dst.spirvAsmSources.add("tessc", spirVAsmBuildOptions)
1439             << makeTessControlShaderAssembly(passthru) << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1440         dst.spirvAsmSources.add("tesse", spirVAsmBuildOptions)
1441             << makeTessEvalShaderAssembly(context.testCodeFragments)
1442             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1443         dst.spirvAsmSources.add("frag", spirVAsmBuildOptions)
1444             << makeFragmentShaderAssembly(passthru) << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1445     }
1446 }
1447 
addShaderCodeCustomTessEval(vk::SourceCollections & dst,InstanceContext context)1448 void addShaderCodeCustomTessEval(vk::SourceCollections &dst, InstanceContext context)
1449 {
1450     addShaderCodeCustomTessEval(dst, context, DE_NULL);
1451 }
1452 
1453 // Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
1454 // Geometry shader gets custom code from context, the rest are pass-through.
addShaderCodeCustomGeometry(vk::SourceCollections & dst,InstanceContext & context,const SpirVAsmBuildOptions * spirVAsmBuildOptions)1455 void addShaderCodeCustomGeometry(vk::SourceCollections &dst, InstanceContext &context,
1456                                  const SpirVAsmBuildOptions *spirVAsmBuildOptions)
1457 {
1458     const uint32_t vulkanVersion = dst.usedVulkanVersion;
1459     SpirvVersion targetSpirvVersion;
1460 
1461     if (spirVAsmBuildOptions == DE_NULL)
1462         targetSpirvVersion = context.resources.spirvVersion;
1463     else
1464         targetSpirvVersion = spirVAsmBuildOptions->targetVersion;
1465 
1466     if (!context.interfaces.empty())
1467     {
1468         // Inject boilerplate code to wire up additional input/output variables between stages.
1469         // Just copy the contents in input variable to output variable in all stages except
1470         // the customized stage.
1471         dst.spirvAsmSources.add("vert", spirVAsmBuildOptions)
1472             << StringTemplate(makeVertexShaderAssembly(fillInterfacePlaceholderVert()))
1473                    .specialize(passthruInterface(context.interfaces.getInputType()))
1474             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1475         dst.spirvAsmSources.add("geom", spirVAsmBuildOptions)
1476             << StringTemplate(makeGeometryShaderAssembly(fillInterfacePlaceholderTessEvalGeom()))
1477                    .specialize(context.testCodeFragments)
1478             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1479         dst.spirvAsmSources.add("frag", spirVAsmBuildOptions)
1480             << StringTemplate(makeFragmentShaderAssembly(fillInterfacePlaceholderFrag()))
1481                    .specialize(passthruInterface(context.interfaces.getOutputType()))
1482             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1483     }
1484     else
1485     {
1486         map<string, string> passthru = passthruFragments();
1487         dst.spirvAsmSources.add("vert", spirVAsmBuildOptions)
1488             << makeVertexShaderAssembly(passthru) << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1489         dst.spirvAsmSources.add("geom", spirVAsmBuildOptions)
1490             << makeGeometryShaderAssembly(context.testCodeFragments)
1491             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1492         dst.spirvAsmSources.add("frag", spirVAsmBuildOptions)
1493             << makeFragmentShaderAssembly(passthru) << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1494     }
1495 }
1496 
addShaderCodeCustomGeometry(vk::SourceCollections & dst,InstanceContext context)1497 void addShaderCodeCustomGeometry(vk::SourceCollections &dst, InstanceContext context)
1498 {
1499     addShaderCodeCustomGeometry(dst, context, DE_NULL);
1500 }
1501 
1502 // Adds shader assembly text to dst.spirvAsmSources for all shader kinds.
1503 // Fragment shader gets custom code from context, the rest are pass-through.
addShaderCodeCustomFragment(vk::SourceCollections & dst,InstanceContext & context,const SpirVAsmBuildOptions * spirVAsmBuildOptions)1504 void addShaderCodeCustomFragment(vk::SourceCollections &dst, InstanceContext &context,
1505                                  const SpirVAsmBuildOptions *spirVAsmBuildOptions)
1506 {
1507     const uint32_t vulkanVersion = dst.usedVulkanVersion;
1508     SpirvVersion targetSpirvVersion;
1509 
1510     if (spirVAsmBuildOptions == DE_NULL)
1511         targetSpirvVersion = context.resources.spirvVersion;
1512     else
1513         targetSpirvVersion = spirVAsmBuildOptions->targetVersion;
1514 
1515     if (!context.interfaces.empty())
1516     {
1517         // Inject boilerplate code to wire up additional input/output variables between stages.
1518         // Just copy the contents in input variable to output variable in all stages except
1519         // the customized stage.
1520         dst.spirvAsmSources.add("vert", spirVAsmBuildOptions)
1521             << StringTemplate(makeVertexShaderAssembly(fillInterfacePlaceholderVert()))
1522                    .specialize(passthruInterface(context.interfaces.getInputType()))
1523             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1524         dst.spirvAsmSources.add("frag", spirVAsmBuildOptions)
1525             << StringTemplate(makeFragmentShaderAssembly(fillInterfacePlaceholderFrag()))
1526                    .specialize(context.testCodeFragments)
1527             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1528     }
1529     else
1530     {
1531         map<string, string> passthru = passthruFragments();
1532         dst.spirvAsmSources.add("vert", spirVAsmBuildOptions)
1533             << makeVertexShaderAssembly(passthru) << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1534         dst.spirvAsmSources.add("frag", spirVAsmBuildOptions)
1535             << makeFragmentShaderAssembly(context.testCodeFragments)
1536             << SpirVAsmBuildOptions(vulkanVersion, targetSpirvVersion);
1537     }
1538 }
1539 
addShaderCodeCustomFragment(vk::SourceCollections & dst,InstanceContext context)1540 void addShaderCodeCustomFragment(vk::SourceCollections &dst, InstanceContext context)
1541 {
1542     addShaderCodeCustomFragment(dst, context, DE_NULL);
1543 }
1544 
createCombinedModule(vk::SourceCollections & dst,InstanceContext ctx)1545 void createCombinedModule(vk::SourceCollections &dst, InstanceContext ctx)
1546 {
1547     const bool useTessellation(
1548         ctx.requiredStages & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT));
1549     const bool useGeometry(ctx.requiredStages & VK_SHADER_STAGE_GEOMETRY_BIT);
1550     std::stringstream combinedModule;
1551     std::stringstream opCapabilities;
1552     std::stringstream opEntryPoints;
1553 
1554     // opCapabilities
1555     {
1556         opCapabilities << "OpCapability Shader\n";
1557 
1558         if (useGeometry)
1559             opCapabilities << "OpCapability Geometry\n";
1560 
1561         if (useTessellation)
1562             opCapabilities << "OpCapability Tessellation\n";
1563     }
1564 
1565     // opEntryPoints
1566     {
1567         if (useTessellation)
1568             opEntryPoints << "OpEntryPoint Vertex %vert_main \"main\" %vert_Position %vert_vtxColor %vert_color "
1569                              "%vert_vtxPosition %vert_vertex_id %vert_instance_id\n";
1570         else
1571             opEntryPoints << "OpEntryPoint Vertex %vert_main \"main\" %vert_Position %vert_vtxColor %vert_color "
1572                              "%vert_glPerVertex %vert_vertex_id %vert_instance_id\n";
1573 
1574         if (useGeometry)
1575             opEntryPoints << "OpEntryPoint Geometry %geom_main \"main\" %geom_out_gl_position %geom_gl_in "
1576                              "%geom_out_color %geom_in_color\n";
1577 
1578         if (useTessellation)
1579         {
1580             opEntryPoints << "OpEntryPoint TessellationControl %tessc_main \"main\" %tessc_out_color "
1581                              "%tessc_gl_InvocationID %tessc_in_color %tessc_out_position %tessc_in_position "
1582                              "%tessc_gl_TessLevelOuter %tessc_gl_TessLevelInner\n"
1583                              "OpEntryPoint TessellationEvaluation %tesse_main \"main\" %tesse_stream "
1584                              "%tesse_gl_tessCoord %tesse_in_position %tesse_out_color %tesse_in_color \n";
1585         }
1586 
1587         opEntryPoints << "OpEntryPoint Fragment %frag_main \"main\" %frag_vtxColor %frag_fragColor\n";
1588     }
1589 
1590     combinedModule << opCapabilities.str() << "OpMemoryModel Logical GLSL450\n" << opEntryPoints.str();
1591 
1592     if (useGeometry)
1593     {
1594         combinedModule << "OpExecutionMode %geom_main Triangles\n"
1595                           "OpExecutionMode %geom_main Invocations 1\n"
1596                           "OpExecutionMode %geom_main OutputTriangleStrip\n"
1597                           "OpExecutionMode %geom_main OutputVertices 3\n";
1598     }
1599 
1600     if (useTessellation)
1601     {
1602         combinedModule << "OpExecutionMode %tessc_main OutputVertices 3\n"
1603                           "OpExecutionMode %tesse_main Triangles\n"
1604                           "OpExecutionMode %tesse_main SpacingEqual\n"
1605                           "OpExecutionMode %tesse_main VertexOrderCcw\n";
1606     }
1607 
1608     combinedModule << "OpExecutionMode %frag_main OriginUpperLeft\n"
1609 
1610                       "; Vertex decorations\n"
1611                       "OpDecorate %vert_Position Location 0\n"
1612                       "OpDecorate %vert_vtxColor Location 1\n"
1613                       "OpDecorate %vert_color Location 1\n"
1614                       "OpDecorate %vert_vertex_id BuiltIn VertexIndex\n"
1615                       "OpDecorate %vert_instance_id BuiltIn InstanceIndex\n";
1616 
1617     // If tessellation is used, vertex position is written by tessellation stage.
1618     // Otherwise it will be written by vertex stage.
1619     if (useTessellation)
1620         combinedModule << "OpDecorate %vert_vtxPosition Location 2\n";
1621     else
1622     {
1623         combinedModule << "OpMemberDecorate %vert_per_vertex_out 0 BuiltIn Position\n"
1624                           "OpMemberDecorate %vert_per_vertex_out 1 BuiltIn PointSize\n"
1625                           "OpMemberDecorate %vert_per_vertex_out 2 BuiltIn ClipDistance\n"
1626                           "OpMemberDecorate %vert_per_vertex_out 3 BuiltIn CullDistance\n"
1627                           "OpDecorate %vert_per_vertex_out Block\n";
1628     }
1629 
1630     if (useGeometry)
1631     {
1632         combinedModule << "; Geometry decorations\n"
1633                           "OpDecorate %geom_out_gl_position BuiltIn Position\n"
1634                           "OpMemberDecorate %geom_per_vertex_in 0 BuiltIn Position\n"
1635                           "OpMemberDecorate %geom_per_vertex_in 1 BuiltIn PointSize\n"
1636                           "OpMemberDecorate %geom_per_vertex_in 2 BuiltIn ClipDistance\n"
1637                           "OpMemberDecorate %geom_per_vertex_in 3 BuiltIn CullDistance\n"
1638                           "OpDecorate %geom_per_vertex_in Block\n"
1639                           "OpDecorate %geom_out_color Location 1\n"
1640                           "OpDecorate %geom_in_color Location 1\n";
1641     }
1642 
1643     if (useTessellation)
1644     {
1645         combinedModule << "; Tessellation Control decorations\n"
1646                           "OpDecorate %tessc_out_color Location 1\n"
1647                           "OpDecorate %tessc_gl_InvocationID BuiltIn InvocationId\n"
1648                           "OpDecorate %tessc_in_color Location 1\n"
1649                           "OpDecorate %tessc_out_position Location 2\n"
1650                           "OpDecorate %tessc_in_position Location 2\n"
1651                           "OpDecorate %tessc_gl_TessLevelOuter Patch\n"
1652                           "OpDecorate %tessc_gl_TessLevelOuter BuiltIn TessLevelOuter\n"
1653                           "OpDecorate %tessc_gl_TessLevelInner Patch\n"
1654                           "OpDecorate %tessc_gl_TessLevelInner BuiltIn TessLevelInner\n"
1655 
1656                           "; Tessellation Evaluation decorations\n"
1657                           "OpMemberDecorate %tesse_per_vertex_out 0 BuiltIn Position\n"
1658                           "OpMemberDecorate %tesse_per_vertex_out 1 BuiltIn PointSize\n"
1659                           "OpMemberDecorate %tesse_per_vertex_out 2 BuiltIn ClipDistance\n"
1660                           "OpMemberDecorate %tesse_per_vertex_out 3 BuiltIn CullDistance\n"
1661                           "OpDecorate %tesse_per_vertex_out Block\n"
1662                           "OpDecorate %tesse_gl_tessCoord BuiltIn TessCoord\n"
1663                           "OpDecorate %tesse_in_position Location 2\n"
1664                           "OpDecorate %tesse_out_color Location 1\n"
1665                           "OpDecorate %tesse_in_color Location 1\n";
1666     }
1667 
1668     combinedModule << "; Fragment decorations\n"
1669                       "OpDecorate %frag_fragColor Location 0\n"
1670                       "OpDecorate %frag_vtxColor Location 1\n"
1671 
1672         SPIRV_ASSEMBLY_TYPES SPIRV_ASSEMBLY_CONSTANTS SPIRV_ASSEMBLY_ARRAYS
1673 
1674                       "; Vertex Variables\n"
1675                       "%vert_Position = OpVariable %ip_v4f32 Input\n"
1676                       "%vert_vtxColor = OpVariable %op_v4f32 Output\n"
1677                       "%vert_color = OpVariable %ip_v4f32 Input\n"
1678                       "%vert_vertex_id = OpVariable %ip_i32 Input\n"
1679                       "%vert_instance_id = OpVariable %ip_i32 Input\n";
1680 
1681     if (useTessellation)
1682         combinedModule << "%vert_vtxPosition = OpVariable %op_v4f32 Output\n";
1683     else
1684     {
1685         combinedModule << "%vert_per_vertex_out = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
1686                           "%vert_op_per_vertex_out = OpTypePointer Output %vert_per_vertex_out\n"
1687                           "%vert_glPerVertex = OpVariable %vert_op_per_vertex_out Output\n";
1688     }
1689 
1690     if (useGeometry)
1691     {
1692         combinedModule << "; Geometry Variables\n"
1693                           "%geom_per_vertex_in = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
1694                           "%geom_a3_per_vertex_in = OpTypeArray %geom_per_vertex_in %c_u32_3\n"
1695                           "%geom_ip_a3_per_vertex_in = OpTypePointer Input %geom_a3_per_vertex_in\n"
1696                           "%geom_gl_in = OpVariable %geom_ip_a3_per_vertex_in Input\n"
1697                           "%geom_out_color = OpVariable %op_v4f32 Output\n"
1698                           "%geom_in_color = OpVariable %ip_a3v4f32 Input\n"
1699                           "%geom_out_gl_position = OpVariable %op_v4f32 Output\n";
1700     }
1701 
1702     if (useTessellation)
1703     {
1704         combinedModule << "; Tessellation Control Variables\n"
1705                           "%tessc_out_color = OpVariable %op_a3v4f32 Output\n"
1706                           "%tessc_gl_InvocationID = OpVariable %ip_i32 Input\n"
1707                           "%tessc_in_color = OpVariable %ip_a32v4f32 Input\n"
1708                           "%tessc_out_position = OpVariable %op_a3v4f32 Output\n"
1709                           "%tessc_in_position = OpVariable %ip_a32v4f32 Input\n"
1710                           "%tessc_gl_TessLevelOuter = OpVariable %op_a4f32 Output\n"
1711                           "%tessc_gl_TessLevelInner = OpVariable %op_a2f32 Output\n"
1712 
1713                           "; Tessellation Evaluation Decorations\n"
1714                           "%tesse_per_vertex_out = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
1715                           "%tesse_op_per_vertex_out = OpTypePointer Output %tesse_per_vertex_out\n"
1716                           "%tesse_stream = OpVariable %tesse_op_per_vertex_out Output\n"
1717                           "%tesse_gl_tessCoord = OpVariable %ip_v3f32 Input\n"
1718                           "%tesse_in_position = OpVariable %ip_a32v4f32 Input\n"
1719                           "%tesse_out_color = OpVariable %op_v4f32 Output\n"
1720                           "%tesse_in_color = OpVariable %ip_a32v4f32 Input\n";
1721     }
1722 
1723     combinedModule << "; Fragment Variables\n"
1724                       "%frag_fragColor = OpVariable %op_v4f32 Output\n"
1725                       "%frag_vtxColor = OpVariable %ip_v4f32 Input\n"
1726 
1727                       "; Vertex Entry\n"
1728                       "%vert_main = OpFunction %void None %voidf\n"
1729                       "%vert_label = OpLabel\n"
1730                       "%vert_tmp_position = OpLoad %v4f32 %vert_Position\n";
1731 
1732     if (useTessellation)
1733         combinedModule << "OpStore %vert_vtxPosition %vert_tmp_position\n";
1734     else
1735     {
1736         combinedModule << "%vert_out_pos_ptr = OpAccessChain %op_v4f32 %vert_glPerVertex %c_i32_0\n"
1737                           "OpStore %vert_out_pos_ptr %vert_tmp_position\n";
1738     }
1739 
1740     combinedModule << "%vert_tmp_color = OpLoad %v4f32 %vert_color\n"
1741                       "OpStore %vert_vtxColor %vert_tmp_color\n"
1742                       "OpReturn\n"
1743                       "OpFunctionEnd\n";
1744 
1745     if (useGeometry)
1746     {
1747         combinedModule << "; Geometry Entry\n"
1748                           "%geom_main = OpFunction %void None %voidf\n"
1749                           "%geom_label = OpLabel\n"
1750                           "%geom_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %geom_gl_in %c_i32_0 %c_i32_0\n"
1751                           "%geom_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %geom_gl_in %c_i32_1 %c_i32_0\n"
1752                           "%geom_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %geom_gl_in %c_i32_2 %c_i32_0\n"
1753                           "%geom_in_position_0 = OpLoad %v4f32 %geom_gl_in_0_gl_position\n"
1754                           "%geom_in_position_1 = OpLoad %v4f32 %geom_gl_in_1_gl_position\n"
1755                           "%geom_in_position_2 = OpLoad %v4f32 %geom_gl_in_2_gl_position \n"
1756                           "%geom_in_color_0_ptr = OpAccessChain %ip_v4f32 %geom_in_color %c_i32_0\n"
1757                           "%geom_in_color_1_ptr = OpAccessChain %ip_v4f32 %geom_in_color %c_i32_1\n"
1758                           "%geom_in_color_2_ptr = OpAccessChain %ip_v4f32 %geom_in_color %c_i32_2\n"
1759                           "%geom_in_color_0 = OpLoad %v4f32 %geom_in_color_0_ptr\n"
1760                           "%geom_in_color_1 = OpLoad %v4f32 %geom_in_color_1_ptr\n"
1761                           "%geom_in_color_2 = OpLoad %v4f32 %geom_in_color_2_ptr\n"
1762                           "OpStore %geom_out_gl_position %geom_in_position_0\n"
1763                           "OpStore %geom_out_color %geom_in_color_0\n"
1764                           "OpEmitVertex\n"
1765                           "OpStore %geom_out_gl_position %geom_in_position_1\n"
1766                           "OpStore %geom_out_color %geom_in_color_1\n"
1767                           "OpEmitVertex\n"
1768                           "OpStore %geom_out_gl_position %geom_in_position_2\n"
1769                           "OpStore %geom_out_color %geom_in_color_2\n"
1770                           "OpEmitVertex\n"
1771                           "OpEndPrimitive\n"
1772                           "OpReturn\n"
1773                           "OpFunctionEnd\n";
1774     }
1775 
1776     if (useTessellation)
1777     {
1778         combinedModule
1779             << "; Tessellation Control Entry\n"
1780                "%tessc_main = OpFunction %void None %voidf\n"
1781                "%tessc_label = OpLabel\n"
1782                "%tessc_invocation_id = OpLoad %i32 %tessc_gl_InvocationID\n"
1783                "%tessc_in_color_ptr = OpAccessChain %ip_v4f32 %tessc_in_color %tessc_invocation_id\n"
1784                "%tessc_in_position_ptr = OpAccessChain %ip_v4f32 %tessc_in_position %tessc_invocation_id\n"
1785                "%tessc_in_color_val = OpLoad %v4f32 %tessc_in_color_ptr\n"
1786                "%tessc_in_position_val = OpLoad %v4f32 %tessc_in_position_ptr\n"
1787                "%tessc_out_color_ptr = OpAccessChain %op_v4f32 %tessc_out_color %tessc_invocation_id\n"
1788                "%tessc_out_position_ptr = OpAccessChain %op_v4f32 %tessc_out_position %tessc_invocation_id\n"
1789                "OpStore %tessc_out_color_ptr %tessc_in_color_val\n"
1790                "OpStore %tessc_out_position_ptr %tessc_in_position_val\n"
1791                "%tessc_is_first_invocation = OpIEqual %bool %tessc_invocation_id %c_i32_0\n"
1792                "OpSelectionMerge %tessc_merge_label None\n"
1793                "OpBranchConditional %tessc_is_first_invocation %tessc_first_invocation %tessc_merge_label\n"
1794                "%tessc_first_invocation = OpLabel\n"
1795                "%tessc_tess_outer_0 = OpAccessChain %op_f32 %tessc_gl_TessLevelOuter %c_i32_0\n"
1796                "%tessc_tess_outer_1 = OpAccessChain %op_f32 %tessc_gl_TessLevelOuter %c_i32_1\n"
1797                "%tessc_tess_outer_2 = OpAccessChain %op_f32 %tessc_gl_TessLevelOuter %c_i32_2\n"
1798                "%tessc_tess_inner = OpAccessChain %op_f32 %tessc_gl_TessLevelInner %c_i32_0\n"
1799                "OpStore %tessc_tess_outer_0 %c_f32_1\n"
1800                "OpStore %tessc_tess_outer_1 %c_f32_1\n"
1801                "OpStore %tessc_tess_outer_2 %c_f32_1\n"
1802                "OpStore %tessc_tess_inner %c_f32_1\n"
1803                "OpBranch %tessc_merge_label\n"
1804                "%tessc_merge_label = OpLabel\n"
1805                "OpReturn\n"
1806                "OpFunctionEnd\n"
1807 
1808                "; Tessellation Evaluation Entry\n"
1809                "%tesse_main = OpFunction %void None %voidf\n"
1810                "%tesse_label = OpLabel\n"
1811                "%tesse_tc_0_ptr = OpAccessChain %ip_f32 %tesse_gl_tessCoord %c_u32_0\n"
1812                "%tesse_tc_1_ptr = OpAccessChain %ip_f32 %tesse_gl_tessCoord %c_u32_1\n"
1813                "%tesse_tc_2_ptr = OpAccessChain %ip_f32 %tesse_gl_tessCoord %c_u32_2\n"
1814                "%tesse_tc_0 = OpLoad %f32 %tesse_tc_0_ptr\n"
1815                "%tesse_tc_1 = OpLoad %f32 %tesse_tc_1_ptr\n"
1816                "%tesse_tc_2 = OpLoad %f32 %tesse_tc_2_ptr\n"
1817                "%tesse_in_pos_0_ptr = OpAccessChain %ip_v4f32 %tesse_in_position %c_i32_0\n"
1818                "%tesse_in_pos_1_ptr = OpAccessChain %ip_v4f32 %tesse_in_position %c_i32_1\n"
1819                "%tesse_in_pos_2_ptr = OpAccessChain %ip_v4f32 %tesse_in_position %c_i32_2\n"
1820                "%tesse_in_pos_0 = OpLoad %v4f32 %tesse_in_pos_0_ptr\n"
1821                "%tesse_in_pos_1 = OpLoad %v4f32 %tesse_in_pos_1_ptr\n"
1822                "%tesse_in_pos_2 = OpLoad %v4f32 %tesse_in_pos_2_ptr\n"
1823                "%tesse_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse_in_pos_0 %tesse_tc_0\n"
1824                "%tesse_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse_in_pos_1 %tesse_tc_1\n"
1825                "%tesse_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse_in_pos_2 %tesse_tc_2\n"
1826                "%tesse_out_pos_ptr = OpAccessChain %op_v4f32 %tesse_stream %c_i32_0\n"
1827                "%tesse_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse_in_pos_0_weighted %tesse_in_pos_1_weighted\n"
1828                "%tesse_computed_out = OpFAdd %v4f32 %tesse_in_pos_0_plus_pos_1 %tesse_in_pos_2_weighted\n"
1829                "OpStore %tesse_out_pos_ptr %tesse_computed_out\n"
1830                "%tesse_in_clr_0_ptr = OpAccessChain %ip_v4f32 %tesse_in_color %c_i32_0\n"
1831                "%tesse_in_clr_1_ptr = OpAccessChain %ip_v4f32 %tesse_in_color %c_i32_1\n"
1832                "%tesse_in_clr_2_ptr = OpAccessChain %ip_v4f32 %tesse_in_color %c_i32_2\n"
1833                "%tesse_in_clr_0 = OpLoad %v4f32 %tesse_in_clr_0_ptr\n"
1834                "%tesse_in_clr_1 = OpLoad %v4f32 %tesse_in_clr_1_ptr\n"
1835                "%tesse_in_clr_2 = OpLoad %v4f32 %tesse_in_clr_2_ptr\n"
1836                "%tesse_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse_in_clr_0 %tesse_tc_0\n"
1837                "%tesse_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse_in_clr_1 %tesse_tc_1\n"
1838                "%tesse_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse_in_clr_2 %tesse_tc_2\n"
1839                "%tesse_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse_in_clr_0_weighted %tesse_in_clr_1_weighted\n"
1840                "%tesse_computed_clr = OpFAdd %v4f32 %tesse_in_clr_0_plus_col_1 %tesse_in_clr_2_weighted\n"
1841                "OpStore %tesse_out_color %tesse_computed_clr\n"
1842                "OpReturn\n"
1843                "OpFunctionEnd\n";
1844     }
1845 
1846     combinedModule << "; Fragment Entry\n"
1847                       "%frag_main = OpFunction %void None %voidf\n"
1848                       "%frag_label_main = OpLabel\n"
1849                       "%frag_tmp1 = OpLoad %v4f32 %frag_vtxColor\n"
1850                       "OpStore %frag_fragColor %frag_tmp1\n"
1851                       "OpReturn\n"
1852                       "OpFunctionEnd\n";
1853 
1854     dst.spirvAsmSources.add("module") << combinedModule.str();
1855 }
1856 
createUnusedVariableModules(vk::SourceCollections & dst,UnusedVariableContext ctx)1857 void createUnusedVariableModules(vk::SourceCollections &dst, UnusedVariableContext ctx)
1858 {
1859     if (ctx.shaderTasks[SHADER_TASK_INDEX_VERTEX] != SHADER_TASK_NONE)
1860     {
1861         std::ostringstream shader;
1862         bool tessellation      = (ctx.shaderTasks[SHADER_TASK_INDEX_TESS_CONTROL] != SHADER_TASK_NONE ||
1863                              ctx.shaderTasks[SHADER_TASK_INDEX_TESS_EVAL] != SHADER_TASK_NONE);
1864         const ShaderTask &task = ctx.shaderTasks[SHADER_TASK_INDEX_VERTEX];
1865 
1866         shader << "OpCapability Shader\n"
1867                << "OpMemoryModel Logical GLSL450\n";
1868 
1869         // Entry point depends on if tessellation is enabled or not to provide the vertex position.
1870         shader << "OpEntryPoint Vertex %main \"main\" %Position %vtxColor %color "
1871                << (tessellation ? "%vtxPosition" : "%vtx_glPerVertex") << " %vertex_id %instance_id\n";
1872         if (task == SHADER_TASK_UNUSED_FUNC)
1873         {
1874             shader << getUnusedEntryPoint();
1875         }
1876 
1877         // Decorations.
1878         shader << "OpDecorate %Position Location 0\n"
1879                << "OpDecorate %vtxColor Location 1\n"
1880                << "OpDecorate %color Location 1\n"
1881                << "OpDecorate %vertex_id BuiltIn VertexIndex\n"
1882                << "OpDecorate %instance_id BuiltIn InstanceIndex\n";
1883         if (tessellation)
1884         {
1885             shader << "OpDecorate %vtxPosition Location 2\n";
1886         }
1887         else
1888         {
1889             shader << "OpMemberDecorate %vert_per_vertex_out 0 BuiltIn Position\n"
1890                    << "OpMemberDecorate %vert_per_vertex_out 1 BuiltIn PointSize\n"
1891                    << "OpMemberDecorate %vert_per_vertex_out 2 BuiltIn ClipDistance\n"
1892                    << "OpMemberDecorate %vert_per_vertex_out 3 BuiltIn CullDistance\n"
1893                    << "OpDecorate %vert_per_vertex_out Block\n";
1894         }
1895         if (task != SHADER_TASK_NORMAL)
1896         {
1897             shader << getUnusedDecorations(ctx.variableLocation);
1898         }
1899 
1900         // Standard types, constants and arrays.
1901         shader << "; Start of standard types, constants and arrays\n"
1902                << SPIRV_ASSEMBLY_TYPES << SPIRV_ASSEMBLY_CONSTANTS << SPIRV_ASSEMBLY_ARRAYS
1903                << "; End of standard types, constants and arrays\n";
1904         if (task != SHADER_TASK_NORMAL)
1905         {
1906             shader << getUnusedTypesAndConstants();
1907         }
1908 
1909         // Variables.
1910         if (tessellation)
1911         {
1912             shader << "%vtxPosition = OpVariable %op_v4f32 Output\n";
1913         }
1914         else
1915         {
1916             shader << "%vert_per_vertex_out = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
1917                    << "%vert_op_per_vertex_out = OpTypePointer Output %vert_per_vertex_out\n"
1918                    << "%vtx_glPerVertex = OpVariable %vert_op_per_vertex_out Output\n";
1919         }
1920         shader << "%Position = OpVariable %ip_v4f32 Input\n"
1921                << "%vtxColor = OpVariable %op_v4f32 Output\n"
1922                << "%color = OpVariable %ip_v4f32 Input\n"
1923                << "%vertex_id = OpVariable %ip_i32 Input\n"
1924                << "%instance_id = OpVariable %ip_i32 Input\n";
1925         if (task != SHADER_TASK_NORMAL)
1926         {
1927             shader << getUnusedBuffer();
1928         }
1929 
1930         // Vertex main function.
1931         shader << "%main = OpFunction %void None %voidf\n"
1932                << "%label = OpLabel\n"
1933                << "%tmp_position = OpLoad %v4f32 %Position\n";
1934         if (tessellation)
1935         {
1936             shader << "OpStore %vtxPosition %tmp_position\n";
1937         }
1938         else
1939         {
1940             shader << "%vert_out_pos_ptr = OpAccessChain %op_v4f32 %vtx_glPerVertex %c_i32_0\n"
1941                    << "OpStore %vert_out_pos_ptr %tmp_position\n";
1942         }
1943         shader << "%tmp_color = OpLoad %v4f32 %color\n"
1944                << "OpStore %vtxColor %tmp_color\n"
1945                << "OpReturn\n"
1946                << "OpFunctionEnd\n";
1947         if (task == SHADER_TASK_UNUSED_FUNC)
1948         {
1949             shader << getUnusedFunctionBody();
1950         }
1951 
1952         dst.spirvAsmSources.add("vert") << shader.str();
1953     }
1954 
1955     if (ctx.shaderTasks[SHADER_TASK_INDEX_GEOMETRY] != SHADER_TASK_NONE)
1956     {
1957         const ShaderTask &task = ctx.shaderTasks[SHADER_TASK_INDEX_GEOMETRY];
1958         std::ostringstream shader;
1959 
1960         if (task != SHADER_TASK_NORMAL)
1961         {
1962             shader << getOpCapabilityShader();
1963         }
1964         shader << "OpCapability Geometry\n"
1965                << "OpMemoryModel Logical GLSL450\n";
1966 
1967         // Entry points.
1968         shader << "OpEntryPoint Geometry %geom1_main \"main\" %out_gl_position %gl_in %out_color %in_color\n";
1969         if (task == SHADER_TASK_UNUSED_FUNC)
1970         {
1971             shader << getUnusedEntryPoint();
1972         }
1973         shader << "OpExecutionMode %geom1_main Triangles\n"
1974                << "OpExecutionMode %geom1_main OutputTriangleStrip\n"
1975                << "OpExecutionMode %geom1_main OutputVertices 3\n"
1976                << "OpExecutionMode %geom1_main Invocations 1\n";
1977 
1978         // Decorations.
1979         shader << "OpDecorate %out_gl_position BuiltIn Position\n"
1980                << "OpMemberDecorate %per_vertex_in 0 BuiltIn Position\n"
1981                << "OpMemberDecorate %per_vertex_in 1 BuiltIn PointSize\n"
1982                << "OpMemberDecorate %per_vertex_in 2 BuiltIn ClipDistance\n"
1983                << "OpMemberDecorate %per_vertex_in 3 BuiltIn CullDistance\n"
1984                << "OpDecorate %per_vertex_in Block\n"
1985                << "OpDecorate %out_color Location 1\n"
1986                << "OpDecorate %in_color Location 1\n";
1987         if (task != SHADER_TASK_NORMAL)
1988         {
1989             shader << getUnusedDecorations(ctx.variableLocation);
1990         }
1991 
1992         // Standard types, constants and arrays.
1993         shader << "; Start of standard types, constants and arrays\n"
1994                << SPIRV_ASSEMBLY_TYPES << SPIRV_ASSEMBLY_CONSTANTS << SPIRV_ASSEMBLY_ARRAYS
1995                << "; End of standard types, constants and arrays\n";
1996         if (task != SHADER_TASK_NORMAL)
1997         {
1998             shader << getUnusedTypesAndConstants();
1999         }
2000 
2001         // Variables.
2002         shader << "%per_vertex_in = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
2003                << "%a3_per_vertex_in = OpTypeArray %per_vertex_in %c_u32_3\n"
2004                << "%ip_a3_per_vertex_in = OpTypePointer Input %a3_per_vertex_in\n"
2005                << "%gl_in = OpVariable %ip_a3_per_vertex_in Input\n"
2006                << "%out_color = OpVariable %op_v4f32 Output\n"
2007                << "%in_color = OpVariable %ip_a3v4f32 Input\n"
2008                << "%out_gl_position = OpVariable %op_v4f32 Output\n";
2009         if (task != SHADER_TASK_NORMAL)
2010         {
2011             shader << getUnusedBuffer();
2012         }
2013 
2014         // Main function.
2015         shader << "%geom1_main = OpFunction %void None %voidf\n"
2016                << "%geom1_label = OpLabel\n"
2017                << "%geom1_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_0 %c_i32_0\n"
2018                << "%geom1_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_1 %c_i32_0\n"
2019                << "%geom1_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_2 %c_i32_0\n"
2020                << "%geom1_in_position_0 = OpLoad %v4f32 %geom1_gl_in_0_gl_position\n"
2021                << "%geom1_in_position_1 = OpLoad %v4f32 %geom1_gl_in_1_gl_position\n"
2022                << "%geom1_in_position_2 = OpLoad %v4f32 %geom1_gl_in_2_gl_position \n"
2023                << "%geom1_in_color_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
2024                << "%geom1_in_color_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
2025                << "%geom1_in_color_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
2026                << "%geom1_in_color_0 = OpLoad %v4f32 %geom1_in_color_0_ptr\n"
2027                << "%geom1_in_color_1 = OpLoad %v4f32 %geom1_in_color_1_ptr\n"
2028                << "%geom1_in_color_2 = OpLoad %v4f32 %geom1_in_color_2_ptr\n"
2029                << "OpStore %out_gl_position %geom1_in_position_0\n"
2030                << "OpStore %out_color %geom1_in_color_0\n"
2031                << "OpEmitVertex\n"
2032                << "OpStore %out_gl_position %geom1_in_position_1\n"
2033                << "OpStore %out_color %geom1_in_color_1\n"
2034                << "OpEmitVertex\n"
2035                << "OpStore %out_gl_position %geom1_in_position_2\n"
2036                << "OpStore %out_color %geom1_in_color_2\n"
2037                << "OpEmitVertex\n"
2038                << "OpEndPrimitive\n"
2039                << "OpReturn\n"
2040                << "OpFunctionEnd\n";
2041         if (task == SHADER_TASK_UNUSED_FUNC)
2042         {
2043             shader << getUnusedFunctionBody();
2044         }
2045 
2046         dst.spirvAsmSources.add("geom") << shader.str();
2047     }
2048 
2049     if (ctx.shaderTasks[SHADER_TASK_INDEX_TESS_CONTROL] != SHADER_TASK_NONE)
2050     {
2051         const ShaderTask &task = ctx.shaderTasks[SHADER_TASK_INDEX_TESS_CONTROL];
2052         std::ostringstream shader;
2053 
2054         if (task != SHADER_TASK_NORMAL)
2055         {
2056             shader << getOpCapabilityShader();
2057         }
2058         shader << "OpCapability Tessellation\n"
2059                << "OpMemoryModel Logical GLSL450\n";
2060 
2061         // Entry point.
2062         shader << "OpEntryPoint TessellationControl %tessc1_main \"main\" %out_color %gl_InvocationID %in_color "
2063                   "%out_position %in_position %gl_TessLevelOuter %gl_TessLevelInner\n";
2064         if (task == SHADER_TASK_UNUSED_FUNC)
2065         {
2066             shader << getUnusedEntryPoint();
2067         }
2068         shader << "OpExecutionMode %tessc1_main OutputVertices 3\n";
2069 
2070         // Decorations.
2071         shader << "OpDecorate %out_color Location 1\n"
2072                << "OpDecorate %gl_InvocationID BuiltIn InvocationId\n"
2073                << "OpDecorate %in_color Location 1\n"
2074                << "OpDecorate %out_position Location 2\n"
2075                << "OpDecorate %in_position Location 2\n"
2076                << "OpDecorate %gl_TessLevelOuter Patch\n"
2077                << "OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter\n"
2078                << "OpDecorate %gl_TessLevelInner Patch\n"
2079                << "OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner\n";
2080         if (task != SHADER_TASK_NORMAL)
2081         {
2082             shader << getUnusedDecorations(ctx.variableLocation);
2083         }
2084 
2085         // Standard types, constants and arrays.
2086         shader << "; Start of standard types, constants and arrays\n"
2087                << SPIRV_ASSEMBLY_TYPES << SPIRV_ASSEMBLY_CONSTANTS << SPIRV_ASSEMBLY_ARRAYS
2088                << "; End of standard types, constants and arrays\n";
2089         if (task != SHADER_TASK_NORMAL)
2090         {
2091             shader << getUnusedTypesAndConstants();
2092         }
2093 
2094         // Variables.
2095         shader << "%out_color = OpVariable %op_a3v4f32 Output\n"
2096                << "%gl_InvocationID = OpVariable %ip_i32 Input\n"
2097                << "%in_color = OpVariable %ip_a32v4f32 Input\n"
2098                << "%out_position = OpVariable %op_a3v4f32 Output\n"
2099                << "%in_position = OpVariable %ip_a32v4f32 Input\n"
2100                << "%gl_TessLevelOuter = OpVariable %op_a4f32 Output\n"
2101                << "%gl_TessLevelInner = OpVariable %op_a2f32 Output\n";
2102         if (task != SHADER_TASK_NORMAL)
2103         {
2104             shader << getUnusedBuffer();
2105         }
2106 
2107         // Main entry point.
2108         shader << "%tessc1_main = OpFunction %void None %voidf\n"
2109                << "%tessc1_label = OpLabel\n"
2110                << "%tessc1_invocation_id = OpLoad %i32 %gl_InvocationID\n"
2111                << "%tessc1_in_color_ptr = OpAccessChain %ip_v4f32 %in_color %tessc1_invocation_id\n"
2112                << "%tessc1_in_position_ptr = OpAccessChain %ip_v4f32 %in_position %tessc1_invocation_id\n"
2113                << "%tessc1_in_color_val = OpLoad %v4f32 %tessc1_in_color_ptr\n"
2114                << "%tessc1_in_position_val = OpLoad %v4f32 %tessc1_in_position_ptr\n"
2115                << "%tessc1_out_color_ptr = OpAccessChain %op_v4f32 %out_color %tessc1_invocation_id\n"
2116                << "%tessc1_out_position_ptr = OpAccessChain %op_v4f32 %out_position %tessc1_invocation_id\n"
2117                << "OpStore %tessc1_out_color_ptr %tessc1_in_color_val\n"
2118                << "OpStore %tessc1_out_position_ptr %tessc1_in_position_val\n"
2119                << "%tessc1_is_first_invocation = OpIEqual %bool %tessc1_invocation_id %c_i32_0\n"
2120                << "OpSelectionMerge %tessc1_merge_label None\n"
2121                << "OpBranchConditional %tessc1_is_first_invocation %tessc1_first_invocation %tessc1_merge_label\n"
2122                << "%tessc1_first_invocation = OpLabel\n"
2123                << "%tessc1_tess_outer_0 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_0\n"
2124                << "%tessc1_tess_outer_1 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_1\n"
2125                << "%tessc1_tess_outer_2 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_2\n"
2126                << "%tessc1_tess_inner = OpAccessChain %op_f32 %gl_TessLevelInner %c_i32_0\n"
2127                << "OpStore %tessc1_tess_outer_0 %c_f32_1\n"
2128                << "OpStore %tessc1_tess_outer_1 %c_f32_1\n"
2129                << "OpStore %tessc1_tess_outer_2 %c_f32_1\n"
2130                << "OpStore %tessc1_tess_inner %c_f32_1\n"
2131                << "OpBranch %tessc1_merge_label\n"
2132                << "%tessc1_merge_label = OpLabel\n"
2133                << "OpReturn\n"
2134                << "OpFunctionEnd\n";
2135         if (task == SHADER_TASK_UNUSED_FUNC)
2136         {
2137             shader << getUnusedFunctionBody();
2138         }
2139 
2140         dst.spirvAsmSources.add("tessc") << shader.str();
2141     }
2142 
2143     if (ctx.shaderTasks[SHADER_TASK_INDEX_TESS_EVAL] != SHADER_TASK_NONE)
2144     {
2145         const ShaderTask &task = ctx.shaderTasks[SHADER_TASK_INDEX_TESS_EVAL];
2146         std::ostringstream shader;
2147 
2148         if (task != SHADER_TASK_NORMAL)
2149         {
2150             shader << getOpCapabilityShader();
2151         }
2152         shader << "OpCapability Tessellation\n"
2153                << "OpMemoryModel Logical GLSL450\n";
2154 
2155         // Entry point.
2156         shader << "OpEntryPoint TessellationEvaluation %tesse1_main \"main\" %stream %gl_tessCoord %in_position "
2157                   "%out_color %in_color \n";
2158         if (task == SHADER_TASK_UNUSED_FUNC)
2159         {
2160             shader << getUnusedEntryPoint();
2161         }
2162         shader << "OpExecutionMode %tesse1_main Triangles\n"
2163                << "OpExecutionMode %tesse1_main SpacingEqual\n"
2164                << "OpExecutionMode %tesse1_main VertexOrderCcw\n";
2165 
2166         // Decorations.
2167         shader << "OpMemberDecorate %per_vertex_out 0 BuiltIn Position\n"
2168                << "OpMemberDecorate %per_vertex_out 1 BuiltIn PointSize\n"
2169                << "OpMemberDecorate %per_vertex_out 2 BuiltIn ClipDistance\n"
2170                << "OpMemberDecorate %per_vertex_out 3 BuiltIn CullDistance\n"
2171                << "OpDecorate %per_vertex_out Block\n"
2172                << "OpDecorate %gl_tessCoord BuiltIn TessCoord\n"
2173                << "OpDecorate %in_position Location 2\n"
2174                << "OpDecorate %out_color Location 1\n"
2175                << "OpDecorate %in_color Location 1\n";
2176         if (task != SHADER_TASK_NORMAL)
2177         {
2178             shader << getUnusedDecorations(ctx.variableLocation);
2179         }
2180 
2181         // Standard types, constants and arrays.
2182         shader << "; Start of standard types, constants and arrays\n"
2183                << SPIRV_ASSEMBLY_TYPES << SPIRV_ASSEMBLY_CONSTANTS << SPIRV_ASSEMBLY_ARRAYS
2184                << "; End of standard types, constants and arrays\n";
2185         if (task != SHADER_TASK_NORMAL)
2186         {
2187             shader << getUnusedTypesAndConstants();
2188         }
2189 
2190         // Variables.
2191         shader << "%per_vertex_out = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
2192                << "%op_per_vertex_out = OpTypePointer Output %per_vertex_out\n"
2193                << "%stream = OpVariable %op_per_vertex_out Output\n"
2194                << "%gl_tessCoord = OpVariable %ip_v3f32 Input\n"
2195                << "%in_position = OpVariable %ip_a32v4f32 Input\n"
2196                << "%out_color = OpVariable %op_v4f32 Output\n"
2197                << "%in_color = OpVariable %ip_a32v4f32 Input\n";
2198         if (task != SHADER_TASK_NORMAL)
2199         {
2200             shader << getUnusedBuffer();
2201         }
2202 
2203         // Main entry point.
2204         shader << "%tesse1_main = OpFunction %void None %voidf\n"
2205                << "%tesse1_label = OpLabel\n"
2206                << "%tesse1_tc_0_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_0\n"
2207                << "%tesse1_tc_1_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_1\n"
2208                << "%tesse1_tc_2_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_2\n"
2209                << "%tesse1_tc_0 = OpLoad %f32 %tesse1_tc_0_ptr\n"
2210                << "%tesse1_tc_1 = OpLoad %f32 %tesse1_tc_1_ptr\n"
2211                << "%tesse1_tc_2 = OpLoad %f32 %tesse1_tc_2_ptr\n"
2212                << "%tesse1_in_pos_0_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_0\n"
2213                << "%tesse1_in_pos_1_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_1\n"
2214                << "%tesse1_in_pos_2_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_2\n"
2215                << "%tesse1_in_pos_0 = OpLoad %v4f32 %tesse1_in_pos_0_ptr\n"
2216                << "%tesse1_in_pos_1 = OpLoad %v4f32 %tesse1_in_pos_1_ptr\n"
2217                << "%tesse1_in_pos_2 = OpLoad %v4f32 %tesse1_in_pos_2_ptr\n"
2218                << "%tesse1_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_0 %tesse1_tc_0\n"
2219                << "%tesse1_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_1 %tesse1_tc_1\n"
2220                << "%tesse1_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_2 %tesse1_tc_2\n"
2221                << "%tesse1_out_pos_ptr = OpAccessChain %op_v4f32 %stream %c_i32_0\n"
2222                << "%tesse1_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse1_in_pos_0_weighted %tesse1_in_pos_1_weighted\n"
2223                << "%tesse1_computed_out = OpFAdd %v4f32 %tesse1_in_pos_0_plus_pos_1 %tesse1_in_pos_2_weighted\n"
2224                << "OpStore %tesse1_out_pos_ptr %tesse1_computed_out\n"
2225                << "%tesse1_in_clr_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
2226                << "%tesse1_in_clr_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
2227                << "%tesse1_in_clr_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
2228                << "%tesse1_in_clr_0 = OpLoad %v4f32 %tesse1_in_clr_0_ptr\n"
2229                << "%tesse1_in_clr_1 = OpLoad %v4f32 %tesse1_in_clr_1_ptr\n"
2230                << "%tesse1_in_clr_2 = OpLoad %v4f32 %tesse1_in_clr_2_ptr\n"
2231                << "%tesse1_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_0 %tesse1_tc_0\n"
2232                << "%tesse1_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_1 %tesse1_tc_1\n"
2233                << "%tesse1_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_2 %tesse1_tc_2\n"
2234                << "%tesse1_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse1_in_clr_0_weighted %tesse1_in_clr_1_weighted\n"
2235                << "%tesse1_computed_clr = OpFAdd %v4f32 %tesse1_in_clr_0_plus_col_1 %tesse1_in_clr_2_weighted\n"
2236                << "OpStore %out_color %tesse1_computed_clr\n"
2237                << "OpReturn\n"
2238                << "OpFunctionEnd\n";
2239         if (task == SHADER_TASK_UNUSED_FUNC)
2240         {
2241             shader << getUnusedFunctionBody();
2242         }
2243 
2244         dst.spirvAsmSources.add("tesse") << shader.str();
2245     }
2246 
2247     if (ctx.shaderTasks[SHADER_TASK_INDEX_FRAGMENT] != SHADER_TASK_NONE)
2248     {
2249         const ShaderTask &task = ctx.shaderTasks[SHADER_TASK_INDEX_FRAGMENT];
2250         std::ostringstream shader;
2251 
2252         shader << "OpCapability Shader\n"
2253                << "OpMemoryModel Logical GLSL450\n";
2254 
2255         // Entry point.
2256         shader << "OpEntryPoint Fragment %main \"main\" %vtxColor %fragColor\n";
2257         if (task == SHADER_TASK_UNUSED_FUNC)
2258         {
2259             shader << getUnusedEntryPoint();
2260         }
2261         shader << "OpExecutionMode %main OriginUpperLeft\n";
2262 
2263         // Decorations.
2264         shader << "OpDecorate %fragColor Location 0\n"
2265                << "OpDecorate %vtxColor Location 1\n";
2266         if (task != SHADER_TASK_NORMAL)
2267         {
2268             shader << getUnusedDecorations(ctx.variableLocation);
2269         }
2270 
2271         // Standard types, constants and arrays.
2272         shader << "; Start of standard types, constants and arrays\n"
2273                << SPIRV_ASSEMBLY_TYPES << SPIRV_ASSEMBLY_CONSTANTS << SPIRV_ASSEMBLY_ARRAYS
2274                << "; End of standard types, constants and arrays\n";
2275         if (task != SHADER_TASK_NORMAL)
2276         {
2277             shader << getUnusedTypesAndConstants();
2278         }
2279 
2280         // Variables.
2281         shader << "%fragColor = OpVariable %op_v4f32 Output\n"
2282                << "%vtxColor = OpVariable %ip_v4f32 Input\n";
2283         if (task != SHADER_TASK_NORMAL)
2284         {
2285             shader << getUnusedBuffer();
2286         }
2287 
2288         // Main entry point.
2289         shader << "%main = OpFunction %void None %voidf\n"
2290                << "%label_main = OpLabel\n"
2291                << "%tmp1 = OpLoad %v4f32 %vtxColor\n"
2292                << "OpStore %fragColor %tmp1\n"
2293                << "OpReturn\n"
2294                << "OpFunctionEnd\n";
2295         if (task == SHADER_TASK_UNUSED_FUNC)
2296         {
2297             shader << getUnusedFunctionBody();
2298         }
2299 
2300         dst.spirvAsmSources.add("frag") << shader.str();
2301     }
2302 }
2303 
createMultipleEntries(vk::SourceCollections & dst,InstanceContext)2304 void createMultipleEntries(vk::SourceCollections &dst, InstanceContext)
2305 {
2306     dst.spirvAsmSources.add("vert") <<
2307         // This module contains 2 vertex shaders. One that is a passthrough
2308         // and a second that inverts the color of the output (1.0 - color).
2309         "OpCapability Shader\n"
2310         "OpMemoryModel Logical GLSL450\n"
2311         "OpEntryPoint Vertex %main \"vert1\" %Position %vtxColor %color %vtxPosition %vertex_id %instance_id\n"
2312         "OpEntryPoint Vertex %main2 \"vert2\" %Position %vtxColor %color %vtxPosition %vertex_id %instance_id\n"
2313 
2314         "OpDecorate %vtxPosition Location 2\n"
2315         "OpDecorate %Position Location 0\n"
2316         "OpDecorate %vtxColor Location 1\n"
2317         "OpDecorate %color Location 1\n"
2318         "OpDecorate %vertex_id BuiltIn VertexIndex\n"
2319         "OpDecorate %instance_id BuiltIn InstanceIndex\n" SPIRV_ASSEMBLY_TYPES SPIRV_ASSEMBLY_CONSTANTS
2320             SPIRV_ASSEMBLY_ARRAYS "%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
2321         "%vtxPosition = OpVariable %op_v4f32 Output\n"
2322         "%Position = OpVariable %ip_v4f32 Input\n"
2323         "%vtxColor = OpVariable %op_v4f32 Output\n"
2324         "%color = OpVariable %ip_v4f32 Input\n"
2325         "%vertex_id = OpVariable %ip_i32 Input\n"
2326         "%instance_id = OpVariable %ip_i32 Input\n"
2327 
2328         "%main = OpFunction %void None %voidf\n"
2329         "%label = OpLabel\n"
2330         "%tmp_position = OpLoad %v4f32 %Position\n"
2331         "OpStore %vtxPosition %tmp_position\n"
2332         "%tmp_color = OpLoad %v4f32 %color\n"
2333         "OpStore %vtxColor %tmp_color\n"
2334         "OpReturn\n"
2335         "OpFunctionEnd\n"
2336 
2337         "%main2 = OpFunction %void None %voidf\n"
2338         "%label2 = OpLabel\n"
2339         "%tmp_position2 = OpLoad %v4f32 %Position\n"
2340         "OpStore %vtxPosition %tmp_position2\n"
2341         "%tmp_color2 = OpLoad %v4f32 %color\n"
2342         "%tmp_color3 = OpFSub %v4f32 %cval %tmp_color2\n"
2343         "%tmp_color4 = OpVectorInsertDynamic %v4f32 %tmp_color3 %c_f32_1 %c_i32_3\n"
2344         "OpStore %vtxColor %tmp_color4\n"
2345         "OpReturn\n"
2346         "OpFunctionEnd\n";
2347 
2348     dst.spirvAsmSources.add("frag") <<
2349         // This is a single module that contains 2 fragment shaders.
2350         // One that passes color through and the other that inverts the output
2351         // color (1.0 - color).
2352         "OpCapability Shader\n"
2353         "OpMemoryModel Logical GLSL450\n"
2354         "OpEntryPoint Fragment %main \"frag1\" %vtxColor %fragColor\n"
2355         "OpEntryPoint Fragment %main2 \"frag2\" %vtxColor %fragColor\n"
2356         "OpExecutionMode %main OriginUpperLeft\n"
2357         "OpExecutionMode %main2 OriginUpperLeft\n"
2358 
2359         "OpDecorate %fragColor Location 0\n"
2360         "OpDecorate %vtxColor Location 1\n" SPIRV_ASSEMBLY_TYPES SPIRV_ASSEMBLY_CONSTANTS SPIRV_ASSEMBLY_ARRAYS
2361         "%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
2362         "%fragColor = OpVariable %op_v4f32 Output\n"
2363         "%vtxColor = OpVariable %ip_v4f32 Input\n"
2364 
2365         "%main = OpFunction %void None %voidf\n"
2366         "%label_main = OpLabel\n"
2367         "%tmp1 = OpLoad %v4f32 %vtxColor\n"
2368         "OpStore %fragColor %tmp1\n"
2369         "OpReturn\n"
2370         "OpFunctionEnd\n"
2371 
2372         "%main2 = OpFunction %void None %voidf\n"
2373         "%label_main2 = OpLabel\n"
2374         "%tmp2 = OpLoad %v4f32 %vtxColor\n"
2375         "%tmp3 = OpFSub %v4f32 %cval %tmp2\n"
2376         "%tmp4 = OpVectorInsertDynamic %v4f32 %tmp3 %c_f32_1 %c_i32_3\n"
2377         "OpStore %fragColor %tmp4\n"
2378         "OpReturn\n"
2379         "OpFunctionEnd\n";
2380 
2381     dst.spirvAsmSources.add("geom")
2382         << "OpCapability Geometry\n"
2383            "OpMemoryModel Logical GLSL450\n"
2384            "OpEntryPoint Geometry %geom1_main \"geom1\" %out_gl_position %gl_in %out_color %in_color\n"
2385            "OpEntryPoint Geometry %geom2_main \"geom2\" %out_gl_position %gl_in %out_color %in_color\n"
2386            "OpExecutionMode %geom1_main Triangles\n"
2387            "OpExecutionMode %geom2_main Triangles\n"
2388            "OpExecutionMode %geom1_main OutputTriangleStrip\n"
2389            "OpExecutionMode %geom2_main OutputTriangleStrip\n"
2390            "OpExecutionMode %geom1_main OutputVertices 3\n"
2391            "OpExecutionMode %geom2_main OutputVertices 3\n"
2392            "OpExecutionMode %geom1_main Invocations 1\n"
2393            "OpExecutionMode %geom2_main Invocations 1\n"
2394            "OpDecorate %out_gl_position BuiltIn Position\n"
2395            "OpMemberDecorate %per_vertex_in 0 BuiltIn Position\n"
2396            "OpMemberDecorate %per_vertex_in 1 BuiltIn PointSize\n"
2397            "OpMemberDecorate %per_vertex_in 2 BuiltIn ClipDistance\n"
2398            "OpMemberDecorate %per_vertex_in 3 BuiltIn CullDistance\n"
2399            "OpDecorate %per_vertex_in Block\n"
2400            "OpDecorate %out_color Location 1\n"
2401            "OpDecorate %in_color Location 1\n" SPIRV_ASSEMBLY_TYPES SPIRV_ASSEMBLY_CONSTANTS SPIRV_ASSEMBLY_ARRAYS
2402            "%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
2403            "%per_vertex_in = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
2404            "%a3_per_vertex_in = OpTypeArray %per_vertex_in %c_u32_3\n"
2405            "%ip_a3_per_vertex_in = OpTypePointer Input %a3_per_vertex_in\n"
2406            "%gl_in = OpVariable %ip_a3_per_vertex_in Input\n"
2407            "%out_color = OpVariable %op_v4f32 Output\n"
2408            "%in_color = OpVariable %ip_a3v4f32 Input\n"
2409            "%out_gl_position = OpVariable %op_v4f32 Output\n"
2410 
2411            "%geom1_main = OpFunction %void None %voidf\n"
2412            "%geom1_label = OpLabel\n"
2413            "%geom1_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_0 %c_i32_0\n"
2414            "%geom1_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_1 %c_i32_0\n"
2415            "%geom1_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_2 %c_i32_0\n"
2416            "%geom1_in_position_0 = OpLoad %v4f32 %geom1_gl_in_0_gl_position\n"
2417            "%geom1_in_position_1 = OpLoad %v4f32 %geom1_gl_in_1_gl_position\n"
2418            "%geom1_in_position_2 = OpLoad %v4f32 %geom1_gl_in_2_gl_position \n"
2419            "%geom1_in_color_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
2420            "%geom1_in_color_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
2421            "%geom1_in_color_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
2422            "%geom1_in_color_0 = OpLoad %v4f32 %geom1_in_color_0_ptr\n"
2423            "%geom1_in_color_1 = OpLoad %v4f32 %geom1_in_color_1_ptr\n"
2424            "%geom1_in_color_2 = OpLoad %v4f32 %geom1_in_color_2_ptr\n"
2425            "OpStore %out_gl_position %geom1_in_position_0\n"
2426            "OpStore %out_color %geom1_in_color_0\n"
2427            "OpEmitVertex\n"
2428            "OpStore %out_gl_position %geom1_in_position_1\n"
2429            "OpStore %out_color %geom1_in_color_1\n"
2430            "OpEmitVertex\n"
2431            "OpStore %out_gl_position %geom1_in_position_2\n"
2432            "OpStore %out_color %geom1_in_color_2\n"
2433            "OpEmitVertex\n"
2434            "OpEndPrimitive\n"
2435            "OpReturn\n"
2436            "OpFunctionEnd\n"
2437 
2438            "%geom2_main = OpFunction %void None %voidf\n"
2439            "%geom2_label = OpLabel\n"
2440            "%geom2_gl_in_0_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_0 %c_i32_0\n"
2441            "%geom2_gl_in_1_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_1 %c_i32_0\n"
2442            "%geom2_gl_in_2_gl_position = OpAccessChain %ip_v4f32 %gl_in %c_i32_2 %c_i32_0\n"
2443            "%geom2_in_position_0 = OpLoad %v4f32 %geom2_gl_in_0_gl_position\n"
2444            "%geom2_in_position_1 = OpLoad %v4f32 %geom2_gl_in_1_gl_position\n"
2445            "%geom2_in_position_2 = OpLoad %v4f32 %geom2_gl_in_2_gl_position \n"
2446            "%geom2_in_color_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
2447            "%geom2_in_color_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
2448            "%geom2_in_color_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
2449            "%geom2_in_color_0 = OpLoad %v4f32 %geom2_in_color_0_ptr\n"
2450            "%geom2_in_color_1 = OpLoad %v4f32 %geom2_in_color_1_ptr\n"
2451            "%geom2_in_color_2 = OpLoad %v4f32 %geom2_in_color_2_ptr\n"
2452            "%geom2_transformed_in_color_0 = OpFSub %v4f32 %cval %geom2_in_color_0\n"
2453            "%geom2_transformed_in_color_1 = OpFSub %v4f32 %cval %geom2_in_color_1\n"
2454            "%geom2_transformed_in_color_2 = OpFSub %v4f32 %cval %geom2_in_color_2\n"
2455            "%geom2_transformed_in_color_0_a = OpVectorInsertDynamic %v4f32 %geom2_transformed_in_color_0 %c_f32_1 "
2456            "%c_i32_3\n"
2457            "%geom2_transformed_in_color_1_a = OpVectorInsertDynamic %v4f32 %geom2_transformed_in_color_1 %c_f32_1 "
2458            "%c_i32_3\n"
2459            "%geom2_transformed_in_color_2_a = OpVectorInsertDynamic %v4f32 %geom2_transformed_in_color_2 %c_f32_1 "
2460            "%c_i32_3\n"
2461            "OpStore %out_gl_position %geom2_in_position_0\n"
2462            "OpStore %out_color %geom2_transformed_in_color_0_a\n"
2463            "OpEmitVertex\n"
2464            "OpStore %out_gl_position %geom2_in_position_1\n"
2465            "OpStore %out_color %geom2_transformed_in_color_1_a\n"
2466            "OpEmitVertex\n"
2467            "OpStore %out_gl_position %geom2_in_position_2\n"
2468            "OpStore %out_color %geom2_transformed_in_color_2_a\n"
2469            "OpEmitVertex\n"
2470            "OpEndPrimitive\n"
2471            "OpReturn\n"
2472            "OpFunctionEnd\n";
2473 
2474     dst.spirvAsmSources.add("tessc")
2475         << "OpCapability Tessellation\n"
2476            "OpMemoryModel Logical GLSL450\n"
2477            "OpEntryPoint TessellationControl %tessc1_main \"tessc1\" %out_color %gl_InvocationID %in_color "
2478            "%out_position %in_position %gl_TessLevelOuter %gl_TessLevelInner\n"
2479            "OpEntryPoint TessellationControl %tessc2_main \"tessc2\" %out_color %gl_InvocationID %in_color "
2480            "%out_position %in_position %gl_TessLevelOuter %gl_TessLevelInner\n"
2481            "OpExecutionMode %tessc1_main OutputVertices 3\n"
2482            "OpExecutionMode %tessc2_main OutputVertices 3\n"
2483            "OpDecorate %out_color Location 1\n"
2484            "OpDecorate %gl_InvocationID BuiltIn InvocationId\n"
2485            "OpDecorate %in_color Location 1\n"
2486            "OpDecorate %out_position Location 2\n"
2487            "OpDecorate %in_position Location 2\n"
2488            "OpDecorate %gl_TessLevelOuter Patch\n"
2489            "OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter\n"
2490            "OpDecorate %gl_TessLevelInner Patch\n"
2491            "OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner\n" SPIRV_ASSEMBLY_TYPES SPIRV_ASSEMBLY_CONSTANTS
2492                SPIRV_ASSEMBLY_ARRAYS "%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
2493            "%out_color = OpVariable %op_a3v4f32 Output\n"
2494            "%gl_InvocationID = OpVariable %ip_i32 Input\n"
2495            "%in_color = OpVariable %ip_a32v4f32 Input\n"
2496            "%out_position = OpVariable %op_a3v4f32 Output\n"
2497            "%in_position = OpVariable %ip_a32v4f32 Input\n"
2498            "%gl_TessLevelOuter = OpVariable %op_a4f32 Output\n"
2499            "%gl_TessLevelInner = OpVariable %op_a2f32 Output\n"
2500 
2501            "%tessc1_main = OpFunction %void None %voidf\n"
2502            "%tessc1_label = OpLabel\n"
2503            "%tessc1_invocation_id = OpLoad %i32 %gl_InvocationID\n"
2504            "%tessc1_in_color_ptr = OpAccessChain %ip_v4f32 %in_color %tessc1_invocation_id\n"
2505            "%tessc1_in_position_ptr = OpAccessChain %ip_v4f32 %in_position %tessc1_invocation_id\n"
2506            "%tessc1_in_color_val = OpLoad %v4f32 %tessc1_in_color_ptr\n"
2507            "%tessc1_in_position_val = OpLoad %v4f32 %tessc1_in_position_ptr\n"
2508            "%tessc1_out_color_ptr = OpAccessChain %op_v4f32 %out_color %tessc1_invocation_id\n"
2509            "%tessc1_out_position_ptr = OpAccessChain %op_v4f32 %out_position %tessc1_invocation_id\n"
2510            "OpStore %tessc1_out_color_ptr %tessc1_in_color_val\n"
2511            "OpStore %tessc1_out_position_ptr %tessc1_in_position_val\n"
2512            "%tessc1_is_first_invocation = OpIEqual %bool %tessc1_invocation_id %c_i32_0\n"
2513            "OpSelectionMerge %tessc1_merge_label None\n"
2514            "OpBranchConditional %tessc1_is_first_invocation %tessc1_first_invocation %tessc1_merge_label\n"
2515            "%tessc1_first_invocation = OpLabel\n"
2516            "%tessc1_tess_outer_0 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_0\n"
2517            "%tessc1_tess_outer_1 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_1\n"
2518            "%tessc1_tess_outer_2 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_2\n"
2519            "%tessc1_tess_inner = OpAccessChain %op_f32 %gl_TessLevelInner %c_i32_0\n"
2520            "OpStore %tessc1_tess_outer_0 %c_f32_1\n"
2521            "OpStore %tessc1_tess_outer_1 %c_f32_1\n"
2522            "OpStore %tessc1_tess_outer_2 %c_f32_1\n"
2523            "OpStore %tessc1_tess_inner %c_f32_1\n"
2524            "OpBranch %tessc1_merge_label\n"
2525            "%tessc1_merge_label = OpLabel\n"
2526            "OpReturn\n"
2527            "OpFunctionEnd\n"
2528 
2529            "%tessc2_main = OpFunction %void None %voidf\n"
2530            "%tessc2_label = OpLabel\n"
2531            "%tessc2_invocation_id = OpLoad %i32 %gl_InvocationID\n"
2532            "%tessc2_in_color_ptr = OpAccessChain %ip_v4f32 %in_color %tessc2_invocation_id\n"
2533            "%tessc2_in_position_ptr = OpAccessChain %ip_v4f32 %in_position %tessc2_invocation_id\n"
2534            "%tessc2_in_color_val = OpLoad %v4f32 %tessc2_in_color_ptr\n"
2535            "%tessc2_in_position_val = OpLoad %v4f32 %tessc2_in_position_ptr\n"
2536            "%tessc2_out_color_ptr = OpAccessChain %op_v4f32 %out_color %tessc2_invocation_id\n"
2537            "%tessc2_out_position_ptr = OpAccessChain %op_v4f32 %out_position %tessc2_invocation_id\n"
2538            "%tessc2_transformed_color = OpFSub %v4f32 %cval %tessc2_in_color_val\n"
2539            "%tessc2_transformed_color_a = OpVectorInsertDynamic %v4f32 %tessc2_transformed_color %c_f32_1 %c_i32_3\n"
2540            "OpStore %tessc2_out_color_ptr %tessc2_transformed_color_a\n"
2541            "OpStore %tessc2_out_position_ptr %tessc2_in_position_val\n"
2542            "%tessc2_is_first_invocation = OpIEqual %bool %tessc2_invocation_id %c_i32_0\n"
2543            "OpSelectionMerge %tessc2_merge_label None\n"
2544            "OpBranchConditional %tessc2_is_first_invocation %tessc2_first_invocation %tessc2_merge_label\n"
2545            "%tessc2_first_invocation = OpLabel\n"
2546            "%tessc2_tess_outer_0 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_0\n"
2547            "%tessc2_tess_outer_1 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_1\n"
2548            "%tessc2_tess_outer_2 = OpAccessChain %op_f32 %gl_TessLevelOuter %c_i32_2\n"
2549            "%tessc2_tess_inner = OpAccessChain %op_f32 %gl_TessLevelInner %c_i32_0\n"
2550            "OpStore %tessc2_tess_outer_0 %c_f32_1\n"
2551            "OpStore %tessc2_tess_outer_1 %c_f32_1\n"
2552            "OpStore %tessc2_tess_outer_2 %c_f32_1\n"
2553            "OpStore %tessc2_tess_inner %c_f32_1\n"
2554            "OpBranch %tessc2_merge_label\n"
2555            "%tessc2_merge_label = OpLabel\n"
2556            "OpReturn\n"
2557            "OpFunctionEnd\n";
2558 
2559     dst.spirvAsmSources.add("tesse")
2560         << "OpCapability Tessellation\n"
2561            "OpMemoryModel Logical GLSL450\n"
2562            "OpEntryPoint TessellationEvaluation %tesse1_main \"tesse1\" %stream %gl_tessCoord %in_position %out_color "
2563            "%in_color \n"
2564            "OpEntryPoint TessellationEvaluation %tesse2_main \"tesse2\" %stream %gl_tessCoord %in_position %out_color "
2565            "%in_color \n"
2566            "OpExecutionMode %tesse1_main Triangles\n"
2567            "OpExecutionMode %tesse1_main SpacingEqual\n"
2568            "OpExecutionMode %tesse1_main VertexOrderCcw\n"
2569            "OpExecutionMode %tesse2_main Triangles\n"
2570            "OpExecutionMode %tesse2_main SpacingEqual\n"
2571            "OpExecutionMode %tesse2_main VertexOrderCcw\n"
2572            "OpMemberDecorate %per_vertex_out 0 BuiltIn Position\n"
2573            "OpMemberDecorate %per_vertex_out 1 BuiltIn PointSize\n"
2574            "OpMemberDecorate %per_vertex_out 2 BuiltIn ClipDistance\n"
2575            "OpMemberDecorate %per_vertex_out 3 BuiltIn CullDistance\n"
2576            "OpDecorate %per_vertex_out Block\n"
2577            "OpDecorate %gl_tessCoord BuiltIn TessCoord\n"
2578            "OpDecorate %in_position Location 2\n"
2579            "OpDecorate %out_color Location 1\n"
2580            "OpDecorate %in_color Location 1\n" SPIRV_ASSEMBLY_TYPES SPIRV_ASSEMBLY_CONSTANTS SPIRV_ASSEMBLY_ARRAYS
2581            "%cval = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_0\n"
2582            "%per_vertex_out = OpTypeStruct %v4f32 %f32 %a1f32 %a1f32\n"
2583            "%op_per_vertex_out = OpTypePointer Output %per_vertex_out\n"
2584            "%stream = OpVariable %op_per_vertex_out Output\n"
2585            "%gl_tessCoord = OpVariable %ip_v3f32 Input\n"
2586            "%in_position = OpVariable %ip_a32v4f32 Input\n"
2587            "%out_color = OpVariable %op_v4f32 Output\n"
2588            "%in_color = OpVariable %ip_a32v4f32 Input\n"
2589 
2590            "%tesse1_main = OpFunction %void None %voidf\n"
2591            "%tesse1_label = OpLabel\n"
2592            "%tesse1_tc_0_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_0\n"
2593            "%tesse1_tc_1_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_1\n"
2594            "%tesse1_tc_2_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_2\n"
2595            "%tesse1_tc_0 = OpLoad %f32 %tesse1_tc_0_ptr\n"
2596            "%tesse1_tc_1 = OpLoad %f32 %tesse1_tc_1_ptr\n"
2597            "%tesse1_tc_2 = OpLoad %f32 %tesse1_tc_2_ptr\n"
2598            "%tesse1_in_pos_0_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_0\n"
2599            "%tesse1_in_pos_1_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_1\n"
2600            "%tesse1_in_pos_2_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_2\n"
2601            "%tesse1_in_pos_0 = OpLoad %v4f32 %tesse1_in_pos_0_ptr\n"
2602            "%tesse1_in_pos_1 = OpLoad %v4f32 %tesse1_in_pos_1_ptr\n"
2603            "%tesse1_in_pos_2 = OpLoad %v4f32 %tesse1_in_pos_2_ptr\n"
2604            "%tesse1_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_0 %tesse1_tc_0\n"
2605            "%tesse1_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_1 %tesse1_tc_1\n"
2606            "%tesse1_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_2 %tesse1_tc_2\n"
2607            "%tesse1_out_pos_ptr = OpAccessChain %op_v4f32 %stream %c_i32_0\n"
2608            "%tesse1_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse1_in_pos_0_weighted %tesse1_in_pos_1_weighted\n"
2609            "%tesse1_computed_out = OpFAdd %v4f32 %tesse1_in_pos_0_plus_pos_1 %tesse1_in_pos_2_weighted\n"
2610            "OpStore %tesse1_out_pos_ptr %tesse1_computed_out\n"
2611            "%tesse1_in_clr_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
2612            "%tesse1_in_clr_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
2613            "%tesse1_in_clr_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
2614            "%tesse1_in_clr_0 = OpLoad %v4f32 %tesse1_in_clr_0_ptr\n"
2615            "%tesse1_in_clr_1 = OpLoad %v4f32 %tesse1_in_clr_1_ptr\n"
2616            "%tesse1_in_clr_2 = OpLoad %v4f32 %tesse1_in_clr_2_ptr\n"
2617            "%tesse1_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_0 %tesse1_tc_0\n"
2618            "%tesse1_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_1 %tesse1_tc_1\n"
2619            "%tesse1_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_2 %tesse1_tc_2\n"
2620            "%tesse1_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse1_in_clr_0_weighted %tesse1_in_clr_1_weighted\n"
2621            "%tesse1_computed_clr = OpFAdd %v4f32 %tesse1_in_clr_0_plus_col_1 %tesse1_in_clr_2_weighted\n"
2622            "OpStore %out_color %tesse1_computed_clr\n"
2623            "OpReturn\n"
2624            "OpFunctionEnd\n"
2625 
2626            "%tesse2_main = OpFunction %void None %voidf\n"
2627            "%tesse2_label = OpLabel\n"
2628            "%tesse2_tc_0_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_0\n"
2629            "%tesse2_tc_1_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_1\n"
2630            "%tesse2_tc_2_ptr = OpAccessChain %ip_f32 %gl_tessCoord %c_u32_2\n"
2631            "%tesse2_tc_0 = OpLoad %f32 %tesse2_tc_0_ptr\n"
2632            "%tesse2_tc_1 = OpLoad %f32 %tesse2_tc_1_ptr\n"
2633            "%tesse2_tc_2 = OpLoad %f32 %tesse2_tc_2_ptr\n"
2634            "%tesse2_in_pos_0_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_0\n"
2635            "%tesse2_in_pos_1_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_1\n"
2636            "%tesse2_in_pos_2_ptr = OpAccessChain %ip_v4f32 %in_position %c_i32_2\n"
2637            "%tesse2_in_pos_0 = OpLoad %v4f32 %tesse2_in_pos_0_ptr\n"
2638            "%tesse2_in_pos_1 = OpLoad %v4f32 %tesse2_in_pos_1_ptr\n"
2639            "%tesse2_in_pos_2 = OpLoad %v4f32 %tesse2_in_pos_2_ptr\n"
2640            "%tesse2_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_pos_0 %tesse2_tc_0\n"
2641            "%tesse2_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_pos_1 %tesse2_tc_1\n"
2642            "%tesse2_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_pos_2 %tesse2_tc_2\n"
2643            "%tesse2_out_pos_ptr = OpAccessChain %op_v4f32 %stream %c_i32_0\n"
2644            "%tesse2_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse2_in_pos_0_weighted %tesse2_in_pos_1_weighted\n"
2645            "%tesse2_computed_out = OpFAdd %v4f32 %tesse2_in_pos_0_plus_pos_1 %tesse2_in_pos_2_weighted\n"
2646            "OpStore %tesse2_out_pos_ptr %tesse2_computed_out\n"
2647            "%tesse2_in_clr_0_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_0\n"
2648            "%tesse2_in_clr_1_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_1\n"
2649            "%tesse2_in_clr_2_ptr = OpAccessChain %ip_v4f32 %in_color %c_i32_2\n"
2650            "%tesse2_in_clr_0 = OpLoad %v4f32 %tesse2_in_clr_0_ptr\n"
2651            "%tesse2_in_clr_1 = OpLoad %v4f32 %tesse2_in_clr_1_ptr\n"
2652            "%tesse2_in_clr_2 = OpLoad %v4f32 %tesse2_in_clr_2_ptr\n"
2653            "%tesse2_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_clr_0 %tesse2_tc_0\n"
2654            "%tesse2_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_clr_1 %tesse2_tc_1\n"
2655            "%tesse2_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_clr_2 %tesse2_tc_2\n"
2656            "%tesse2_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse2_in_clr_0_weighted %tesse2_in_clr_1_weighted\n"
2657            "%tesse2_computed_clr = OpFAdd %v4f32 %tesse2_in_clr_0_plus_col_1 %tesse2_in_clr_2_weighted\n"
2658            "%tesse2_clr_transformed = OpFSub %v4f32 %cval %tesse2_computed_clr\n"
2659            "%tesse2_clr_transformed_a = OpVectorInsertDynamic %v4f32 %tesse2_clr_transformed %c_f32_1 %c_i32_3\n"
2660            "OpStore %out_color %tesse2_clr_transformed_a\n"
2661            "OpReturn\n"
2662            "OpFunctionEnd\n";
2663 }
2664 
compare16BitFloat(float original,uint16_t returned,RoundingModeFlags flags,tcu::TestLog & log)2665 bool compare16BitFloat(float original, uint16_t returned, RoundingModeFlags flags, tcu::TestLog &log)
2666 {
2667     // We only support RTE, RTZ, or both.
2668     DE_ASSERT(static_cast<int>(flags) > 0 && static_cast<int>(flags) < 4);
2669 
2670     const Float32 originalFloat(original);
2671     const Float16 returnedFloat(returned);
2672 
2673     // Zero are turned into zero under both RTE and RTZ.
2674     if (originalFloat.isZero())
2675     {
2676         if (returnedFloat.isZero())
2677             return true;
2678 
2679         log << TestLog::Message << "Error: expected zero but returned " << returned << TestLog::EndMessage;
2680         return false;
2681     }
2682 
2683     // Any denormalized value input into a shader may be flushed to 0.
2684     if (originalFloat.isDenorm() && returnedFloat.isZero())
2685         return true;
2686 
2687     // Inf are always turned into Inf with the same sign, too.
2688     if (originalFloat.isInf())
2689     {
2690         if (returnedFloat.isInf() && originalFloat.signBit() == returnedFloat.signBit())
2691             return true;
2692 
2693         log << TestLog::Message << "Error: expected Inf but returned " << returned << TestLog::EndMessage;
2694         return false;
2695     }
2696 
2697     // NaN are always turned into NaN, too.
2698     if (originalFloat.isNaN())
2699     {
2700         if (returnedFloat.isNaN())
2701             return true;
2702 
2703         log << TestLog::Message << "Error: expected NaN but returned " << returned << TestLog::EndMessage;
2704         return false;
2705     }
2706 
2707     // Check all rounding modes
2708     for (int bitNdx = 0; bitNdx < 2; ++bitNdx)
2709     {
2710         if ((flags & (1u << bitNdx)) == 0)
2711             continue; // This rounding mode is not selected.
2712 
2713         const Float16 expectedFloat(deFloat32To16Round(original, deRoundingMode(bitNdx)));
2714 
2715         // Any denormalized value potentially generated by any instruction in a shader may be flushed to 0.
2716         if (expectedFloat.isDenorm() && returnedFloat.isZero())
2717             return true;
2718 
2719         // If not matched in the above cases, they should have the same bit pattern.
2720         if (expectedFloat.bits() == returnedFloat.bits())
2721             return true;
2722     }
2723 
2724     log << TestLog::Message << "Error: found unmatched 32-bit and 16-bit floats: " << originalFloat.bits() << " vs "
2725         << returned << TestLog::EndMessage;
2726     return false;
2727 }
2728 
compare16BitFloat(uint16_t original,uint16_t returned,tcu::TestLog & log)2729 bool compare16BitFloat(uint16_t original, uint16_t returned, tcu::TestLog &log)
2730 {
2731     const Float16 originalFloat(original);
2732     const Float16 returnedFloat(returned);
2733 
2734     if (originalFloat.isZero())
2735     {
2736         if (returnedFloat.isZero())
2737             return true;
2738 
2739         log << TestLog::Message << "Error: expected zero but returned " << returned << TestLog::EndMessage;
2740         return false;
2741     }
2742 
2743     // Any denormalized value input into a shader or potentially generated by any instruction in a shader
2744     // may be flushed to 0.
2745     if (originalFloat.isDenorm() && returnedFloat.isZero())
2746         return true;
2747 
2748     // Inf are always turned into Inf with the same sign, too.
2749     if (originalFloat.isInf())
2750     {
2751         if (returnedFloat.isInf() && originalFloat.signBit() == returnedFloat.signBit())
2752             return true;
2753 
2754         log << TestLog::Message << "Error: expected Inf but returned " << returned << TestLog::EndMessage;
2755         return false;
2756     }
2757 
2758     // NaN are always turned into NaN, too.
2759     if (originalFloat.isNaN())
2760     {
2761         if (returnedFloat.isNaN())
2762             return true;
2763 
2764         log << TestLog::Message << "Error: expected NaN but returned " << returned << TestLog::EndMessage;
2765         return false;
2766     }
2767 
2768     // If not matched in the above cases, they should have the same bit pattern.
2769     if (originalFloat.bits() == returnedFloat.bits())
2770         return true;
2771 
2772     log << TestLog::Message << "Error: found unmatched 16-bit and 16-bit floats: " << original << " vs " << returned
2773         << TestLog::EndMessage;
2774     return false;
2775 }
2776 
compare16BitFloat(uint16_t original,float returned,tcu::TestLog & log)2777 bool compare16BitFloat(uint16_t original, float returned, tcu::TestLog &log)
2778 {
2779     const Float16 originalFloat(original);
2780     const Float32 returnedFloat(returned);
2781 
2782     // Zero are turned into zero under both RTE and RTZ.
2783     if (originalFloat.isZero())
2784     {
2785         if (returnedFloat.isZero())
2786             return true;
2787 
2788         log << TestLog::Message << "Error: expected zero but returned " << returned << TestLog::EndMessage;
2789         return false;
2790     }
2791 
2792     // Any denormalized value input into a shader may be flushed to 0.
2793     if (originalFloat.isDenorm() && returnedFloat.isZero())
2794         return true;
2795 
2796     // Inf are always turned into Inf with the same sign, too.
2797     if (originalFloat.isInf())
2798     {
2799         if (returnedFloat.isInf() && originalFloat.signBit() == returnedFloat.signBit())
2800             return true;
2801 
2802         log << TestLog::Message << "Error: expected Inf but returned " << returned << TestLog::EndMessage;
2803         return false;
2804     }
2805 
2806     // NaN are always turned into NaN, too.
2807     if (originalFloat.isNaN())
2808     {
2809         if (returnedFloat.isNaN())
2810             return true;
2811 
2812         log << TestLog::Message << "Error: expected NaN but returned " << returned << TestLog::EndMessage;
2813         return false;
2814     }
2815 
2816     // In all other cases, conversion should be exact.
2817     const Float32 expectedFloat(deFloat16To32(original));
2818     if (expectedFloat.bits() == returnedFloat.bits())
2819         return true;
2820 
2821     log << TestLog::Message << "Error: found unmatched 16-bit and 32-bit floats: " << original << " vs "
2822         << returnedFloat.bits() << TestLog::EndMessage;
2823     return false;
2824 }
2825 
compare16BitFloat(deFloat16 original,deFloat16 returned,std::string & error)2826 bool compare16BitFloat(deFloat16 original, deFloat16 returned, std::string &error)
2827 {
2828     std::ostringstream log;
2829     const Float16 originalFloat(original);
2830     const Float16 returnedFloat(returned);
2831 
2832     if (originalFloat.isZero())
2833     {
2834         if (returnedFloat.isZero())
2835             return true;
2836 
2837         log << "Error: expected zero but returned " << std::hex << "0x" << returned << " (" << returnedFloat.asFloat()
2838             << ")";
2839         error = log.str();
2840         return false;
2841     }
2842 
2843     // Any denormalized value input into a shader may be flushed to 0.
2844     if (originalFloat.isDenorm() && returnedFloat.isZero())
2845         return true;
2846 
2847     // Inf are always turned into Inf with the same sign, too.
2848     if (originalFloat.isInf())
2849     {
2850         if (returnedFloat.isInf() && originalFloat.signBit() == returnedFloat.signBit())
2851             return true;
2852 
2853         log << "Error: expected Inf but returned " << std::hex << "0x" << returned << " (" << returnedFloat.asFloat()
2854             << ")";
2855         error = log.str();
2856         return false;
2857     }
2858 
2859     // NaN are always turned into NaN, too.
2860     if (originalFloat.isNaN())
2861     {
2862         if (returnedFloat.isNaN())
2863             return true;
2864 
2865         log << "Error: expected NaN but returned " << std::hex << "0x" << returned << " (" << returnedFloat.asFloat()
2866             << ")";
2867         error = log.str();
2868         return false;
2869     }
2870 
2871     // Any denormalized value potentially generated by any instruction in a shader may be flushed to 0.
2872     if (originalFloat.isDenorm() && returnedFloat.isZero())
2873         return true;
2874 
2875     // If not matched in the above cases, they should have the same bit pattern.
2876     if (originalFloat.bits() == returnedFloat.bits())
2877         return true;
2878 
2879     log << "Error: found unmatched 16-bit and 16-bit floats: 0x" << std::hex << original << " <=> 0x" << returned
2880         << " (" << originalFloat.asFloat() << " <=> " << returnedFloat.asFloat() << ")";
2881     error = log.str();
2882     return false;
2883 }
2884 
compare16BitFloat64(double original,uint16_t returned,RoundingModeFlags flags,tcu::TestLog & log)2885 bool compare16BitFloat64(double original, uint16_t returned, RoundingModeFlags flags, tcu::TestLog &log)
2886 {
2887     // We only support RTE, RTZ, or both.
2888     DE_ASSERT(static_cast<int>(flags) > 0 && static_cast<int>(flags) < 4);
2889 
2890     const Float64 originalFloat(original);
2891     const Float16 returnedFloat(returned);
2892 
2893     // Zero are turned into zero under both RTE and RTZ.
2894     if (originalFloat.isZero())
2895     {
2896         if (returnedFloat.isZero())
2897             return true;
2898 
2899         log << TestLog::Message << "Error: expected zero but returned " << returned << TestLog::EndMessage;
2900         return false;
2901     }
2902 
2903     // Any denormalized value input into a shader may be flushed to 0.
2904     if (originalFloat.isDenorm() && returnedFloat.isZero())
2905         return true;
2906 
2907     // Inf are always turned into Inf with the same sign, too.
2908     if (originalFloat.isInf())
2909     {
2910         if (returnedFloat.isInf() && originalFloat.signBit() == returnedFloat.signBit())
2911             return true;
2912 
2913         log << TestLog::Message << "Error: expected Inf but returned " << returned << TestLog::EndMessage;
2914         return false;
2915     }
2916 
2917     // NaN are always turned into NaN, too.
2918     if (originalFloat.isNaN())
2919     {
2920         if (returnedFloat.isNaN())
2921             return true;
2922 
2923         log << TestLog::Message << "Error: expected NaN but returned " << returned << TestLog::EndMessage;
2924         return false;
2925     }
2926 
2927     // Check all rounding modes
2928     for (int bitNdx = 0; bitNdx < 2; ++bitNdx)
2929     {
2930         if ((flags & (1u << bitNdx)) == 0)
2931             continue; // This rounding mode is not selected.
2932 
2933         const Float16 expectedFloat(deFloat64To16Round(original, deRoundingMode(bitNdx)));
2934 
2935         // Any denormalized value potentially generated by any instruction in a shader may be flushed to 0.
2936         if (expectedFloat.isDenorm() && returnedFloat.isZero())
2937             return true;
2938 
2939         // If not matched in the above cases, they should have the same bit pattern.
2940         if (expectedFloat.bits() == returnedFloat.bits())
2941             return true;
2942     }
2943 
2944     log << TestLog::Message << "Error: found unmatched 64-bit and 16-bit floats: " << originalFloat.bits() << " vs "
2945         << returned << TestLog::EndMessage;
2946     return false;
2947 }
2948 
compare32BitFloat(float expected,float returned,tcu::TestLog & log)2949 bool compare32BitFloat(float expected, float returned, tcu::TestLog &log)
2950 {
2951     const Float32 expectedFloat(expected);
2952     const Float32 returnedFloat(returned);
2953 
2954     // Any denormalized value potentially generated by any instruction in a shader may be flushed to 0.
2955     if (expectedFloat.isDenorm() && returnedFloat.isZero())
2956         return true;
2957 
2958     {
2959         const Float16 originalFloat(deFloat32To16(expected));
2960 
2961         // Any denormalized value input into a shader may be flushed to 0.
2962         if (originalFloat.isDenorm() && returnedFloat.isZero())
2963             return true;
2964     }
2965 
2966     if (expectedFloat.isNaN())
2967     {
2968         if (returnedFloat.isNaN())
2969             return true;
2970 
2971         log << TestLog::Message << "Error: expected NaN but returned " << returned << TestLog::EndMessage;
2972         return false;
2973     }
2974 
2975     if (returned == expected)
2976         return true;
2977 
2978     log << TestLog::Message << "Error: found unmatched 32-bit float: expected " << expectedFloat.bits()
2979         << " vs. returned " << returnedFloat.bits() << TestLog::EndMessage;
2980     return false;
2981 }
2982 
compare64BitFloat(double expected,double returned,tcu::TestLog & log)2983 bool compare64BitFloat(double expected, double returned, tcu::TestLog &log)
2984 {
2985     const Float64 expectedDouble(expected);
2986     const Float64 returnedDouble(returned);
2987 
2988     // Any denormalized value potentially generated by any instruction in a shader may be flushed to 0.
2989     if (expectedDouble.isDenorm() && returnedDouble.isZero())
2990         return true;
2991 
2992     {
2993         const Float16 originalDouble(deFloat64To16(expected));
2994 
2995         // Any denormalized value input into a shader may be flushed to 0.
2996         if (originalDouble.isDenorm() && returnedDouble.isZero())
2997             return true;
2998     }
2999 
3000     if (expectedDouble.isNaN())
3001     {
3002         if (returnedDouble.isNaN())
3003             return true;
3004 
3005         log << TestLog::Message << "Error: expected NaN but returned " << returned << TestLog::EndMessage;
3006         return false;
3007     }
3008 
3009     if (returned == expected)
3010         return true;
3011 
3012     log << TestLog::Message << "Error: found unmatched 64-bit float: expected " << expectedDouble.bits()
3013         << " vs. returned " << returnedDouble.bits() << TestLog::EndMessage;
3014     return false;
3015 }
3016 
createBufferForResource(const DeviceInterface & vk,const VkDevice vkDevice,const Resource & resource,uint32_t queueFamilyIndex)3017 Move<VkBuffer> createBufferForResource(const DeviceInterface &vk, const VkDevice vkDevice, const Resource &resource,
3018                                        uint32_t queueFamilyIndex)
3019 {
3020     const vk::VkDescriptorType resourceType = resource.getDescriptorType();
3021 
3022     vector<uint8_t> resourceBytes;
3023     resource.getBytes(resourceBytes);
3024 
3025     const VkBufferCreateInfo resourceBufferParams = {
3026         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,                            // sType
3027         DE_NULL,                                                         // pNext
3028         (VkBufferCreateFlags)0,                                          // flags
3029         (VkDeviceSize)resourceBytes.size(),                              // size
3030         (VkBufferUsageFlags)getMatchingBufferUsageFlagBit(resourceType), // usage
3031         VK_SHARING_MODE_EXCLUSIVE,                                       // sharingMode
3032         1u,                                                              // queueFamilyCount
3033         &queueFamilyIndex,                                               // pQueueFamilyIndices
3034     };
3035 
3036     return createBuffer(vk, vkDevice, &resourceBufferParams);
3037 }
3038 
createImageForResource(const DeviceInterface & vk,const VkDevice vkDevice,const Resource & resource,VkFormat inputFormat,uint32_t queueFamilyIndex)3039 Move<VkImage> createImageForResource(const DeviceInterface &vk, const VkDevice vkDevice, const Resource &resource,
3040                                      VkFormat inputFormat, uint32_t queueFamilyIndex)
3041 {
3042     const VkImageCreateInfo resourceImageParams = {
3043         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                      // VkStructureType sType;
3044         DE_NULL,                                                  // const void* pNext;
3045         0u,                                                       // VkImageCreateFlags flags;
3046         VK_IMAGE_TYPE_2D,                                         // VkImageType imageType;
3047         inputFormat,                                              // VkFormat format;
3048         {8, 8, 1},                                                // VkExtent3D extent;
3049         1u,                                                       // uint32_t mipLevels;
3050         1u,                                                       // uint32_t arraySize;
3051         VK_SAMPLE_COUNT_1_BIT,                                    // uint32_t samples;
3052         VK_IMAGE_TILING_OPTIMAL,                                  // VkImageTiling tiling;
3053         getMatchingImageUsageFlags(resource.getDescriptorType()), // VkImageUsageFlags usage;
3054         VK_SHARING_MODE_EXCLUSIVE,                                // VkSharingMode sharingMode;
3055         1u,                                                       // uint32_t queueFamilyCount;
3056         &queueFamilyIndex,                                        // const uint32_t* pQueueFamilyIndices;
3057         VK_IMAGE_LAYOUT_UNDEFINED                                 // VkImageLayout initialLayout;
3058     };
3059 
3060     return createImage(vk, vkDevice, &resourceImageParams);
3061 }
3062 
copyBufferToImage(Context & context,const DeviceInterface & vk,const VkDevice & device,const VkQueue & queue,VkCommandPool cmdPool,VkCommandBuffer cmdBuffer,VkBuffer buffer,VkImage image,VkImageAspectFlags aspect)3063 void copyBufferToImage(Context &context, const DeviceInterface &vk, const VkDevice &device, const VkQueue &queue,
3064                        VkCommandPool cmdPool, VkCommandBuffer cmdBuffer, VkBuffer buffer, VkImage image,
3065                        VkImageAspectFlags aspect)
3066 {
3067     const VkBufferImageCopy copyRegion = {
3068         0u, // VkDeviceSize bufferOffset;
3069         0u, // uint32_t bufferRowLength;
3070         0u, // uint32_t bufferImageHeight;
3071         {
3072             aspect, // VkImageAspectFlags aspect;
3073             0u,     // uint32_t mipLevel;
3074             0u,     // uint32_t baseArrayLayer;
3075             1u,     // uint32_t layerCount;
3076         },          // VkImageSubresourceLayers imageSubresource;
3077         {0, 0, 0},  // VkOffset3D imageOffset;
3078         {8, 8, 1}   // VkExtent3D imageExtent;
3079     };
3080 
3081     // Copy buffer to image
3082     beginCommandBuffer(vk, cmdBuffer);
3083 
3084     copyBufferToImage(vk, cmdBuffer, buffer, VK_WHOLE_SIZE, vector<VkBufferImageCopy>(1, copyRegion), aspect, 1u, 1u,
3085                       image, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
3086 
3087     endCommandBuffer(vk, cmdBuffer);
3088 
3089     submitCommandsAndWait(vk, device, queue, cmdBuffer);
3090     context.resetCommandPoolForVKSC(device, cmdPool);
3091 }
3092 
getImageAspectFlags(VkFormat format)3093 VkImageAspectFlags getImageAspectFlags(VkFormat format)
3094 {
3095     const tcu::TextureFormat::ChannelOrder channelOrder = vk::mapVkFormat(format).order;
3096     VkImageAspectFlags aspectFlags                      = (VkImageAspectFlags)0u;
3097 
3098     if (tcu::hasDepthComponent(channelOrder))
3099         aspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
3100 
3101     if (tcu::hasStencilComponent(channelOrder))
3102         aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
3103 
3104     if (!aspectFlags)
3105         aspectFlags |= VK_IMAGE_ASPECT_COLOR_BIT;
3106 
3107     return aspectFlags;
3108 }
3109 
runAndVerifyUnusedVariablePipeline(Context & context,UnusedVariableContext unusedVariableContext)3110 TestStatus runAndVerifyUnusedVariablePipeline(Context &context, UnusedVariableContext unusedVariableContext)
3111 {
3112     return runAndVerifyDefaultPipeline(context, unusedVariableContext.instanceContext);
3113 }
3114 
runAndVerifyDefaultPipeline(Context & context,InstanceContext instance)3115 TestStatus runAndVerifyDefaultPipeline(Context &context, InstanceContext instance)
3116 {
3117     if (getMinRequiredVulkanVersion(instance.resources.spirvVersion) > context.getUsedApiVersion())
3118     {
3119         TCU_THROW(NotSupportedError,
3120                   string("Vulkan higher than or equal to " +
3121                          getVulkanName(getMinRequiredVulkanVersion(instance.resources.spirvVersion)) +
3122                          " is required for this test to run")
3123                       .c_str());
3124     }
3125 
3126     const DeviceInterface &vk               = context.getDeviceInterface();
3127     const InstanceInterface &vkInstance     = context.getInstanceInterface();
3128     const VkPhysicalDevice vkPhysicalDevice = context.getPhysicalDevice();
3129     const uint32_t queueFamilyIndex         = context.getUniversalQueueFamilyIndex();
3130     const VkQueue queue                     = context.getUniversalQueue();
3131     const VkDevice &device                  = context.getDevice();
3132     Allocator &allocator                    = context.getDefaultAllocator();
3133     vector<ModuleHandleSp> modules;
3134     map<VkShaderStageFlagBits, VkShaderModule> moduleByStage;
3135     const uint32_t fullRenderSize    = 256;
3136     const uint32_t quarterRenderSize = 64;
3137     const tcu::UVec2 renderSize(fullRenderSize, fullRenderSize);
3138     const int testSpecificSeed     = 31354125;
3139     const int seed                 = context.getTestContext().getCommandLine().getBaseSeed() ^ testSpecificSeed;
3140     bool supportsGeometry          = false;
3141     bool supportsTessellation      = false;
3142     bool hasGeometry               = false;
3143     bool hasTessellation           = false;
3144     const bool hasPushConstants    = !instance.pushConstants.empty();
3145     const uint32_t numInResources  = static_cast<uint32_t>(instance.resources.inputs.size());
3146     const uint32_t numOutResources = static_cast<uint32_t>(instance.resources.outputs.size());
3147     const uint32_t numResources    = numInResources + numOutResources;
3148     const bool needInterface       = !instance.interfaces.empty();
3149     const VkPhysicalDeviceFeatures &features = context.getDeviceFeatures();
3150     const Vec4 defaulClearColor(0.125f, 0.25f, 0.75f, 1.0f);
3151     bool splitRenderArea = instance.splitRenderArea;
3152 
3153     const uint32_t renderDimension = splitRenderArea ? quarterRenderSize : fullRenderSize;
3154     const int numRenderSegments    = splitRenderArea ? 4 : 1;
3155 
3156     supportsGeometry     = features.geometryShader == VK_TRUE;
3157     supportsTessellation = features.tessellationShader == VK_TRUE;
3158     hasGeometry          = (instance.requiredStages & VK_SHADER_STAGE_GEOMETRY_BIT);
3159     hasTessellation      = (instance.requiredStages & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) ||
3160                       (instance.requiredStages & VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
3161 
3162     if (hasGeometry && !supportsGeometry)
3163     {
3164         TCU_THROW(NotSupportedError, "Geometry not supported");
3165     }
3166 
3167     if (hasTessellation && !supportsTessellation)
3168     {
3169         TCU_THROW(NotSupportedError, "Tessellation not supported");
3170     }
3171 
3172     // Check all required extensions are supported
3173     for (std::vector<std::string>::const_iterator i = instance.requiredDeviceExtensions.begin();
3174          i != instance.requiredDeviceExtensions.end(); ++i)
3175     {
3176         if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), *i))
3177             TCU_THROW(NotSupportedError, (std::string("Extension not supported: ") + *i).c_str());
3178     }
3179 
3180 #ifndef CTS_USES_VULKANSC
3181     if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
3182         !context.getPortabilitySubsetFeatures().mutableComparisonSamplers)
3183     {
3184         // In portability when mutableComparisonSamplers is false then
3185         // VkSamplerCreateInfo can't have compareEnable set to true
3186         for (uint32_t inputNdx = 0; inputNdx < numInResources; ++inputNdx)
3187         {
3188             const Resource &resource = instance.resources.inputs[inputNdx];
3189             const bool hasSampler    = (resource.getDescriptorType() == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
3190                                     (resource.getDescriptorType() == VK_DESCRIPTOR_TYPE_SAMPLER) ||
3191                                     (resource.getDescriptorType() == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
3192             if (hasSampler && tcu::hasDepthComponent(vk::mapVkFormat(instance.resources.inputFormat).order))
3193             {
3194                 TCU_THROW(
3195                     NotSupportedError,
3196                     "VK_KHR_portability_subset: mutableComparisonSamplers are not supported by this implementation");
3197             }
3198         }
3199     }
3200 #endif // CTS_USES_VULKANSC
3201 
3202     {
3203         VulkanFeatures localRequired = instance.requestedFeatures;
3204 
3205         const VkShaderStageFlags vertexPipelineStoresAndAtomicsAffected =
3206             vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT |
3207             vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | vk::VK_SHADER_STAGE_GEOMETRY_BIT;
3208 
3209         // reset fragment stores and atomics feature requirement
3210         if ((localRequired.coreFeatures.fragmentStoresAndAtomics != false) &&
3211             (instance.customizedStages & vk::VK_SHADER_STAGE_FRAGMENT_BIT) == 0)
3212         {
3213             localRequired.coreFeatures.fragmentStoresAndAtomics = false;
3214         }
3215 
3216         // reset vertex pipeline stores and atomics feature requirement
3217         if (localRequired.coreFeatures.vertexPipelineStoresAndAtomics != false &&
3218             (instance.customizedStages & vertexPipelineStoresAndAtomicsAffected) == 0)
3219         {
3220             localRequired.coreFeatures.vertexPipelineStoresAndAtomics = false;
3221         }
3222 
3223         const char *unsupportedFeature = DE_NULL;
3224         if (!isVulkanFeaturesSupported(context, localRequired, &unsupportedFeature))
3225             TCU_THROW(NotSupportedError,
3226                       std::string("At least following requested feature not supported: ") + unsupportedFeature);
3227     }
3228 
3229     // Check Interface Input/Output formats are supported
3230     if (needInterface)
3231     {
3232         VkFormatProperties formatProperties;
3233         vkInstance.getPhysicalDeviceFormatProperties(vkPhysicalDevice, instance.interfaces.getInputType().getVkFormat(),
3234                                                      &formatProperties);
3235         if ((formatProperties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) == 0)
3236         {
3237             std::string error            = "Interface Input format (";
3238             const std::string formatName = getFormatName(instance.interfaces.getInputType().getVkFormat());
3239             error += formatName + ") not supported";
3240             TCU_THROW(NotSupportedError, error.c_str());
3241         }
3242 
3243         vkInstance.getPhysicalDeviceFormatProperties(
3244             vkPhysicalDevice, instance.interfaces.getOutputType().getVkFormat(), &formatProperties);
3245         if (((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0) ||
3246             ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT) == 0))
3247         {
3248             std::string error            = "Interface Output format (";
3249             const std::string formatName = getFormatName(instance.interfaces.getInputType().getVkFormat());
3250             error += formatName + ") not supported";
3251             TCU_THROW(NotSupportedError, error.c_str());
3252         }
3253     }
3254 
3255     de::Random(seed).shuffle(instance.inputColors, instance.inputColors + 4);
3256     de::Random(seed).shuffle(instance.outputColors, instance.outputColors + 4);
3257     const Vec4 vertexData[] = {
3258         // Upper left corner:
3259         Vec4(-1.0f, -1.0f, 0.0f, 1.0f), instance.inputColors[0].toVec(), //1
3260         Vec4(-0.5f, -1.0f, 0.0f, 1.0f), instance.inputColors[0].toVec(), //2
3261         Vec4(-1.0f, -0.5f, 0.0f, 1.0f), instance.inputColors[0].toVec(), //3
3262 
3263         // Upper right corner:
3264         Vec4(+0.5f, -1.0f, 0.0f, 1.0f), instance.inputColors[1].toVec(), //4
3265         Vec4(+1.0f, -1.0f, 0.0f, 1.0f), instance.inputColors[1].toVec(), //5
3266         Vec4(+1.0f, -0.5f, 0.0f, 1.0f), instance.inputColors[1].toVec(), //6
3267 
3268         // Lower left corner:
3269         Vec4(-1.0f, +0.5f, 0.0f, 1.0f), instance.inputColors[2].toVec(), //7
3270         Vec4(-0.5f, +1.0f, 0.0f, 1.0f), instance.inputColors[2].toVec(), //8
3271         Vec4(-1.0f, +1.0f, 0.0f, 1.0f), instance.inputColors[2].toVec(), //9
3272 
3273         // Lower right corner:
3274         Vec4(+1.0f, +0.5f, 0.0f, 1.0f), instance.inputColors[3].toVec(), //10
3275         Vec4(+1.0f, +1.0f, 0.0f, 1.0f), instance.inputColors[3].toVec(), //11
3276         Vec4(+0.5f, +1.0f, 0.0f, 1.0f), instance.inputColors[3].toVec(), //12
3277 
3278         // The rest is used only renderFullSquare specified. Fills area already filled with clear color
3279         // Left 1
3280         Vec4(-1.0f, -0.5f, 0.0f, 1.0f), defaulClearColor, //3
3281         Vec4(-0.5f, -1.0f, 0.0f, 1.0f), defaulClearColor, //2
3282         Vec4(-1.0f, +0.5f, 0.0f, 1.0f), defaulClearColor, //7
3283 
3284         // Left 2
3285         Vec4(-1.0f, +0.5f, 0.0f, 1.0f), defaulClearColor, //7
3286         Vec4(-0.5f, -1.0f, 0.0f, 1.0f), defaulClearColor, //2
3287         Vec4(-0.5f, +1.0f, 0.0f, 1.0f), defaulClearColor, //8
3288 
3289         // Left-Center
3290         Vec4(-0.5f, +1.0f, 0.0f, 1.0f), defaulClearColor, //8
3291         Vec4(-0.5f, -1.0f, 0.0f, 1.0f), defaulClearColor, //2
3292         Vec4(+0.5f, -1.0f, 0.0f, 1.0f), defaulClearColor, //4
3293 
3294         // Right-Center
3295         Vec4(+0.5f, -1.0f, 0.0f, 1.0f), defaulClearColor, //4
3296         Vec4(+0.5f, +1.0f, 0.0f, 1.0f), defaulClearColor, //12
3297         Vec4(-0.5f, +1.0f, 0.0f, 1.0f), defaulClearColor, //8
3298 
3299         // Right 2
3300         Vec4(+0.5f, -1.0f, 0.0f, 1.0f), defaulClearColor, //4
3301         Vec4(+1.0f, -0.5f, 0.0f, 1.0f), defaulClearColor, //6
3302         Vec4(+0.5f, +1.0f, 0.0f, 1.0f), defaulClearColor, //12
3303 
3304         // Right 1
3305         Vec4(+0.5f, +1.0f, 0.0f, 1.0f), defaulClearColor, //12
3306         Vec4(+1.0f, -0.5f, 0.0f, 1.0f), defaulClearColor, //6
3307         Vec4(+1.0f, +0.5f, 0.0f, 1.0f), defaulClearColor, //10
3308     };
3309 
3310     const size_t singleVertexDataSize = 2 * sizeof(Vec4);
3311     const size_t vertexCount          = instance.renderFullSquare ? sizeof(vertexData) / singleVertexDataSize : 4 * 3;
3312     const size_t vertexDataSize       = vertexCount * singleVertexDataSize;
3313 
3314     Move<VkBuffer> vertexInputBuffer;
3315     de::MovePtr<Allocation> vertexInputMemory;
3316     Move<VkBuffer> fragOutputBuffer;
3317     de::MovePtr<Allocation> fragOutputMemory;
3318     Move<VkImage> fragOutputImage;
3319     de::MovePtr<Allocation> fragOutputImageMemory;
3320     Move<VkImageView> fragOutputImageView;
3321 
3322     const VkBufferCreateInfo vertexBufferParams = {
3323         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
3324         DE_NULL,                              // const void* pNext;
3325         0u,                                   // VkBufferCreateFlags flags;
3326         (VkDeviceSize)vertexDataSize,         // VkDeviceSize size;
3327         VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,    // VkBufferUsageFlags usage;
3328         VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
3329         1u,                                   // uint32_t queueFamilyCount;
3330         &queueFamilyIndex,                    // const uint32_t* pQueueFamilyIndices;
3331     };
3332     const Unique<VkBuffer> vertexBuffer(createBuffer(vk, device, &vertexBufferParams));
3333     const UniquePtr<Allocation> vertexBufferMemory(
3334         allocator.allocate(getBufferMemoryRequirements(vk, device, *vertexBuffer), MemoryRequirement::HostVisible));
3335 
3336     VK_CHECK(
3337         vk.bindBufferMemory(device, *vertexBuffer, vertexBufferMemory->getMemory(), vertexBufferMemory->getOffset()));
3338 
3339     const VkDeviceSize imageSizeBytes              = (VkDeviceSize)(sizeof(uint32_t) * renderSize.x() * renderSize.y());
3340     const VkBufferCreateInfo readImageBufferParams = {
3341         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
3342         DE_NULL,                              // const void* pNext;
3343         0u,                                   // VkBufferCreateFlags flags;
3344         imageSizeBytes,                       // VkDeviceSize size;
3345         VK_BUFFER_USAGE_TRANSFER_DST_BIT,     // VkBufferUsageFlags usage;
3346         VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
3347         1u,                                   // uint32_t queueFamilyCount;
3348         &queueFamilyIndex,                    // const uint32_t* pQueueFamilyIndices;
3349     };
3350     const Unique<VkBuffer> readImageBuffer(createBuffer(vk, device, &readImageBufferParams));
3351     const UniquePtr<Allocation> readImageBufferMemory(
3352         allocator.allocate(getBufferMemoryRequirements(vk, device, *readImageBuffer), MemoryRequirement::HostVisible));
3353 
3354     VK_CHECK(vk.bindBufferMemory(device, *readImageBuffer, readImageBufferMemory->getMemory(),
3355                                  readImageBufferMemory->getOffset()));
3356 
3357     VkImageCreateInfo imageParams = {
3358         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                   // VkStructureType sType;
3359         DE_NULL,                                                               // const void* pNext;
3360         0u,                                                                    // VkImageCreateFlags flags;
3361         VK_IMAGE_TYPE_2D,                                                      // VkImageType imageType;
3362         VK_FORMAT_R8G8B8A8_UNORM,                                              // VkFormat format;
3363         {renderSize.x(), renderSize.y(), 1},                                   // VkExtent3D extent;
3364         1u,                                                                    // uint32_t mipLevels;
3365         1u,                                                                    // uint32_t arraySize;
3366         VK_SAMPLE_COUNT_1_BIT,                                                 // uint32_t samples;
3367         VK_IMAGE_TILING_OPTIMAL,                                               // VkImageTiling tiling;
3368         VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
3369         VK_SHARING_MODE_EXCLUSIVE,                                             // VkSharingMode sharingMode;
3370         1u,                                                                    // uint32_t queueFamilyCount;
3371         &queueFamilyIndex,                                                     // const uint32_t* pQueueFamilyIndices;
3372         VK_IMAGE_LAYOUT_UNDEFINED,                                             // VkImageLayout initialLayout;
3373     };
3374 
3375     const Unique<VkImage> image(createImage(vk, device, &imageParams));
3376     const UniquePtr<Allocation> imageMemory(
3377         allocator.allocate(getImageMemoryRequirements(vk, device, *image), MemoryRequirement::Any));
3378 
3379     VK_CHECK(vk.bindImageMemory(device, *image, imageMemory->getMemory(), imageMemory->getOffset()));
3380 
3381     if (needInterface)
3382     {
3383         // The pipeline renders four triangles, each with three vertexes.
3384         // Test instantialization only provides four data points, each
3385         // for one triangle. So we need allocate space of three times of
3386         // input buffer's size.
3387         vector<uint8_t> inputBufferBytes;
3388         instance.interfaces.getInputBuffer()->getBytes(inputBufferBytes);
3389 
3390         const uint32_t inputNumBytes = uint32_t(inputBufferBytes.size() * 3);
3391         // Create an additional buffer and backing memory for one input variable.
3392         const VkBufferCreateInfo vertexInputParams = {
3393             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
3394             DE_NULL,                              // const void* pNext;
3395             0u,                                   // VkBufferCreateFlags flags;
3396             inputNumBytes,                        // VkDeviceSize size;
3397             VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,    // VkBufferUsageFlags usage;
3398             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
3399             1u,                                   // uint32_t queueFamilyCount;
3400             &queueFamilyIndex,                    // const uint32_t* pQueueFamilyIndices;
3401         };
3402 
3403         vertexInputBuffer = createBuffer(vk, device, &vertexInputParams);
3404         vertexInputMemory = allocator.allocate(getBufferMemoryRequirements(vk, device, *vertexInputBuffer),
3405                                                MemoryRequirement::HostVisible);
3406         VK_CHECK(vk.bindBufferMemory(device, *vertexInputBuffer, vertexInputMemory->getMemory(),
3407                                      vertexInputMemory->getOffset()));
3408 
3409         // Create an additional buffer and backing memory for an output variable.
3410         const VkDeviceSize fragOutputImgSize =
3411             (VkDeviceSize)(instance.interfaces.getOutputType().getNumBytes() * renderSize.x() * renderSize.y());
3412         const VkBufferCreateInfo fragOutputParams = {
3413             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
3414             DE_NULL,                              // const void* pNext;
3415             0u,                                   // VkBufferCreateFlags flags;
3416             fragOutputImgSize,                    // VkDeviceSize size;
3417             VK_BUFFER_USAGE_TRANSFER_DST_BIT,     // VkBufferUsageFlags usage;
3418             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
3419             1u,                                   // uint32_t queueFamilyCount;
3420             &queueFamilyIndex,                    // const uint32_t* pQueueFamilyIndices;
3421         };
3422         fragOutputBuffer = createBuffer(vk, device, &fragOutputParams);
3423         fragOutputMemory = allocator.allocate(getBufferMemoryRequirements(vk, device, *fragOutputBuffer),
3424                                               MemoryRequirement::HostVisible);
3425         VK_CHECK(vk.bindBufferMemory(device, *fragOutputBuffer, fragOutputMemory->getMemory(),
3426                                      fragOutputMemory->getOffset()));
3427 
3428         // Create an additional image and backing memory for attachment.
3429         // Reuse the previous imageParams since we only need to change the image format.
3430         imageParams.format = instance.interfaces.getOutputType().getVkFormat();
3431 
3432         // Check the usage bits on the given image format are supported.
3433         requireFormatUsageSupport(vkInstance, vkPhysicalDevice, imageParams.format, imageParams.tiling,
3434                                   imageParams.usage);
3435 
3436         fragOutputImage = createImage(vk, device, &imageParams);
3437         fragOutputImageMemory =
3438             allocator.allocate(getImageMemoryRequirements(vk, device, *fragOutputImage), MemoryRequirement::Any);
3439 
3440         VK_CHECK(vk.bindImageMemory(device, *fragOutputImage, fragOutputImageMemory->getMemory(),
3441                                     fragOutputImageMemory->getOffset()));
3442     }
3443 
3444     vector<VkAttachmentDescription> colorAttDescs;
3445     vector<VkAttachmentReference> colorAttRefs;
3446     {
3447         const VkAttachmentDescription attDesc = {
3448             0u,                                       // VkAttachmentDescriptionFlags flags;
3449             VK_FORMAT_R8G8B8A8_UNORM,                 // VkFormat format;
3450             VK_SAMPLE_COUNT_1_BIT,                    // uint32_t samples;
3451             VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp loadOp;
3452             VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp storeOp;
3453             VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp stencilLoadOp;
3454             VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp stencilStoreOp;
3455             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
3456             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
3457         };
3458         colorAttDescs.push_back(attDesc);
3459 
3460         const VkAttachmentReference attRef = {
3461             0u,                                       // uint32_t attachment;
3462             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
3463         };
3464         colorAttRefs.push_back(attRef);
3465     }
3466 
3467     if (needInterface)
3468     {
3469         const VkAttachmentDescription attDesc = {
3470             0u,                                                // VkAttachmentDescriptionFlags flags;
3471             instance.interfaces.getOutputType().getVkFormat(), // VkFormat format;
3472             VK_SAMPLE_COUNT_1_BIT,                             // uint32_t samples;
3473             VK_ATTACHMENT_LOAD_OP_CLEAR,                       // VkAttachmentLoadOp loadOp;
3474             VK_ATTACHMENT_STORE_OP_STORE,                      // VkAttachmentStoreOp storeOp;
3475             VK_ATTACHMENT_LOAD_OP_DONT_CARE,                   // VkAttachmentLoadOp stencilLoadOp;
3476             VK_ATTACHMENT_STORE_OP_DONT_CARE,                  // VkAttachmentStoreOp stencilStoreOp;
3477             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,          // VkImageLayout initialLayout;
3478             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,          // VkImageLayout finalLayout;
3479         };
3480         colorAttDescs.push_back(attDesc);
3481 
3482         const VkAttachmentReference attRef = {
3483             1u,                                       // uint32_t attachment;
3484             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
3485         };
3486         colorAttRefs.push_back(attRef);
3487     }
3488 
3489     VkSubpassDescription subpassDesc = {
3490         0u,                              // VkSubpassDescriptionFlags flags;
3491         VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
3492         0u,                              // uint32_t inputCount;
3493         DE_NULL,                         // const VkAttachmentReference* pInputAttachments;
3494         1u,                              // uint32_t colorCount;
3495         colorAttRefs.data(),             // const VkAttachmentReference* pColorAttachments;
3496         DE_NULL,                         // const VkAttachmentReference* pResolveAttachments;
3497         DE_NULL,                         // const VkAttachmentReference* pDepthStencilAttachment;
3498         0u,                              // uint32_t preserveCount;
3499         DE_NULL,                         // const VkAttachmentReference* pPreserveAttachments;
3500 
3501     };
3502     VkRenderPassCreateInfo renderPassParams = {
3503         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
3504         DE_NULL,                                   // const void* pNext;
3505         (VkRenderPassCreateFlags)0,
3506         1u,                   // uint32_t attachmentCount;
3507         colorAttDescs.data(), // const VkAttachmentDescription* pAttachments;
3508         1u,                   // uint32_t subpassCount;
3509         &subpassDesc,         // const VkSubpassDescription* pSubpasses;
3510         0u,                   // uint32_t dependencyCount;
3511         DE_NULL,              // const VkSubpassDependency* pDependencies;
3512     };
3513 
3514     if (needInterface)
3515     {
3516         subpassDesc.colorAttachmentCount += 1;
3517         renderPassParams.attachmentCount += 1;
3518     }
3519 
3520     const Unique<VkRenderPass> renderPass(createRenderPass(vk, device, &renderPassParams));
3521 
3522     const VkImageViewCreateInfo colorAttViewParams = {
3523         VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
3524         DE_NULL,                                  // const void* pNext;
3525         0u,                                       // VkImageViewCreateFlags flags;
3526         *image,                                   // VkImage image;
3527         VK_IMAGE_VIEW_TYPE_2D,                    // VkImageViewType viewType;
3528         VK_FORMAT_R8G8B8A8_UNORM,                 // VkFormat format;
3529         {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
3530          VK_COMPONENT_SWIZZLE_A}, // VkChannelMapping channels;
3531         {
3532             VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
3533             0u,                        // uint32_t baseMipLevel;
3534             1u,                        // uint32_t mipLevels;
3535             0u,                        // uint32_t baseArrayLayer;
3536             1u,                        // uint32_t arraySize;
3537         },                             // VkImageSubresourceRange subresourceRange;
3538     };
3539     const Unique<VkImageView> colorAttView(createImageView(vk, device, &colorAttViewParams));
3540     const VkImageAspectFlags inputImageAspect = getImageAspectFlags(instance.resources.inputFormat);
3541 
3542     vector<VkImageView> attViews;
3543     attViews.push_back(*colorAttView);
3544 
3545     // Handle resources requested by the test instantiation.
3546     // These variables should be placed out of the following if block to avoid deallocation after out of scope.
3547     vector<AllocationSp> inResourceMemories;
3548     vector<AllocationSp> outResourceMemories;
3549     vector<BufferHandleSp> inResourceBuffers;
3550     vector<BufferHandleSp> outResourceBuffers;
3551     vector<ImageHandleSp> inResourceImages;
3552     vector<ImageViewHandleSp> inResourceImageViews;
3553     vector<SamplerHandleSp> inResourceSamplers;
3554     Move<VkDescriptorPool> descriptorPool;
3555     Move<VkDescriptorSetLayout> setLayout;
3556     VkDescriptorSetLayout rawSetLayout = DE_NULL;
3557     VkDescriptorSet rawSet             = DE_NULL;
3558 
3559     const Unique<VkCommandPool> cmdPool(
3560         createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
3561 
3562     // Command buffer
3563     const Unique<VkCommandBuffer> cmdBuf(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
3564 
3565     if (numResources != 0)
3566     {
3567         vector<VkDescriptorSetLayoutBinding> setLayoutBindings;
3568         vector<VkDescriptorPoolSize> poolSizes;
3569 
3570         setLayoutBindings.reserve(numResources);
3571         poolSizes.reserve(numResources);
3572 
3573         // Process all input resources.
3574         for (uint32_t inputNdx = 0; inputNdx < numInResources; ++inputNdx)
3575         {
3576             const Resource &resource = instance.resources.inputs[inputNdx];
3577 
3578             const bool hasImage = (resource.getDescriptorType() == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ||
3579                                   (resource.getDescriptorType() == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
3580                                   (resource.getDescriptorType() == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
3581 
3582             const bool hasSampler = (resource.getDescriptorType() == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
3583                                     (resource.getDescriptorType() == VK_DESCRIPTOR_TYPE_SAMPLER) ||
3584                                     (resource.getDescriptorType() == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
3585 
3586             // Resource is a buffer
3587             if (!hasImage && !hasSampler)
3588             {
3589                 Move<VkBuffer> resourceBuffer = createBufferForResource(vk, device, resource, queueFamilyIndex);
3590                 de::MovePtr<Allocation> resourceMemory = allocator.allocate(
3591                     getBufferMemoryRequirements(vk, device, *resourceBuffer), MemoryRequirement::HostVisible);
3592 
3593                 VK_CHECK(vk.bindBufferMemory(device, *resourceBuffer, resourceMemory->getMemory(),
3594                                              resourceMemory->getOffset()));
3595 
3596                 // Copy data to memory.
3597                 {
3598                     vector<uint8_t> resourceBytes;
3599                     resource.getBytes(resourceBytes);
3600 
3601                     deMemcpy(resourceMemory->getHostPtr(), &resourceBytes.front(), resourceBytes.size());
3602                     flushAlloc(vk, device, *resourceMemory);
3603                 }
3604 
3605                 inResourceMemories.push_back(AllocationSp(resourceMemory.release()));
3606                 inResourceBuffers.push_back(BufferHandleSp(new BufferHandleUp(resourceBuffer)));
3607             }
3608             // Resource is an image
3609             else if (hasImage)
3610             {
3611                 Move<VkBuffer> resourceBuffer = createBufferForResource(vk, device, resource, queueFamilyIndex);
3612                 de::MovePtr<Allocation> resourceMemory = allocator.allocate(
3613                     getBufferMemoryRequirements(vk, device, *resourceBuffer), MemoryRequirement::HostVisible);
3614 
3615                 VK_CHECK(vk.bindBufferMemory(device, *resourceBuffer, resourceMemory->getMemory(),
3616                                              resourceMemory->getOffset()));
3617 
3618                 // Copy data to memory.
3619                 {
3620                     vector<uint8_t> resourceBytes;
3621                     resource.getBytes(resourceBytes);
3622 
3623                     deMemcpy(resourceMemory->getHostPtr(), &resourceBytes.front(), resourceBytes.size());
3624                     flushAlloc(vk, device, *resourceMemory);
3625                 }
3626 
3627                 Move<VkImage> resourceImage =
3628                     createImageForResource(vk, device, resource, instance.resources.inputFormat, queueFamilyIndex);
3629                 de::MovePtr<Allocation> resourceImageMemory =
3630                     allocator.allocate(getImageMemoryRequirements(vk, device, *resourceImage), MemoryRequirement::Any);
3631 
3632                 VK_CHECK(vk.bindImageMemory(device, *resourceImage, resourceImageMemory->getMemory(),
3633                                             resourceImageMemory->getOffset()));
3634 
3635                 copyBufferToImage(context, vk, device, queue, *cmdPool, *cmdBuf, resourceBuffer.get(),
3636                                   resourceImage.get(), inputImageAspect);
3637 
3638                 inResourceMemories.push_back(AllocationSp(resourceImageMemory.release()));
3639                 inResourceImages.push_back(ImageHandleSp(new ImageHandleUp(resourceImage)));
3640             }
3641 
3642             // Prepare descriptor bindings and pool sizes for creating descriptor set layout and pool.
3643             const VkDescriptorSetLayoutBinding binding = {
3644                 inputNdx,                     // binding
3645                 resource.getDescriptorType(), // descriptorType
3646                 1u,                           // descriptorCount
3647                 VK_SHADER_STAGE_ALL_GRAPHICS, // stageFlags
3648                 DE_NULL,                      // pImmutableSamplers
3649             };
3650             setLayoutBindings.push_back(binding);
3651 
3652             // Note: the following code doesn't check and unify descriptors of the same type.
3653             const VkDescriptorPoolSize poolSize = {
3654                 resource.getDescriptorType(), // type
3655                 1u,                           // descriptorCount
3656             };
3657             poolSizes.push_back(poolSize);
3658         }
3659 
3660         // Process all output resources.
3661         for (uint32_t outputNdx = 0; outputNdx < numOutResources; ++outputNdx)
3662         {
3663             const Resource &resource = instance.resources.outputs[outputNdx];
3664             // Create buffer and allocate memory.
3665             Move<VkBuffer> resourceBuffer          = createBufferForResource(vk, device, resource, queueFamilyIndex);
3666             de::MovePtr<Allocation> resourceMemory = allocator.allocate(
3667                 getBufferMemoryRequirements(vk, device, *resourceBuffer), MemoryRequirement::HostVisible);
3668             vector<uint8_t> resourceBytes;
3669 
3670             VK_CHECK(
3671                 vk.bindBufferMemory(device, *resourceBuffer, resourceMemory->getMemory(), resourceMemory->getOffset()));
3672 
3673             // Fill memory with all ones.
3674             resource.getBytes(resourceBytes);
3675             deMemset((uint8_t *)resourceMemory->getHostPtr(), 0xff, resourceBytes.size());
3676             flushAlloc(vk, device, *resourceMemory);
3677 
3678             outResourceMemories.push_back(AllocationSp(resourceMemory.release()));
3679             outResourceBuffers.push_back(BufferHandleSp(new BufferHandleUp(resourceBuffer)));
3680 
3681             // Prepare descriptor bindings and pool sizes for creating descriptor set layout and pool.
3682             const VkDescriptorSetLayoutBinding binding = {
3683                 numInResources + outputNdx,   // binding
3684                 resource.getDescriptorType(), // descriptorType
3685                 1u,                           // descriptorCount
3686                 VK_SHADER_STAGE_ALL_GRAPHICS, // stageFlags
3687                 DE_NULL,                      // pImmutableSamplers
3688             };
3689             setLayoutBindings.push_back(binding);
3690 
3691             // Note: the following code doesn't check and unify descriptors of the same type.
3692             const VkDescriptorPoolSize poolSize = {
3693                 resource.getDescriptorType(), // type
3694                 1u,                           // descriptorCount
3695             };
3696             poolSizes.push_back(poolSize);
3697         }
3698 
3699         // Create descriptor set layout, descriptor pool, and allocate descriptor set.
3700         const VkDescriptorSetLayoutCreateInfo setLayoutParams = {
3701             VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // sType
3702             DE_NULL,                                             // pNext
3703             (VkDescriptorSetLayoutCreateFlags)0,                 // flags
3704             numResources,                                        // bindingCount
3705             setLayoutBindings.data(),                            // pBindings
3706         };
3707         setLayout    = createDescriptorSetLayout(vk, device, &setLayoutParams);
3708         rawSetLayout = *setLayout;
3709 
3710         const VkDescriptorPoolCreateInfo poolParams = {
3711             VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, // sType
3712             DE_NULL,                                       // pNext
3713             (VkDescriptorPoolCreateFlags)0,                // flags
3714             1u,                                            // maxSets
3715             numResources,                                  // poolSizeCount
3716             poolSizes.data(),                              // pPoolSizes
3717         };
3718         descriptorPool = createDescriptorPool(vk, device, &poolParams);
3719 
3720         const VkDescriptorSetAllocateInfo setAllocParams = {
3721             VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // sType
3722             DE_NULL,                                        // pNext
3723             *descriptorPool,                                // descriptorPool
3724             1u,                                             // descriptorSetCount
3725             &rawSetLayout,                                  // pSetLayouts
3726         };
3727         VK_CHECK(vk.allocateDescriptorSets(device, &setAllocParams, &rawSet));
3728 
3729         // Update descriptor set.
3730         vector<VkWriteDescriptorSet> writeSpecs;
3731         vector<VkDescriptorBufferInfo> dBufferInfos;
3732         vector<VkDescriptorImageInfo> dImageInfos;
3733 
3734         writeSpecs.reserve(numResources);
3735         dBufferInfos.reserve(numResources);
3736         dImageInfos.reserve(numResources);
3737 
3738         uint32_t imgResourceNdx = 0u;
3739         uint32_t bufResourceNdx = 0u;
3740 
3741         for (uint32_t inputNdx = 0; inputNdx < numInResources; ++inputNdx)
3742         {
3743             const Resource &resource = instance.resources.inputs[inputNdx];
3744 
3745             const bool hasImage = (resource.getDescriptorType() == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) ||
3746                                   (resource.getDescriptorType() == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
3747                                   (resource.getDescriptorType() == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
3748 
3749             const bool hasSampler = (resource.getDescriptorType() == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) ||
3750                                     (resource.getDescriptorType() == VK_DESCRIPTOR_TYPE_SAMPLER) ||
3751                                     (resource.getDescriptorType() == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
3752 
3753             // Create image view and sampler
3754             if (hasImage || hasSampler)
3755             {
3756                 if (resource.getDescriptorType() != VK_DESCRIPTOR_TYPE_SAMPLER)
3757                 {
3758                     const VkImageViewCreateInfo imgViewParams = {
3759                         VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
3760                         DE_NULL,                                  // const void* pNext;
3761                         0u,                                       // VkImageViewCreateFlags flags;
3762                         **inResourceImages[imgResourceNdx++],     // VkImage image;
3763                         VK_IMAGE_VIEW_TYPE_2D,                    // VkImageViewType viewType;
3764                         instance.resources.inputFormat,           // VkFormat format;
3765                         {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
3766                          VK_COMPONENT_SWIZZLE_A}, // VkComponentMapping channels;
3767                         {
3768                             inputImageAspect, // VkImageAspectFlags aspectMask;
3769                             0u,               // uint32_t baseMipLevel;
3770                             1u,               // uint32_t mipLevels;
3771                             0u,               // uint32_t baseArrayLayer;
3772                             1u,               // uint32_t arraySize;
3773                         },                    // VkImageSubresourceRange subresourceRange;
3774                     };
3775 
3776                     Move<VkImageView> imgView(createImageView(vk, device, &imgViewParams));
3777                     inResourceImageViews.push_back(ImageViewHandleSp(new ImageViewHandleUp(imgView)));
3778                 }
3779 
3780                 if (hasSampler)
3781                 {
3782                     const bool hasDepthComponent =
3783                         tcu::hasDepthComponent(vk::mapVkFormat(instance.resources.inputFormat).order);
3784                     const VkSamplerCreateInfo samplerParams{
3785                         VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,    // VkStructureType sType;
3786                         DE_NULL,                                  // const void* pNext;
3787                         0,                                        // VkSamplerCreateFlags flags;
3788                         VK_FILTER_NEAREST,                        // VkFilter                    magFilter:
3789                         VK_FILTER_NEAREST,                        // VkFilter minFilter;
3790                         VK_SAMPLER_MIPMAP_MODE_NEAREST,           // VkSamplerMipmapMode mipmapMode;
3791                         VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,    // VkSamplerAddressMode addressModeU;
3792                         VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,    // VkSamplerAddressMode addressModeV;
3793                         VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,    // VkSamplerAddressMode addressModeW;
3794                         0.0f,                                     // float mipLodBias;
3795                         VK_FALSE,                                 // VkBool32 anistoropyEnable;
3796                         1.0f,                                     // float maxAnisotropy;
3797                         (hasDepthComponent) ? VK_TRUE : VK_FALSE, // VkBool32 compareEnable;
3798                         VK_COMPARE_OP_LESS,                       // VkCompareOp compareOp;
3799                         0.0f,                                     // float minLod;
3800                         0.0f,                                     // float maxLod;
3801                         VK_BORDER_COLOR_INT_OPAQUE_BLACK,         // VkBorderColor borderColor;
3802                         VK_FALSE                                  // VkBool32 unnormalizedCoordinates;
3803                     };
3804 
3805                     Move<VkSampler> sampler(createSampler(vk, device, &samplerParams));
3806                     inResourceSamplers.push_back(SamplerHandleSp(new SamplerHandleUp(sampler)));
3807                 }
3808             }
3809 
3810             // Create descriptor buffer and image infos
3811             switch (resource.getDescriptorType())
3812             {
3813             case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
3814             case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
3815             {
3816                 const VkDescriptorBufferInfo bufInfo = {
3817                     **inResourceBuffers[bufResourceNdx++], // buffer
3818                     0,                                     // offset
3819                     VK_WHOLE_SIZE,                         // size
3820                 };
3821                 dBufferInfos.push_back(bufInfo);
3822                 break;
3823             }
3824             case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
3825             case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
3826             {
3827                 const VkDescriptorImageInfo imgInfo = {
3828                     DE_NULL,                       // sampler
3829                     **inResourceImageViews.back(), // imageView
3830                     VK_IMAGE_LAYOUT_GENERAL        // imageLayout
3831                 };
3832                 dImageInfos.push_back(imgInfo);
3833                 break;
3834             }
3835             case VK_DESCRIPTOR_TYPE_SAMPLER:
3836             {
3837                 const VkDescriptorImageInfo imgInfo = {
3838                     **inResourceSamplers.back(), // sampler
3839                     DE_NULL,                     // imageView
3840                     VK_IMAGE_LAYOUT_GENERAL      // imageLayout
3841                 };
3842                 dImageInfos.push_back(imgInfo);
3843                 break;
3844             }
3845             case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
3846             {
3847 
3848                 const VkDescriptorImageInfo imgInfo = {
3849                     **inResourceSamplers.back(),   // sampler
3850                     **inResourceImageViews.back(), // imageView
3851                     VK_IMAGE_LAYOUT_GENERAL        // imageLayout
3852                 };
3853                 dImageInfos.push_back(imgInfo);
3854                 break;
3855             }
3856             default:
3857                 DE_FATAL("Not implemented");
3858             }
3859 
3860             const VkWriteDescriptorSet writeSpec = {
3861                 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,                      // sType
3862                 DE_NULL,                                                     // pNext
3863                 rawSet,                                                      // dstSet
3864                 inputNdx,                                                    // binding
3865                 0,                                                           // dstArrayElement
3866                 1u,                                                          // descriptorCount
3867                 instance.resources.inputs[inputNdx].getDescriptorType(),     // descriptorType
3868                 ((hasImage | hasSampler) ? &dImageInfos.back() : DE_NULL),   // pImageInfo
3869                 (!(hasImage | hasSampler) ? &dBufferInfos.back() : DE_NULL), // pBufferInfo
3870                 DE_NULL,                                                     // pTexelBufferView
3871             };
3872             writeSpecs.push_back(writeSpec);
3873         }
3874 
3875         for (uint32_t outputNdx = 0; outputNdx < numOutResources; ++outputNdx)
3876         {
3877             const VkDescriptorBufferInfo bufInfo = {
3878                 **outResourceBuffers[outputNdx], // buffer
3879                 0,                               // offset
3880                 VK_WHOLE_SIZE,                   // size
3881             };
3882             dBufferInfos.push_back(bufInfo);
3883 
3884             const VkWriteDescriptorSet writeSpec = {
3885                 VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,                    // sType
3886                 DE_NULL,                                                   // pNext
3887                 rawSet,                                                    // dstSet
3888                 numInResources + outputNdx,                                // binding
3889                 0,                                                         // dstArrayElement
3890                 1u,                                                        // descriptorCount
3891                 instance.resources.outputs[outputNdx].getDescriptorType(), // descriptorType
3892                 DE_NULL,                                                   // pImageInfo
3893                 &dBufferInfos.back(),                                      // pBufferInfo
3894                 DE_NULL,                                                   // pTexelBufferView
3895             };
3896             writeSpecs.push_back(writeSpec);
3897         }
3898         vk.updateDescriptorSets(device, numResources, writeSpecs.data(), 0, DE_NULL);
3899     }
3900 
3901     // Pipeline layout
3902     VkPipelineLayoutCreateInfo pipelineLayoutParams = {
3903         VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
3904         DE_NULL,                                       // const void* pNext;
3905         (VkPipelineLayoutCreateFlags)0,
3906         0u,      // uint32_t descriptorSetCount;
3907         DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
3908         0u,      // uint32_t pushConstantRangeCount;
3909         DE_NULL, // const VkPushConstantRange* pPushConstantRanges;
3910     };
3911 
3912     VkPushConstantRange pushConstantRange = {
3913         VK_SHADER_STAGE_ALL_GRAPHICS, // VkShaderStageFlags    stageFlags;
3914         0,                            // uint32_t              offset;
3915         0,                            // uint32_t              size;
3916     };
3917     if (hasPushConstants)
3918     {
3919         vector<uint8_t> pushConstantsBytes;
3920         instance.pushConstants.getBuffer()->getBytes(pushConstantsBytes);
3921 
3922         pushConstantRange.size                      = static_cast<uint32_t>(pushConstantsBytes.size());
3923         pipelineLayoutParams.pushConstantRangeCount = 1;
3924         pipelineLayoutParams.pPushConstantRanges    = &pushConstantRange;
3925     }
3926     if (numResources != 0)
3927     {
3928         // Update pipeline layout with the descriptor set layout.
3929         pipelineLayoutParams.setLayoutCount = 1;
3930         pipelineLayoutParams.pSetLayouts    = &rawSetLayout;
3931     }
3932     const Unique<VkPipelineLayout> pipelineLayout(createPipelineLayout(vk, device, &pipelineLayoutParams));
3933 
3934     // Pipeline
3935     vector<VkPipelineShaderStageCreateInfo> shaderStageParams;
3936     // We need these vectors to make sure that information about specialization constants for each stage can outlive createGraphicsPipeline().
3937     vector<vector<VkSpecializationMapEntry>> specConstantEntries;
3938     vector<VkSpecializationInfo> specializationInfos;
3939     if (DE_NULL != instance.resources.verifyBinary)
3940     {
3941         std::string shaderName;
3942         switch (instance.customizedStages)
3943         {
3944         case VK_SHADER_STAGE_VERTEX_BIT:
3945             shaderName = "vert";
3946             break;
3947         case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
3948             shaderName = "tessc";
3949             break;
3950         case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
3951             shaderName = "tesse";
3952             break;
3953         case VK_SHADER_STAGE_GEOMETRY_BIT:
3954             shaderName = "geom";
3955             break;
3956         case VK_SHADER_STAGE_FRAGMENT_BIT:
3957             shaderName = "frag";
3958             break;
3959         default:
3960             DE_ASSERT(0);
3961             break;
3962         }
3963         const ProgramBinary &binary = context.getBinaryCollection().get(shaderName);
3964         if (!instance.resources.verifyBinary(binary))
3965             return tcu::TestStatus::fail("Binary verification of SPIR-V in the test failed");
3966     }
3967     createPipelineShaderStages(vk, device, instance, context, modules, shaderStageParams);
3968 
3969     // And we don't want the reallocation of these vectors to invalidate pointers pointing to their contents.
3970     specConstantEntries.reserve(shaderStageParams.size());
3971     specializationInfos.reserve(shaderStageParams.size());
3972 
3973     // Patch the specialization info field in PipelineShaderStageCreateInfos.
3974     for (vector<VkPipelineShaderStageCreateInfo>::iterator stageInfo = shaderStageParams.begin();
3975          stageInfo != shaderStageParams.end(); ++stageInfo)
3976     {
3977         const StageToSpecConstantMap::const_iterator stageIt = instance.specConstants.find(stageInfo->stage);
3978 
3979         if (stageIt != instance.specConstants.end())
3980         {
3981             const size_t numSpecConstants = stageIt->second.getValuesCount();
3982             vector<VkSpecializationMapEntry> entries;
3983             VkSpecializationInfo specInfo;
3984             size_t offset = 0;
3985 
3986             entries.resize(numSpecConstants);
3987 
3988             // Constant IDs are numbered sequentially starting from 0.
3989             for (size_t ndx = 0; ndx < numSpecConstants; ++ndx)
3990             {
3991                 const size_t valueSize = stageIt->second.getValueSize(ndx);
3992 
3993                 entries[ndx].constantID = (uint32_t)ndx;
3994                 entries[ndx].offset     = static_cast<uint32_t>(offset);
3995                 entries[ndx].size       = valueSize;
3996 
3997                 offset += valueSize;
3998             }
3999 
4000             specConstantEntries.push_back(entries);
4001 
4002             specInfo.mapEntryCount = (uint32_t)numSpecConstants;
4003             specInfo.pMapEntries   = specConstantEntries.back().data();
4004             specInfo.dataSize      = offset;
4005             specInfo.pData         = stageIt->second.getValuesBuffer();
4006             specializationInfos.push_back(specInfo);
4007 
4008             stageInfo->pSpecializationInfo = &specializationInfos.back();
4009         }
4010     }
4011     const VkPipelineDepthStencilStateCreateInfo depthStencilParams = {
4012         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
4013         DE_NULL,                                                    // const void* pNext;
4014         (VkPipelineDepthStencilStateCreateFlags)0,
4015         false,                // uint32_t depthTestEnable;
4016         false,                // uint32_t depthWriteEnable;
4017         VK_COMPARE_OP_ALWAYS, // VkCompareOp depthCompareOp;
4018         false,                // uint32_t depthBoundsTestEnable;
4019         false,                // uint32_t stencilTestEnable;
4020         {
4021             VK_STENCIL_OP_KEEP,   // VkStencilOp stencilFailOp;
4022             VK_STENCIL_OP_KEEP,   // VkStencilOp stencilPassOp;
4023             VK_STENCIL_OP_KEEP,   // VkStencilOp stencilDepthFailOp;
4024             VK_COMPARE_OP_ALWAYS, // VkCompareOp stencilCompareOp;
4025             0u,                   // uint32_t stencilCompareMask;
4026             0u,                   // uint32_t stencilWriteMask;
4027             0u,                   // uint32_t stencilReference;
4028         },                        // VkStencilOpState front;
4029         {
4030             VK_STENCIL_OP_KEEP,   // VkStencilOp stencilFailOp;
4031             VK_STENCIL_OP_KEEP,   // VkStencilOp stencilPassOp;
4032             VK_STENCIL_OP_KEEP,   // VkStencilOp stencilDepthFailOp;
4033             VK_COMPARE_OP_ALWAYS, // VkCompareOp stencilCompareOp;
4034             0u,                   // uint32_t stencilCompareMask;
4035             0u,                   // uint32_t stencilWriteMask;
4036             0u,                   // uint32_t stencilReference;
4037         },                        // VkStencilOpState back;
4038         -1.0f,                    // float minDepthBounds;
4039         +1.0f,                    // float maxDepthBounds;
4040     };
4041     const VkViewport viewport0                             = makeViewport(renderSize);
4042     const VkRect2D scissor0                                = makeRect2D(0u, 0u);
4043     const VkPipelineViewportStateCreateInfo viewportParams = {
4044         VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
4045         DE_NULL,                                               // const void* pNext;
4046         (VkPipelineViewportStateCreateFlags)0,
4047         1u, // uint32_t viewportCount;
4048         &viewport0,
4049         1u,
4050         &scissor0};
4051     const VkSampleMask sampleMask                                = ~0u;
4052     const VkPipelineMultisampleStateCreateInfo multisampleParams = {
4053         VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
4054         DE_NULL,                                                  // const void* pNext;
4055         (VkPipelineMultisampleStateCreateFlags)0,
4056         VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterSamples;
4057         false,                 // uint32_t sampleShadingEnable;
4058         0.0f,                  // float minSampleShading;
4059         &sampleMask,           // const VkSampleMask* pSampleMask;
4060         false,                 // VkBool32 alphaToCoverageEnable;
4061         false,                 // VkBool32 alphaToOneEnable;
4062     };
4063     const VkPipelineRasterizationStateCreateInfo rasterParams = {
4064         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
4065         DE_NULL,                                                    // const void* pNext;
4066         (VkPipelineRasterizationStateCreateFlags)0,
4067         false,                           // uint32_t depthClampEnable;
4068         false,                           // uint32_t rasterizerDiscardEnable;
4069         VK_POLYGON_MODE_FILL,            // VkFillMode fillMode;
4070         VK_CULL_MODE_NONE,               // VkCullMode cullMode;
4071         VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
4072         VK_FALSE,                        // VkBool32 depthBiasEnable;
4073         0.0f,                            // float depthBias;
4074         0.0f,                            // float depthBiasClamp;
4075         0.0f,                            // float slopeScaledDepthBias;
4076         1.0f,                            // float lineWidth;
4077     };
4078     const VkPrimitiveTopology topology =
4079         hasTessellation ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
4080     const VkPipelineInputAssemblyStateCreateInfo inputAssemblyParams = {
4081         VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
4082         DE_NULL,                                                     // const void* pNext;
4083         (VkPipelineInputAssemblyStateCreateFlags)0,
4084         topology, // VkPrimitiveTopology topology;
4085         false,    // uint32_t primitiveRestartEnable;
4086     };
4087 
4088     vector<VkVertexInputBindingDescription> vertexBindings;
4089     vector<VkVertexInputAttributeDescription> vertexAttribs;
4090 
4091     const VkVertexInputBindingDescription vertexBinding0 = {
4092         0u,                             // uint32_t binding;
4093         uint32_t(singleVertexDataSize), // uint32_t strideInBytes;
4094         VK_VERTEX_INPUT_RATE_VERTEX     // VkVertexInputStepRate stepRate;
4095     };
4096     vertexBindings.push_back(vertexBinding0);
4097 
4098     {
4099         VkVertexInputAttributeDescription attr0 = {
4100             0u,                            // uint32_t location;
4101             0u,                            // uint32_t binding;
4102             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
4103             0u                             // uint32_t offsetInBytes;
4104         };
4105         vertexAttribs.push_back(attr0);
4106 
4107         VkVertexInputAttributeDescription attr1 = {
4108             1u,                            // uint32_t location;
4109             0u,                            // uint32_t binding;
4110             VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
4111             sizeof(Vec4),                  // uint32_t offsetInBytes;
4112         };
4113         vertexAttribs.push_back(attr1);
4114     }
4115 
4116     // If the test instantiation has additional input/output interface variables, we need to create additional bindings.
4117     // Right now we only support one additional input varible for the vertex stage, and that will be bound to binding #1
4118     // with location #2.
4119     if (needInterface)
4120     {
4121         // Portability requires stride to be multiply of minVertexInputBindingStrideAlignment
4122         // this value is usually 4 and current tests meet this requirement but
4123         // if this changes in future then this limit should be verified in checkSupport
4124         const uint32_t stride = instance.interfaces.getInputType().getNumBytes();
4125 #ifndef CTS_USES_VULKANSC
4126         if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
4127             ((stride % context.getPortabilitySubsetProperties().minVertexInputBindingStrideAlignment) != 0))
4128         {
4129             DE_FATAL("stride is not multiply of minVertexInputBindingStrideAlignment");
4130         }
4131 #endif // CTS_USES_VULKANSC
4132 
4133         const VkVertexInputBindingDescription vertexBinding1 = {
4134             1u,                         // uint32_t binding;
4135             stride,                     // uint32_t strideInBytes;
4136             VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate stepRate;
4137         };
4138         vertexBindings.push_back(vertexBinding1);
4139 
4140         VkVertexInputAttributeDescription attr = {
4141             2u,                                               // uint32_t location;
4142             1u,                                               // uint32_t binding;
4143             instance.interfaces.getInputType().getVkFormat(), // VkFormat format;
4144             0,                                                // uint32_t offsetInBytes;
4145         };
4146         vertexAttribs.push_back(attr);
4147     }
4148 
4149     VkPipelineVertexInputStateCreateInfo vertexInputStateParams = {
4150         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
4151         DE_NULL,                                                   // const void* pNext;
4152         (VkPipelineVertexInputStateCreateFlags)0,
4153         1u,                    // uint32_t bindingCount;
4154         vertexBindings.data(), // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
4155         2u,                    // uint32_t attributeCount;
4156         vertexAttribs.data(),  // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
4157     };
4158 
4159     if (needInterface)
4160     {
4161         vertexInputStateParams.vertexBindingDescriptionCount += 1;
4162         vertexInputStateParams.vertexAttributeDescriptionCount += 1;
4163     }
4164 
4165     vector<VkPipelineColorBlendAttachmentState> attBlendStates;
4166     const VkPipelineColorBlendAttachmentState attBlendState = {
4167         false,                // uint32_t blendEnable;
4168         VK_BLEND_FACTOR_ONE,  // VkBlend srcBlendColor;
4169         VK_BLEND_FACTOR_ZERO, // VkBlend destBlendColor;
4170         VK_BLEND_OP_ADD,      // VkBlendOp blendOpColor;
4171         VK_BLEND_FACTOR_ONE,  // VkBlend srcBlendAlpha;
4172         VK_BLEND_FACTOR_ZERO, // VkBlend destBlendAlpha;
4173         VK_BLEND_OP_ADD,      // VkBlendOp blendOpAlpha;
4174         (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT |
4175          VK_COLOR_COMPONENT_A_BIT), // VkChannelFlags channelWriteMask;
4176     };
4177     attBlendStates.push_back(attBlendState);
4178 
4179     if (needInterface)
4180         attBlendStates.push_back(attBlendState);
4181 
4182     VkPipelineColorBlendStateCreateInfo blendParams = {
4183         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
4184         DE_NULL,                                                  // const void* pNext;
4185         (VkPipelineColorBlendStateCreateFlags)0,
4186         false,                    // VkBool32 logicOpEnable;
4187         VK_LOGIC_OP_COPY,         // VkLogicOp logicOp;
4188         1u,                       // uint32_t attachmentCount;
4189         attBlendStates.data(),    // const VkPipelineColorBlendAttachmentState* pAttachments;
4190         {0.0f, 0.0f, 0.0f, 0.0f}, // float blendConst[4];
4191     };
4192     if (needInterface)
4193     {
4194         blendParams.attachmentCount += 1;
4195     }
4196     const VkPipelineTessellationStateCreateInfo tessellationState = {
4197         VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, DE_NULL, (VkPipelineTessellationStateCreateFlags)0,
4198         3u};
4199 
4200     const VkDynamicState dynamicStates[] = {VK_DYNAMIC_STATE_SCISSOR};
4201 
4202     const VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = {
4203         VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // sType
4204         DE_NULL,                                              // pNext
4205         0u,                                                   // flags
4206         DE_LENGTH_OF_ARRAY(dynamicStates),                    // dynamicStateCount
4207         dynamicStates                                         // pDynamicStates
4208     };
4209 
4210     const VkPipelineTessellationStateCreateInfo *tessellationInfo = hasTessellation ? &tessellationState : DE_NULL;
4211     const VkGraphicsPipelineCreateInfo pipelineParams             = {
4212         VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
4213         DE_NULL,                                         // const void* pNext;
4214         0u,                                              // VkPipelineCreateFlags flags;
4215         (uint32_t)shaderStageParams.size(),              // uint32_t stageCount;
4216         &shaderStageParams[0],                           // const VkPipelineShaderStageCreateInfo* pStages;
4217         &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
4218         &inputAssemblyParams,    // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
4219         tessellationInfo,        // const VkPipelineTessellationStateCreateInfo* pTessellationState;
4220         &viewportParams,         // const VkPipelineViewportStateCreateInfo* pViewportState;
4221         &rasterParams,           // const VkPipelineRasterStateCreateInfo* pRasterState;
4222         &multisampleParams,      // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
4223         &depthStencilParams,     // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
4224         &blendParams,            // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
4225         &dynamicStateCreateInfo, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
4226         *pipelineLayout,         // VkPipelineLayout layout;
4227         *renderPass,             // VkRenderPass renderPass;
4228         0u,                      // uint32_t subpass;
4229         DE_NULL,                 // VkPipeline basePipelineHandle;
4230         0u,                      // int32_t basePipelineIndex;
4231     };
4232 
4233     const Unique<VkPipeline> pipeline(createGraphicsPipeline(vk, device, DE_NULL, &pipelineParams));
4234 
4235     if (needInterface)
4236     {
4237         const VkImageViewCreateInfo fragOutputViewParams = {
4238             VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,          // VkStructureType sType;
4239             DE_NULL,                                           // const void* pNext;
4240             0u,                                                // VkImageViewCreateFlags flags;
4241             *fragOutputImage,                                  // VkImage image;
4242             VK_IMAGE_VIEW_TYPE_2D,                             // VkImageViewType viewType;
4243             instance.interfaces.getOutputType().getVkFormat(), // VkFormat format;
4244             {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
4245              VK_COMPONENT_SWIZZLE_A}, // VkChannelMapping channels;
4246             {
4247                 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
4248                 0u,                        // uint32_t baseMipLevel;
4249                 1u,                        // uint32_t mipLevels;
4250                 0u,                        // uint32_t baseArrayLayer;
4251                 1u,                        // uint32_t arraySize;
4252             },                             // VkImageSubresourceRange subresourceRange;
4253         };
4254         fragOutputImageView = createImageView(vk, device, &fragOutputViewParams);
4255         attViews.push_back(*fragOutputImageView);
4256     }
4257 
4258     // Framebuffer
4259     VkFramebufferCreateInfo framebufferParams = {
4260         VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
4261         DE_NULL,                                   // const void* pNext;
4262         (VkFramebufferCreateFlags)0,
4263         *renderPass,              // VkRenderPass renderPass;
4264         1u,                       // uint32_t attachmentCount;
4265         attViews.data(),          // const VkImageView* pAttachments;
4266         (uint32_t)renderSize.x(), // uint32_t width;
4267         (uint32_t)renderSize.y(), // uint32_t height;
4268         1u,                       // uint32_t layers;
4269     };
4270 
4271     if (needInterface)
4272         framebufferParams.attachmentCount += 1;
4273 
4274     const Unique<VkFramebuffer> framebuffer(createFramebuffer(vk, device, &framebufferParams));
4275 
4276     bool firstPass = true;
4277 
4278     for (int x = 0; x < numRenderSegments; x++)
4279     {
4280         for (int y = 0; y < numRenderSegments; y++)
4281         {
4282             // Record commands
4283             beginCommandBuffer(vk, *cmdBuf);
4284 
4285             if (firstPass)
4286             {
4287                 const VkMemoryBarrier vertFlushBarrier = {
4288                     VK_STRUCTURE_TYPE_MEMORY_BARRIER,    // VkStructureType sType;
4289                     DE_NULL,                             // const void* pNext;
4290                     VK_ACCESS_HOST_WRITE_BIT,            // VkMemoryOutputFlags outputMask;
4291                     VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, // VkMemoryInputFlags inputMask;
4292                 };
4293                 vector<VkImageMemoryBarrier> colorAttBarriers;
4294 
4295                 VkImageMemoryBarrier imgBarrier = {
4296                     VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,   // VkStructureType sType;
4297                     DE_NULL,                                  // const void* pNext;
4298                     0u,                                       // VkMemoryOutputFlags outputMask;
4299                     VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,     // VkMemoryInputFlags inputMask;
4300                     VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout oldLayout;
4301                     VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout;
4302                     queueFamilyIndex,                         // uint32_t srcQueueFamilyIndex;
4303                     queueFamilyIndex,                         // uint32_t destQueueFamilyIndex;
4304                     *image,                                   // VkImage image;
4305                     {
4306                         VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspect aspect;
4307                         0u,                        // uint32_t baseMipLevel;
4308                         1u,                        // uint32_t mipLevels;
4309                         0u,                        // uint32_t baseArraySlice;
4310                         1u,                        // uint32_t arraySize;
4311                     }                              // VkImageSubresourceRange subresourceRange;
4312                 };
4313                 colorAttBarriers.push_back(imgBarrier);
4314                 if (needInterface)
4315                 {
4316                     imgBarrier.image = *fragOutputImage;
4317                     colorAttBarriers.push_back(imgBarrier);
4318                     vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
4319                                           (VkDependencyFlags)0, 1, &vertFlushBarrier, 0,
4320                                           (const VkBufferMemoryBarrier *)DE_NULL, 2, colorAttBarriers.data());
4321                 }
4322                 else
4323                 {
4324                     vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
4325                                           (VkDependencyFlags)0, 1, &vertFlushBarrier, 0,
4326                                           (const VkBufferMemoryBarrier *)DE_NULL, 1, colorAttBarriers.data());
4327                 }
4328             }
4329 
4330             {
4331                 vector<VkClearValue> clearValue;
4332                 clearValue.push_back(makeClearValueColorF32(defaulClearColor[0], defaulClearColor[1],
4333                                                             defaulClearColor[2], defaulClearColor[3]));
4334                 if (needInterface)
4335                 {
4336                     clearValue.push_back(makeClearValueColorU32(0, 0, 0, 0));
4337                 }
4338 
4339                 vk::VkRect2D scissor =
4340                     makeRect2D(x * renderDimension, y * renderDimension, renderDimension, renderDimension);
4341                 vk.cmdSetScissor(*cmdBuf, 0u, 1u, &scissor);
4342 
4343                 beginRenderPass(vk, *cmdBuf, *renderPass, *framebuffer, scissor, (uint32_t)clearValue.size(),
4344                                 clearValue.data());
4345             }
4346 
4347             vk.cmdBindPipeline(*cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
4348             {
4349                 const VkDeviceSize bindingOffset = 0;
4350                 vk.cmdBindVertexBuffers(*cmdBuf, 0u, 1u, &vertexBuffer.get(), &bindingOffset);
4351             }
4352             if (needInterface)
4353             {
4354                 const VkDeviceSize bindingOffset = 0;
4355                 vk.cmdBindVertexBuffers(*cmdBuf, 1u, 1u, &vertexInputBuffer.get(), &bindingOffset);
4356             }
4357             if (hasPushConstants)
4358             {
4359                 vector<uint8_t> pushConstantsBytes;
4360                 instance.pushConstants.getBuffer()->getBytes(pushConstantsBytes);
4361 
4362                 const uint32_t size = static_cast<uint32_t>(pushConstantsBytes.size());
4363                 const void *data    = &pushConstantsBytes.front();
4364 
4365                 vk.cmdPushConstants(*cmdBuf, *pipelineLayout, VK_SHADER_STAGE_ALL_GRAPHICS, 0, size, data);
4366             }
4367             if (numResources != 0)
4368             {
4369                 // Bind to set number 0.
4370                 vk.cmdBindDescriptorSets(*cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0, 1, &rawSet, 0,
4371                                          DE_NULL);
4372             }
4373             vk.cmdDraw(*cmdBuf, uint32_t(vertexCount), 1u /*run pipeline once*/, 0u /*first vertex*/,
4374                        0u /*first instanceIndex*/);
4375             endRenderPass(vk, *cmdBuf);
4376 
4377             if (x == numRenderSegments - 1 && y == numRenderSegments - 1)
4378             {
4379                 {
4380                     vector<VkImageMemoryBarrier> renderFinishBarrier;
4381                     VkImageMemoryBarrier imgBarrier = {
4382                         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,   // VkStructureType sType;
4383                         DE_NULL,                                  // const void* pNext;
4384                         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,     // VkMemoryOutputFlags outputMask;
4385                         VK_ACCESS_TRANSFER_READ_BIT,              // VkMemoryInputFlags inputMask;
4386                         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout;
4387                         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,     // VkImageLayout newLayout;
4388                         queueFamilyIndex,                         // uint32_t srcQueueFamilyIndex;
4389                         queueFamilyIndex,                         // uint32_t destQueueFamilyIndex;
4390                         *image,                                   // VkImage image;
4391                         {
4392                             VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
4393                             0u,                        // uint32_t baseMipLevel;
4394                             1u,                        // uint32_t mipLevels;
4395                             0u,                        // uint32_t baseArraySlice;
4396                             1u,                        // uint32_t arraySize;
4397                         }                              // VkImageSubresourceRange subresourceRange;
4398                     };
4399                     renderFinishBarrier.push_back(imgBarrier);
4400 
4401                     if (needInterface)
4402                     {
4403                         imgBarrier.image = *fragOutputImage;
4404                         renderFinishBarrier.push_back(imgBarrier);
4405                         vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
4406                                               VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0,
4407                                               (const VkMemoryBarrier *)DE_NULL, 0,
4408                                               (const VkBufferMemoryBarrier *)DE_NULL, 2, renderFinishBarrier.data());
4409                     }
4410                     else
4411                     {
4412                         vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
4413                                               VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0,
4414                                               (const VkMemoryBarrier *)DE_NULL, 0,
4415                                               (const VkBufferMemoryBarrier *)DE_NULL, 1, renderFinishBarrier.data());
4416                     }
4417                 }
4418 
4419                 {
4420                     const VkBufferImageCopy copyParams = {(VkDeviceSize)0u,         // VkDeviceSize bufferOffset;
4421                                                           (uint32_t)renderSize.x(), // uint32_t bufferRowLength;
4422                                                           (uint32_t)renderSize.y(), // uint32_t bufferImageHeight;
4423                                                           {
4424                                                               VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspect aspect;
4425                                                               0u,                        // uint32_t mipLevel;
4426                                                               0u,                        // uint32_t arrayLayer;
4427                                                               1u,                        // uint32_t arraySize;
4428                                                           },            // VkImageSubresourceCopy imageSubresource;
4429                                                           {0u, 0u, 0u}, // VkOffset3D imageOffset;
4430                                                           {renderSize.x(), renderSize.y(), 1u}};
4431                     vk.cmdCopyImageToBuffer(*cmdBuf, *image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *readImageBuffer, 1u,
4432                                             &copyParams);
4433 
4434                     if (needInterface)
4435                     {
4436                         vk.cmdCopyImageToBuffer(*cmdBuf, *fragOutputImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
4437                                                 *fragOutputBuffer, 1u, &copyParams);
4438                     }
4439                 }
4440 
4441                 {
4442                     vector<VkBufferMemoryBarrier> cpFinishBarriers;
4443                     VkBufferMemoryBarrier copyFinishBarrier = {
4444                         VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
4445                         DE_NULL,                                 // const void* pNext;
4446                         VK_ACCESS_TRANSFER_WRITE_BIT,            // VkMemoryOutputFlags outputMask;
4447                         VK_ACCESS_HOST_READ_BIT,                 // VkMemoryInputFlags inputMask;
4448                         queueFamilyIndex,                        // uint32_t srcQueueFamilyIndex;
4449                         queueFamilyIndex,                        // uint32_t destQueueFamilyIndex;
4450                         *readImageBuffer,                        // VkBuffer buffer;
4451                         0u,                                      // VkDeviceSize offset;
4452                         imageSizeBytes                           // VkDeviceSize size;
4453                     };
4454                     cpFinishBarriers.push_back(copyFinishBarrier);
4455 
4456                     if (needInterface)
4457                     {
4458                         copyFinishBarrier.buffer = *fragOutputBuffer;
4459                         copyFinishBarrier.size   = VK_WHOLE_SIZE;
4460                         cpFinishBarriers.push_back(copyFinishBarrier);
4461 
4462                         vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
4463                                               (VkDependencyFlags)0, 0, (const VkMemoryBarrier *)DE_NULL, 2,
4464                                               cpFinishBarriers.data(), 0, (const VkImageMemoryBarrier *)DE_NULL);
4465                     }
4466                     else
4467                     {
4468                         vk.cmdPipelineBarrier(*cmdBuf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
4469                                               (VkDependencyFlags)0, 0, (const VkMemoryBarrier *)DE_NULL, 1,
4470                                               cpFinishBarriers.data(), 0, (const VkImageMemoryBarrier *)DE_NULL);
4471                     }
4472                 }
4473             }
4474 
4475             endCommandBuffer(vk, *cmdBuf);
4476 
4477             if (firstPass)
4478             {
4479                 // Upload vertex data
4480                 {
4481                     void *vertexBufPtr = vertexBufferMemory->getHostPtr();
4482                     deMemcpy(vertexBufPtr, &vertexData[0], vertexDataSize);
4483                     flushAlloc(vk, device, *vertexBufferMemory);
4484                 }
4485 
4486                 if (needInterface)
4487                 {
4488                     vector<uint8_t> inputBufferBytes;
4489                     instance.interfaces.getInputBuffer()->getBytes(inputBufferBytes);
4490 
4491                     const uint32_t typNumBytes = instance.interfaces.getInputType().getNumBytes();
4492                     const uint32_t bufNumBytes = static_cast<uint32_t>(inputBufferBytes.size());
4493 
4494                     // Require that the test instantation provides four output values.
4495                     DE_ASSERT(bufNumBytes == 4 * typNumBytes);
4496 
4497                     // We have four triangles. Because interpolation happens before executing the fragment shader,
4498                     // we need to provide the same vertex attribute for the same triangle. That means, duplicate each
4499                     // value three times for all four values.
4500 
4501                     const uint8_t *provided = static_cast<const uint8_t *>(&inputBufferBytes.front());
4502                     vector<uint8_t> data;
4503 
4504                     data.reserve(3 * bufNumBytes);
4505 
4506                     for (uint32_t offset = 0; offset < bufNumBytes; offset += typNumBytes)
4507                         for (uint32_t vertexNdx = 0; vertexNdx < 3; ++vertexNdx)
4508                             for (uint32_t byteNdx = 0; byteNdx < typNumBytes; ++byteNdx)
4509                                 data.push_back(provided[offset + byteNdx]);
4510 
4511                     deMemcpy(vertexInputMemory->getHostPtr(), data.data(), data.size());
4512 
4513                     flushAlloc(vk, device, *vertexInputMemory);
4514                 }
4515                 firstPass = false;
4516             }
4517 
4518             // Submit & wait for completion
4519             submitCommandsAndWait(vk, device, queue, cmdBuf.get());
4520             context.resetCommandPoolForVKSC(device, *cmdPool);
4521         }
4522     }
4523 
4524     const void *imagePtr = readImageBufferMemory->getHostPtr();
4525     const tcu::ConstPixelBufferAccess pixelBuffer(
4526         tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), renderSize.x(), renderSize.y(), 1,
4527         imagePtr);
4528     // Log image
4529     invalidateAlloc(vk, device, *readImageBufferMemory);
4530     context.getTestContext().getLog() << TestLog::Image("Result", "Result", pixelBuffer);
4531 
4532     if (needInterface)
4533         invalidateAlloc(vk, device, *fragOutputMemory);
4534 
4535     // Make sure all output resources are ready.
4536     for (uint32_t outputNdx = 0; outputNdx < numOutResources; ++outputNdx)
4537         invalidateAlloc(vk, device, *outResourceMemories[outputNdx]);
4538 
4539     const RGBA threshold(1, 1, 1, 1);
4540 
4541     const RGBA upperLeft(pixelBuffer.getPixel(1, 1));
4542     if (!tcu::compareThreshold(upperLeft, instance.outputColors[0], threshold))
4543         return TestStatus(instance.failResult, instance.getSpecializedFailMessage("Upper left corner mismatch"));
4544 
4545     const RGBA upperRight(pixelBuffer.getPixel(pixelBuffer.getWidth() - 1, 1));
4546     if (!tcu::compareThreshold(upperRight, instance.outputColors[1], threshold))
4547         return TestStatus(instance.failResult, instance.getSpecializedFailMessage("Upper right corner mismatch"));
4548 
4549     const RGBA lowerLeft(pixelBuffer.getPixel(1, pixelBuffer.getHeight() - 1));
4550     if (!tcu::compareThreshold(lowerLeft, instance.outputColors[2], threshold))
4551         return TestStatus(instance.failResult, instance.getSpecializedFailMessage("Lower left corner mismatch"));
4552 
4553     const RGBA lowerRight(pixelBuffer.getPixel(pixelBuffer.getWidth() - 1, pixelBuffer.getHeight() - 1));
4554     if (!tcu::compareThreshold(lowerRight, instance.outputColors[3], threshold))
4555         return TestStatus(instance.failResult, instance.getSpecializedFailMessage("Lower right corner mismatch"));
4556 
4557     // Check that the contents in the ouput variable matches expected.
4558     if (needInterface)
4559     {
4560         vector<uint8_t> inputBufferBytes;
4561         vector<uint8_t> outputBufferBytes;
4562 
4563         instance.interfaces.getInputBuffer()->getBytes(inputBufferBytes);
4564         instance.interfaces.getOutputBuffer()->getBytes(outputBufferBytes);
4565 
4566         const IFDataType &inputType  = instance.interfaces.getInputType();
4567         const IFDataType &outputType = instance.interfaces.getOutputType();
4568         const void *inputData        = &inputBufferBytes.front();
4569         const void *outputData       = &outputBufferBytes.front();
4570         vector<std::pair<int, int>> positions;
4571         const tcu::ConstPixelBufferAccess fragOutputBufferAccess(outputType.getTextureFormat(), renderSize.x(),
4572                                                                  renderSize.y(), 1, fragOutputMemory->getHostPtr());
4573 
4574         positions.push_back(std::make_pair(1, 1));
4575         positions.push_back(std::make_pair(fragOutputBufferAccess.getWidth() - 1, 1));
4576         positions.push_back(std::make_pair(1, fragOutputBufferAccess.getHeight() - 1));
4577         positions.push_back(
4578             std::make_pair(fragOutputBufferAccess.getWidth() - 1, fragOutputBufferAccess.getHeight() - 1));
4579 
4580         for (uint32_t posNdx = 0; posNdx < positions.size(); ++posNdx)
4581         {
4582             const int x = positions[posNdx].first;
4583             const int y = positions[posNdx].second;
4584             bool equal  = true;
4585 
4586             if (outputType.elementType == NUMBERTYPE_FLOAT32)
4587             {
4588                 const float *expected = static_cast<const float *>(outputData) + posNdx * outputType.numElements;
4589                 const float *actual   = static_cast<const float *>(fragOutputBufferAccess.getPixelPtr(x, y));
4590 
4591                 for (uint32_t eleNdx = 0; eleNdx < outputType.numElements; ++eleNdx)
4592                     if (!compare32BitFloat(expected[eleNdx], actual[eleNdx], context.getTestContext().getLog()))
4593                         equal = false;
4594             }
4595             else if (outputType.elementType == NUMBERTYPE_INT32)
4596             {
4597                 const int32_t *expected = static_cast<const int32_t *>(outputData) + posNdx * outputType.numElements;
4598                 const int32_t *actual   = static_cast<const int32_t *>(fragOutputBufferAccess.getPixelPtr(x, y));
4599 
4600                 for (uint32_t eleNdx = 0; eleNdx < outputType.numElements; ++eleNdx)
4601                     if (expected[eleNdx] != actual[eleNdx])
4602                         equal = false;
4603             }
4604             else if (outputType.elementType == NUMBERTYPE_UINT32)
4605             {
4606                 const uint32_t *expected = static_cast<const uint32_t *>(outputData) + posNdx * outputType.numElements;
4607                 const uint32_t *actual   = static_cast<const uint32_t *>(fragOutputBufferAccess.getPixelPtr(x, y));
4608 
4609                 for (uint32_t eleNdx = 0; eleNdx < outputType.numElements; ++eleNdx)
4610                     if (expected[eleNdx] != actual[eleNdx])
4611                         equal = false;
4612             }
4613             else if (outputType.elementType == NUMBERTYPE_FLOAT16 && inputType.elementType == NUMBERTYPE_FLOAT64)
4614             {
4615                 const double *original  = static_cast<const double *>(inputData) + posNdx * outputType.numElements;
4616                 const deFloat16 *actual = static_cast<const deFloat16 *>(fragOutputBufferAccess.getPixelPtr(x, y));
4617 
4618                 for (uint32_t eleNdx = 0; eleNdx < outputType.numElements; ++eleNdx)
4619                     if (!compare16BitFloat64(original[eleNdx], actual[eleNdx], instance.interfaces.getRoundingMode(),
4620                                              context.getTestContext().getLog()))
4621                         equal = false;
4622             }
4623             else if (outputType.elementType == NUMBERTYPE_FLOAT16 && inputType.elementType != NUMBERTYPE_FLOAT64)
4624             {
4625                 if (inputType.elementType == NUMBERTYPE_FLOAT16)
4626                 {
4627                     const deFloat16 *original =
4628                         static_cast<const deFloat16 *>(inputData) + posNdx * outputType.numElements;
4629                     const deFloat16 *actual = static_cast<const deFloat16 *>(fragOutputBufferAccess.getPixelPtr(x, y));
4630 
4631                     for (uint32_t eleNdx = 0; eleNdx < outputType.numElements; ++eleNdx)
4632                         if (!compare16BitFloat(original[eleNdx], actual[eleNdx], context.getTestContext().getLog()))
4633                             equal = false;
4634                 }
4635                 else
4636                 {
4637                     const float *original   = static_cast<const float *>(inputData) + posNdx * outputType.numElements;
4638                     const deFloat16 *actual = static_cast<const deFloat16 *>(fragOutputBufferAccess.getPixelPtr(x, y));
4639 
4640                     for (uint32_t eleNdx = 0; eleNdx < outputType.numElements; ++eleNdx)
4641                         if (!compare16BitFloat(original[eleNdx], actual[eleNdx], instance.interfaces.getRoundingMode(),
4642                                                context.getTestContext().getLog()))
4643                             equal = false;
4644                 }
4645             }
4646             else if (outputType.elementType == NUMBERTYPE_INT16)
4647             {
4648                 const int16_t *expected = static_cast<const int16_t *>(outputData) + posNdx * outputType.numElements;
4649                 const int16_t *actual   = static_cast<const int16_t *>(fragOutputBufferAccess.getPixelPtr(x, y));
4650 
4651                 for (uint32_t eleNdx = 0; eleNdx < outputType.numElements; ++eleNdx)
4652                     if (expected[eleNdx] != actual[eleNdx])
4653                         equal = false;
4654             }
4655             else if (outputType.elementType == NUMBERTYPE_UINT16)
4656             {
4657                 const uint16_t *expected = static_cast<const uint16_t *>(outputData) + posNdx * outputType.numElements;
4658                 const uint16_t *actual   = static_cast<const uint16_t *>(fragOutputBufferAccess.getPixelPtr(x, y));
4659 
4660                 for (uint32_t eleNdx = 0; eleNdx < outputType.numElements; ++eleNdx)
4661                     if (expected[eleNdx] != actual[eleNdx])
4662                         equal = false;
4663             }
4664             else if (outputType.elementType == NUMBERTYPE_FLOAT64)
4665             {
4666                 const double *expected = static_cast<const double *>(outputData) + posNdx * outputType.numElements;
4667                 const double *actual   = static_cast<const double *>(fragOutputBufferAccess.getPixelPtr(x, y));
4668 
4669                 for (uint32_t eleNdx = 0; eleNdx < outputType.numElements; ++eleNdx)
4670                     if (!compare64BitFloat(expected[eleNdx], actual[eleNdx], context.getTestContext().getLog()))
4671                         equal = false;
4672             }
4673             else
4674             {
4675                 DE_ASSERT(0 && "unhandled type");
4676             }
4677 
4678             if (!equal)
4679                 return TestStatus(instance.failResult,
4680                                   instance.getSpecializedFailMessage("fragment output dat point #" +
4681                                                                      numberToString(posNdx) + " mismatch"));
4682         }
4683     }
4684 
4685     // Check the contents in output resources match with expected.
4686     for (uint32_t outputNdx = 0; outputNdx < numOutResources; ++outputNdx)
4687     {
4688         const BufferSp &expected = instance.resources.outputs[outputNdx].getBuffer();
4689 
4690         if (instance.resources.verifyIO != DE_NULL)
4691         {
4692             if (!(*instance.resources.verifyIO)(instance.resources.inputs, outResourceMemories,
4693                                                 instance.resources.outputs, context.getTestContext().getLog()))
4694                 return tcu::TestStatus::fail("Resource returned doesn't match with expected");
4695         }
4696         else
4697         {
4698             vector<uint8_t> expectedBytes;
4699             expected->getBytes(expectedBytes);
4700 
4701             if (deMemCmp(&expectedBytes.front(), outResourceMemories[outputNdx]->getHostPtr(), expectedBytes.size()))
4702             {
4703                 const size_t numExpectedEntries = expectedBytes.size() / sizeof(float);
4704                 float *expectedFloats           = reinterpret_cast<float *>(&expectedBytes.front());
4705                 float *outputFloats = reinterpret_cast<float *>(outResourceMemories[outputNdx]->getHostPtr());
4706                 float diff          = 0.0f;
4707                 uint32_t bitDiff    = 0;
4708 
4709                 for (size_t expectedNdx = 0; expectedNdx < numExpectedEntries; ++expectedNdx)
4710                 {
4711                     // RTZ and RNE can introduce a difference of a single ULP
4712                     // The RTZ output will always be either equal or lower than the RNE expected,
4713                     // so perform a bitwise subtractraction and check for the ULP difference
4714                     bitDiff = *reinterpret_cast<uint32_t *>(&expectedFloats[expectedNdx]) -
4715                               *reinterpret_cast<uint32_t *>(&outputFloats[expectedNdx]);
4716 
4717                     // Allow a maximum of 1 ULP difference to account for RTZ rounding
4718                     if (bitDiff & (~0x1))
4719                     {
4720                         // Note: RTZ/RNE rounding leniency isn't applied for the checks below:
4721 
4722                         // Some *variable_pointers* tests store counters in buffer
4723                         // whose value may vary if the same shader may be executed for multiple times
4724                         // in this case the output value can be expected value + non-negative integer N
4725                         if (instance.customizedStages == VK_SHADER_STAGE_VERTEX_BIT ||
4726                             instance.customizedStages == VK_SHADER_STAGE_GEOMETRY_BIT ||
4727                             instance.customizedStages == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
4728                             instance.customizedStages == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
4729                         {
4730                             if (deFloatIsInf(outputFloats[expectedNdx]) || deFloatIsNaN(outputFloats[expectedNdx]))
4731                                 return tcu::TestStatus::fail("Value returned is invalid");
4732 
4733                             diff             = outputFloats[expectedNdx] - expectedFloats[expectedNdx];
4734                             uint32_t intDiff = static_cast<uint32_t>(diff);
4735 
4736                             if ((diff < 0.0f) || (expectedFloats[expectedNdx] + static_cast<float>(intDiff)) !=
4737                                                      outputFloats[expectedNdx])
4738                                 return tcu::TestStatus::fail(
4739                                     "Value returned should be equal to expected value plus non-negative integer");
4740                         }
4741                         else
4742                         {
4743                             return tcu::TestStatus::fail(
4744                                 "Resource returned should be equal to expected, allowing for RTZ/RNE rounding");
4745                         }
4746                     }
4747                 }
4748             }
4749         }
4750     }
4751 
4752     return TestStatus::pass("Rendered output matches input");
4753 }
4754 
getVertFragPipelineStages(void)4755 const vector<ShaderElement> &getVertFragPipelineStages(void)
4756 {
4757     static vector<ShaderElement> vertFragPipelineStages;
4758     if (vertFragPipelineStages.empty())
4759     {
4760         vertFragPipelineStages.push_back(ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT));
4761         vertFragPipelineStages.push_back(ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT));
4762     }
4763     return vertFragPipelineStages;
4764 }
4765 
getTessPipelineStages(void)4766 const vector<ShaderElement> &getTessPipelineStages(void)
4767 {
4768     static vector<ShaderElement> tessPipelineStages;
4769     if (tessPipelineStages.empty())
4770     {
4771         tessPipelineStages.push_back(ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT));
4772         tessPipelineStages.push_back(ShaderElement("tessc", "main", VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT));
4773         tessPipelineStages.push_back(ShaderElement("tesse", "main", VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT));
4774         tessPipelineStages.push_back(ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT));
4775     }
4776     return tessPipelineStages;
4777 }
4778 
getGeomPipelineStages(void)4779 const vector<ShaderElement> &getGeomPipelineStages(void)
4780 {
4781     static vector<ShaderElement> geomPipelineStages;
4782     if (geomPipelineStages.empty())
4783     {
4784         geomPipelineStages.push_back(ShaderElement("vert", "main", VK_SHADER_STAGE_VERTEX_BIT));
4785         geomPipelineStages.push_back(ShaderElement("geom", "main", VK_SHADER_STAGE_GEOMETRY_BIT));
4786         geomPipelineStages.push_back(ShaderElement("frag", "main", VK_SHADER_STAGE_FRAGMENT_BIT));
4787     }
4788     return geomPipelineStages;
4789 }
4790 
4791 // Helper structure used by addTestForStage function.
4792 struct StageData
4793 {
4794     typedef const vector<ShaderElement> &(*GetPipelineStagesFn)();
4795     typedef void (*AddShaderCodeCustomStageFn)(vk::SourceCollections &, InstanceContext);
4796 
4797     GetPipelineStagesFn getPipelineFn;
4798     AddShaderCodeCustomStageFn initProgramsFn;
4799 
StageDatavkt::SpirVAssembly::StageData4800     StageData() : getPipelineFn(DE_NULL), initProgramsFn(DE_NULL)
4801     {
4802     }
4803 
StageDatavkt::SpirVAssembly::StageData4804     StageData(GetPipelineStagesFn pipelineGetter, AddShaderCodeCustomStageFn programsInitializer)
4805         : getPipelineFn(pipelineGetter)
4806         , initProgramsFn(programsInitializer)
4807     {
4808     }
4809 };
4810 
4811 // Helper function used by addTestForStage function.
getStageData(vk::VkShaderStageFlagBits stage)4812 const StageData &getStageData(vk::VkShaderStageFlagBits stage)
4813 {
4814     // Construct map
4815     static map<vk::VkShaderStageFlagBits, StageData> testedStageData;
4816     if (testedStageData.empty())
4817     {
4818         testedStageData[VK_SHADER_STAGE_VERTEX_BIT] = StageData(getVertFragPipelineStages, addShaderCodeCustomVertex);
4819         testedStageData[VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT] =
4820             StageData(getTessPipelineStages, addShaderCodeCustomTessControl);
4821         testedStageData[VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT] =
4822             StageData(getTessPipelineStages, addShaderCodeCustomTessEval);
4823         testedStageData[VK_SHADER_STAGE_GEOMETRY_BIT] = StageData(getGeomPipelineStages, addShaderCodeCustomGeometry);
4824         testedStageData[VK_SHADER_STAGE_FRAGMENT_BIT] =
4825             StageData(getVertFragPipelineStages, addShaderCodeCustomFragment);
4826     }
4827 
4828     return testedStageData[stage];
4829 }
4830 
createTestForStage(vk::VkShaderStageFlagBits stage,const std::string & name,const RGBA (& inputColors)[4],const RGBA (& outputColors)[4],const map<string,string> & testCodeFragments,const SpecConstants & specConstants,const PushConstants & pushConstants,const GraphicsResources & resources,const GraphicsInterfaces & interfaces,const vector<string> & extensions,VulkanFeatures vulkanFeatures,tcu::TestCaseGroup * tests,const qpTestResult failResult,const string & failMessageTemplate,const bool renderFullSquare,const bool splitRenderArea)4831 void createTestForStage(vk::VkShaderStageFlagBits stage, const std::string &name, const RGBA (&inputColors)[4],
4832                         const RGBA (&outputColors)[4], const map<string, string> &testCodeFragments,
4833                         const SpecConstants &specConstants, const PushConstants &pushConstants,
4834                         const GraphicsResources &resources, const GraphicsInterfaces &interfaces,
4835                         const vector<string> &extensions, VulkanFeatures vulkanFeatures, tcu::TestCaseGroup *tests,
4836                         const qpTestResult failResult, const string &failMessageTemplate, const bool renderFullSquare,
4837                         const bool splitRenderArea)
4838 {
4839     const StageData &stageData = getStageData(stage);
4840     DE_ASSERT(stageData.getPipelineFn || stageData.initProgramsFn);
4841     const vector<ShaderElement> &pipeline = stageData.getPipelineFn();
4842 
4843     StageToSpecConstantMap specConstantMap;
4844     if (!specConstants.empty())
4845         specConstantMap[stage] = specConstants;
4846 
4847     InstanceContext ctx(inputColors, outputColors, testCodeFragments, specConstantMap, pushConstants, resources,
4848                         interfaces, extensions, vulkanFeatures, stage);
4849     ctx.splitRenderArea = splitRenderArea;
4850     for (size_t i = 0; i < pipeline.size(); ++i)
4851     {
4852         ctx.moduleMap[pipeline[i].moduleName].push_back(std::make_pair(pipeline[i].entryName, pipeline[i].stage));
4853         ctx.requiredStages = static_cast<VkShaderStageFlagBits>(ctx.requiredStages | pipeline[i].stage);
4854     }
4855 
4856     ctx.failResult = failResult;
4857     if (!failMessageTemplate.empty())
4858         ctx.failMessageTemplate = failMessageTemplate;
4859 
4860     ctx.renderFullSquare = renderFullSquare;
4861     ctx.splitRenderArea  = splitRenderArea;
4862     addFunctionCaseWithPrograms<InstanceContext>(tests, name, stageData.initProgramsFn, runAndVerifyDefaultPipeline,
4863                                                  ctx);
4864 }
4865 
createTestsForAllStages(const std::string & name,const RGBA (& inputColors)[4],const RGBA (& outputColors)[4],const map<string,string> & testCodeFragments,const SpecConstants & specConstants,const PushConstants & pushConstants,const GraphicsResources & resources,const GraphicsInterfaces & interfaces,const vector<string> & extensions,VulkanFeatures vulkanFeatures,tcu::TestCaseGroup * tests,const qpTestResult failResult,const string & failMessageTemplate,const bool splitRenderArea)4866 void createTestsForAllStages(const std::string &name, const RGBA (&inputColors)[4], const RGBA (&outputColors)[4],
4867                              const map<string, string> &testCodeFragments, const SpecConstants &specConstants,
4868                              const PushConstants &pushConstants, const GraphicsResources &resources,
4869                              const GraphicsInterfaces &interfaces, const vector<string> &extensions,
4870                              VulkanFeatures vulkanFeatures, tcu::TestCaseGroup *tests, const qpTestResult failResult,
4871                              const string &failMessageTemplate, const bool splitRenderArea)
4872 {
4873     createTestForStage(VK_SHADER_STAGE_VERTEX_BIT, name + "_vert", inputColors, outputColors, testCodeFragments,
4874                        specConstants, pushConstants, resources, interfaces, extensions, vulkanFeatures, tests,
4875                        failResult, failMessageTemplate);
4876 
4877     createTestForStage(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, name + "_tessc", inputColors, outputColors,
4878                        testCodeFragments, specConstants, pushConstants, resources, interfaces, extensions,
4879                        vulkanFeatures, tests, failResult, failMessageTemplate);
4880 
4881     createTestForStage(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, name + "_tesse", inputColors, outputColors,
4882                        testCodeFragments, specConstants, pushConstants, resources, interfaces, extensions,
4883                        vulkanFeatures, tests, failResult, failMessageTemplate);
4884 
4885     createTestForStage(VK_SHADER_STAGE_GEOMETRY_BIT, name + "_geom", inputColors, outputColors, testCodeFragments,
4886                        specConstants, pushConstants, resources, interfaces, extensions, vulkanFeatures, tests,
4887                        failResult, failMessageTemplate);
4888 
4889     createTestForStage(VK_SHADER_STAGE_FRAGMENT_BIT, name + "_frag", inputColors, outputColors, testCodeFragments,
4890                        specConstants, pushConstants, resources, interfaces, extensions, vulkanFeatures, tests,
4891                        failResult, failMessageTemplate, false, splitRenderArea);
4892 }
4893 
addTessCtrlTest(tcu::TestCaseGroup * group,const char * name,const map<string,string> & fragments)4894 void addTessCtrlTest(tcu::TestCaseGroup *group, const char *name, const map<string, string> &fragments)
4895 {
4896     RGBA defaultColors[4];
4897     getDefaultColors(defaultColors);
4898 
4899     createTestForStage(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, name, defaultColors, defaultColors, fragments,
4900                        SpecConstants(), PushConstants(), GraphicsResources(), GraphicsInterfaces(), vector<string>(),
4901                        VulkanFeatures(), group);
4902 }
4903 
4904 } // namespace SpirVAssembly
4905 } // namespace vkt
4906