1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2019 Valve Corporation.
6 * Copyright (c) 2019 The Khronos Group Inc.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief 64-bit data type comparison operations.
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktSpvAsm64bitCompareTests.hpp"
26 #include "vktTestGroupUtil.hpp"
27 #include "vktSpvAsmUtils.hpp"
28 #include "vkDefs.hpp"
29 #include "vktTestCase.hpp"
30 #include "vkQueryUtil.hpp"
31 #include "vkMemUtil.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vkBuilderUtil.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkCmdUtil.hpp"
36
37 #include "tcuStringTemplate.hpp"
38
39 #include <string>
40 #include <vector>
41 #include <utility>
42 #include <cmath>
43 #include <sstream>
44 #include <memory>
45 #include <limits>
46
47 namespace vkt
48 {
49 namespace SpirVAssembly
50 {
51 namespace
52 {
53
54 template <typename T>
55 class CompareOperation
56 {
57 public:
~CompareOperation()58 virtual ~CompareOperation()
59 {
60 }
61
62 virtual std::string spirvName() const = 0;
63 virtual bool run(T left, T right) const = 0;
64 };
65
66 // Helper intermediate class to be able to implement Ordered and Unordered floating point operations in a simpler way.
67 class DoubleCompareOperation : public CompareOperation<double>
68 {
69 public:
70 struct BasicImplementation
71 {
~BasicImplementationvkt::SpirVAssembly::__anon071ae8e90111::DoubleCompareOperation::BasicImplementation72 virtual ~BasicImplementation()
73 {
74 }
75 virtual std::string nameSuffix() const = 0;
76 virtual bool run(double left, double right) const = 0; // No NaNs here.
77 };
78
spirvName() const79 virtual std::string spirvName() const
80 {
81 return "OpF" + std::string(m_ordered ? "Ord" : "Unord") + m_impl.nameSuffix();
82 }
83
run(double left,double right) const84 virtual bool run(double left, double right) const
85 {
86 if (nanInvolved(left, right))
87 return !m_ordered; // Ordered operations return false when NaN is involved.
88 return m_impl.run(left, right);
89 }
90
DoubleCompareOperation(bool ordered,const BasicImplementation & impl)91 DoubleCompareOperation(bool ordered, const BasicImplementation &impl) : m_ordered(ordered), m_impl(impl)
92 {
93 }
94
95 private:
nanInvolved(double left,double right) const96 bool nanInvolved(double left, double right) const
97 {
98 return std::isnan(left) || std::isnan(right);
99 }
100
101 const bool m_ordered;
102 const BasicImplementation &m_impl;
103 };
104
105 #define GEN_DOUBLE_BASIC_IMPL(NAME, OPERATION) \
106 struct NAME##DoubleBasicImplClass : public DoubleCompareOperation::BasicImplementation \
107 { \
108 virtual std::string nameSuffix() const \
109 { \
110 return #NAME; \
111 } \
112 virtual bool run(double left, double right) const \
113 { \
114 return left OPERATION right; \
115 } \
116 }; \
117 NAME##DoubleBasicImplClass NAME##DoubleBasicImplInstance;
118
119 GEN_DOUBLE_BASIC_IMPL(Equal, ==)
120 GEN_DOUBLE_BASIC_IMPL(NotEqual, !=)
121 GEN_DOUBLE_BASIC_IMPL(LessThan, <)
122 GEN_DOUBLE_BASIC_IMPL(GreaterThan, >)
123 GEN_DOUBLE_BASIC_IMPL(LessThanEqual, <=)
124 GEN_DOUBLE_BASIC_IMPL(GreaterThanEqual, >=)
125
126 #define GEN_FORDERED_OP(NAME) DoubleCompareOperation FOrdered##NAME##Op(true, NAME##DoubleBasicImplInstance)
127 #define GEN_FUNORDERED_OP(NAME) DoubleCompareOperation FUnordered##NAME##Op(false, NAME##DoubleBasicImplInstance)
128 #define GEN_FBOTH_OP(NAME) \
129 GEN_FORDERED_OP(NAME); \
130 GEN_FUNORDERED_OP(NAME);
131
132 GEN_FBOTH_OP(Equal)
133 GEN_FBOTH_OP(NotEqual)
134 GEN_FBOTH_OP(LessThan)
135 GEN_FBOTH_OP(GreaterThan)
136 GEN_FBOTH_OP(LessThanEqual)
137 GEN_FBOTH_OP(GreaterThanEqual)
138
139 template <typename IntClass>
140 class IntCompareOperation : public CompareOperation<IntClass>
141 {
142 public:
143 struct Implementation
144 {
~Implementationvkt::SpirVAssembly::__anon071ae8e90111::IntCompareOperation::Implementation145 virtual ~Implementation()
146 {
147 }
148
149 virtual std::string typeChar() const = 0;
150 virtual std::string opName() const = 0;
151 virtual bool run(IntClass left, IntClass right) const = 0;
152 };
153
spirvName() const154 virtual std::string spirvName() const
155 {
156 return "Op" + m_impl.typeChar() + m_impl.opName();
157 }
158
run(IntClass left,IntClass right) const159 virtual bool run(IntClass left, IntClass right) const
160 {
161 return m_impl.run(left, right);
162 }
163
IntCompareOperation(const Implementation & impl)164 IntCompareOperation(const Implementation &impl) : m_impl(impl)
165 {
166 }
167
168 private:
169 const Implementation &m_impl;
170 };
171
172 #define GEN_INT_IMPL(INTTYPE, PREFIX, TYPECHAR, OPNAME, OPERATOR) \
173 struct PREFIX##OPNAME##IntImplClass : public IntCompareOperation<INTTYPE>::Implementation \
174 { \
175 virtual std::string typeChar() const \
176 { \
177 return #TYPECHAR; \
178 } \
179 virtual std::string opName() const \
180 { \
181 return #OPNAME; \
182 } \
183 virtual bool run(INTTYPE left, INTTYPE right) const \
184 { \
185 return left OPERATOR right; \
186 } \
187 }; \
188 PREFIX##OPNAME##IntImplClass PREFIX##OPNAME##IntImplInstance;
189
190 #define GEN_ALL_INT_TYPE_IMPL(INTTYPE, PREFIX, TYPECHAR) \
191 GEN_INT_IMPL(INTTYPE, PREFIX, I, Equal, ==) \
192 GEN_INT_IMPL(INTTYPE, PREFIX, I, NotEqual, !=) \
193 GEN_INT_IMPL(INTTYPE, PREFIX, TYPECHAR, GreaterThan, >) \
194 GEN_INT_IMPL(INTTYPE, PREFIX, TYPECHAR, GreaterThanEqual, >=) \
195 GEN_INT_IMPL(INTTYPE, PREFIX, TYPECHAR, LessThan, <) \
196 GEN_INT_IMPL(INTTYPE, PREFIX, TYPECHAR, LessThanEqual, <=)
197
198 GEN_ALL_INT_TYPE_IMPL(int64_t, int64, S)
199 GEN_ALL_INT_TYPE_IMPL(uint64_t, uint64, U)
200
201 #define GEN_INT_OP(INTTYPE, PREFIX, OPNAME) \
202 struct PREFIX##OPNAME##OpClass : public IntCompareOperation<INTTYPE> \
203 { \
204 PREFIX##OPNAME##OpClass() : IntCompareOperation<INTTYPE>(PREFIX##OPNAME##IntImplInstance) \
205 { \
206 } \
207 }; \
208 PREFIX##OPNAME##OpClass PREFIX##OPNAME##Op;
209
210 #define GEN_ALL_INT_OPS(INTTYPE, PREFIX) \
211 GEN_INT_OP(INTTYPE, PREFIX, Equal) \
212 GEN_INT_OP(INTTYPE, PREFIX, NotEqual) \
213 GEN_INT_OP(INTTYPE, PREFIX, GreaterThan) \
214 GEN_INT_OP(INTTYPE, PREFIX, GreaterThanEqual) \
215 GEN_INT_OP(INTTYPE, PREFIX, LessThan) \
216 GEN_INT_OP(INTTYPE, PREFIX, LessThanEqual)
217
218 GEN_ALL_INT_OPS(int64_t, int64)
219 GEN_ALL_INT_OPS(uint64_t, uint64)
220
221 enum DataType
222 {
223 DATA_TYPE_SINGLE = 0,
224 DATA_TYPE_VECTOR,
225 DATA_TYPE_MAX_ENUM,
226 };
227
228 template <class T>
229 using OperandsVector = std::vector<std::pair<T, T>>;
230
231 template <class T>
232 struct TestParameters
233 {
234 DataType dataType;
235 const CompareOperation<T> &operation;
236 vk::VkShaderStageFlagBits stage;
237 const OperandsVector<T> &operands;
238 bool requireNanPreserve;
239 };
240
241 // Shader template for the compute stage using single scalars.
242 // Generated from the following GLSL shader, replacing some bits by template parameters.
243 #if 0
244 #version 430
245
246 // Left operands, right operands and results.
247 layout(binding = 0) buffer Input1 { double values[]; } input1;
248 layout(binding = 1) buffer Input2 { double values[]; } input2;
249 layout(binding = 2) buffer Output1 { int values[]; } output1;
250
251 void main()
252 {
253 for (int i = 0; i < 20; i++) {
254 output1.values[i] = int(input1.values[i] == input2.values[i]);
255 }
256 }
257 #endif
258 const tcu::StringTemplate CompShaderSingle(R"(
259 OpCapability Shader
260 ${OPCAPABILITY}
261 ${NANCAP}
262 ${NANEXT}
263 %1 = OpExtInstImport "GLSL.std.450"
264 OpMemoryModel Logical GLSL450
265 OpEntryPoint GLCompute %main "main"
266 ${NANMODE}
267 OpExecutionMode %main LocalSize 1 1 1
268 OpName %main "main"
269 OpName %i "i"
270 OpName %Output1 "Output1"
271 OpMemberName %Output1 0 "values"
272 OpName %output1 "output1"
273 OpName %Input1 "Input1"
274 OpMemberName %Input1 0 "values"
275 OpName %input1 "input1"
276 OpName %Input2 "Input2"
277 OpMemberName %Input2 0 "values"
278 OpName %input2 "input2"
279 OpDecorate %_runtimearr_int ArrayStride 4
280 OpMemberDecorate %Output1 0 Offset 0
281 OpDecorate %Output1 BufferBlock
282 OpDecorate %output1 DescriptorSet 0
283 OpDecorate %output1 Binding 2
284 OpDecorate %_runtimearr_tinput ArrayStride 8
285 OpMemberDecorate %Input1 0 Offset 0
286 OpDecorate %Input1 BufferBlock
287 OpDecorate %input1 DescriptorSet 0
288 OpDecorate %input1 Binding 0
289 OpDecorate %_runtimearr_tinput_0 ArrayStride 8
290 OpMemberDecorate %Input2 0 Offset 0
291 OpDecorate %Input2 BufferBlock
292 OpDecorate %input2 DescriptorSet 0
293 OpDecorate %input2 Binding 1
294 %void = OpTypeVoid
295 %3 = OpTypeFunction %void
296 %int = OpTypeInt 32 1
297 %_ptr_Function_int = OpTypePointer Function %int
298 %int_0 = OpConstant %int 0
299 %niters = OpConstant %int ${ITERS}
300 %bool = OpTypeBool
301 %_runtimearr_int = OpTypeRuntimeArray %int
302 %Output1 = OpTypeStruct %_runtimearr_int
303 %_ptr_Uniform_Output1 = OpTypePointer Uniform %Output1
304 %output1 = OpVariable %_ptr_Uniform_Output1 Uniform
305 %tinput = ${OPTYPE}
306 %_runtimearr_tinput = OpTypeRuntimeArray %tinput
307 %Input1 = OpTypeStruct %_runtimearr_tinput
308 %_ptr_Uniform_Input1 = OpTypePointer Uniform %Input1
309 %input1 = OpVariable %_ptr_Uniform_Input1 Uniform
310 %_ptr_Uniform_tinput = OpTypePointer Uniform %tinput
311 %_runtimearr_tinput_0 = OpTypeRuntimeArray %tinput
312 %Input2 = OpTypeStruct %_runtimearr_tinput_0
313 %_ptr_Uniform_Input2 = OpTypePointer Uniform %Input2
314 %input2 = OpVariable %_ptr_Uniform_Input2 Uniform
315 %int_1 = OpConstant %int 1
316 %_ptr_Uniform_int = OpTypePointer Uniform %int
317 %main = OpFunction %void None %3
318 %5 = OpLabel
319 %i = OpVariable %_ptr_Function_int Function
320 OpStore %i %int_0
321 OpBranch %10
322 %10 = OpLabel
323 OpLoopMerge %12 %13 None
324 OpBranch %14
325 %14 = OpLabel
326 %15 = OpLoad %int %i
327 %18 = OpSLessThan %bool %15 %niters
328 OpBranchConditional %18 %11 %12
329 %11 = OpLabel
330 %23 = OpLoad %int %i
331 %29 = OpLoad %int %i
332 %31 = OpAccessChain %_ptr_Uniform_tinput %input1 %int_0 %29
333 %32 = OpLoad %tinput %31
334 %37 = OpLoad %int %i
335 %38 = OpAccessChain %_ptr_Uniform_tinput %input2 %int_0 %37
336 %39 = OpLoad %tinput %38
337 %40 = ${OPNAME} %bool %32 %39
338 %42 = OpSelect %int %40 %int_1 %int_0
339 %44 = OpAccessChain %_ptr_Uniform_int %output1 %int_0 %23
340 OpStore %44 %42
341 OpBranch %13
342 %13 = OpLabel
343 %45 = OpLoad %int %i
344 %46 = OpIAdd %int %45 %int_1
345 OpStore %i %46
346 OpBranch %10
347 %12 = OpLabel
348 OpReturn
349 OpFunctionEnd
350 )");
351
352 // Shader template for the compute stage using vectors.
353 // Generated from the following GLSL shader, replacing some bits by template parameters.
354 // Note the number of iterations needs to be divided by 4 as the shader will consume 4 doubles at a time.
355 #if 0
356 #version 430
357
358 // Left operands, right operands and results.
359 layout(binding = 0) buffer Input1 { dvec4 values[]; } input1;
360 layout(binding = 1) buffer Input2 { dvec4 values[]; } input2;
361 layout(binding = 2) buffer Output1 { ivec4 values[]; } output1;
362
363 void main()
364 {
365 for (int i = 0; i < 5; i++) {
366 output1.values[i] = ivec4(equal(input1.values[i], input2.values[i]));
367 }
368 }
369 #endif
370 const tcu::StringTemplate CompShaderVector(R"(
371 OpCapability Shader
372 ${OPCAPABILITY}
373 ${NANCAP}
374 ${NANEXT}
375 %1 = OpExtInstImport "GLSL.std.450"
376 OpMemoryModel Logical GLSL450
377 OpEntryPoint GLCompute %main "main"
378 ${NANMODE}
379 OpExecutionMode %main LocalSize 1 1 1
380 OpName %main "main"
381 OpName %i "i"
382 OpName %Output1 "Output1"
383 OpMemberName %Output1 0 "values"
384 OpName %output1 "output1"
385 OpName %Input1 "Input1"
386 OpMemberName %Input1 0 "values"
387 OpName %input1 "input1"
388 OpName %Input2 "Input2"
389 OpMemberName %Input2 0 "values"
390 OpName %input2 "input2"
391 OpDecorate %_runtimearr_v4int ArrayStride 16
392 OpMemberDecorate %Output1 0 Offset 0
393 OpDecorate %Output1 BufferBlock
394 OpDecorate %output1 DescriptorSet 0
395 OpDecorate %output1 Binding 2
396 OpDecorate %_runtimearr_v4tinput ArrayStride 32
397 OpMemberDecorate %Input1 0 Offset 0
398 OpDecorate %Input1 BufferBlock
399 OpDecorate %input1 DescriptorSet 0
400 OpDecorate %input1 Binding 0
401 OpDecorate %_runtimearr_v4tinput_0 ArrayStride 32
402 OpMemberDecorate %Input2 0 Offset 0
403 OpDecorate %Input2 BufferBlock
404 OpDecorate %input2 DescriptorSet 0
405 OpDecorate %input2 Binding 1
406 %void = OpTypeVoid
407 %3 = OpTypeFunction %void
408 %int = OpTypeInt 32 1
409 %_ptr_Function_int = OpTypePointer Function %int
410 %int_0 = OpConstant %int 0
411 %niters = OpConstant %int ${ITERS}
412 %bool = OpTypeBool
413 %v4int = OpTypeVector %int 4
414 %_runtimearr_v4int = OpTypeRuntimeArray %v4int
415 %Output1 = OpTypeStruct %_runtimearr_v4int
416 %_ptr_Uniform_Output1 = OpTypePointer Uniform %Output1
417 %output1 = OpVariable %_ptr_Uniform_Output1 Uniform
418 %tinput = ${OPTYPE}
419 %v4tinput = OpTypeVector %tinput 4
420 %_runtimearr_v4tinput = OpTypeRuntimeArray %v4tinput
421 %Input1 = OpTypeStruct %_runtimearr_v4tinput
422 %_ptr_Uniform_Input1 = OpTypePointer Uniform %Input1
423 %input1 = OpVariable %_ptr_Uniform_Input1 Uniform
424 %_ptr_Uniform_v4tinput = OpTypePointer Uniform %v4tinput
425 %_runtimearr_v4tinput_0 = OpTypeRuntimeArray %v4tinput
426 %Input2 = OpTypeStruct %_runtimearr_v4tinput_0
427 %_ptr_Uniform_Input2 = OpTypePointer Uniform %Input2
428 %input2 = OpVariable %_ptr_Uniform_Input2 Uniform
429 %v4bool = OpTypeVector %bool 4
430 %int_1 = OpConstant %int 1
431 %45 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
432 %46 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
433 %_ptr_Uniform_v4int = OpTypePointer Uniform %v4int
434 %main = OpFunction %void None %3
435 %5 = OpLabel
436 %i = OpVariable %_ptr_Function_int Function
437 OpStore %i %int_0
438 OpBranch %10
439 %10 = OpLabel
440 OpLoopMerge %12 %13 None
441 OpBranch %14
442 %14 = OpLabel
443 %15 = OpLoad %int %i
444 %18 = OpSLessThan %bool %15 %niters
445 OpBranchConditional %18 %11 %12
446 %11 = OpLabel
447 %24 = OpLoad %int %i
448 %31 = OpLoad %int %i
449 %33 = OpAccessChain %_ptr_Uniform_v4tinput %input1 %int_0 %31
450 %34 = OpLoad %v4tinput %33
451 %39 = OpLoad %int %i
452 %40 = OpAccessChain %_ptr_Uniform_v4tinput %input2 %int_0 %39
453 %41 = OpLoad %v4tinput %40
454 %43 = ${OPNAME} %v4bool %34 %41
455 %47 = OpSelect %v4int %43 %46 %45
456 %49 = OpAccessChain %_ptr_Uniform_v4int %output1 %int_0 %24
457 OpStore %49 %47
458 OpBranch %13
459 %13 = OpLabel
460 %50 = OpLoad %int %i
461 %51 = OpIAdd %int %50 %int_1
462 OpStore %i %51
463 OpBranch %10
464 %12 = OpLabel
465 OpReturn
466 OpFunctionEnd
467 )");
468
469 // Shader template for the vertex stage using single scalars.
470 // Generated from the following GLSL shader, replacing some bits by template parameters.
471 #if 0
472 #version 430
473
474 // Left operands, right operands and results.
475 layout(binding = 0) buffer Input1 { double values[]; } input1;
476 layout(binding = 1) buffer Input2 { double values[]; } input2;
477 layout(binding = 2) buffer Output1 { int values[]; } output1;
478
479 void main()
480 {
481 gl_PointSize = 1;
482 gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
483
484 for (int i = 0; i < 20; i++) {
485 output1.values[i] = int(input1.values[i] == input2.values[i]);
486 }
487 }
488 #endif
489 const tcu::StringTemplate VertShaderSingle(R"(
490 OpCapability Shader
491 ${OPCAPABILITY}
492 ${NANCAP}
493 ${NANEXT}
494 %1 = OpExtInstImport "GLSL.std.450"
495 OpMemoryModel Logical GLSL450
496 OpEntryPoint Vertex %main "main" %_
497 ${NANMODE}
498 OpName %main "main"
499 OpName %gl_PerVertex "gl_PerVertex"
500 OpMemberName %gl_PerVertex 0 "gl_Position"
501 OpMemberName %gl_PerVertex 1 "gl_PointSize"
502 OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
503 OpName %_ ""
504 OpName %i "i"
505 OpName %Output1 "Output1"
506 OpMemberName %Output1 0 "values"
507 OpName %output1 "output1"
508 OpName %Input1 "Input1"
509 OpMemberName %Input1 0 "values"
510 OpName %input1 "input1"
511 OpName %Input2 "Input2"
512 OpMemberName %Input2 0 "values"
513 OpName %input2 "input2"
514 OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
515 OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
516 OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
517 OpDecorate %gl_PerVertex Block
518 OpDecorate %_runtimearr_int ArrayStride 4
519 OpMemberDecorate %Output1 0 Offset 0
520 OpDecorate %Output1 BufferBlock
521 OpDecorate %output1 DescriptorSet 0
522 OpDecorate %output1 Binding 2
523 OpDecorate %_runtimearr_tinput ArrayStride 8
524 OpMemberDecorate %Input1 0 Offset 0
525 OpDecorate %Input1 BufferBlock
526 OpDecorate %input1 DescriptorSet 0
527 OpDecorate %input1 Binding 0
528 OpDecorate %_runtimearr_tinput_0 ArrayStride 8
529 OpMemberDecorate %Input2 0 Offset 0
530 OpDecorate %Input2 BufferBlock
531 OpDecorate %input2 DescriptorSet 0
532 OpDecorate %input2 Binding 1
533 %void = OpTypeVoid
534 %3 = OpTypeFunction %void
535 %float = OpTypeFloat 32
536 %v4float = OpTypeVector %float 4
537 %uint = OpTypeInt 32 0
538 %uint_1 = OpConstant %uint 1
539 %_arr_float_uint_1 = OpTypeArray %float %uint_1
540 %gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1
541 %_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
542 %_ = OpVariable %_ptr_Output_gl_PerVertex Output
543 %int = OpTypeInt 32 1
544 %int_1 = OpConstant %int 1
545 %float_1 = OpConstant %float 1
546 %_ptr_Output_float = OpTypePointer Output %float
547 %int_0 = OpConstant %int 0
548 %float_0 = OpConstant %float 0
549 %21 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1
550 %_ptr_Output_v4float = OpTypePointer Output %v4float
551 %_ptr_Function_int = OpTypePointer Function %int
552 %niters = OpConstant %int ${ITERS}
553 %bool = OpTypeBool
554 %_runtimearr_int = OpTypeRuntimeArray %int
555 %Output1 = OpTypeStruct %_runtimearr_int
556 %_ptr_Uniform_Output1 = OpTypePointer Uniform %Output1
557 %output1 = OpVariable %_ptr_Uniform_Output1 Uniform
558 %tinput = ${OPTYPE}
559 %_runtimearr_tinput = OpTypeRuntimeArray %tinput
560 %Input1 = OpTypeStruct %_runtimearr_tinput
561 %_ptr_Uniform_Input1 = OpTypePointer Uniform %Input1
562 %input1 = OpVariable %_ptr_Uniform_Input1 Uniform
563 %_ptr_Uniform_tinput = OpTypePointer Uniform %tinput
564 %_runtimearr_tinput_0 = OpTypeRuntimeArray %tinput
565 %Input2 = OpTypeStruct %_runtimearr_tinput_0
566 %_ptr_Uniform_Input2 = OpTypePointer Uniform %Input2
567 %input2 = OpVariable %_ptr_Uniform_Input2 Uniform
568 %_ptr_Uniform_int = OpTypePointer Uniform %int
569 %main = OpFunction %void None %3
570 %5 = OpLabel
571 %i = OpVariable %_ptr_Function_int Function
572 %18 = OpAccessChain %_ptr_Output_float %_ %int_1
573 OpStore %18 %float_1
574 %23 = OpAccessChain %_ptr_Output_v4float %_ %int_0
575 OpStore %23 %21
576 OpStore %i %int_0
577 OpBranch %26
578 %26 = OpLabel
579 OpLoopMerge %28 %29 None
580 OpBranch %30
581 %30 = OpLabel
582 %31 = OpLoad %int %i
583 %34 = OpSLessThan %bool %31 %niters
584 OpBranchConditional %34 %27 %28
585 %27 = OpLabel
586 %39 = OpLoad %int %i
587 %45 = OpLoad %int %i
588 %47 = OpAccessChain %_ptr_Uniform_tinput %input1 %int_0 %45
589 %48 = OpLoad %tinput %47
590 %53 = OpLoad %int %i
591 %54 = OpAccessChain %_ptr_Uniform_tinput %input2 %int_0 %53
592 %55 = OpLoad %tinput %54
593 %56 = ${OPNAME} %bool %48 %55
594 %57 = OpSelect %int %56 %int_1 %int_0
595 %59 = OpAccessChain %_ptr_Uniform_int %output1 %int_0 %39
596 OpStore %59 %57
597 OpBranch %29
598 %29 = OpLabel
599 %60 = OpLoad %int %i
600 %61 = OpIAdd %int %60 %int_1
601 OpStore %i %61
602 OpBranch %26
603 %28 = OpLabel
604 OpReturn
605 OpFunctionEnd
606 )");
607
608 // Shader template for the vertex stage using vectors.
609 // Generated from the following GLSL shader, replacing some bits by template parameters.
610 // Note the number of iterations needs to be divided by 4 as the shader will consume 4 doubles at a time.
611 #if 0
612 #version 430
613
614 // Left operands, right operands and results.
615 layout(binding = 0) buffer Input1 { dvec4 values[]; } input1;
616 layout(binding = 1) buffer Input2 { dvec4 values[]; } input2;
617 layout(binding = 2) buffer Output1 { ivec4 values[]; } output1;
618
619 void main()
620 {
621 gl_PointSize = 1;
622 gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
623
624 for (int i = 0; i < 5; i++) {
625 output1.values[i] = ivec4(equal(input1.values[i], input2.values[i]));
626 }
627 }
628 #endif
629 const tcu::StringTemplate VertShaderVector(R"(
630 OpCapability Shader
631 ${OPCAPABILITY}
632 ${NANCAP}
633 ${NANEXT}
634 %1 = OpExtInstImport "GLSL.std.450"
635 OpMemoryModel Logical GLSL450
636 OpEntryPoint Vertex %main "main" %_
637 ${NANMODE}
638 OpName %main "main"
639 OpName %gl_PerVertex "gl_PerVertex"
640 OpMemberName %gl_PerVertex 0 "gl_Position"
641 OpMemberName %gl_PerVertex 1 "gl_PointSize"
642 OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
643 OpName %_ ""
644 OpName %i "i"
645 OpName %Output1 "Output1"
646 OpMemberName %Output1 0 "values"
647 OpName %output1 "output1"
648 OpName %Input1 "Input1"
649 OpMemberName %Input1 0 "values"
650 OpName %input1 "input1"
651 OpName %Input2 "Input2"
652 OpMemberName %Input2 0 "values"
653 OpName %input2 "input2"
654 OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
655 OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
656 OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
657 OpDecorate %gl_PerVertex Block
658 OpDecorate %_runtimearr_v4int ArrayStride 16
659 OpMemberDecorate %Output1 0 Offset 0
660 OpDecorate %Output1 BufferBlock
661 OpDecorate %output1 DescriptorSet 0
662 OpDecorate %output1 Binding 2
663 OpDecorate %_runtimearr_v4tinput ArrayStride 32
664 OpMemberDecorate %Input1 0 Offset 0
665 OpDecorate %Input1 BufferBlock
666 OpDecorate %input1 DescriptorSet 0
667 OpDecorate %input1 Binding 0
668 OpDecorate %_runtimearr_v4tinput_0 ArrayStride 32
669 OpMemberDecorate %Input2 0 Offset 0
670 OpDecorate %Input2 BufferBlock
671 OpDecorate %input2 DescriptorSet 0
672 OpDecorate %input2 Binding 1
673 %void = OpTypeVoid
674 %3 = OpTypeFunction %void
675 %float = OpTypeFloat 32
676 %v4float = OpTypeVector %float 4
677 %uint = OpTypeInt 32 0
678 %uint_1 = OpConstant %uint 1
679 %_arr_float_uint_1 = OpTypeArray %float %uint_1
680 %gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1
681 %_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
682 %_ = OpVariable %_ptr_Output_gl_PerVertex Output
683 %int = OpTypeInt 32 1
684 %int_1 = OpConstant %int 1
685 %float_1 = OpConstant %float 1
686 %_ptr_Output_float = OpTypePointer Output %float
687 %int_0 = OpConstant %int 0
688 %float_0 = OpConstant %float 0
689 %21 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1
690 %_ptr_Output_v4float = OpTypePointer Output %v4float
691 %_ptr_Function_int = OpTypePointer Function %int
692 %niters = OpConstant %int ${ITERS}
693 %bool = OpTypeBool
694 %v4int = OpTypeVector %int 4
695 %_runtimearr_v4int = OpTypeRuntimeArray %v4int
696 %Output1 = OpTypeStruct %_runtimearr_v4int
697 %_ptr_Uniform_Output1 = OpTypePointer Uniform %Output1
698 %output1 = OpVariable %_ptr_Uniform_Output1 Uniform
699 %tinput = ${OPTYPE}
700 %v4tinput = OpTypeVector %tinput 4
701 %_runtimearr_v4tinput = OpTypeRuntimeArray %v4tinput
702 %Input1 = OpTypeStruct %_runtimearr_v4tinput
703 %_ptr_Uniform_Input1 = OpTypePointer Uniform %Input1
704 %input1 = OpVariable %_ptr_Uniform_Input1 Uniform
705 %_ptr_Uniform_v4tinput = OpTypePointer Uniform %v4tinput
706 %_runtimearr_v4tinput_0 = OpTypeRuntimeArray %v4tinput
707 %Input2 = OpTypeStruct %_runtimearr_v4tinput_0
708 %_ptr_Uniform_Input2 = OpTypePointer Uniform %Input2
709 %input2 = OpVariable %_ptr_Uniform_Input2 Uniform
710 %v4bool = OpTypeVector %bool 4
711 %60 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
712 %61 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
713 %_ptr_Uniform_v4int = OpTypePointer Uniform %v4int
714 %main = OpFunction %void None %3
715 %5 = OpLabel
716 %i = OpVariable %_ptr_Function_int Function
717 %18 = OpAccessChain %_ptr_Output_float %_ %int_1
718 OpStore %18 %float_1
719 %23 = OpAccessChain %_ptr_Output_v4float %_ %int_0
720 OpStore %23 %21
721 OpStore %i %int_0
722 OpBranch %26
723 %26 = OpLabel
724 OpLoopMerge %28 %29 None
725 OpBranch %30
726 %30 = OpLabel
727 %31 = OpLoad %int %i
728 %34 = OpSLessThan %bool %31 %niters
729 OpBranchConditional %34 %27 %28
730 %27 = OpLabel
731 %40 = OpLoad %int %i
732 %47 = OpLoad %int %i
733 %49 = OpAccessChain %_ptr_Uniform_v4tinput %input1 %int_0 %47
734 %50 = OpLoad %v4tinput %49
735 %55 = OpLoad %int %i
736 %56 = OpAccessChain %_ptr_Uniform_v4tinput %input2 %int_0 %55
737 %57 = OpLoad %v4tinput %56
738 %59 = ${OPNAME} %v4bool %50 %57
739 %62 = OpSelect %v4int %59 %61 %60
740 %64 = OpAccessChain %_ptr_Uniform_v4int %output1 %int_0 %40
741 OpStore %64 %62
742 OpBranch %29
743 %29 = OpLabel
744 %65 = OpLoad %int %i
745 %66 = OpIAdd %int %65 %int_1
746 OpStore %i %66
747 OpBranch %26
748 %28 = OpLabel
749 OpReturn
750 OpFunctionEnd
751 )");
752
753 // GLSL passthrough vertex shader to test the fragment shader.
754 const std::string VertShaderPassThrough = R"(
755 #version 430
756
757 layout(location = 0) out vec4 out_color;
758
759 void main()
760 {
761 gl_PointSize = 1;
762 gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
763 out_color = vec4(0.0, 0.0, 0.0, 1.0);
764 }
765 )";
766
767 // Shader template for the fragment stage using single scalars.
768 // Generated from the following GLSL shader, replacing some bits by template parameters.
769 #if 0
770 #version 430
771
772 // Left operands, right operands and results.
773 layout(binding = 0) buffer Input1 { double values[]; } input1;
774 layout(binding = 1) buffer Input2 { double values[]; } input2;
775 layout(binding = 2) buffer Output1 { int values[]; } output1;
776
777 void main()
778 {
779 for (int i = 0; i < 20; i++) {
780 output1.values[i] = int(input1.values[i] == input2.values[i]);
781 }
782 }
783 #endif
784 const tcu::StringTemplate FragShaderSingle(R"(
785 OpCapability Shader
786 ${OPCAPABILITY}
787 ${NANCAP}
788 ${NANEXT}
789 %1 = OpExtInstImport "GLSL.std.450"
790 OpMemoryModel Logical GLSL450
791 OpEntryPoint Fragment %main "main"
792 ${NANMODE}
793 OpExecutionMode %main OriginUpperLeft
794 OpSource GLSL 430
795 OpName %main "main"
796 OpName %i "i"
797 OpName %Output1 "Output1"
798 OpMemberName %Output1 0 "values"
799 OpName %output1 "output1"
800 OpName %Input1 "Input1"
801 OpMemberName %Input1 0 "values"
802 OpName %input1 "input1"
803 OpName %Input2 "Input2"
804 OpMemberName %Input2 0 "values"
805 OpName %input2 "input2"
806 OpDecorate %_runtimearr_int ArrayStride 4
807 OpMemberDecorate %Output1 0 Offset 0
808 OpDecorate %Output1 BufferBlock
809 OpDecorate %output1 DescriptorSet 0
810 OpDecorate %output1 Binding 2
811 OpDecorate %_runtimearr_tinput ArrayStride 8
812 OpMemberDecorate %Input1 0 Offset 0
813 OpDecorate %Input1 BufferBlock
814 OpDecorate %input1 DescriptorSet 0
815 OpDecorate %input1 Binding 0
816 OpDecorate %_runtimearr_tinput_0 ArrayStride 8
817 OpMemberDecorate %Input2 0 Offset 0
818 OpDecorate %Input2 BufferBlock
819 OpDecorate %input2 DescriptorSet 0
820 OpDecorate %input2 Binding 1
821 %void = OpTypeVoid
822 %3 = OpTypeFunction %void
823 %int = OpTypeInt 32 1
824 %_ptr_Function_int = OpTypePointer Function %int
825 %int_0 = OpConstant %int 0
826 %niters = OpConstant %int ${ITERS}
827 %bool = OpTypeBool
828 %_runtimearr_int = OpTypeRuntimeArray %int
829 %Output1 = OpTypeStruct %_runtimearr_int
830 %_ptr_Uniform_Output1 = OpTypePointer Uniform %Output1
831 %output1 = OpVariable %_ptr_Uniform_Output1 Uniform
832 %tinput = ${OPTYPE}
833 %_runtimearr_tinput = OpTypeRuntimeArray %tinput
834 %Input1 = OpTypeStruct %_runtimearr_tinput
835 %_ptr_Uniform_Input1 = OpTypePointer Uniform %Input1
836 %input1 = OpVariable %_ptr_Uniform_Input1 Uniform
837 %_ptr_Uniform_tinput = OpTypePointer Uniform %tinput
838 %_runtimearr_tinput_0 = OpTypeRuntimeArray %tinput
839 %Input2 = OpTypeStruct %_runtimearr_tinput_0
840 %_ptr_Uniform_Input2 = OpTypePointer Uniform %Input2
841 %input2 = OpVariable %_ptr_Uniform_Input2 Uniform
842 %int_1 = OpConstant %int 1
843 %_ptr_Uniform_int = OpTypePointer Uniform %int
844 %main = OpFunction %void None %3
845 %5 = OpLabel
846 %i = OpVariable %_ptr_Function_int Function
847 OpStore %i %int_0
848 OpBranch %10
849 %10 = OpLabel
850 OpLoopMerge %12 %13 None
851 OpBranch %14
852 %14 = OpLabel
853 %15 = OpLoad %int %i
854 %18 = OpSLessThan %bool %15 %niters
855 OpBranchConditional %18 %11 %12
856 %11 = OpLabel
857 %23 = OpLoad %int %i
858 %29 = OpLoad %int %i
859 %31 = OpAccessChain %_ptr_Uniform_tinput %input1 %int_0 %29
860 %32 = OpLoad %tinput %31
861 %37 = OpLoad %int %i
862 %38 = OpAccessChain %_ptr_Uniform_tinput %input2 %int_0 %37
863 %39 = OpLoad %tinput %38
864 %40 = ${OPNAME} %bool %32 %39
865 %42 = OpSelect %int %40 %int_1 %int_0
866 %44 = OpAccessChain %_ptr_Uniform_int %output1 %int_0 %23
867 OpStore %44 %42
868 OpBranch %13
869 %13 = OpLabel
870 %45 = OpLoad %int %i
871 %46 = OpIAdd %int %45 %int_1
872 OpStore %i %46
873 OpBranch %10
874 %12 = OpLabel
875 OpReturn
876 OpFunctionEnd
877 )");
878
879 // Shader template for the fragment stage using vectors.
880 // Generated from the following GLSL shader, replacing some bits by template parameters.
881 // Note the number of iterations needs to be divided by 4 as the shader will consume 4 doubles at a time.
882 #if 0
883 #version 430
884
885 // Left operands, right operands and results.
886 layout(binding = 0) buffer Input1 { dvec4 values[]; } input1;
887 layout(binding = 1) buffer Input2 { dvec4 values[]; } input2;
888 layout(binding = 2) buffer Output1 { ivec4 values[]; } output1;
889
890 void main()
891 {
892 for (int i = 0; i < 5; i++) {
893 output1.values[i] = ivec4(equal(input1.values[i], input2.values[i]));
894 }
895 }
896 #endif
897 const tcu::StringTemplate FragShaderVector(R"(
898 OpCapability Shader
899 ${OPCAPABILITY}
900 ${NANCAP}
901 ${NANEXT}
902 %1 = OpExtInstImport "GLSL.std.450"
903 OpMemoryModel Logical GLSL450
904 OpEntryPoint Fragment %main "main"
905 ${NANMODE}
906 OpExecutionMode %main OriginUpperLeft
907 OpName %main "main"
908 OpName %i "i"
909 OpName %Output1 "Output1"
910 OpMemberName %Output1 0 "values"
911 OpName %output1 "output1"
912 OpName %Input1 "Input1"
913 OpMemberName %Input1 0 "values"
914 OpName %input1 "input1"
915 OpName %Input2 "Input2"
916 OpMemberName %Input2 0 "values"
917 OpName %input2 "input2"
918 OpDecorate %_runtimearr_v4int ArrayStride 16
919 OpMemberDecorate %Output1 0 Offset 0
920 OpDecorate %Output1 BufferBlock
921 OpDecorate %output1 DescriptorSet 0
922 OpDecorate %output1 Binding 2
923 OpDecorate %_runtimearr_v4tinput ArrayStride 32
924 OpMemberDecorate %Input1 0 Offset 0
925 OpDecorate %Input1 BufferBlock
926 OpDecorate %input1 DescriptorSet 0
927 OpDecorate %input1 Binding 0
928 OpDecorate %_runtimearr_v4tinput_0 ArrayStride 32
929 OpMemberDecorate %Input2 0 Offset 0
930 OpDecorate %Input2 BufferBlock
931 OpDecorate %input2 DescriptorSet 0
932 OpDecorate %input2 Binding 1
933 %void = OpTypeVoid
934 %3 = OpTypeFunction %void
935 %int = OpTypeInt 32 1
936 %_ptr_Function_int = OpTypePointer Function %int
937 %int_0 = OpConstant %int 0
938 %niters = OpConstant %int ${ITERS}
939 %bool = OpTypeBool
940 %v4int = OpTypeVector %int 4
941 %_runtimearr_v4int = OpTypeRuntimeArray %v4int
942 %Output1 = OpTypeStruct %_runtimearr_v4int
943 %_ptr_Uniform_Output1 = OpTypePointer Uniform %Output1
944 %output1 = OpVariable %_ptr_Uniform_Output1 Uniform
945 %tinput = ${OPTYPE}
946 %v4tinput = OpTypeVector %tinput 4
947 %_runtimearr_v4tinput = OpTypeRuntimeArray %v4tinput
948 %Input1 = OpTypeStruct %_runtimearr_v4tinput
949 %_ptr_Uniform_Input1 = OpTypePointer Uniform %Input1
950 %input1 = OpVariable %_ptr_Uniform_Input1 Uniform
951 %_ptr_Uniform_v4tinput = OpTypePointer Uniform %v4tinput
952 %_runtimearr_v4tinput_0 = OpTypeRuntimeArray %v4tinput
953 %Input2 = OpTypeStruct %_runtimearr_v4tinput_0
954 %_ptr_Uniform_Input2 = OpTypePointer Uniform %Input2
955 %input2 = OpVariable %_ptr_Uniform_Input2 Uniform
956 %v4bool = OpTypeVector %bool 4
957 %int_1 = OpConstant %int 1
958 %45 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
959 %46 = OpConstantComposite %v4int %int_1 %int_1 %int_1 %int_1
960 %_ptr_Uniform_v4int = OpTypePointer Uniform %v4int
961 %main = OpFunction %void None %3
962 %5 = OpLabel
963 %i = OpVariable %_ptr_Function_int Function
964 OpStore %i %int_0
965 OpBranch %10
966 %10 = OpLabel
967 OpLoopMerge %12 %13 None
968 OpBranch %14
969 %14 = OpLabel
970 %15 = OpLoad %int %i
971 %18 = OpSLessThan %bool %15 %niters
972 OpBranchConditional %18 %11 %12
973 %11 = OpLabel
974 %24 = OpLoad %int %i
975 %31 = OpLoad %int %i
976 %33 = OpAccessChain %_ptr_Uniform_v4tinput %input1 %int_0 %31
977 %34 = OpLoad %v4tinput %33
978 %39 = OpLoad %int %i
979 %40 = OpAccessChain %_ptr_Uniform_v4tinput %input2 %int_0 %39
980 %41 = OpLoad %v4tinput %40
981 %43 = ${OPNAME} %v4bool %34 %41
982 %47 = OpSelect %v4int %43 %46 %45
983 %49 = OpAccessChain %_ptr_Uniform_v4int %output1 %int_0 %24
984 OpStore %49 %47
985 OpBranch %13
986 %13 = OpLabel
987 %50 = OpLoad %int %i
988 %51 = OpIAdd %int %50 %int_1
989 OpStore %i %51
990 OpBranch %10
991 %12 = OpLabel
992 OpReturn
993 OpFunctionEnd
994 )");
995
996 struct SpirvTemplateManager
997 {
getTemplatevkt::SpirVAssembly::__anon071ae8e90111::SpirvTemplateManager998 static const tcu::StringTemplate &getTemplate(DataType type, vk::VkShaderStageFlagBits stage)
999 {
1000 DE_ASSERT(type == DATA_TYPE_SINGLE || type == DATA_TYPE_VECTOR);
1001 DE_ASSERT(stage == vk::VK_SHADER_STAGE_COMPUTE_BIT || stage == vk::VK_SHADER_STAGE_VERTEX_BIT ||
1002 stage == vk::VK_SHADER_STAGE_FRAGMENT_BIT);
1003
1004 if (type == DATA_TYPE_SINGLE)
1005 {
1006 if (stage == vk::VK_SHADER_STAGE_COMPUTE_BIT)
1007 return CompShaderSingle;
1008 if (stage == vk::VK_SHADER_STAGE_VERTEX_BIT)
1009 return VertShaderSingle;
1010 else
1011 return FragShaderSingle;
1012 }
1013 else
1014 {
1015 if (stage == vk::VK_SHADER_STAGE_COMPUTE_BIT)
1016 return CompShaderVector;
1017 if (stage == vk::VK_SHADER_STAGE_VERTEX_BIT)
1018 return VertShaderVector;
1019 else
1020 return FragShaderVector;
1021 }
1022 }
1023
1024 // Specialized below for different types.
1025 template <class T>
1026 static std::string getOpCapability();
1027
1028 // Same.
1029 template <class T>
1030 static std::string getOpType();
1031
1032 // Return the capabilities, extensions and execution modes for NaN preservation.
1033 static std::string getNanCapability(bool preserve);
1034 static std::string getNanExtension(bool preserve);
1035 static std::string getNanExeMode(bool preserve);
1036 };
1037
1038 template <>
getOpCapability()1039 std::string SpirvTemplateManager::getOpCapability<double>()
1040 {
1041 return "OpCapability Float64";
1042 }
1043 template <>
getOpCapability()1044 std::string SpirvTemplateManager::getOpCapability<int64_t>()
1045 {
1046 return "OpCapability Int64";
1047 }
1048 template <>
getOpCapability()1049 std::string SpirvTemplateManager::getOpCapability<uint64_t>()
1050 {
1051 return "OpCapability Int64";
1052 }
1053
1054 template <>
getOpType()1055 std::string SpirvTemplateManager::getOpType<double>()
1056 {
1057 return "OpTypeFloat 64";
1058 }
1059 template <>
getOpType()1060 std::string SpirvTemplateManager::getOpType<int64_t>()
1061 {
1062 return "OpTypeInt 64 1";
1063 }
1064 template <>
getOpType()1065 std::string SpirvTemplateManager::getOpType<uint64_t>()
1066 {
1067 return "OpTypeInt 64 0";
1068 }
1069
getNanCapability(bool preserve)1070 std::string SpirvTemplateManager::getNanCapability(bool preserve)
1071 {
1072 return (preserve ? "OpCapability SignedZeroInfNanPreserve" : "");
1073 }
1074
getNanExtension(bool preserve)1075 std::string SpirvTemplateManager::getNanExtension(bool preserve)
1076 {
1077 return (preserve ? "OpExtension \"SPV_KHR_float_controls\"" : "");
1078 }
1079
getNanExeMode(bool preserve)1080 std::string SpirvTemplateManager::getNanExeMode(bool preserve)
1081 {
1082 return (preserve ? "OpExecutionMode %main SignedZeroInfNanPreserve 64" : "");
1083 }
1084
1085 struct BufferWithMemory
1086 {
1087 vk::Move<vk::VkBuffer> buffer;
1088 de::MovePtr<vk::Allocation> allocation;
1089
BufferWithMemoryvkt::SpirVAssembly::__anon071ae8e90111::BufferWithMemory1090 BufferWithMemory() : buffer(), allocation()
1091 {
1092 }
1093
BufferWithMemoryvkt::SpirVAssembly::__anon071ae8e90111::BufferWithMemory1094 BufferWithMemory(BufferWithMemory &&other) : buffer(other.buffer), allocation(other.allocation)
1095 {
1096 }
1097
operator =vkt::SpirVAssembly::__anon071ae8e90111::BufferWithMemory1098 BufferWithMemory &operator=(BufferWithMemory &&other)
1099 {
1100 buffer = other.buffer;
1101 allocation = other.allocation;
1102 return *this;
1103 }
1104 };
1105
1106 // Create storage buffer, bind memory to it and return both things.
createStorageBuffer(const vk::DeviceInterface & vkdi,const vk::VkDevice device,vk::Allocator & allocator,size_t numBytes)1107 BufferWithMemory createStorageBuffer(const vk::DeviceInterface &vkdi, const vk::VkDevice device,
1108 vk::Allocator &allocator, size_t numBytes)
1109 {
1110 const vk::VkBufferCreateInfo bufferCreateInfo = {
1111 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // sType
1112 DE_NULL, // pNext
1113 0u, // flags
1114 numBytes, // size
1115 vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, // usage
1116 vk::VK_SHARING_MODE_EXCLUSIVE, // sharingMode
1117 0u, // queueFamilyCount
1118 DE_NULL, // pQueueFamilyIndices
1119 };
1120
1121 BufferWithMemory bufmem;
1122
1123 bufmem.buffer = vk::createBuffer(vkdi, device, &bufferCreateInfo);
1124 const vk::VkMemoryRequirements requirements = getBufferMemoryRequirements(vkdi, device, *bufmem.buffer);
1125 bufmem.allocation = allocator.allocate(requirements, vk::MemoryRequirement::HostVisible);
1126
1127 VK_CHECK(
1128 vkdi.bindBufferMemory(device, *bufmem.buffer, bufmem.allocation->getMemory(), bufmem.allocation->getOffset()));
1129
1130 return bufmem;
1131 }
1132
1133 // Make sure the length of the following vectors is a multiple of 4. This will make sure operands can be reused for vectorized tests.
1134 const OperandsVector<double> DOUBLE_OPERANDS = {
1135 {-8.0, -5.0}, {-5.0, -8.0}, {-5.0, -5.0}, {-5.0, 0.0}, {0.0, -5.0}, {5.0, 0.0}, {0.0, 5.0},
1136 {0.0, 0.0}, {-5.0, 5.0}, {5.0, -5.0}, {5.0, 8.0}, {8.0, 5.0}, {5.0, 5.0}, {-6.0, -5.0},
1137 {6.0, 5.0}, {0.0, 1.0}, {1.0, 0.0}, {0.0, NAN}, {NAN, 0.0}, {NAN, NAN},
1138 };
1139
1140 const OperandsVector<int64_t> INT64_OPERANDS = {
1141 {-8, -5}, {-5, -8}, {-5, -5}, {-5, 0}, {0, -5}, {5, 0}, {0, 5}, {0, 0},
1142 {-5, 5}, {5, -5}, {5, 8}, {8, 5}, {5, 5}, {-6, -5}, {6, 5}, {0, 1},
1143 };
1144
1145 constexpr auto MAX_DEUINT64 = std::numeric_limits<uint64_t>::max();
1146 const OperandsVector<uint64_t> UINT64_OPERANDS = {
1147 {0, 0},
1148 {1, 0},
1149 {0, 1},
1150 {1, 1},
1151 {5, 8},
1152 {8, 5},
1153 {5, 5},
1154 {0, MAX_DEUINT64},
1155 {MAX_DEUINT64, 0},
1156 {MAX_DEUINT64 - 1, MAX_DEUINT64},
1157 {MAX_DEUINT64, MAX_DEUINT64 - 1},
1158 {MAX_DEUINT64, MAX_DEUINT64},
1159 };
1160
1161 template <class T>
1162 class T64bitCompareTestInstance : public TestInstance
1163 {
1164 public:
1165 T64bitCompareTestInstance(Context &ctx, const TestParameters<T> ¶ms);
1166 tcu::TestStatus iterate(void);
1167
1168 private:
1169 const TestParameters<T> m_params;
1170 const size_t m_numOperations;
1171 const size_t m_inputBufferSize;
1172 const size_t m_outputBufferSize;
1173 };
1174
1175 template <class T>
T64bitCompareTestInstance(Context & ctx,const TestParameters<T> & params)1176 T64bitCompareTestInstance<T>::T64bitCompareTestInstance(Context &ctx, const TestParameters<T> ¶ms)
1177 : TestInstance(ctx)
1178 , m_params(params)
1179 , m_numOperations(m_params.operands.size())
1180 , m_inputBufferSize(m_numOperations * sizeof(T))
1181 , m_outputBufferSize(m_numOperations * sizeof(int))
1182 {
1183 }
1184
1185 template <class T>
genericIsNan(T)1186 bool genericIsNan(T)
1187 {
1188 return false;
1189 }
1190
1191 template <>
genericIsNan(double value)1192 bool genericIsNan<double>(double value)
1193 {
1194 return std::isnan(value);
1195 }
1196
1197 template <class T>
iterate(void)1198 tcu::TestStatus T64bitCompareTestInstance<T>::iterate(void)
1199 {
1200 DE_ASSERT(m_params.stage == vk::VK_SHADER_STAGE_COMPUTE_BIT || m_params.stage == vk::VK_SHADER_STAGE_VERTEX_BIT ||
1201 m_params.stage == vk::VK_SHADER_STAGE_FRAGMENT_BIT);
1202
1203 auto &vkdi = m_context.getDeviceInterface();
1204 auto device = m_context.getDevice();
1205 auto &allocator = m_context.getDefaultAllocator();
1206
1207 // Create storage buffers (left operands, right operands and results buffer).
1208 BufferWithMemory input1 = createStorageBuffer(vkdi, device, allocator, m_inputBufferSize);
1209 BufferWithMemory input2 = createStorageBuffer(vkdi, device, allocator, m_inputBufferSize);
1210 BufferWithMemory output1 = createStorageBuffer(vkdi, device, allocator, m_outputBufferSize);
1211
1212 // Create an array of buffers.
1213 std::vector<vk::VkBuffer> buffers;
1214 buffers.push_back(input1.buffer.get());
1215 buffers.push_back(input2.buffer.get());
1216 buffers.push_back(output1.buffer.get());
1217
1218 // Create descriptor set layout.
1219 std::vector<vk::VkDescriptorSetLayoutBinding> bindings;
1220 for (size_t i = 0; i < buffers.size(); ++i)
1221 {
1222 vk::VkDescriptorSetLayoutBinding binding = {
1223 static_cast<uint32_t>(i), // uint32_t binding;
1224 vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, // VkDescriptorType descriptorType;
1225 1u, // uint32_t descriptorCount;
1226 static_cast<vk::VkShaderStageFlags>(m_params.stage), // VkShaderStageFlags stageFlags;
1227 DE_NULL // const VkSampler* pImmutableSamplers;
1228 };
1229 bindings.push_back(binding);
1230 }
1231
1232 const vk::VkDescriptorSetLayoutCreateInfo layoutCreateInfo = {
1233 vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType;
1234 DE_NULL, // const void* pNext;
1235 0, // VkDescriptorSetLayoutCreateFlags flags;
1236 static_cast<uint32_t>(bindings.size()), // uint32_t bindingCount;
1237 bindings.data() // const VkDescriptorSetLayoutBinding* pBindings;
1238 };
1239 auto descriptorSetLayout = vk::createDescriptorSetLayout(vkdi, device, &layoutCreateInfo);
1240
1241 // Create descriptor set.
1242 vk::DescriptorPoolBuilder poolBuilder;
1243 poolBuilder.addType(bindings[0].descriptorType, static_cast<uint32_t>(bindings.size()));
1244 auto descriptorPool = poolBuilder.build(vkdi, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1245
1246 const vk::VkDescriptorSetAllocateInfo allocateInfo = {
1247 vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
1248 DE_NULL, // const void* pNext;
1249 *descriptorPool, // VkDescriptorPool descriptorPool;
1250 1u, // uint32_t descriptorSetCount;
1251 &descriptorSetLayout.get() // const VkDescriptorSetLayout* pSetLayouts;
1252 };
1253 auto descriptorSet = vk::allocateDescriptorSet(vkdi, device, &allocateInfo);
1254
1255 // Update descriptor set.
1256 std::vector<vk::VkDescriptorBufferInfo> descriptorBufferInfos;
1257 std::vector<vk::VkWriteDescriptorSet> descriptorWrites;
1258
1259 descriptorBufferInfos.reserve(buffers.size());
1260 descriptorWrites.reserve(buffers.size());
1261
1262 for (size_t i = 0; i < buffers.size(); ++i)
1263 {
1264 vk::VkDescriptorBufferInfo bufferInfo = {
1265 buffers[i], // VkBuffer buffer;
1266 0u, // VkDeviceSize offset;
1267 VK_WHOLE_SIZE, // VkDeviceSize range;
1268 };
1269 descriptorBufferInfos.push_back(bufferInfo);
1270 }
1271
1272 for (size_t i = 0; i < buffers.size(); ++i)
1273 {
1274 vk::VkWriteDescriptorSet write = {
1275 vk::VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType;
1276 DE_NULL, // const void* pNext;
1277 *descriptorSet, // VkDescriptorSet dstSet;
1278 static_cast<uint32_t>(i), // uint32_t dstBinding;
1279 0u, // uint32_t dstArrayElement;
1280 1u, // uint32_t descriptorCount;
1281 bindings[i].descriptorType, // VkDescriptorType descriptorType;
1282 DE_NULL, // const VkDescriptorImageInfo* pImageInfo;
1283 &descriptorBufferInfos[i], // const VkDescriptorBufferInfo* pBufferInfo;
1284 DE_NULL, // const VkBufferView* pTexelBufferView;
1285 };
1286 descriptorWrites.push_back(write);
1287 }
1288 vkdi.updateDescriptorSets(device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0u,
1289 DE_NULL);
1290
1291 // Fill storage buffers with data. Note: VkPhysicalDeviceLimits.minMemoryMapAlignment guarantees this cast is safe.
1292 T *input1Ptr = reinterpret_cast<T *>(input1.allocation->getHostPtr());
1293 T *input2Ptr = reinterpret_cast<T *>(input2.allocation->getHostPtr());
1294 int *output1Ptr = reinterpret_cast<int *>(output1.allocation->getHostPtr());
1295
1296 for (size_t i = 0; i < m_numOperations; ++i)
1297 {
1298 input1Ptr[i] = m_params.operands[i].first;
1299 input2Ptr[i] = m_params.operands[i].second;
1300 output1Ptr[i] = -9;
1301 }
1302
1303 // Flush memory.
1304 vk::flushAlloc(vkdi, device, *input1.allocation);
1305 vk::flushAlloc(vkdi, device, *input2.allocation);
1306 vk::flushAlloc(vkdi, device, *output1.allocation);
1307
1308 // Prepare barriers in advance so data is visible to the shaders and the host.
1309 std::vector<vk::VkBufferMemoryBarrier> hostToDevBarriers;
1310 std::vector<vk::VkBufferMemoryBarrier> devToHostBarriers;
1311 for (size_t i = 0; i < buffers.size(); ++i)
1312 {
1313 const vk::VkBufferMemoryBarrier hostDev = {
1314 vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
1315 DE_NULL, // const void* pNext;
1316 vk::VK_ACCESS_HOST_WRITE_BIT, // VkAccessFlags srcAccessMask;
1317 (vk::VK_ACCESS_SHADER_READ_BIT | vk::VK_ACCESS_SHADER_WRITE_BIT), // VkAccessFlags dstAccessMask;
1318 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1319 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1320 buffers[i], // VkBuffer buffer;
1321 0u, // VkDeviceSize offset;
1322 VK_WHOLE_SIZE, // VkDeviceSize size;
1323 };
1324 hostToDevBarriers.push_back(hostDev);
1325
1326 const vk::VkBufferMemoryBarrier devHost = {
1327 vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType;
1328 DE_NULL, // const void* pNext;
1329 vk::VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags srcAccessMask;
1330 vk::VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask;
1331 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1332 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1333 buffers[i], // VkBuffer buffer;
1334 0u, // VkDeviceSize offset;
1335 VK_WHOLE_SIZE, // VkDeviceSize size;
1336 };
1337 devToHostBarriers.push_back(devHost);
1338 }
1339
1340 // Create command pool and command buffer.
1341 auto queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1342
1343 const vk::VkCommandPoolCreateInfo cmdPoolCreateInfo = {
1344 vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, // VkStructureType sType;
1345 DE_NULL, // const void* pNext;
1346 vk::VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // VkCommandPoolCreateFlags flags;
1347 queueFamilyIndex, // uint32_t queueFamilyIndex;
1348 };
1349 auto cmdPool = vk::createCommandPool(vkdi, device, &cmdPoolCreateInfo);
1350
1351 const vk::VkCommandBufferAllocateInfo cmdBufferAllocateInfo = {
1352 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType;
1353 DE_NULL, // const void* pNext;
1354 *cmdPool, // VkCommandPool commandPool;
1355 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level;
1356 1u, // uint32_t commandBufferCount;
1357 };
1358 auto cmdBuffer = vk::allocateCommandBuffer(vkdi, device, &cmdBufferAllocateInfo);
1359
1360 // Create pipeline layout.
1361 const vk::VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
1362 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
1363 DE_NULL, // const void* pNext;
1364 0, // VkPipelineLayoutCreateFlags flags;
1365 1u, // uint32_t setLayoutCount;
1366 &descriptorSetLayout.get(), // const VkDescriptorSetLayout* pSetLayouts;
1367 0u, // uint32_t pushConstantRangeCount;
1368 DE_NULL, // const VkPushConstantRange* pPushConstantRanges;
1369 };
1370 auto pipelineLayout = vk::createPipelineLayout(vkdi, device, &pipelineLayoutCreateInfo);
1371
1372 if (m_params.stage == vk::VK_SHADER_STAGE_COMPUTE_BIT)
1373 {
1374 // Create compute pipeline.
1375 auto compShaderModule = createShaderModule(vkdi, device, m_context.getBinaryCollection().get("comp"));
1376
1377 const vk::VkComputePipelineCreateInfo computeCreateInfo = {
1378 vk::VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // VkStructureType sType;
1379 DE_NULL, // const void* pNext;
1380 0, // VkPipelineCreateFlags flags;
1381 {
1382 // VkPipelineShaderStageCreateInfo stage;
1383 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1384 DE_NULL, // const void* pNext;
1385 0, // VkPipelineShaderStageCreateFlags flags;
1386 vk::VK_SHADER_STAGE_COMPUTE_BIT, // VkShaderStageFlagBits stage;
1387 *compShaderModule, // VkShaderModule module;
1388 "main", // const char* pName;
1389 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
1390 },
1391 *pipelineLayout, // VkPipelineLayout layout;
1392 DE_NULL, // VkPipeline basePipelineHandle;
1393 0, // int32_t basePipelineIndex;
1394 };
1395 auto computePipeline = vk::createComputePipeline(vkdi, device, DE_NULL, &computeCreateInfo);
1396
1397 // Run the shader.
1398 vk::beginCommandBuffer(vkdi, *cmdBuffer);
1399 vkdi.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline);
1400 vkdi.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0, 1u,
1401 &descriptorSet.get(), 0u, DE_NULL);
1402 vkdi.cmdPipelineBarrier(*cmdBuffer, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0,
1403 0u, DE_NULL, static_cast<uint32_t>(hostToDevBarriers.size()), hostToDevBarriers.data(),
1404 0u, DE_NULL);
1405 vkdi.cmdDispatch(*cmdBuffer, 1u, 1u, 1u);
1406 vkdi.cmdPipelineBarrier(*cmdBuffer, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, 0,
1407 0u, DE_NULL, static_cast<uint32_t>(devToHostBarriers.size()), devToHostBarriers.data(),
1408 0u, DE_NULL);
1409 vk::endCommandBuffer(vkdi, *cmdBuffer);
1410 vk::submitCommandsAndWait(vkdi, device, m_context.getUniversalQueue(), *cmdBuffer);
1411 }
1412 else if (m_params.stage == vk::VK_SHADER_STAGE_VERTEX_BIT || m_params.stage == vk::VK_SHADER_STAGE_FRAGMENT_BIT)
1413 {
1414 const bool isFrag = (m_params.stage == vk::VK_SHADER_STAGE_FRAGMENT_BIT);
1415
1416 // Create graphics pipeline.
1417 auto vertShaderModule = createShaderModule(vkdi, device, m_context.getBinaryCollection().get("vert"));
1418 vk::Move<vk::VkShaderModule> fragShaderModule;
1419 std::vector<vk::VkPipelineShaderStageCreateInfo> shaderStages;
1420
1421 const vk::VkPipelineShaderStageCreateInfo vertexStage = {
1422 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1423 DE_NULL, // const void* pNext;
1424 0, // VkPipelineShaderStageCreateFlags flags;
1425 vk::VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
1426 *vertShaderModule, // VkShaderModule module;
1427 "main", // const char* pName;
1428 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
1429 };
1430 shaderStages.push_back(vertexStage);
1431
1432 if (isFrag)
1433 {
1434 fragShaderModule = createShaderModule(vkdi, device, m_context.getBinaryCollection().get("frag"));
1435
1436 const vk::VkPipelineShaderStageCreateInfo fragmentStage = {
1437 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1438 DE_NULL, // const void* pNext;
1439 0, // VkPipelineShaderStageCreateFlags flags;
1440 vk::VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
1441 *fragShaderModule, // VkShaderModule module;
1442 "main", // const char* pName;
1443 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
1444 };
1445 shaderStages.push_back(fragmentStage);
1446 }
1447
1448 const vk::VkPipelineVertexInputStateCreateInfo vertexInputInfo = {
1449 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
1450 DE_NULL, // const void* pNext;
1451 0, // VkPipelineVertexInputStateCreateFlags flags;
1452 0u, // uint32_t vertexBindingDescriptionCount;
1453 DE_NULL, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
1454 0u, // uint32_t vertexAttributeDescriptionCount;
1455 DE_NULL, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
1456 };
1457
1458 const vk::VkPipelineInputAssemblyStateCreateInfo inputAssembly = {
1459 vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
1460 DE_NULL, // const void* pNext;
1461 0u, // VkPipelineInputAssemblyStateCreateFlags flags;
1462 vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST, // VkPrimitiveTopology topology;
1463 VK_FALSE, // VkBool32 primitiveRestartEnable;
1464 };
1465
1466 const vk::VkPipelineRasterizationStateCreateInfo rasterizationState = {
1467 vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
1468 DE_NULL, // const void* pNext;
1469 0, // VkPipelineRasterizationStateCreateFlags flags;
1470 VK_FALSE, // VkBool32 depthClampEnable;
1471 (isFrag ? VK_FALSE : VK_TRUE), // VkBool32 rasterizerDiscardEnable;
1472 vk::VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
1473 vk::VK_CULL_MODE_NONE, // VkCullModeFlags cullMode;
1474 vk::VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace;
1475 VK_FALSE, // VkBool32 depthBiasEnable;
1476 0.0f, // float depthBiasConstantFactor;
1477 0.0f, // float depthBiasClamp;
1478 0.0f, // float depthBiasSlopeFactor;
1479 1.0f, // float lineWidth;
1480 };
1481
1482 const vk::VkSubpassDescription subpassDescription = {
1483 0, // VkSubpassDescriptionFlags flags;
1484 vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
1485 0u, // uint32_t inputAttachmentCount;
1486 DE_NULL, // const VkAttachmentReference* pInputAttachments;
1487 0u, // uint32_t colorAttachmentCount;
1488 DE_NULL, // const VkAttachmentReference* pColorAttachments;
1489 DE_NULL, // const VkAttachmentReference* pResolveAttachments;
1490 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
1491 0u, // uint32_t preserveAttachmentCount;
1492 0u, // const uint32_t* pPreserveAttachments;
1493 };
1494
1495 const vk::VkRenderPassCreateInfo renderPassCreateInfo = {
1496 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
1497 DE_NULL, // const void* pNext;
1498 0, // VkRenderPassCreateFlags flags;
1499 0u, // uint32_t attachmentCount;
1500 DE_NULL, // const VkAttachmentDescription* pAttachments;
1501 1u, // uint32_t subpassCount;
1502 &subpassDescription, // const VkSubpassDescription* pSubpasses;
1503 0u, // uint32_t dependencyCount;
1504 DE_NULL, // const VkSubpassDependency* pDependencies;
1505 };
1506 auto renderPass = vk::createRenderPass(vkdi, device, &renderPassCreateInfo);
1507
1508 std::unique_ptr<vk::VkPipelineMultisampleStateCreateInfo> multisampleState;
1509 if (isFrag)
1510 {
1511 multisampleState.reset(new vk::VkPipelineMultisampleStateCreateInfo);
1512 *multisampleState = {
1513 vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
1514 DE_NULL, // const void* pNext;
1515 0, // VkPipelineMultisampleStateCreateFlags flags;
1516 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
1517 VK_FALSE, // VkBool32 sampleShadingEnable;
1518 0.0f, // float minSampleShading;
1519 DE_NULL, // const VkSampleMask* pSampleMask;
1520 VK_FALSE, // VkBool32 alphaToCoverageEnable;
1521 VK_FALSE, // VkBool32 alphaToOneEnable;
1522 };
1523 }
1524
1525 const vk::VkViewport viewport = {
1526 0.0f, // float x;
1527 0.0f, // float y;
1528 1.0f, // float width;
1529 1.0f, // float height;
1530 0.0f, // float minDepth;
1531 1.0f, // float maxDepth;
1532 };
1533
1534 const vk::VkRect2D renderArea = {{0u, 0u}, {1u, 1u}};
1535
1536 std::unique_ptr<vk::VkPipelineViewportStateCreateInfo> viewportState;
1537
1538 if (isFrag)
1539 {
1540 viewportState.reset(new vk::VkPipelineViewportStateCreateInfo);
1541 *viewportState = {
1542 vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
1543 DE_NULL, // const void* pNext;
1544 0, // VkPipelineViewportStateCreateFlags flags;
1545 1u, // uint32_t viewportCount;
1546 &viewport, // const VkViewport* pViewports;
1547 1u, // uint32_t scissorCount;
1548 &renderArea, // const VkRect2D* pScissors;
1549 };
1550 }
1551
1552 const vk::VkGraphicsPipelineCreateInfo graphicsCreateInfo = {
1553 vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
1554 DE_NULL, // const void* pNext;
1555 0, // VkPipelineCreateFlags flags;
1556 static_cast<uint32_t>(shaderStages.size()), // uint32_t stageCount;
1557 shaderStages.data(), // const VkPipelineShaderStageCreateInfo* pStages;
1558 &vertexInputInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
1559 &inputAssembly, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
1560 DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
1561 viewportState.get(), // const VkPipelineViewportStateCreateInfo* pViewportState;
1562 &rasterizationState, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
1563 multisampleState.get(), // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
1564 DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
1565 DE_NULL, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
1566 DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
1567 *pipelineLayout, // VkPipelineLayout layout;
1568 *renderPass, // VkRenderPass renderPass;
1569 0u, // uint32_t subpass;
1570 DE_NULL, // VkPipeline basePipelineHandle;
1571 0u, // int32_t basePipelineIndex;
1572 };
1573 auto graphicsPipeline = vk::createGraphicsPipeline(vkdi, device, DE_NULL, &graphicsCreateInfo);
1574
1575 const vk::VkFramebufferCreateInfo frameBufferCreateInfo = {
1576 vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
1577 DE_NULL, // const void* pNext;
1578 0, // VkFramebufferCreateFlags flags;
1579 *renderPass, // VkRenderPass renderPass;
1580 0u, // uint32_t attachmentCount;
1581 DE_NULL, // const VkImageView* pAttachments;
1582 1u, // uint32_t width;
1583 1u, // uint32_t height;
1584 1u, // uint32_t layers;
1585 };
1586 auto frameBuffer = vk::createFramebuffer(vkdi, device, &frameBufferCreateInfo);
1587
1588 const vk::VkRenderPassBeginInfo renderPassBeginInfo = {
1589 vk::VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
1590 DE_NULL, // const void* pNext;
1591 *renderPass, // VkRenderPass renderPass;
1592 *frameBuffer, // VkFramebuffer framebuffer;
1593 renderArea, // VkRect2D renderArea;
1594 0u, // uint32_t clearValueCount;
1595 DE_NULL, // const VkClearValue* pClearValues;
1596 };
1597
1598 // Run the shader.
1599 vk::VkPipelineStageFlags pipelineStage =
1600 (isFrag ? vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT : vk::VK_PIPELINE_STAGE_VERTEX_SHADER_BIT);
1601
1602 vk::beginCommandBuffer(vkdi, *cmdBuffer);
1603 vkdi.cmdPipelineBarrier(*cmdBuffer, vk::VK_PIPELINE_STAGE_HOST_BIT, pipelineStage, 0, 0u, DE_NULL,
1604 static_cast<uint32_t>(hostToDevBarriers.size()), hostToDevBarriers.data(), 0u, DE_NULL);
1605 vkdi.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, vk::VK_SUBPASS_CONTENTS_INLINE);
1606 vkdi.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
1607 vkdi.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0, 1u,
1608 &descriptorSet.get(), 0u, DE_NULL);
1609 vkdi.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u);
1610 vkdi.cmdEndRenderPass(*cmdBuffer);
1611 vkdi.cmdPipelineBarrier(*cmdBuffer, pipelineStage, vk::VK_PIPELINE_STAGE_HOST_BIT, 0, 0u, DE_NULL,
1612 static_cast<uint32_t>(devToHostBarriers.size()), devToHostBarriers.data(), 0u, DE_NULL);
1613 vk::endCommandBuffer(vkdi, *cmdBuffer);
1614 vk::submitCommandsAndWait(vkdi, device, m_context.getUniversalQueue(), *cmdBuffer);
1615 }
1616
1617 // Invalidate allocations.
1618 vk::invalidateAlloc(vkdi, device, *input1.allocation);
1619 vk::invalidateAlloc(vkdi, device, *input2.allocation);
1620 vk::invalidateAlloc(vkdi, device, *output1.allocation);
1621
1622 // Read and verify results.
1623 std::vector<int> results(m_numOperations);
1624 deMemcpy(results.data(), output1.allocation->getHostPtr(), m_outputBufferSize);
1625 for (size_t i = 0; i < m_numOperations; ++i)
1626 {
1627 int expected =
1628 static_cast<int>(m_params.operation.run(m_params.operands[i].first, m_params.operands[i].second));
1629 if (results[i] != expected && (m_params.requireNanPreserve || (!genericIsNan<T>(m_params.operands[i].first) &&
1630 !genericIsNan<T>(m_params.operands[i].second))))
1631 {
1632 std::ostringstream msg;
1633 msg << "Invalid result found in position " << i << ": expected " << expected << " and found " << results[i];
1634 return tcu::TestStatus::fail(msg.str());
1635 }
1636 }
1637
1638 return tcu::TestStatus::pass("Pass");
1639 }
1640
1641 template <class T>
1642 class T64bitCompareTest : public TestCase
1643 {
1644 public:
1645 T64bitCompareTest(tcu::TestContext &testCtx, const std::string &name, const TestParameters<T> ¶ms);
1646 virtual void checkSupport(Context &context) const;
1647 virtual void initPrograms(vk::SourceCollections &programCollection) const;
1648 virtual TestInstance *createInstance(Context &ctx) const;
1649
1650 private:
1651 const TestParameters<T> m_params;
1652 };
1653
1654 template <class T>
T64bitCompareTest(tcu::TestContext & testCtx,const std::string & name,const TestParameters<T> & params)1655 T64bitCompareTest<T>::T64bitCompareTest(tcu::TestContext &testCtx, const std::string &name,
1656 const TestParameters<T> ¶ms)
1657 : TestCase(testCtx, name)
1658 , m_params(params)
1659 {
1660 // This is needed so that the same operands can be used for single-element comparisons or for vectorized comparisons (which use *vec4 types).
1661 DE_ASSERT(m_params.operands.size() % 4 == 0);
1662 }
1663
1664 // This template checks the needed type support features in shaders for type T.
1665 // Specializations are provided below.
1666 template <class T>
1667 void checkTypeSupport(const vk::VkPhysicalDeviceFeatures &features);
1668
1669 template <>
checkTypeSupport(const vk::VkPhysicalDeviceFeatures & features)1670 void checkTypeSupport<double>(const vk::VkPhysicalDeviceFeatures &features)
1671 {
1672 if (!features.shaderFloat64)
1673 TCU_THROW(NotSupportedError, "64-bit floats not supported in shaders");
1674 }
1675
check64bitIntegers(const vk::VkPhysicalDeviceFeatures & features)1676 void check64bitIntegers(const vk::VkPhysicalDeviceFeatures &features)
1677 {
1678 if (!features.shaderInt64)
1679 TCU_THROW(NotSupportedError, "64-bit integer types not supported in shaders");
1680 }
1681
1682 template <>
checkTypeSupport(const vk::VkPhysicalDeviceFeatures & features)1683 void checkTypeSupport<int64_t>(const vk::VkPhysicalDeviceFeatures &features)
1684 {
1685 check64bitIntegers(features);
1686 }
1687
1688 template <>
checkTypeSupport(const vk::VkPhysicalDeviceFeatures & features)1689 void checkTypeSupport<uint64_t>(const vk::VkPhysicalDeviceFeatures &features)
1690 {
1691 check64bitIntegers(features);
1692 }
1693
1694 template <class T>
checkSupport(Context & context) const1695 void T64bitCompareTest<T>::checkSupport(Context &context) const
1696 {
1697 auto &vki = context.getInstanceInterface();
1698 auto physicalDevice = context.getPhysicalDevice();
1699 auto features = vk::getPhysicalDeviceFeatures(vki, physicalDevice);
1700
1701 checkTypeSupport<T>(features);
1702
1703 switch (m_params.stage)
1704 {
1705 case vk::VK_SHADER_STAGE_COMPUTE_BIT:
1706 break;
1707 case vk::VK_SHADER_STAGE_VERTEX_BIT:
1708 if (!features.vertexPipelineStoresAndAtomics)
1709 TCU_THROW(NotSupportedError, "Vertex shader does not support stores");
1710 break;
1711 case vk::VK_SHADER_STAGE_FRAGMENT_BIT:
1712 if (!features.fragmentStoresAndAtomics)
1713 TCU_THROW(NotSupportedError, "Fragment shader does not support stores");
1714 break;
1715 default:
1716 DE_ASSERT(DE_NULL == "Invalid shader stage specified");
1717 }
1718
1719 vk::VkPhysicalDeviceFloatControlsProperties fcFeatures;
1720 deMemset(&fcFeatures, 0, sizeof(fcFeatures));
1721 fcFeatures.shaderSignedZeroInfNanPreserveFloat64 = VK_TRUE;
1722
1723 const char *unused;
1724 if (m_params.requireNanPreserve && !isFloatControlsFeaturesSupported(context, fcFeatures, &unused))
1725 TCU_THROW(NotSupportedError, "NaN preservation not supported");
1726 }
1727
1728 template <class T>
initPrograms(vk::SourceCollections & programCollection) const1729 void T64bitCompareTest<T>::initPrograms(vk::SourceCollections &programCollection) const
1730 {
1731 DE_ASSERT(m_params.stage == vk::VK_SHADER_STAGE_COMPUTE_BIT || m_params.stage == vk::VK_SHADER_STAGE_VERTEX_BIT ||
1732 m_params.stage == vk::VK_SHADER_STAGE_FRAGMENT_BIT);
1733
1734 std::map<std::string, std::string> replacements;
1735 replacements["ITERS"] =
1736 de::toString((m_params.dataType == DATA_TYPE_SINGLE) ? m_params.operands.size() : m_params.operands.size() / 4);
1737 replacements["OPNAME"] = m_params.operation.spirvName();
1738 replacements["OPCAPABILITY"] = SpirvTemplateManager::getOpCapability<T>();
1739 replacements["OPTYPE"] = SpirvTemplateManager::getOpType<T>();
1740 replacements["NANCAP"] = SpirvTemplateManager::getNanCapability(m_params.requireNanPreserve);
1741 replacements["NANEXT"] = SpirvTemplateManager::getNanExtension(m_params.requireNanPreserve);
1742 replacements["NANMODE"] = SpirvTemplateManager::getNanExeMode(m_params.requireNanPreserve);
1743
1744 static const std::map<vk::VkShaderStageFlagBits, std::string> sourceNames = {
1745 std::make_pair(vk::VK_SHADER_STAGE_COMPUTE_BIT, "comp"),
1746 std::make_pair(vk::VK_SHADER_STAGE_VERTEX_BIT, "vert"),
1747 std::make_pair(vk::VK_SHADER_STAGE_FRAGMENT_BIT, "frag"),
1748 };
1749
1750 // Add the proper template under the proper name.
1751 programCollection.spirvAsmSources.add(sourceNames.find(m_params.stage)->second)
1752 << SpirvTemplateManager::getTemplate(m_params.dataType, m_params.stage).specialize(replacements);
1753
1754 // Add the passthrough vertex shader needed for the fragment shader.
1755 if (m_params.stage == vk::VK_SHADER_STAGE_FRAGMENT_BIT)
1756 programCollection.glslSources.add("vert") << glu::VertexSource(VertShaderPassThrough);
1757 }
1758
1759 template <class T>
createInstance(Context & ctx) const1760 TestInstance *T64bitCompareTest<T>::createInstance(Context &ctx) const
1761 {
1762 return new T64bitCompareTestInstance<T>(ctx, m_params);
1763 }
1764
1765 const std::map<bool, std::string> requireNanName = {
1766 std::make_pair(false, "nonan"),
1767 std::make_pair(true, "withnan"),
1768 };
1769
1770 const std::map<DataType, std::string> dataTypeName = {
1771 std::make_pair(DATA_TYPE_SINGLE, "single"),
1772 std::make_pair(DATA_TYPE_VECTOR, "vector"),
1773 };
1774
1775 using StageName = std::map<vk::VkShaderStageFlagBits, std::string>;
1776
createDoubleCompareTestsInGroup(tcu::TestCaseGroup * tests,const StageName * stageNames)1777 void createDoubleCompareTestsInGroup(tcu::TestCaseGroup *tests, const StageName *stageNames)
1778 {
1779 static const std::vector<const CompareOperation<double> *> operationList = {
1780 // Ordered operations.
1781 &FOrderedEqualOp,
1782 &FOrderedNotEqualOp,
1783 &FOrderedLessThanOp,
1784 &FOrderedLessThanEqualOp,
1785 &FOrderedGreaterThanOp,
1786 &FOrderedGreaterThanEqualOp,
1787 // Unordered operations.
1788 &FUnorderedEqualOp,
1789 &FUnorderedNotEqualOp,
1790 &FUnorderedLessThanOp,
1791 &FUnorderedLessThanEqualOp,
1792 &FUnorderedGreaterThanOp,
1793 &FUnorderedGreaterThanEqualOp,
1794 };
1795
1796 for (const auto &stageNamePair : *stageNames)
1797 for (const auto &typeNamePair : dataTypeName)
1798 for (const auto &requireNanPair : requireNanName)
1799 for (const auto opPtr : operationList)
1800 {
1801 TestParameters<double> params = {typeNamePair.first, *opPtr, stageNamePair.first, DOUBLE_OPERANDS,
1802 requireNanPair.first};
1803 std::string testName = stageNamePair.second + "_" + de::toLower(opPtr->spirvName()) + "_" +
1804 requireNanPair.second + "_" + typeNamePair.second;
1805 tests->addChild(new T64bitCompareTest<double>(tests->getTestContext(), testName, params));
1806 }
1807 }
1808
createInt64CompareTestsInGroup(tcu::TestCaseGroup * tests,const StageName * stageNames)1809 void createInt64CompareTestsInGroup(tcu::TestCaseGroup *tests, const StageName *stageNames)
1810 {
1811 static const std::vector<const CompareOperation<int64_t> *> operationList = {
1812 &int64EqualOp, &int64NotEqualOp, &int64LessThanOp,
1813 &int64LessThanEqualOp, &int64GreaterThanOp, &int64GreaterThanEqualOp,
1814 };
1815
1816 for (const auto &stageNamePair : *stageNames)
1817 for (const auto &typeNamePair : dataTypeName)
1818 for (const auto opPtr : operationList)
1819 {
1820 TestParameters<int64_t> params = {typeNamePair.first, *opPtr, stageNamePair.first, INT64_OPERANDS,
1821 false};
1822 std::string testName =
1823 stageNamePair.second + "_" + de::toLower(opPtr->spirvName()) + "_" + typeNamePair.second;
1824 tests->addChild(new T64bitCompareTest<int64_t>(tests->getTestContext(), testName, params));
1825 }
1826 }
1827
createUint64CompareTestsInGroup(tcu::TestCaseGroup * tests,const StageName * stageNames)1828 void createUint64CompareTestsInGroup(tcu::TestCaseGroup *tests, const StageName *stageNames)
1829 {
1830 static const std::vector<const CompareOperation<uint64_t> *> operationList = {
1831 &uint64EqualOp, &uint64NotEqualOp, &uint64LessThanOp,
1832 &uint64LessThanEqualOp, &uint64GreaterThanOp, &uint64GreaterThanEqualOp,
1833 };
1834
1835 for (const auto &stageNamePair : *stageNames)
1836 for (const auto &typeNamePair : dataTypeName)
1837 for (const auto opPtr : operationList)
1838 {
1839 TestParameters<uint64_t> params = {typeNamePair.first, *opPtr, stageNamePair.first, UINT64_OPERANDS,
1840 false};
1841 std::string testName =
1842 stageNamePair.second + "_" + de::toLower(opPtr->spirvName()) + "_" + typeNamePair.second;
1843 tests->addChild(new T64bitCompareTest<uint64_t>(tests->getTestContext(), testName, params));
1844 }
1845 }
1846
1847 struct TestMgr
1848 {
1849 typedef void (*CreationFunctionPtr)(tcu::TestCaseGroup *, const StageName *);
1850
getParentGroupNamevkt::SpirVAssembly::__anon071ae8e90111::TestMgr1851 static const char *getParentGroupName()
1852 {
1853 return "64bit_compare";
1854 }
getParentGroupDescvkt::SpirVAssembly::__anon071ae8e90111::TestMgr1855 static const char *getParentGroupDesc()
1856 {
1857 return "64-bit type comparison operations";
1858 }
1859
1860 template <class T>
1861 static std::string getGroupName();
1862
1863 template <class T>
1864 static CreationFunctionPtr getCreationFunction();
1865 };
1866
1867 template <>
getGroupName()1868 std::string TestMgr::getGroupName<double>()
1869 {
1870 return "double";
1871 }
1872 template <>
getGroupName()1873 std::string TestMgr::getGroupName<int64_t>()
1874 {
1875 return "int64";
1876 }
1877 template <>
getGroupName()1878 std::string TestMgr::getGroupName<uint64_t>()
1879 {
1880 return "uint64";
1881 }
1882
1883 template <>
getCreationFunction()1884 TestMgr::CreationFunctionPtr TestMgr::getCreationFunction<double>()
1885 {
1886 return createDoubleCompareTestsInGroup;
1887 }
1888 template <>
getCreationFunction()1889 TestMgr::CreationFunctionPtr TestMgr::getCreationFunction<int64_t>()
1890 {
1891 return createInt64CompareTestsInGroup;
1892 }
1893 template <>
getCreationFunction()1894 TestMgr::CreationFunctionPtr TestMgr::getCreationFunction<uint64_t>()
1895 {
1896 return createUint64CompareTestsInGroup;
1897 }
1898
1899 } // namespace
1900
create64bitCompareGraphicsGroup(tcu::TestContext & testCtx)1901 tcu::TestCaseGroup *create64bitCompareGraphicsGroup(tcu::TestContext &testCtx)
1902 {
1903 static const StageName graphicStages = {
1904 std::make_pair(vk::VK_SHADER_STAGE_VERTEX_BIT, "vert"),
1905 std::make_pair(vk::VK_SHADER_STAGE_FRAGMENT_BIT, "frag"),
1906 };
1907
1908 tcu::TestCaseGroup *newGroup = new tcu::TestCaseGroup(testCtx, TestMgr::getParentGroupName());
1909 newGroup->addChild(createTestGroup(testCtx, TestMgr::getGroupName<double>(), TestMgr::getCreationFunction<double>(),
1910 &graphicStages));
1911 newGroup->addChild(createTestGroup(testCtx, TestMgr::getGroupName<int64_t>(),
1912 TestMgr::getCreationFunction<int64_t>(), &graphicStages));
1913 newGroup->addChild(createTestGroup(testCtx, TestMgr::getGroupName<uint64_t>(),
1914 TestMgr::getCreationFunction<uint64_t>(), &graphicStages));
1915 return newGroup;
1916 }
1917
create64bitCompareComputeGroup(tcu::TestContext & testCtx)1918 tcu::TestCaseGroup *create64bitCompareComputeGroup(tcu::TestContext &testCtx)
1919 {
1920 static const StageName computeStages = {
1921 std::make_pair(vk::VK_SHADER_STAGE_COMPUTE_BIT, "comp"),
1922 };
1923
1924 tcu::TestCaseGroup *newGroup = new tcu::TestCaseGroup(testCtx, TestMgr::getParentGroupName());
1925 newGroup->addChild(createTestGroup(testCtx, TestMgr::getGroupName<double>(), TestMgr::getCreationFunction<double>(),
1926 &computeStages));
1927 newGroup->addChild(createTestGroup(testCtx, TestMgr::getGroupName<int64_t>(),
1928 TestMgr::getCreationFunction<int64_t>(), &computeStages));
1929 newGroup->addChild(createTestGroup(testCtx, TestMgr::getGroupName<uint64_t>(),
1930 TestMgr::getCreationFunction<uint64_t>(), &computeStages));
1931 return newGroup;
1932 }
1933
1934 } // namespace SpirVAssembly
1935 } // namespace vkt
1936