Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/angle
Path: blob/main_old/src/tests/compiler_tests/Precise_test.cpp
1693 views
1
//
2
// Copyright 2021 The ANGLE Project Authors. All rights reserved.
3
// Use of this source code is governed by a BSD-style license that can be
4
// found in the LICENSE file.
5
//
6
// Precise_test.cpp:
7
// Test that precise produces the right number of NoContraction decorations in the generated
8
// SPIR-V.
9
//
10
11
#include "GLSLANG/ShaderLang.h"
12
#include "angle_gl.h"
13
#include "common/spirv/spirv_instruction_parser_autogen.h"
14
#include "gtest/gtest.h"
15
16
namespace spirv = angle::spirv;
17
18
namespace
19
{
20
class PreciseTest : public testing::TestWithParam<bool>
21
{
22
public:
23
void SetUp() override
24
{
25
std::map<ShShaderOutput, std::string> shaderOutputList = {
26
{SH_SPIRV_VULKAN_OUTPUT, "SH_SPIRV_VULKAN_OUTPUT"}};
27
28
Initialize(shaderOutputList);
29
}
30
31
void TearDown() override
32
{
33
for (auto shaderOutputType : mShaderOutputList)
34
{
35
DestroyCompiler(shaderOutputType.first);
36
}
37
}
38
39
void Initialize(std::map<ShShaderOutput, std::string> &shaderOutputList)
40
{
41
mShaderOutputList = std::move(shaderOutputList);
42
43
for (auto shaderOutputType : mShaderOutputList)
44
{
45
sh::InitBuiltInResources(&mResourceList[shaderOutputType.first]);
46
mCompilerList[shaderOutputType.first] = nullptr;
47
}
48
}
49
50
void DestroyCompiler(ShShaderOutput shaderOutputType)
51
{
52
if (mCompilerList[shaderOutputType])
53
{
54
sh::Destruct(mCompilerList[shaderOutputType]);
55
mCompilerList[shaderOutputType] = nullptr;
56
}
57
}
58
59
void InitializeCompiler()
60
{
61
for (auto shaderOutputType : mShaderOutputList)
62
{
63
InitializeCompiler(shaderOutputType.first);
64
}
65
}
66
67
void InitializeCompiler(ShShaderOutput shaderOutputType)
68
{
69
DestroyCompiler(shaderOutputType);
70
71
mCompilerList[shaderOutputType] = sh::ConstructCompiler(
72
GL_VERTEX_SHADER, SH_GLES3_2_SPEC, shaderOutputType, &mResourceList[shaderOutputType]);
73
ASSERT_TRUE(mCompilerList[shaderOutputType] != nullptr)
74
<< "Compiler for " << mShaderOutputList[shaderOutputType]
75
<< " could not be constructed.";
76
}
77
78
bool isDirectSPIRVGen() const { return GetParam(); }
79
80
testing::AssertionResult TestShaderCompile(ShShaderOutput shaderOutputType,
81
const char *shaderSource)
82
{
83
const char *shaderStrings[] = {shaderSource};
84
85
const ShCompileOptions options =
86
SH_VARIABLES | SH_OBJECT_CODE | (isDirectSPIRVGen() ? SH_GENERATE_SPIRV_DIRECTLY : 0);
87
88
bool success = sh::Compile(mCompilerList[shaderOutputType], shaderStrings, 1, options);
89
if (success)
90
{
91
return ::testing::AssertionSuccess()
92
<< "Compilation success(" << mShaderOutputList[shaderOutputType] << ")";
93
}
94
return ::testing::AssertionFailure() << sh::GetInfoLog(mCompilerList[shaderOutputType]);
95
}
96
97
void TestShaderCompile(const char *shaderSource, size_t expectedNoContractionDecorationCount)
98
{
99
for (auto shaderOutputType : mShaderOutputList)
100
{
101
EXPECT_TRUE(TestShaderCompile(shaderOutputType.first, shaderSource));
102
103
const spirv::Blob &blob =
104
sh::GetObjectBinaryBlob(mCompilerList[shaderOutputType.first]);
105
ValidateDecorations(blob, expectedNoContractionDecorationCount);
106
}
107
}
108
109
void ValidateDecorations(const spirv::Blob &blob, size_t expectedNoContractionDecorationCount);
110
111
private:
112
std::map<ShShaderOutput, std::string> mShaderOutputList;
113
std::map<ShShaderOutput, ShHandle> mCompilerList;
114
std::map<ShShaderOutput, ShBuiltInResources> mResourceList;
115
};
116
117
// Parse the SPIR-V and verify that there are as many NoContraction decorations as expected.
118
void PreciseTest::ValidateDecorations(const spirv::Blob &blob,
119
size_t expectedNoContractionDecorationCount)
120
{
121
size_t currentWord = spirv::kHeaderIndexInstructions;
122
size_t noContractionDecorationCount = 0;
123
124
while (currentWord < blob.size())
125
{
126
uint32_t wordCount;
127
spv::Op opCode;
128
const uint32_t *instruction = &blob[currentWord];
129
spirv::GetInstructionOpAndLength(instruction, &opCode, &wordCount);
130
131
currentWord += wordCount;
132
133
// Early out when the decorations section is visited.
134
if (opCode == spv::OpTypeVoid || opCode == spv::OpTypeInt || opCode == spv::OpTypeFloat ||
135
opCode == spv::OpTypeBool)
136
{
137
break;
138
}
139
140
if (opCode == spv::OpMemberDecorate)
141
{
142
spirv::IdRef type;
143
spirv::LiteralInteger member;
144
spv::Decoration decoration;
145
spirv::ParseMemberDecorate(instruction, &type, &member, &decoration, nullptr);
146
147
// NoContraction should be applied to arithmetic instructions, and should not be seen on
148
// block members.
149
EXPECT_NE(decoration, spv::DecorationNoContraction);
150
}
151
else if (opCode == spv::OpDecorate)
152
{
153
spirv::IdRef target;
154
spv::Decoration decoration;
155
spirv::ParseDecorate(instruction, &target, &decoration, nullptr);
156
157
if (decoration == spv::DecorationNoContraction)
158
{
159
++noContractionDecorationCount;
160
}
161
}
162
}
163
164
EXPECT_EQ(noContractionDecorationCount, expectedNoContractionDecorationCount);
165
}
166
167
// Test that precise on a local variable works.
168
TEST_P(PreciseTest, LocalVariable)
169
{
170
constexpr char kVS[] = R"(#version 320 es
171
172
uniform float u;
173
174
void main()
175
{
176
float f1 = u, f2 = u; // f1 is precise, but f2 isn't.
177
178
f1 += 1.0; // NoContraction
179
f2 += 1.0;
180
181
float f3 = f1 * f1; // NoContraction
182
f3 /= 2.0; // NoContraction
183
184
int i1 = int(f3); // i1 is precise
185
++i1; // NoContraction
186
--i1; // NoContraction
187
i1++; // NoContraction
188
i1--; // NoContraction
189
190
int i2 = i1 % 3;
191
f2 -= float(i2);
192
193
precise float p = float(i1) / 1.5; // NoContraction
194
195
gl_Position = vec4(p, f2, 0, 0);
196
})";
197
198
InitializeCompiler();
199
TestShaderCompile(kVS, 8);
200
}
201
202
// Test that precise on gl_Position works.
203
TEST_P(PreciseTest, Position)
204
{
205
if (!isDirectSPIRVGen())
206
{
207
// glslang doesn't apply NoContraction to dot(), while its code seemingly means to. Unclear
208
// whether dot() requires NoContraction.
209
// https://github.com/KhronosGroup/glslang/issues/2708
210
std::cout << "Test skipped on glslang" << std::endl;
211
return;
212
}
213
214
constexpr char kVS[] = R"(#version 320 es
215
216
uniform float u;
217
218
out float o;
219
220
precise gl_Position;
221
222
void main()
223
{
224
mat4 m1 = mat4(u); // m1 is precise, even if not all components are used to determine the
225
// gl_Position.
226
vec4 v1 = vec4(u); // v1 is precise
227
228
vec4 v2 = m1 * v1;
229
v1 *= m1; // NoContraction
230
m1 *= m1; // NoContraction
231
m1 *= u; // NoContraction
232
v1 *= u; // NoContraction
233
234
float f1 = dot(v1, v1);
235
float f2 = dot(v1, v1); // NoContraction
236
237
gl_Position = vec4(m1[0][0], v1[0], f2, 0);
238
o = f1;
239
})";
240
241
InitializeCompiler();
242
TestShaderCompile(kVS, 5);
243
}
244
245
// Test that precise on struct member works.
246
TEST_P(PreciseTest, StructMember)
247
{
248
constexpr char kVS[] = R"(#version 320 es
249
250
uniform float u;
251
252
struct S1
253
{
254
precise float f;
255
int i;
256
};
257
258
struct S2
259
{
260
float f;
261
};
262
263
struct S3
264
{
265
precise uint u;
266
S1 s1[2];
267
precise S2 s2;
268
};
269
270
layout(std430) buffer B
271
{
272
S3 o1;
273
S3 o2;
274
S3 o3;
275
};
276
277
void main()
278
{
279
S2 a = S2(u), b = S2(u), c = S2(u); // a and c are precise
280
281
++a.f; // NoContraction
282
o1.s2 = a;
283
284
c.f += a.f; // NoContraction
285
o2.s1[0].i = int(a.f);
286
o2.s1[0].i *= 2;
287
o2.s1[0].i /= int(b.f);
288
289
o1.s1[1].i = int(u);
290
--o1.s1[1].i; // NoContraction
291
292
o2.s1[0].f = c.f;
293
294
o3.u = o1.u + uint(o1.s1[1].i); // NoContraction
295
})";
296
297
InitializeCompiler();
298
TestShaderCompile(kVS, 4);
299
}
300
301
// Test that precise on function parameters and return value works.
302
TEST_P(PreciseTest, Functions)
303
{
304
constexpr char kVS[] = R"(#version 320 es
305
306
uniform float u;
307
308
struct S1
309
{
310
float f;
311
int i;
312
};
313
314
precise float f1(S1 s, out int io)
315
{
316
float f = s.f; // f is precise
317
f *= float(s.i); // NoContraction
318
319
io = s.i;
320
++io;
321
322
return s.f / f; // NoContraction
323
}
324
325
void f2(S1 s, precise out S1 so)
326
{
327
float f = s.f; // f is precise
328
f /= float(s.i); // NoContraction
329
330
int i = s.i; // i is precise
331
++i; // NoContraction
332
333
so = S1(f, i);
334
}
335
336
void main()
337
{
338
precise S1 s1;
339
S1 s2;
340
341
int i;
342
float f = f1(s1, i); // f1's return value being precise doesn't affect f
343
344
f2(s1, s2); // f2's out parameter being precise doesn't affect s2
345
346
i /= 2;
347
f *= 2.0;
348
s2.f += float(s2.i);
349
350
gl_Position = vec4(s1.f);
351
})";
352
353
InitializeCompiler();
354
TestShaderCompile(kVS, 4);
355
}
356
357
// Test that struct constructors only apply precise to the precise fields.
358
TEST_P(PreciseTest, StructConstructor)
359
{
360
if (!isDirectSPIRVGen())
361
{
362
// glslang doesn't apply NoContraction through constructor arguments correctly.
363
// https://github.com/KhronosGroup/glslang/issues/2709
364
std::cout << "Test skipped on glslang" << std::endl;
365
return;
366
}
367
368
constexpr char kVS[] = R"(#version 320 es
369
370
uniform float u;
371
372
struct S1
373
{
374
precise float f;
375
int i;
376
precise vec4 v;
377
mat4 m;
378
};
379
380
void main()
381
{
382
float f = u; // f is precise
383
int i = int(u);
384
vec4 v1 = vec4(u); // v1 is precise
385
vec4 v2 = vec4(u);
386
387
f += 1.0; // NoContraction
388
389
i--;
390
i--;
391
392
v1 *= 2.0; // NoContraction
393
v1 *= 2.0; // NoContraction
394
v1 *= 2.0; // NoContraction
395
v1 *= 2.0; // NoContraction
396
397
v2 /= 3.0;
398
v2 /= 3.0;
399
v2 /= 3.0;
400
v2 /= 3.0;
401
v2 /= 3.0;
402
v2 /= 3.0;
403
v2 /= 3.0;
404
v2 /= 3.0;
405
v2 /= 3.0;
406
407
S1 s = S1(f, i, v1, mat4(v2, v2, v2, v2));
408
409
gl_Position = vec4(s.f, float(s.i), s.v[0], s.m[0][0]);
410
})";
411
412
InitializeCompiler();
413
TestShaderCompile(kVS, 5);
414
}
415
416
// Test that function call arguments become precise when the return value is assigned to a precise
417
// object.
418
TEST_P(PreciseTest, FunctionParams)
419
{
420
if (!isDirectSPIRVGen())
421
{
422
// glslang doesn't apply NoContraction through function arguments correctly.
423
// https://github.com/KhronosGroup/glslang/issues/2710
424
std::cout << "Test skipped on glslang" << std::endl;
425
return;
426
}
427
428
constexpr char kVS[] = R"(#version 320 es
429
430
uniform float u;
431
432
struct S1
433
{
434
precise float f;
435
int i;
436
precise vec4 v;
437
mat4 m;
438
};
439
440
S1 func(float f, int i, vec4 v, mat4 m)
441
{
442
m /= f;
443
--i;
444
v *= m;
445
return S1(f, i, v, m);
446
}
447
448
void main()
449
{
450
float f = u; // f is precise
451
int i = int(u); // i is precise
452
vec4 v1 = vec4(u); // v1 is precise
453
vec4 v2 = vec4(u); // v2 is precise
454
455
f += 1.0; // NoContraction
456
457
i--; // NoContraction
458
i--; // NoContraction
459
460
v1 *= 2.0; // NoContraction
461
v1 *= 2.0; // NoContraction
462
v1 *= 2.0; // NoContraction
463
v1 *= 2.0; // NoContraction
464
465
v2 /= 3.0; // NoContraction
466
v2 /= 3.0; // NoContraction
467
v2 /= 3.0; // NoContraction
468
v2 /= 3.0; // NoContraction
469
v2 /= 3.0; // NoContraction
470
v2 /= 3.0; // NoContraction
471
v2 /= 3.0; // NoContraction
472
v2 /= 3.0; // NoContraction
473
v2 /= 3.0; // NoContraction
474
475
// s.f and s.v1 are precise, but to calculate them, all parameters of the function must be made
476
// precise.
477
S1 s = func(f, i, v1, mat4(v2, v2, v2, v2));
478
479
gl_Position = vec4(s.f, float(s.i), s.v[0], s.m[0][0]);
480
})";
481
482
InitializeCompiler();
483
TestShaderCompile(kVS, 16);
484
}
485
486
INSTANTIATE_TEST_SUITE_P(, PreciseTest, testing::Bool());
487
488
} // anonymous namespace
489
490