Path: blob/main_old/src/tests/compiler_tests/Precise_test.cpp
1693 views
//1// Copyright 2021 The ANGLE Project Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4//5// Precise_test.cpp:6// Test that precise produces the right number of NoContraction decorations in the generated7// SPIR-V.8//910#include "GLSLANG/ShaderLang.h"11#include "angle_gl.h"12#include "common/spirv/spirv_instruction_parser_autogen.h"13#include "gtest/gtest.h"1415namespace spirv = angle::spirv;1617namespace18{19class PreciseTest : public testing::TestWithParam<bool>20{21public:22void SetUp() override23{24std::map<ShShaderOutput, std::string> shaderOutputList = {25{SH_SPIRV_VULKAN_OUTPUT, "SH_SPIRV_VULKAN_OUTPUT"}};2627Initialize(shaderOutputList);28}2930void TearDown() override31{32for (auto shaderOutputType : mShaderOutputList)33{34DestroyCompiler(shaderOutputType.first);35}36}3738void Initialize(std::map<ShShaderOutput, std::string> &shaderOutputList)39{40mShaderOutputList = std::move(shaderOutputList);4142for (auto shaderOutputType : mShaderOutputList)43{44sh::InitBuiltInResources(&mResourceList[shaderOutputType.first]);45mCompilerList[shaderOutputType.first] = nullptr;46}47}4849void DestroyCompiler(ShShaderOutput shaderOutputType)50{51if (mCompilerList[shaderOutputType])52{53sh::Destruct(mCompilerList[shaderOutputType]);54mCompilerList[shaderOutputType] = nullptr;55}56}5758void InitializeCompiler()59{60for (auto shaderOutputType : mShaderOutputList)61{62InitializeCompiler(shaderOutputType.first);63}64}6566void InitializeCompiler(ShShaderOutput shaderOutputType)67{68DestroyCompiler(shaderOutputType);6970mCompilerList[shaderOutputType] = sh::ConstructCompiler(71GL_VERTEX_SHADER, SH_GLES3_2_SPEC, shaderOutputType, &mResourceList[shaderOutputType]);72ASSERT_TRUE(mCompilerList[shaderOutputType] != nullptr)73<< "Compiler for " << mShaderOutputList[shaderOutputType]74<< " could not be constructed.";75}7677bool isDirectSPIRVGen() const { return GetParam(); }7879testing::AssertionResult TestShaderCompile(ShShaderOutput shaderOutputType,80const char *shaderSource)81{82const char *shaderStrings[] = {shaderSource};8384const ShCompileOptions options =85SH_VARIABLES | SH_OBJECT_CODE | (isDirectSPIRVGen() ? SH_GENERATE_SPIRV_DIRECTLY : 0);8687bool success = sh::Compile(mCompilerList[shaderOutputType], shaderStrings, 1, options);88if (success)89{90return ::testing::AssertionSuccess()91<< "Compilation success(" << mShaderOutputList[shaderOutputType] << ")";92}93return ::testing::AssertionFailure() << sh::GetInfoLog(mCompilerList[shaderOutputType]);94}9596void TestShaderCompile(const char *shaderSource, size_t expectedNoContractionDecorationCount)97{98for (auto shaderOutputType : mShaderOutputList)99{100EXPECT_TRUE(TestShaderCompile(shaderOutputType.first, shaderSource));101102const spirv::Blob &blob =103sh::GetObjectBinaryBlob(mCompilerList[shaderOutputType.first]);104ValidateDecorations(blob, expectedNoContractionDecorationCount);105}106}107108void ValidateDecorations(const spirv::Blob &blob, size_t expectedNoContractionDecorationCount);109110private:111std::map<ShShaderOutput, std::string> mShaderOutputList;112std::map<ShShaderOutput, ShHandle> mCompilerList;113std::map<ShShaderOutput, ShBuiltInResources> mResourceList;114};115116// Parse the SPIR-V and verify that there are as many NoContraction decorations as expected.117void PreciseTest::ValidateDecorations(const spirv::Blob &blob,118size_t expectedNoContractionDecorationCount)119{120size_t currentWord = spirv::kHeaderIndexInstructions;121size_t noContractionDecorationCount = 0;122123while (currentWord < blob.size())124{125uint32_t wordCount;126spv::Op opCode;127const uint32_t *instruction = &blob[currentWord];128spirv::GetInstructionOpAndLength(instruction, &opCode, &wordCount);129130currentWord += wordCount;131132// Early out when the decorations section is visited.133if (opCode == spv::OpTypeVoid || opCode == spv::OpTypeInt || opCode == spv::OpTypeFloat ||134opCode == spv::OpTypeBool)135{136break;137}138139if (opCode == spv::OpMemberDecorate)140{141spirv::IdRef type;142spirv::LiteralInteger member;143spv::Decoration decoration;144spirv::ParseMemberDecorate(instruction, &type, &member, &decoration, nullptr);145146// NoContraction should be applied to arithmetic instructions, and should not be seen on147// block members.148EXPECT_NE(decoration, spv::DecorationNoContraction);149}150else if (opCode == spv::OpDecorate)151{152spirv::IdRef target;153spv::Decoration decoration;154spirv::ParseDecorate(instruction, &target, &decoration, nullptr);155156if (decoration == spv::DecorationNoContraction)157{158++noContractionDecorationCount;159}160}161}162163EXPECT_EQ(noContractionDecorationCount, expectedNoContractionDecorationCount);164}165166// Test that precise on a local variable works.167TEST_P(PreciseTest, LocalVariable)168{169constexpr char kVS[] = R"(#version 320 es170171uniform float u;172173void main()174{175float f1 = u, f2 = u; // f1 is precise, but f2 isn't.176177f1 += 1.0; // NoContraction178f2 += 1.0;179180float f3 = f1 * f1; // NoContraction181f3 /= 2.0; // NoContraction182183int i1 = int(f3); // i1 is precise184++i1; // NoContraction185--i1; // NoContraction186i1++; // NoContraction187i1--; // NoContraction188189int i2 = i1 % 3;190f2 -= float(i2);191192precise float p = float(i1) / 1.5; // NoContraction193194gl_Position = vec4(p, f2, 0, 0);195})";196197InitializeCompiler();198TestShaderCompile(kVS, 8);199}200201// Test that precise on gl_Position works.202TEST_P(PreciseTest, Position)203{204if (!isDirectSPIRVGen())205{206// glslang doesn't apply NoContraction to dot(), while its code seemingly means to. Unclear207// whether dot() requires NoContraction.208// https://github.com/KhronosGroup/glslang/issues/2708209std::cout << "Test skipped on glslang" << std::endl;210return;211}212213constexpr char kVS[] = R"(#version 320 es214215uniform float u;216217out float o;218219precise gl_Position;220221void main()222{223mat4 m1 = mat4(u); // m1 is precise, even if not all components are used to determine the224// gl_Position.225vec4 v1 = vec4(u); // v1 is precise226227vec4 v2 = m1 * v1;228v1 *= m1; // NoContraction229m1 *= m1; // NoContraction230m1 *= u; // NoContraction231v1 *= u; // NoContraction232233float f1 = dot(v1, v1);234float f2 = dot(v1, v1); // NoContraction235236gl_Position = vec4(m1[0][0], v1[0], f2, 0);237o = f1;238})";239240InitializeCompiler();241TestShaderCompile(kVS, 5);242}243244// Test that precise on struct member works.245TEST_P(PreciseTest, StructMember)246{247constexpr char kVS[] = R"(#version 320 es248249uniform float u;250251struct S1252{253precise float f;254int i;255};256257struct S2258{259float f;260};261262struct S3263{264precise uint u;265S1 s1[2];266precise S2 s2;267};268269layout(std430) buffer B270{271S3 o1;272S3 o2;273S3 o3;274};275276void main()277{278S2 a = S2(u), b = S2(u), c = S2(u); // a and c are precise279280++a.f; // NoContraction281o1.s2 = a;282283c.f += a.f; // NoContraction284o2.s1[0].i = int(a.f);285o2.s1[0].i *= 2;286o2.s1[0].i /= int(b.f);287288o1.s1[1].i = int(u);289--o1.s1[1].i; // NoContraction290291o2.s1[0].f = c.f;292293o3.u = o1.u + uint(o1.s1[1].i); // NoContraction294})";295296InitializeCompiler();297TestShaderCompile(kVS, 4);298}299300// Test that precise on function parameters and return value works.301TEST_P(PreciseTest, Functions)302{303constexpr char kVS[] = R"(#version 320 es304305uniform float u;306307struct S1308{309float f;310int i;311};312313precise float f1(S1 s, out int io)314{315float f = s.f; // f is precise316f *= float(s.i); // NoContraction317318io = s.i;319++io;320321return s.f / f; // NoContraction322}323324void f2(S1 s, precise out S1 so)325{326float f = s.f; // f is precise327f /= float(s.i); // NoContraction328329int i = s.i; // i is precise330++i; // NoContraction331332so = S1(f, i);333}334335void main()336{337precise S1 s1;338S1 s2;339340int i;341float f = f1(s1, i); // f1's return value being precise doesn't affect f342343f2(s1, s2); // f2's out parameter being precise doesn't affect s2344345i /= 2;346f *= 2.0;347s2.f += float(s2.i);348349gl_Position = vec4(s1.f);350})";351352InitializeCompiler();353TestShaderCompile(kVS, 4);354}355356// Test that struct constructors only apply precise to the precise fields.357TEST_P(PreciseTest, StructConstructor)358{359if (!isDirectSPIRVGen())360{361// glslang doesn't apply NoContraction through constructor arguments correctly.362// https://github.com/KhronosGroup/glslang/issues/2709363std::cout << "Test skipped on glslang" << std::endl;364return;365}366367constexpr char kVS[] = R"(#version 320 es368369uniform float u;370371struct S1372{373precise float f;374int i;375precise vec4 v;376mat4 m;377};378379void main()380{381float f = u; // f is precise382int i = int(u);383vec4 v1 = vec4(u); // v1 is precise384vec4 v2 = vec4(u);385386f += 1.0; // NoContraction387388i--;389i--;390391v1 *= 2.0; // NoContraction392v1 *= 2.0; // NoContraction393v1 *= 2.0; // NoContraction394v1 *= 2.0; // NoContraction395396v2 /= 3.0;397v2 /= 3.0;398v2 /= 3.0;399v2 /= 3.0;400v2 /= 3.0;401v2 /= 3.0;402v2 /= 3.0;403v2 /= 3.0;404v2 /= 3.0;405406S1 s = S1(f, i, v1, mat4(v2, v2, v2, v2));407408gl_Position = vec4(s.f, float(s.i), s.v[0], s.m[0][0]);409})";410411InitializeCompiler();412TestShaderCompile(kVS, 5);413}414415// Test that function call arguments become precise when the return value is assigned to a precise416// object.417TEST_P(PreciseTest, FunctionParams)418{419if (!isDirectSPIRVGen())420{421// glslang doesn't apply NoContraction through function arguments correctly.422// https://github.com/KhronosGroup/glslang/issues/2710423std::cout << "Test skipped on glslang" << std::endl;424return;425}426427constexpr char kVS[] = R"(#version 320 es428429uniform float u;430431struct S1432{433precise float f;434int i;435precise vec4 v;436mat4 m;437};438439S1 func(float f, int i, vec4 v, mat4 m)440{441m /= f;442--i;443v *= m;444return S1(f, i, v, m);445}446447void main()448{449float f = u; // f is precise450int i = int(u); // i is precise451vec4 v1 = vec4(u); // v1 is precise452vec4 v2 = vec4(u); // v2 is precise453454f += 1.0; // NoContraction455456i--; // NoContraction457i--; // NoContraction458459v1 *= 2.0; // NoContraction460v1 *= 2.0; // NoContraction461v1 *= 2.0; // NoContraction462v1 *= 2.0; // NoContraction463464v2 /= 3.0; // NoContraction465v2 /= 3.0; // NoContraction466v2 /= 3.0; // NoContraction467v2 /= 3.0; // NoContraction468v2 /= 3.0; // NoContraction469v2 /= 3.0; // NoContraction470v2 /= 3.0; // NoContraction471v2 /= 3.0; // NoContraction472v2 /= 3.0; // NoContraction473474// s.f and s.v1 are precise, but to calculate them, all parameters of the function must be made475// precise.476S1 s = func(f, i, v1, mat4(v2, v2, v2, v2));477478gl_Position = vec4(s.f, float(s.i), s.v[0], s.m[0][0]);479})";480481InitializeCompiler();482TestShaderCompile(kVS, 16);483}484485INSTANTIATE_TEST_SUITE_P(, PreciseTest, testing::Bool());486487} // anonymous namespace488489490