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