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