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