OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <GLES2/gl2.h> | |
6 #include <GLES2/gl2ext.h> | |
7 #include <GLES2/gl2extchromium.h> | |
8 #include <GLES3/gl3.h> | |
9 | |
10 #include "base/command_line.h" | |
11 #include "gpu/command_buffer/tests/gl_manager.h" | |
12 #include "gpu/command_buffer/tests/gl_test_utils.h" | |
13 #include "testing/gmock/include/gmock/gmock.h" | |
14 #include "testing/gtest/include/gtest/gtest.h" | |
15 #include "ui/gl/gl_switches.h" | |
16 | |
17 #define SHADER(Src) #Src | |
18 #define BFE_SHADER(Src) "#extension GL_EXT_blend_func_extended : require\n" #Src | |
19 | |
20 namespace { | |
21 // Partial implementation of weight function for GLES 2 blend equation that | |
22 // is dual-source aware. | |
23 template <int factor, int index> | |
24 float Weight(float dst[4], float src[4], float src1[4]) { | |
Zhenyao Mo
2015/08/31 21:12:31
What's the point of passing in dst? It's never use
Kimmo Kinnunen
2015/09/24 13:16:28
Just for clarity. The weight function of GL blend
| |
25 if (factor == GL_SRC_COLOR) | |
26 return src[index]; | |
27 if (factor == GL_SRC_ALPHA) | |
28 return src[3]; | |
29 if (factor == GL_SRC1_COLOR_EXT) | |
30 return src1[index]; | |
31 if (factor == GL_SRC1_ALPHA_EXT) | |
32 return src1[3]; | |
33 if (factor == GL_ONE_MINUS_SRC1_COLOR_EXT) | |
34 return 1.0f - src1[index]; | |
35 if (factor == GL_ONE_MINUS_SRC1_ALPHA_EXT) | |
36 return 1.0f - src1[3]; | |
37 return 0.0f; | |
38 } | |
39 | |
40 // Implementation of GLES 2 blend equation that is dual-source aware. | |
41 template <int RGBs, int RGBd, int As, int Ad> | |
42 void BlendEquationFuncAdd(float dst[4], | |
43 float src[4], | |
44 float src1[4], | |
45 uint8 result[4]) { | |
46 float r[4]; | |
47 r[0] = src[0] * Weight<RGBs, 0>(dst, src, src1) + | |
48 dst[0] * Weight<RGBd, 0>(dst, src, src1); | |
49 r[1] = src[1] * Weight<RGBs, 1>(dst, src, src1) + | |
50 dst[1] * Weight<RGBd, 1>(dst, src, src1); | |
51 r[2] = src[2] * Weight<RGBs, 2>(dst, src, src1) + | |
52 dst[2] * Weight<RGBd, 2>(dst, src, src1); | |
53 r[3] = src[3] * Weight<As, 3>(dst, src, src1) + | |
54 dst[3] * Weight<Ad, 3>(dst, src, src1); | |
55 for (int i = 0; i < 4; ++i) { | |
56 result[i] = static_cast<uint8>( | |
57 std::floor(std::max(0.0f, std::min(1.0f, r[i])) * 255.0f)); | |
58 } | |
59 } | |
60 } | |
61 | |
62 namespace gpu { | |
63 | |
64 class EXTBlendFuncExtendedTest : public testing::Test { | |
65 public: | |
66 protected: | |
67 void SetUp() override { gl_.Initialize(GLManager::Options()); } | |
68 | |
69 void TearDown() override { gl_.Destroy(); } | |
70 bool IsApplicable() const { | |
71 return GLTestHelper::HasExtension("GL_EXT_blend_func_extended"); | |
72 } | |
73 GLManager gl_; | |
74 }; | |
75 | |
76 TEST_F(EXTBlendFuncExtendedTest, TestMaxDualSourceDrawBuffers) { | |
77 if (!IsApplicable()) { | |
78 return; | |
79 } | |
80 | |
81 GLint maxDualSourceDrawBuffers = 0; | |
82 glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, &maxDualSourceDrawBuffers); | |
83 EXPECT_GT(maxDualSourceDrawBuffers, 0); | |
84 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | |
85 } | |
86 | |
87 class EXTBlendFuncExtendedDrawTest : public testing::Test { | |
88 public: | |
89 static const GLsizei kWidth = 100; | |
90 static const GLsizei kHeight = 100; | |
91 EXTBlendFuncExtendedDrawTest() : program_(0) {} | |
92 | |
93 protected: | |
94 void SetUp() override { | |
95 GLManager::Options options; | |
96 options.size = gfx::Size(kWidth, kHeight); | |
97 gl_.Initialize(options); | |
98 } | |
99 | |
100 bool IsApplicable() const { | |
101 return GLTestHelper::HasExtension("GL_EXT_blend_func_extended"); | |
102 } | |
103 | |
104 virtual const char* GetVertexShader() { | |
105 static const char* kVertexShader = SHADER( | |
106 attribute vec4 position; void main() { gl_Position = position; }); | |
107 return kVertexShader; | |
108 } | |
109 | |
110 void CreateProgramWithFragmentShader(const char* fragment_shader_str) { | |
111 GLuint vertex_shader = | |
112 GLTestHelper::LoadShader(GL_VERTEX_SHADER, GetVertexShader()); | |
113 GLuint fragment_shader = | |
114 GLTestHelper::LoadShader(GL_FRAGMENT_SHADER, fragment_shader_str); | |
115 ASSERT_NE(0u, vertex_shader); | |
116 ASSERT_NE(0u, fragment_shader); | |
117 program_ = glCreateProgram(); | |
118 ASSERT_NE(0u, program_); | |
119 glAttachShader(program_, vertex_shader); | |
120 glAttachShader(program_, fragment_shader); | |
121 glDeleteShader(vertex_shader); | |
122 glDeleteShader(fragment_shader); | |
123 } | |
124 | |
125 void LinkProgram() { | |
126 glLinkProgram(program_); | |
127 GLint linked = 0; | |
128 glGetProgramiv(program_, GL_LINK_STATUS, &linked); | |
129 if (linked == 0) { | |
130 char buffer[1024]; | |
131 GLsizei length = 0; | |
132 glGetProgramInfoLog(program_, sizeof(buffer), &length, buffer); | |
133 std::string log(buffer, length); | |
134 EXPECT_EQ(1, linked) << "Error linking program: " << log; | |
135 glDeleteProgram(program_); | |
136 program_ = 0; | |
137 } | |
138 glUseProgram(program_); | |
139 position_loc_ = glGetAttribLocation(program_, "position"); | |
140 src_loc_ = glGetUniformLocation(program_, "src"); | |
141 src1_loc_ = glGetUniformLocation(program_, "src1"); | |
142 } | |
143 | |
144 void TearDown() override { | |
145 if (program_ != 0) { | |
146 glDeleteProgram(program_); | |
147 } | |
148 gl_.Destroy(); | |
149 } | |
150 | |
151 void DrawAndVerify() { | |
152 float kDst[4] = {0.5f, 0.5f, 0.5f, 0.5f}; | |
153 float kSrc[4] = {1.0f, 1.0f, 1.0f, 1.0f}; | |
154 float kSrc1[4] = {0.3f, 0.6f, 0.9f, 0.7f}; | |
155 | |
156 glUniform4f(src_loc_, kSrc[0], kSrc[1], kSrc[2], kSrc[3]); | |
157 glUniform4f(src1_loc_, kSrc1[0], kSrc1[1], kSrc1[2], kSrc1[3]); | |
158 | |
159 GLTestHelper::SetupUnitQuad(position_loc_); | |
160 | |
161 glEnable(GL_BLEND); | |
162 glBlendEquation(GL_FUNC_ADD); | |
163 glBlendFuncSeparate(GL_SRC1_COLOR_EXT, GL_SRC_ALPHA, | |
164 GL_ONE_MINUS_SRC1_COLOR_EXT, | |
165 GL_ONE_MINUS_SRC1_ALPHA_EXT); | |
166 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | |
167 | |
168 // Draw one triangle (bottom left half). | |
169 glViewport(0, 0, kWidth, kHeight); | |
170 glClearColor(kDst[0], kDst[1], kDst[2], kDst[3]); | |
171 glClear(GL_COLOR_BUFFER_BIT); | |
172 glDrawArrays(GL_TRIANGLES, 0, 6); | |
173 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | |
174 | |
175 // Verify. | |
176 uint8 color[4]; | |
177 BlendEquationFuncAdd<GL_SRC1_COLOR_EXT, GL_SRC_ALPHA, | |
178 GL_ONE_MINUS_SRC1_COLOR_EXT, | |
179 GL_ONE_MINUS_SRC1_ALPHA_EXT>(kDst, kSrc, kSrc1, color); | |
180 | |
181 EXPECT_TRUE(GLTestHelper::CheckPixels(kWidth / 4, (3 * kHeight) / 4, 1, 1, | |
182 1, color)); | |
183 EXPECT_TRUE(GLTestHelper::CheckPixels(kWidth - 1, 0, 1, 1, 1, color)); | |
184 } | |
185 | |
186 protected: | |
187 GLuint program_; | |
188 GLuint position_loc_; | |
189 GLuint src_loc_; | |
190 GLuint src1_loc_; | |
191 GLManager gl_; | |
192 }; | |
193 | |
194 TEST_F(EXTBlendFuncExtendedDrawTest, ESSL1FragColor) { | |
195 if (!IsApplicable()) { | |
196 return; | |
197 } | |
198 // clang-format off | |
199 static const char* kFragColorShader = | |
200 BFE_SHADER( | |
201 precision mediump float; | |
202 uniform vec4 src; | |
203 uniform vec4 src1; | |
204 void main() { | |
205 gl_FragColor = src; | |
206 gl_SecondaryFragColorEXT = src1; | |
207 }); | |
208 // clang-format on | |
209 CreateProgramWithFragmentShader(kFragColorShader); | |
210 LinkProgram(); | |
211 DrawAndVerify(); | |
212 } | |
213 | |
214 TEST_F(EXTBlendFuncExtendedDrawTest, ESSL1FragData) { | |
215 if (!IsApplicable()) { | |
216 return; | |
217 } | |
218 // clang-format off | |
219 static const char* kFragDataShader = | |
220 BFE_SHADER( | |
221 precision mediump float; | |
222 uniform vec4 src; | |
223 uniform vec4 src1; | |
224 void main() { | |
225 gl_FragData[0] = src; | |
226 gl_SecondaryFragDataEXT[0] = src1; | |
227 }); | |
228 // clang-format on | |
229 CreateProgramWithFragmentShader(kFragDataShader); | |
230 LinkProgram(); | |
231 DrawAndVerify(); | |
232 } | |
233 | |
234 class EXTBlendFuncExtendedES3DrawTest : public EXTBlendFuncExtendedDrawTest { | |
235 protected: | |
236 void SetUp() override { | |
237 GLManager::Options options; | |
238 options.context_type = gles2::CONTEXT_TYPE_OPENGLES3; | |
239 options.size = gfx::Size(kWidth, kHeight); | |
240 base::CommandLine command_line(*base::CommandLine::ForCurrentProcess()); | |
241 command_line.AppendSwitch(switches::kEnableUnsafeES3APIs); | |
242 gl_.InitializeWithCommandLine(options, &command_line); | |
243 } | |
244 bool IsApplicable() const { | |
245 return gl_.IsInitialized() && EXTBlendFuncExtendedDrawTest::IsApplicable(); | |
246 } | |
247 const char* GetVertexShader() override { | |
248 // clang-format off | |
249 static const char* kVertexShader = | |
250 "#version 300 es\n" | |
251 SHADER( | |
252 in vec4 position; | |
253 void main() { | |
254 gl_Position = position; | |
255 }); | |
256 // clang-format on | |
257 return kVertexShader; | |
258 } | |
259 }; | |
260 | |
261 TEST_F(EXTBlendFuncExtendedES3DrawTest, ESSL3Var) { | |
262 if (!IsApplicable()) { | |
263 return; | |
264 } | |
265 // clang-format off | |
266 static const char* kFragColorShader = | |
267 "#version 300 es\n" | |
268 BFE_SHADER( | |
269 precision mediump float; | |
270 uniform vec4 src; | |
271 uniform vec4 src1; | |
272 out vec4 FragColor; | |
273 out vec4 SecondaryFragColor; | |
274 void main() { | |
275 FragColor = src; | |
276 SecondaryFragColor = src1; | |
277 }); | |
278 // clang-format on | |
279 CreateProgramWithFragmentShader(kFragColorShader); | |
280 glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragColor"); | |
281 LinkProgram(); | |
282 DrawAndVerify(); | |
283 } | |
284 | |
285 TEST_F(EXTBlendFuncExtendedES3DrawTest, ESSL3Array) { | |
286 if (!IsApplicable()) { | |
287 return; | |
288 } | |
289 // clang-format off | |
290 static const char* kFragDataShader = | |
291 "#version 300 es\n" | |
292 BFE_SHADER( | |
293 precision mediump float; | |
294 uniform vec4 src; | |
295 uniform vec4 src1; | |
296 out vec4 FragData[1]; | |
297 out vec4 SecondaryFragData[1]; | |
298 void main() { | |
299 FragData[0] = src; | |
300 SecondaryFragData[0] = src1; | |
301 }); | |
302 // clang-format on | |
303 CreateProgramWithFragmentShader(kFragDataShader); | |
304 glBindFragDataLocationEXT(program_, 0, "FragData"); | |
305 glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragData"); | |
306 LinkProgram(); | |
307 DrawAndVerify(); | |
308 } | |
309 | |
310 TEST_F(EXTBlendFuncExtendedES3DrawTest, ES3Getters) { | |
311 if (!IsApplicable()) { | |
312 return; | |
313 } | |
314 // clang-format off | |
315 static const char* kFragColorShader = | |
316 "#version 300 es\n" | |
317 BFE_SHADER( | |
318 precision mediump float; | |
319 uniform vec4 src; | |
320 uniform vec4 src1; | |
321 out vec4 FragColor; | |
322 out vec4 SecondaryFragColor; | |
323 void main() { | |
324 FragColor = src; | |
325 SecondaryFragColor = src1; | |
326 }); | |
327 // clang-format on | |
328 CreateProgramWithFragmentShader(kFragColorShader); | |
329 glBindFragDataLocationEXT(program_, 0, "FragColor"); | |
330 glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragColor"); | |
331 | |
332 // Getters return GL error before linking. | |
333 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | |
334 GLint location = glGetFragDataLocation(program_, "FragColor"); | |
335 EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); | |
336 GLint index = glGetFragDataIndexEXT(program_, "FragColor"); | |
337 EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); | |
338 location = glGetFragDataLocation(program_, "SecondaryFragColor"); | |
339 EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); | |
340 index = glGetFragDataIndexEXT(program_, "SecondaryFragColor"); | |
341 EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); | |
342 LinkProgram(); | |
343 | |
344 // Getters return location and index after linking. | |
345 for (int i = 0; i < 2; ++i) { | |
Zhenyao Mo
2015/08/31 21:12:31
Why run it twice?
Kimmo Kinnunen
2015/09/24 13:16:28
To confirm the setters do not affect the getters u
| |
346 location = glGetFragDataLocation(program_, "FragColor"); | |
347 EXPECT_EQ(0, location); | |
348 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | |
349 index = glGetFragDataIndexEXT(program_, "FragColor"); | |
350 EXPECT_EQ(0, index); | |
351 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | |
352 location = glGetFragDataLocation(program_, "SecondaryFragColor"); | |
353 EXPECT_EQ(0, location); | |
354 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | |
355 index = glGetFragDataIndexEXT(program_, "SecondaryFragColor"); | |
356 EXPECT_EQ(1, index); | |
357 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | |
358 | |
359 // The calls should not affect the getters until re-linking. | |
360 glBindFragDataLocationEXT(program_, 0, "SecondaryFragColor"); | |
361 glBindFragDataLocationIndexedEXT(program_, 0, 1, "FragColor"); | |
362 } | |
363 | |
364 LinkProgram(); | |
365 | |
366 location = glGetFragDataLocation(program_, "FragColor"); | |
367 EXPECT_EQ(0, location); | |
368 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | |
369 index = glGetFragDataIndexEXT(program_, "FragColor"); | |
370 EXPECT_EQ(1, index); | |
371 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | |
372 location = glGetFragDataLocation(program_, "SecondaryFragColor"); | |
373 EXPECT_EQ(0, location); | |
374 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | |
375 index = glGetFragDataIndexEXT(program_, "SecondaryFragColor"); | |
376 EXPECT_EQ(0, index); | |
377 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | |
378 | |
379 // Unknown colors return location -1, index -1. | |
380 location = glGetFragDataLocation(program_, "UnknownColor"); | |
381 EXPECT_EQ(-1, location); | |
382 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | |
383 index = glGetFragDataIndexEXT(program_, "UnknownColor"); | |
384 EXPECT_EQ(-1, index); | |
385 | |
386 // Reset the settings and verify that the driver gets them correct. | |
387 glBindFragDataLocationEXT(program_, 0, "FragColor"); | |
388 glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragColor"); | |
389 LinkProgram(); | |
390 DrawAndVerify(); | |
391 } | |
392 | |
393 } // namespace gpu | |
OLD | NEW |