• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 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 // ShaderImage_test.cpp:
7 // Tests for images
8 //
9 
10 #include "GLSLANG/ShaderLang.h"
11 #include "angle_gl.h"
12 #include "compiler/translator/StaticType.h"
13 #include "gtest/gtest.h"
14 #include "tests/test_utils/ShaderCompileTreeTest.h"
15 #include "tests/test_utils/compiler_test.h"
16 
17 using namespace sh;
18 
19 namespace
20 {
21 
22 // Checks that the imageStore call with mangled name imageStoreMangledName exists in the AST.
23 // Further each argument is checked whether it matches the expected properties given the compiled
24 // shader.
CheckImageStoreCall(TIntermNode * astRoot,const TString & imageStoreMangledName,TBasicType imageType,int storeLocationNominalSize,TBasicType storeValueType,int storeValueNominalSize)25 void CheckImageStoreCall(TIntermNode *astRoot,
26                          const TString &imageStoreMangledName,
27                          TBasicType imageType,
28                          int storeLocationNominalSize,
29                          TBasicType storeValueType,
30                          int storeValueNominalSize)
31 {
32     const TIntermAggregate *imageStoreFunctionCall =
33         FindFunctionCallNode(astRoot, imageStoreMangledName);
34     ASSERT_NE(nullptr, imageStoreFunctionCall);
35 
36     const TIntermSequence *storeArguments = imageStoreFunctionCall->getSequence();
37     ASSERT_EQ(3u, storeArguments->size());
38 
39     const TIntermTyped *storeArgument1Typed = (*storeArguments)[0]->getAsTyped();
40     ASSERT_EQ(imageType, storeArgument1Typed->getBasicType());
41 
42     const TIntermTyped *storeArgument2Typed = (*storeArguments)[1]->getAsTyped();
43     ASSERT_EQ(EbtInt, storeArgument2Typed->getBasicType());
44     ASSERT_EQ(storeLocationNominalSize, storeArgument2Typed->getNominalSize());
45 
46     const TIntermTyped *storeArgument3Typed = (*storeArguments)[2]->getAsTyped();
47     ASSERT_EQ(storeValueType, storeArgument3Typed->getBasicType());
48     ASSERT_EQ(storeValueNominalSize, storeArgument3Typed->getNominalSize());
49 }
50 
51 // Checks that the imageLoad call with mangled name imageLoadMangledName exists in the AST.
52 // Further each argument is checked whether it matches the expected properties given the compiled
53 // shader.
CheckImageLoadCall(TIntermNode * astRoot,const TString & imageLoadMangledName,TBasicType imageType,int loadLocationNominalSize)54 void CheckImageLoadCall(TIntermNode *astRoot,
55                         const TString &imageLoadMangledName,
56                         TBasicType imageType,
57                         int loadLocationNominalSize)
58 {
59     const TIntermAggregate *imageLoadFunctionCall =
60         FindFunctionCallNode(astRoot, imageLoadMangledName);
61     ASSERT_NE(nullptr, imageLoadFunctionCall);
62 
63     const TIntermSequence *loadArguments = imageLoadFunctionCall->getSequence();
64     ASSERT_EQ(2u, loadArguments->size());
65 
66     const TIntermTyped *loadArgument1Typed = (*loadArguments)[0]->getAsTyped();
67     ASSERT_EQ(imageType, loadArgument1Typed->getBasicType());
68 
69     const TIntermTyped *loadArgument2Typed = (*loadArguments)[1]->getAsTyped();
70     ASSERT_EQ(EbtInt, loadArgument2Typed->getBasicType());
71     ASSERT_EQ(loadLocationNominalSize, loadArgument2Typed->getNominalSize());
72 }
73 
74 // Checks whether the image is properly exported as a uniform by the compiler.
CheckExportedImageUniform(const std::vector<sh::ShaderVariable> & uniforms,size_t uniformIndex,::GLenum imageTypeGL,const TString & imageName)75 void CheckExportedImageUniform(const std::vector<sh::ShaderVariable> &uniforms,
76                                size_t uniformIndex,
77                                ::GLenum imageTypeGL,
78                                const TString &imageName)
79 {
80     ASSERT_EQ(1u, uniforms.size());
81 
82     const auto &imageUniform = uniforms[uniformIndex];
83     ASSERT_EQ(imageTypeGL, imageUniform.type);
84     ASSERT_STREQ(imageUniform.name.c_str(), imageName.c_str());
85 }
86 
87 // Checks whether the image is saved in the AST as a node with the correct properties given the
88 // shader.
CheckImageDeclaration(TIntermNode * astRoot,const ImmutableString & imageName,TBasicType imageType,TLayoutImageInternalFormat internalFormat,bool readonly,bool writeonly,bool coherent,bool restrictQualifier,bool volatileQualifier,int binding)89 void CheckImageDeclaration(TIntermNode *astRoot,
90                            const ImmutableString &imageName,
91                            TBasicType imageType,
92                            TLayoutImageInternalFormat internalFormat,
93                            bool readonly,
94                            bool writeonly,
95                            bool coherent,
96                            bool restrictQualifier,
97                            bool volatileQualifier,
98                            int binding)
99 {
100     const TIntermSymbol *myImageNode = FindSymbolNode(astRoot, imageName);
101     ASSERT_NE(nullptr, myImageNode);
102 
103     ASSERT_EQ(imageType, myImageNode->getBasicType());
104     const TType &myImageType                = myImageNode->getType();
105     TLayoutQualifier myImageLayoutQualifier = myImageType.getLayoutQualifier();
106     ASSERT_EQ(internalFormat, myImageLayoutQualifier.imageInternalFormat);
107     TMemoryQualifier myImageMemoryQualifier = myImageType.getMemoryQualifier();
108     ASSERT_EQ(readonly, myImageMemoryQualifier.readonly);
109     ASSERT_EQ(writeonly, myImageMemoryQualifier.writeonly);
110     ASSERT_EQ(coherent, myImageMemoryQualifier.coherent);
111     ASSERT_EQ(restrictQualifier, myImageMemoryQualifier.restrictQualifier);
112     ASSERT_EQ(volatileQualifier, myImageMemoryQualifier.volatileQualifier);
113     ASSERT_EQ(binding, myImageType.getLayoutQualifier().binding);
114 }
115 
116 }  // namespace
117 
118 class ShaderImageTest : public ShaderCompileTreeTest
119 {
120   public:
ShaderImageTest()121     ShaderImageTest() {}
122 
123   protected:
SetUp()124     void SetUp() override
125     {
126         ShaderCompileTreeTest::SetUp();
127         mExtraCompileOptions |= SH_VARIABLES;
128     }
129 
getShaderType() const130     ::GLenum getShaderType() const override { return GL_COMPUTE_SHADER; }
getShaderSpec() const131     ShShaderSpec getShaderSpec() const override { return SH_GLES3_1_SPEC; }
132 };
133 
134 // Test that an image2D is properly parsed and exported as a uniform.
TEST_F(ShaderImageTest,Image2DDeclaration)135 TEST_F(ShaderImageTest, Image2DDeclaration)
136 {
137     const std::string &shaderString =
138         "#version 310 es\n"
139         "layout(local_size_x = 4) in;\n"
140         "layout(rgba32f, binding = 1) uniform highp readonly image2D myImage;\n"
141         "void main() {\n"
142         "   ivec2 sz = imageSize(myImage);\n"
143         "}";
144     if (!compile(shaderString))
145     {
146         FAIL() << "Shader compilation failed" << mInfoLog;
147     }
148 
149     CheckExportedImageUniform(getUniforms(), 0, GL_IMAGE_2D, "myImage");
150     CheckImageDeclaration(mASTRoot, ImmutableString("myImage"), EbtImage2D, EiifRGBA32F, true,
151                           false, false, false, false, 1);
152 }
153 
154 // Test that an image3D is properly parsed and exported as a uniform.
TEST_F(ShaderImageTest,Image3DDeclaration)155 TEST_F(ShaderImageTest, Image3DDeclaration)
156 {
157     const std::string &shaderString =
158         "#version 310 es\n"
159         "layout(local_size_x = 4) in;\n"
160         "layout(rgba32ui, binding = 3) uniform highp writeonly readonly uimage3D myImage;\n"
161         "void main() {\n"
162         "   ivec3 sz = imageSize(myImage);\n"
163         "}";
164     if (!compile(shaderString))
165     {
166         FAIL() << "Shader compilation failed" << mInfoLog;
167     }
168 
169     CheckExportedImageUniform(getUniforms(), 0, GL_UNSIGNED_INT_IMAGE_3D, "myImage");
170     CheckImageDeclaration(mASTRoot, ImmutableString("myImage"), EbtUImage3D, EiifRGBA32UI, true,
171                           true, false, false, false, 3);
172 }
173 
174 // Check that imageLoad calls get correctly parsed.
TEST_F(ShaderImageTest,ImageLoad)175 TEST_F(ShaderImageTest, ImageLoad)
176 {
177     const std::string &shaderString =
178         "#version 310 es\n"
179         "layout(local_size_x = 4) in;\n"
180         "layout(rgba32f) uniform highp readonly image2D my2DImageInput;\n"
181         "layout(rgba32i) uniform highp readonly iimage3D my3DImageInput;\n"
182         "void main() {\n"
183         "   vec4 result = imageLoad(my2DImageInput, ivec2(gl_LocalInvocationID.xy));\n"
184         "   ivec4 result2 = imageLoad(my3DImageInput, ivec3(gl_LocalInvocationID.xyz));\n"
185         "}";
186     if (!compile(shaderString))
187     {
188         FAIL() << "Shader compilation failed" << mInfoLog;
189     }
190 
191     // imageLoad call with image2D passed
192     std::string mangledName2D = "imageLoad(";
193     mangledName2D += StaticType::GetBasic<EbtImage2D>()->getMangledName();
194     mangledName2D += StaticType::GetBasic<EbtInt, 2>()->getMangledName();
195     CheckImageLoadCall(mASTRoot, mangledName2D.c_str(), EbtImage2D, 2);
196 
197     // imageLoad call with image3D passed
198     std::string mangledName3D = "imageLoad(";
199     mangledName3D += StaticType::GetBasic<EbtIImage3D>()->getMangledName();
200     mangledName3D += StaticType::GetBasic<EbtInt, 3>()->getMangledName();
201     CheckImageLoadCall(mASTRoot, mangledName3D.c_str(), EbtIImage3D, 3);
202 }
203 
204 // Check that imageStore calls get correctly parsed.
TEST_F(ShaderImageTest,ImageStore)205 TEST_F(ShaderImageTest, ImageStore)
206 {
207     const std::string &shaderString =
208         "#version 310 es\n"
209         "layout(local_size_x = 4) in;\n"
210         "layout(rgba32f) uniform highp writeonly image2D my2DImageOutput;\n"
211         "layout(rgba32ui) uniform highp writeonly uimage2DArray my2DImageArrayOutput;\n"
212         "void main() {\n"
213         "   imageStore(my2DImageOutput, ivec2(gl_LocalInvocationID.xy), vec4(0.0));\n"
214         "   imageStore(my2DImageArrayOutput, ivec3(gl_LocalInvocationID.xyz), uvec4(0));\n"
215         "}";
216     if (!compile(shaderString))
217     {
218         FAIL() << "Shader compilation failed" << mInfoLog;
219     }
220 
221     // imageStore call with image2D
222     std::string mangledName2D = "imageStore(";
223     mangledName2D += StaticType::GetBasic<EbtImage2D>()->getMangledName();
224     mangledName2D += StaticType::GetBasic<EbtInt, 2>()->getMangledName();
225     mangledName2D += StaticType::GetBasic<EbtFloat, 4>()->getMangledName();
226     CheckImageStoreCall(mASTRoot, mangledName2D.c_str(), EbtImage2D, 2, EbtFloat, 4);
227 
228     // imageStore call with image2DArray
229     std::string mangledName2DArray = "imageStore(";
230     mangledName2DArray += StaticType::GetBasic<EbtUImage2DArray>()->getMangledName();
231     mangledName2DArray += StaticType::GetBasic<EbtInt, 3>()->getMangledName();
232     mangledName2DArray += StaticType::GetBasic<EbtUInt, 4>()->getMangledName();
233     CheckImageStoreCall(mASTRoot, mangledName2DArray.c_str(), EbtUImage2DArray, 3, EbtUInt, 4);
234 }
235 
236 // Check that memory qualifiers are correctly parsed.
TEST_F(ShaderImageTest,ImageMemoryQualifiers)237 TEST_F(ShaderImageTest, ImageMemoryQualifiers)
238 {
239     const std::string &shaderString =
240         "#version 310 es\n"
241         "layout(local_size_x = 4) in;"
242         "layout(rgba32f) uniform highp coherent readonly image2D image1;\n"
243         "layout(rgba32f) uniform highp volatile writeonly image2D image2;\n"
244         "layout(rgba32f) uniform highp volatile restrict readonly writeonly image2D image3;\n"
245         "void main() {\n"
246         "    imageSize(image1);\n"
247         "    imageSize(image2);\n"
248         "    imageSize(image3);\n"
249         "}";
250     if (!compile(shaderString))
251     {
252         FAIL() << "Shader compilation failed" << mInfoLog;
253     }
254 
255     CheckImageDeclaration(mASTRoot, ImmutableString("image1"), EbtImage2D, EiifRGBA32F, true, false,
256                           true, false, false, -1);
257     CheckImageDeclaration(mASTRoot, ImmutableString("image2"), EbtImage2D, EiifRGBA32F, false, true,
258                           true, false, true, -1);
259     CheckImageDeclaration(mASTRoot, ImmutableString("image3"), EbtImage2D, EiifRGBA32F, true, true,
260                           true, true, true, -1);
261 }
262