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