• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "GLSnapshotTesting.h"
16 
17 #include <gtest/gtest.h>
18 
19 #include <string>
20 
21 namespace gfxstream {
22 namespace gl {
23 namespace {
24 
25 static const char kTestVertexShaderSource[] = R"(
26 attribute vec4 position;
27 uniform mat4 projection;
28 uniform mat4 transform;
29 uniform mat4 screenSpace;
30 varying float linear;
31 void main(void) {
32     vec4 transformedPosition = projection * transform * position;
33     gl_Position = transformedPosition;
34     linear = (screenSpace * position).x;
35 }
36 )";
37 
38 static const char kTestFragmentShaderSource[] = R"(
39 precision mediump float;
40 void main() {
41     gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
42 }
43 )";
44 
45 struct GlShaderState {
46     GLenum type;
47     GLboolean deleteStatus;
48     GLboolean compileStatus;
49     GLint infoLogLength;
50     std::vector<GLchar> infoLog;
51     GLint sourceLength;
52     std::string source;
53 };
54 
55 // SnapshotGlShaderTest - A helper class for testing snapshot's preservation of
56 // a GL shader object's states.
57 //
58 // It operates like SnapshotPreserveTest, and also holds information about a
59 // particular shader object which is manipulated in tests using
60 // SnapshotGlShaderTest as a fixture.
61 // Helper functions like loadSource first need a created shader identified by
62 // |m_shader_name|. This creation happens by default in stateChange. Use them in
63 // a lambda, set through setShaderStateChanger, to set up state without
64 // overriding doCheckedSnapshot.
65 //
66 class SnapshotGlShaderTest : public SnapshotPreserveTest {
67 public:
defaultStateCheck()68     void defaultStateCheck() override {
69         EXPECT_EQ(GL_FALSE, gl->glIsShader(m_shader_name));
70     }
71 
changedStateCheck()72     void changedStateCheck() override {
73         SCOPED_TRACE("for shader " + std::to_string(m_shader_name));
74 
75         EXPECT_TRUE(compareParameter(GL_SHADER_TYPE, m_shader_state.type));
76         EXPECT_TRUE(compareParameter(GL_DELETE_STATUS,
77                                      m_shader_state.deleteStatus));
78         EXPECT_TRUE(compareParameter(GL_COMPILE_STATUS,
79                                      m_shader_state.compileStatus));
80         EXPECT_TRUE(compareParameter(GL_INFO_LOG_LENGTH,
81                                      m_shader_state.infoLogLength));
82         EXPECT_TRUE(compareParameter(GL_SHADER_SOURCE_LENGTH,
83                                      m_shader_state.sourceLength));
84 
85         std::vector<GLchar> srcData = {};
86         srcData.resize(m_shader_state.sourceLength);
87         gl->glGetShaderSource(m_shader_name, m_shader_state.sourceLength,
88                               nullptr, srcData.data());
89         if (srcData.data() == NULL) {
90             EXPECT_EQ(0, m_shader_state.source.length()) << "source is empty";
91         } else {
92             EXPECT_STREQ(m_shader_state.source.c_str(), srcData.data());
93         }
94 
95         std::vector<GLchar> infoLogData = {};
96         infoLogData.resize(m_shader_state.infoLogLength);
97         gl->glGetShaderInfoLog(m_shader_name, m_shader_state.infoLogLength,
98                                nullptr, infoLogData.data());
99         if (infoLogData.data() == NULL) {
100             EXPECT_EQ(0, m_shader_state.infoLogLength) << "info log is empty";
101         } else {
102             EXPECT_STREQ(m_shader_state.infoLog.data(), infoLogData.data());
103         }
104     }
105 
stateChange()106     void stateChange() override {
107         m_shader_name = gl->glCreateShader(m_shader_state.type);
108         m_shader_state_changer();
109 
110         // Store state of info log
111         gl->glGetShaderiv(m_shader_name, GL_INFO_LOG_LENGTH,
112                           &m_shader_state.infoLogLength);
113         m_shader_state.infoLog.resize(m_shader_state.infoLogLength);
114         gl->glGetShaderInfoLog(m_shader_name, m_shader_state.infoLogLength,
115                                nullptr, m_shader_state.infoLog.data());
116     }
117 
loadSource(const std::string & sourceString)118     void loadSource(const std::string& sourceString) {
119         GLboolean compiler;
120         gl->glGetBooleanv(GL_SHADER_COMPILER, &compiler);
121         EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
122         if (compiler == GL_FALSE) {
123             fprintf(stderr, "Shader compiler is not supported.\n");
124             return;
125         }
126 
127         if (m_shader_name == 0) {
128             FAIL() << "Cannot set source without a shader name";
129         }
130         m_shader_state.source = sourceString;
131         GLint len = sourceString.length();
132         if (len > 0) {
133             m_shader_state.sourceLength =
134                     len + 1;  // Counts the null terminator
135         }
136         const char* source = sourceString.c_str();
137         const char** sources = &source;
138         gl->glShaderSource(m_shader_name, 1, sources, &len);
139         EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
140     }
141 
compile(GLboolean expectCompileStatus=GL_TRUE)142     void compile(GLboolean expectCompileStatus = GL_TRUE) {
143         GLboolean compiler;
144         gl->glGetBooleanv(GL_SHADER_COMPILER, &compiler);
145         if (compiler == GL_FALSE) {
146             fprintf(stderr, "Shader compiler is not supported.\n");
147             return;
148         }
149 
150         if (m_shader_name == 0) {
151             ADD_FAILURE() << "Cannot compile shader without a shader name";
152         }
153         if (m_shader_state.source.length() == 0) {
154             ADD_FAILURE() << "Shader needs source to compile";
155         }
156         gl->glCompileShader(m_shader_name);
157         m_shader_state.compileStatus = expectCompileStatus;
158     }
159 
160     // Supply a lambda as |changer| to perform additional state setup after the
161     // shader has been created but before the snapshot is performed.
setShaderStateChanger(std::function<void ()> changer)162     void setShaderStateChanger(std::function<void()> changer) {
163         m_shader_state_changer = changer;
164     }
165 
166 protected:
compareParameter(GLenum paramName,GLenum expected)167     testing::AssertionResult compareParameter(GLenum paramName,
168                                               GLenum expected) {
169         GLint value;
170         gl->glGetShaderiv(m_shader_name, paramName, &value);
171         EXPECT_EQ(GL_NO_ERROR, gl->glGetError());
172         return compareValue<GLint>(
173                 expected, value,
174                 "mismatch on parameter " + describeGlEnum(paramName) +
175                         " for shader " + std::to_string(m_shader_name));
176     }
177 
178     GlShaderState m_shader_state = {};
179     GLuint m_shader_name;
__anon71e431590202null180     std::function<void()> m_shader_state_changer = [] {};
181 };
182 
183 class SnapshotGlVertexShaderTest : public SnapshotGlShaderTest {
184 public:
SnapshotGlVertexShaderTest()185     SnapshotGlVertexShaderTest() { m_shader_state = {GL_VERTEX_SHADER}; }
186 };
187 
TEST_F(SnapshotGlVertexShaderTest,Create)188 TEST_F(SnapshotGlVertexShaderTest, Create) {
189     doCheckedSnapshot();
190 }
191 
TEST_F(SnapshotGlVertexShaderTest,SetSource)192 TEST_F(SnapshotGlVertexShaderTest, SetSource) {
193     setShaderStateChanger(
194             [this] { loadSource(std::string(kTestVertexShaderSource)); });
195     doCheckedSnapshot();
196 }
197 
TEST_F(SnapshotGlVertexShaderTest,CompileSuccess)198 TEST_F(SnapshotGlVertexShaderTest, CompileSuccess) {
199     setShaderStateChanger([this] {
200         loadSource(std::string(kTestVertexShaderSource));
201         compile();
202     });
203     doCheckedSnapshot();
204 }
205 
TEST_F(SnapshotGlVertexShaderTest,CompileFail)206 TEST_F(SnapshotGlVertexShaderTest, CompileFail) {
207     std::string failedShader = "vec3 hi my name is compile failed";
208     setShaderStateChanger([this, &failedShader] {
209         loadSource(failedShader);
210         compile(GL_FALSE);
211     });
212     doCheckedSnapshot();
213 }
214 
215 class SnapshotGlFragmentShaderTest : public SnapshotGlShaderTest {
216 public:
SnapshotGlFragmentShaderTest()217     SnapshotGlFragmentShaderTest() { m_shader_state = {GL_FRAGMENT_SHADER}; }
218 };
219 
TEST_F(SnapshotGlFragmentShaderTest,Create)220 TEST_F(SnapshotGlFragmentShaderTest, Create) {
221     doCheckedSnapshot();
222 }
223 
TEST_F(SnapshotGlFragmentShaderTest,SetSource)224 TEST_F(SnapshotGlFragmentShaderTest, SetSource) {
225     setShaderStateChanger(
226             [this] { loadSource(std::string(kTestFragmentShaderSource)); });
227     doCheckedSnapshot();
228 }
229 
TEST_F(SnapshotGlFragmentShaderTest,CompileSuccess)230 TEST_F(SnapshotGlFragmentShaderTest, CompileSuccess) {
231     setShaderStateChanger([this] {
232         loadSource(std::string(kTestFragmentShaderSource));
233         compile();
234     });
235     doCheckedSnapshot();
236 }
237 
TEST_F(SnapshotGlFragmentShaderTest,CompileFail)238 TEST_F(SnapshotGlFragmentShaderTest, CompileFail) {
239     std::string failedShader = "vec3 nice to meet you compile failed";
240     setShaderStateChanger([this, &failedShader] {
241         loadSource(failedShader);
242         compile(GL_FALSE);
243     });
244     doCheckedSnapshot();
245 }
246 
247 }  // namespace
248 }  // namespace gl
249 }  // namespace gfxstream
250