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