1 // Copyright (c) 2012 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 "ui/gl/gl_gl_api_implementation.h"
6
7 #include <vector>
8
9 #include "base/stl_util.h"
10 #include "base/strings/string_split.h"
11 #include "base/strings/string_util.h"
12 #include "ui/gl/gl_context.h"
13 #include "ui/gl/gl_implementation.h"
14 #include "ui/gl/gl_state_restorer.h"
15 #include "ui/gl/gl_surface.h"
16 #include "ui/gl/gl_switches.h"
17 #include "ui/gl/gl_version_info.h"
18 #include "ui/gl/shader_tracking.h"
19
20 namespace gl {
21
22 // The GL state for when no context is bound
23 static CurrentGL* g_no_context_current_gl = nullptr;
24
25 // If the null draw bindings are currently enabled.
26 // TODO: Consider adding a new GLApi that no-ops these functions
27 static bool g_null_draw_bindings_enabled = false;
28
29 namespace {
30
31 // TODO(epenner): Could the above function be merged into GetInternalFormat and
32 // removed?
GetTexInternalFormat(const GLVersionInfo * version,GLenum internal_format,GLenum format,GLenum type)33 static inline GLenum GetTexInternalFormat(const GLVersionInfo* version,
34 GLenum internal_format,
35 GLenum format,
36 GLenum type) {
37 GLenum gl_internal_format = GetInternalFormat(version, internal_format);
38
39 // g_version_info must be initialized when this function is bound.
40 if (version->is_es3) {
41 if (internal_format == GL_RED_EXT) {
42 // GL_EXT_texture_rg case in ES2.
43 switch (type) {
44 case GL_UNSIGNED_BYTE:
45 gl_internal_format = GL_R8_EXT;
46 break;
47 case GL_UNSIGNED_SHORT:
48 gl_internal_format = GL_R16_EXT;
49 break;
50 case GL_HALF_FLOAT_OES:
51 gl_internal_format = GL_R16F_EXT;
52 break;
53 case GL_FLOAT:
54 gl_internal_format = GL_R32F_EXT;
55 break;
56 default:
57 NOTREACHED();
58 break;
59 }
60 return gl_internal_format;
61 } else if (internal_format == GL_RG_EXT) {
62 // GL_EXT_texture_rg case in ES2.
63 switch (type) {
64 case GL_UNSIGNED_BYTE:
65 gl_internal_format = GL_RG8_EXT;
66 break;
67 case GL_HALF_FLOAT_OES:
68 gl_internal_format = GL_RG16F_EXT;
69 break;
70 case GL_FLOAT:
71 gl_internal_format = GL_RG32F_EXT;
72 break;
73 default:
74 NOTREACHED();
75 break;
76 }
77 return gl_internal_format;
78 }
79 }
80
81 if (version->IsAtLeastGL(2, 1) || version->IsAtLeastGLES(3, 0)) {
82 switch (internal_format) {
83 case GL_SRGB_EXT:
84 gl_internal_format = GL_SRGB8;
85 break;
86 case GL_SRGB_ALPHA_EXT:
87 gl_internal_format = GL_SRGB8_ALPHA8;
88 break;
89 default:
90 break;
91 }
92 }
93
94 if (version->is_es2)
95 return gl_internal_format;
96
97 // For ES3, use sized float/half_float internal formats whenever posssible.
98 if (type == GL_FLOAT) {
99 switch (internal_format) {
100 // We need to map all the unsized internal formats from ES2 clients.
101 case GL_RGBA:
102 gl_internal_format = GL_RGBA32F;
103 break;
104 case GL_RGB:
105 gl_internal_format = GL_RGB32F;
106 break;
107 case GL_LUMINANCE_ALPHA:
108 if (!version->is_es)
109 gl_internal_format = GL_LUMINANCE_ALPHA32F_ARB;
110 break;
111 case GL_LUMINANCE:
112 if (!version->is_es)
113 gl_internal_format = GL_LUMINANCE32F_ARB;
114 break;
115 case GL_ALPHA:
116 if (!version->is_es)
117 gl_internal_format = GL_ALPHA32F_ARB;
118 break;
119 default:
120 // We can't assert here because if the client context is ES3,
121 // all sized internal_format will reach here.
122 break;
123 }
124 } else if (type == GL_HALF_FLOAT_OES) {
125 switch (internal_format) {
126 case GL_RGBA:
127 gl_internal_format = GL_RGBA16F;
128 break;
129 case GL_RGB:
130 gl_internal_format = GL_RGB16F;
131 break;
132 case GL_LUMINANCE_ALPHA:
133 if (!version->is_es)
134 gl_internal_format = GL_LUMINANCE_ALPHA16F_ARB;
135 break;
136 case GL_LUMINANCE:
137 if (!version->is_es)
138 gl_internal_format = GL_LUMINANCE16F_ARB;
139 break;
140 case GL_ALPHA:
141 if (!version->is_es)
142 gl_internal_format = GL_ALPHA16F_ARB;
143 break;
144 default:
145 break;
146 }
147 }
148
149 return gl_internal_format;
150 }
151
GetTexFormat(const GLVersionInfo * version,GLenum format)152 static inline GLenum GetTexFormat(const GLVersionInfo* version, GLenum format) {
153 GLenum gl_format = format;
154
155 if (version->IsAtLeastGL(2, 1) || version->IsAtLeastGLES(3, 0)) {
156 switch (format) {
157 case GL_SRGB_EXT:
158 gl_format = GL_RGB;
159 break;
160 case GL_SRGB_ALPHA_EXT:
161 gl_format = GL_RGBA;
162 break;
163 default:
164 break;
165 }
166 }
167
168 return gl_format;
169 }
170
GetPixelType(const GLVersionInfo * version,GLenum type,GLenum format)171 static inline GLenum GetPixelType(const GLVersionInfo* version,
172 GLenum type,
173 GLenum format) {
174 if (!version->is_es2) {
175 if (type == GL_HALF_FLOAT_OES) {
176 if (version->is_es) {
177 // For ES3+, use HALF_FLOAT instead of HALF_FLOAT_OES whenever possible.
178 switch (format) {
179 case GL_LUMINANCE:
180 case GL_LUMINANCE_ALPHA:
181 case GL_ALPHA:
182 return type;
183 default:
184 break;
185 }
186 }
187 return GL_HALF_FLOAT;
188 }
189 }
190 return type;
191 }
192
193 } // anonymous namespace
194
GetInternalFormat(const GLVersionInfo * version,GLenum internal_format)195 GLenum GetInternalFormat(const GLVersionInfo* version, GLenum internal_format) {
196 if (!version->is_es) {
197 if (internal_format == GL_BGRA_EXT || internal_format == GL_BGRA8_EXT)
198 return GL_RGBA8;
199 }
200 if (version->is_es3 && version->is_mesa) {
201 // Mesa bug workaround: Mipmapping does not work when using GL_BGRA_EXT
202 if (internal_format == GL_BGRA_EXT)
203 return GL_RGBA;
204 }
205 return internal_format;
206 }
207
InitializeStaticGLBindingsGL()208 void InitializeStaticGLBindingsGL() {
209 g_current_gl_context_tls = new base::ThreadLocalPointer<CurrentGL>;
210 g_no_context_current_gl = new CurrentGL;
211 g_no_context_current_gl->Api = new NoContextGLApi;
212 }
213
ClearBindingsGL()214 void ClearBindingsGL() {
215 if (g_no_context_current_gl) {
216 delete g_no_context_current_gl->Api;
217 delete g_no_context_current_gl->Driver;
218 delete g_no_context_current_gl->Version;
219 delete g_no_context_current_gl;
220 g_no_context_current_gl = nullptr;
221 }
222
223 if (g_current_gl_context_tls) {
224 delete g_current_gl_context_tls;
225 g_current_gl_context_tls = nullptr;
226 }
227 }
228
SetNullDrawGLBindingsEnabled(bool enabled)229 bool SetNullDrawGLBindingsEnabled(bool enabled) {
230 bool old_value = g_null_draw_bindings_enabled;
231 g_null_draw_bindings_enabled = enabled;
232 return old_value;
233 }
234
GetNullDrawBindingsEnabled()235 bool GetNullDrawBindingsEnabled() {
236 return g_null_draw_bindings_enabled;
237 }
238
SetCurrentGL(CurrentGL * current)239 void SetCurrentGL(CurrentGL* current) {
240 CurrentGL* new_current = current ? current : g_no_context_current_gl;
241 g_current_gl_context_tls->Set(new_current);
242 }
243
GLApi()244 GLApi::GLApi() {
245 }
246
~GLApi()247 GLApi::~GLApi() {
248 }
249
GLApiBase()250 GLApiBase::GLApiBase() : driver_(nullptr) {}
251
~GLApiBase()252 GLApiBase::~GLApiBase() {
253 }
254
InitializeBase(DriverGL * driver)255 void GLApiBase::InitializeBase(DriverGL* driver) {
256 driver_ = driver;
257 }
258
RealGLApi()259 RealGLApi::RealGLApi() {
260 }
261
~RealGLApi()262 RealGLApi::~RealGLApi() {
263 }
264
Initialize(DriverGL * driver)265 void RealGLApi::Initialize(DriverGL* driver) {
266 InitializeBase(driver);
267 }
268
glGetIntegervFn(GLenum pname,GLint * params)269 void RealGLApi::glGetIntegervFn(GLenum pname, GLint* params) {
270 if (pname == GL_NUM_EXTENSIONS && disabled_exts_.size()) {
271 InitializeFilteredExtensionsIfNeeded();
272 *params = static_cast<GLint>(filtered_exts_.size());
273 } else {
274 GLApiBase::glGetIntegervFn(pname, params);
275 }
276 }
277
glGetStringFn(GLenum name)278 const GLubyte* RealGLApi::glGetStringFn(GLenum name) {
279 if (name == GL_EXTENSIONS && disabled_exts_.size()) {
280 InitializeFilteredExtensionsIfNeeded();
281 return reinterpret_cast<const GLubyte*>(filtered_exts_str_.c_str());
282 }
283 return GLApiBase::glGetStringFn(name);
284 }
285
glGetStringiFn(GLenum name,GLuint index)286 const GLubyte* RealGLApi::glGetStringiFn(GLenum name, GLuint index) {
287 if (name == GL_EXTENSIONS && disabled_exts_.size()) {
288 InitializeFilteredExtensionsIfNeeded();
289 if (index >= filtered_exts_.size()) {
290 return nullptr;
291 }
292 return reinterpret_cast<const GLubyte*>(filtered_exts_[index].c_str());
293 }
294 return GLApiBase::glGetStringiFn(name, index);
295 }
296
glTexImage2DFn(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const void * pixels)297 void RealGLApi::glTexImage2DFn(GLenum target,
298 GLint level,
299 GLint internalformat,
300 GLsizei width,
301 GLsizei height,
302 GLint border,
303 GLenum format,
304 GLenum type,
305 const void* pixels) {
306 GLenum gl_internal_format =
307 GetTexInternalFormat(version_.get(), internalformat, format, type);
308 GLenum gl_format = GetTexFormat(version_.get(), format);
309 GLenum gl_type = GetPixelType(version_.get(), type, format);
310
311 // TODO(yizhou): Check if cubemap, 3d texture or texture2d array has the same
312 // bug on intel mac.
313 if (!version_->is_angle && gl_workarounds_.reset_teximage2d_base_level &&
314 target == GL_TEXTURE_2D) {
315 GLint base_level = 0;
316 GLApiBase::glGetTexParameterivFn(target, GL_TEXTURE_BASE_LEVEL,
317 &base_level);
318 if (base_level) {
319 GLApiBase::glTexParameteriFn(target, GL_TEXTURE_BASE_LEVEL, 0);
320 GLApiBase::glTexImage2DFn(target, level, gl_internal_format, width,
321 height, border, gl_format, gl_type, pixels);
322 GLApiBase::glTexParameteriFn(target, GL_TEXTURE_BASE_LEVEL, base_level);
323 return;
324 }
325 }
326 GLApiBase::glTexImage2DFn(target, level, gl_internal_format, width, height,
327 border, gl_format, gl_type, pixels);
328 }
329
glTexSubImage2DFn(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const void * pixels)330 void RealGLApi::glTexSubImage2DFn(GLenum target,
331 GLint level,
332 GLint xoffset,
333 GLint yoffset,
334 GLsizei width,
335 GLsizei height,
336 GLenum format,
337 GLenum type,
338 const void* pixels) {
339 GLenum gl_format = GetTexFormat(version_.get(), format);
340 GLenum gl_type = GetPixelType(version_.get(), type, format);
341 GLApiBase::glTexSubImage2DFn(target, level, xoffset, yoffset, width, height,
342 gl_format, gl_type, pixels);
343 }
344
glTexStorage2DEXTFn(GLenum target,GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height)345 void RealGLApi::glTexStorage2DEXTFn(GLenum target,
346 GLsizei levels,
347 GLenum internalformat,
348 GLsizei width,
349 GLsizei height) {
350 GLenum gl_internal_format = GetInternalFormat(version_.get(), internalformat);
351 GLApiBase::glTexStorage2DEXTFn(target, levels, gl_internal_format, width,
352 height);
353 }
354
glTexStorageMem2DEXTFn(GLenum target,GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height,GLuint memory,GLuint64 offset)355 void RealGLApi::glTexStorageMem2DEXTFn(GLenum target,
356 GLsizei levels,
357 GLenum internalformat,
358 GLsizei width,
359 GLsizei height,
360 GLuint memory,
361 GLuint64 offset) {
362 internalformat = GetInternalFormat(version_.get(), internalformat);
363 GLApiBase::glTexStorageMem2DEXTFn(target, levels, internalformat, width,
364 height, memory, offset);
365 }
366
glTexStorageMemFlags2DANGLEFn(GLenum target,GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height,GLuint memory,GLuint64 offset,GLbitfield createFlags,GLbitfield usageFlags)367 void RealGLApi::glTexStorageMemFlags2DANGLEFn(GLenum target,
368 GLsizei levels,
369 GLenum internalformat,
370 GLsizei width,
371 GLsizei height,
372 GLuint memory,
373 GLuint64 offset,
374 GLbitfield createFlags,
375 GLbitfield usageFlags) {
376 internalformat = GetInternalFormat(version_.get(), internalformat);
377 GLApiBase::glTexStorageMemFlags2DANGLEFn(target, levels, internalformat,
378 width, height, memory, offset,
379 createFlags, usageFlags);
380 }
381
glRenderbufferStorageEXTFn(GLenum target,GLenum internalformat,GLsizei width,GLsizei height)382 void RealGLApi::glRenderbufferStorageEXTFn(GLenum target,
383 GLenum internalformat,
384 GLsizei width,
385 GLsizei height) {
386 GLenum gl_internal_format = GetInternalFormat(version_.get(), internalformat);
387 GLApiBase::glRenderbufferStorageEXTFn(target, gl_internal_format, width,
388 height);
389 }
390
391 // The ANGLE and IMG variants of glRenderbufferStorageMultisample currently do
392 // not support BGRA render buffers so only the EXT one is customized. If
393 // GL_CHROMIUM_renderbuffer_format_BGRA8888 support is added to ANGLE then the
394 // ANGLE version should also be customized.
glRenderbufferStorageMultisampleEXTFn(GLenum target,GLsizei samples,GLenum internalformat,GLsizei width,GLsizei height)395 void RealGLApi::glRenderbufferStorageMultisampleEXTFn(GLenum target,
396 GLsizei samples,
397 GLenum internalformat,
398 GLsizei width,
399 GLsizei height) {
400 GLenum gl_internal_format = GetInternalFormat(version_.get(), internalformat);
401 GLApiBase::glRenderbufferStorageMultisampleEXTFn(
402 target, samples, gl_internal_format, width, height);
403 }
404
glRenderbufferStorageMultisampleFn(GLenum target,GLsizei samples,GLenum internalformat,GLsizei width,GLsizei height)405 void RealGLApi::glRenderbufferStorageMultisampleFn(GLenum target,
406 GLsizei samples,
407 GLenum internalformat,
408 GLsizei width,
409 GLsizei height) {
410 GLenum gl_internal_format = GetInternalFormat(version_.get(), internalformat);
411 GLApiBase::glRenderbufferStorageMultisampleFn(
412 target, samples, gl_internal_format, width, height);
413 }
414
glReadPixelsFn(GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,void * pixels)415 void RealGLApi::glReadPixelsFn(GLint x,
416 GLint y,
417 GLsizei width,
418 GLsizei height,
419 GLenum format,
420 GLenum type,
421 void* pixels) {
422 GLenum gl_type = GetPixelType(version_.get(), type, format);
423 GLApiBase::glReadPixelsFn(x, y, width, height, format, gl_type, pixels);
424 }
425
glClearFn(GLbitfield mask)426 void RealGLApi::glClearFn(GLbitfield mask) {
427 if (!g_null_draw_bindings_enabled)
428 GLApiBase::glClearFn(mask);
429 }
430
glClearColorFn(GLclampf red,GLclampf green,GLclampf blue,GLclampf alpha)431 void RealGLApi::glClearColorFn(GLclampf red,
432 GLclampf green,
433 GLclampf blue,
434 GLclampf alpha) {
435 if (!version_->is_angle && gl_workarounds_.clear_to_zero_or_one_broken &&
436 (1 == red || 0 == red) && (1 == green || 0 == green) &&
437 (1 == blue || 0 == blue) && (1 == alpha || 0 == alpha)) {
438 if (1 == alpha)
439 alpha = 2;
440 else
441 alpha = -1;
442 }
443 GLApiBase::glClearColorFn(red, green, blue, alpha);
444 }
445
glDrawArraysFn(GLenum mode,GLint first,GLsizei count)446 void RealGLApi::glDrawArraysFn(GLenum mode, GLint first, GLsizei count) {
447 if (!g_null_draw_bindings_enabled)
448 GLApiBase::glDrawArraysFn(mode, first, count);
449 }
450
glDrawElementsFn(GLenum mode,GLsizei count,GLenum type,const void * indices)451 void RealGLApi::glDrawElementsFn(GLenum mode,
452 GLsizei count,
453 GLenum type,
454 const void* indices) {
455 if (!g_null_draw_bindings_enabled)
456 GLApiBase::glDrawElementsFn(mode, count, type, indices);
457 }
458
glClearDepthFn(GLclampd depth)459 void RealGLApi::glClearDepthFn(GLclampd depth) {
460 // OpenGL ES only has glClearDepthf, forward the parameters from glClearDepth.
461 // Many mock tests expect only glClearDepth is called so don't make the
462 // interception when testing with mocks.
463 if (version_->is_es && GetGLImplementation() != kGLImplementationMockGL) {
464 DCHECK(driver_->fn.glClearDepthfFn);
465 GLApiBase::glClearDepthfFn(static_cast<GLclampf>(depth));
466 } else {
467 DCHECK(driver_->fn.glClearDepthFn);
468 GLApiBase::glClearDepthFn(depth);
469 }
470 }
471
glDepthRangeFn(GLclampd z_near,GLclampd z_far)472 void RealGLApi::glDepthRangeFn(GLclampd z_near, GLclampd z_far) {
473 // OpenGL ES only has glDepthRangef, forward the parameters from glDepthRange.
474 // Many mock tests expect only glDepthRange is called so don't make the
475 // interception when testing with mocks.
476 if (version_->is_es && GetGLImplementation() != kGLImplementationMockGL) {
477 DCHECK(driver_->fn.glDepthRangefFn);
478 GLApiBase::glDepthRangefFn(static_cast<GLclampf>(z_near),
479 static_cast<GLclampf>(z_far));
480 } else {
481 DCHECK(driver_->fn.glDepthRangeFn);
482 GLApiBase::glDepthRangeFn(z_near, z_far);
483 }
484 }
485
glUseProgramFn(GLuint program)486 void RealGLApi::glUseProgramFn(GLuint program) {
487 ShaderTracking* shader_tracking = ShaderTracking::GetInstance();
488 if (shader_tracking) {
489 std::vector<char> buffers[2];
490 char* strings[2] = {nullptr, nullptr};
491 if (program) {
492 // The following only works with ANGLE backend because ANGLE makes sure
493 // a program's shaders are not actually deleted and source can still be
494 // queried even if glDeleteShaders() has been called on them.
495
496 // Also, in theory, different shaders can be attached to the program
497 // after the last link, but for now, ignore such corner case patterns.
498 GLsizei count = 0;
499 GLuint shaders[2] = {0};
500 glGetAttachedShadersFn(program, 2, &count, shaders);
501 for (GLsizei ii = 0; ii < std::min(2, count); ++ii) {
502 buffers[ii].resize(ShaderTracking::kMaxShaderSize);
503 glGetShaderSourceFn(shaders[ii], ShaderTracking::kMaxShaderSize,
504 nullptr, buffers[ii].data());
505 strings[ii] = buffers[ii].data();
506 }
507 }
508 shader_tracking->SetShaders(strings[0], strings[1]);
509 }
510 GLApiBase::glUseProgramFn(program);
511 }
512
InitializeFilteredExtensionsIfNeeded()513 void RealGLApi::InitializeFilteredExtensionsIfNeeded() {
514 DCHECK(disabled_exts_.size());
515 if (filtered_exts_.size())
516 return;
517 DCHECK(filtered_exts_str_.empty());
518 if (WillUseGLGetStringForExtensions(this)) {
519 filtered_exts_str_ = FilterGLExtensionList(
520 reinterpret_cast<const char*>(GLApiBase::glGetStringFn(GL_EXTENSIONS)),
521 disabled_exts_);
522 filtered_exts_ = base::SplitString(
523 filtered_exts_str_, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
524 } else {
525 GLint num_extensions = 0;
526 GLApiBase::glGetIntegervFn(GL_NUM_EXTENSIONS, &num_extensions);
527 for (GLint i = 0; i < num_extensions; ++i) {
528 const char* gl_extension = reinterpret_cast<const char*>(
529 GLApiBase::glGetStringiFn(GL_EXTENSIONS, i));
530 DCHECK(gl_extension);
531 if (!base::Contains(disabled_exts_, gl_extension))
532 filtered_exts_.push_back(gl_extension);
533 }
534 filtered_exts_str_ = base::JoinString(filtered_exts_, " ");
535 }
536 }
537
SetDisabledExtensions(const std::string & disabled_extensions)538 void RealGLApi::SetDisabledExtensions(const std::string& disabled_extensions) {
539 ClearCachedGLExtensions();
540 disabled_exts_.clear();
541 if (disabled_extensions.empty())
542 return;
543 disabled_exts_ =
544 base::SplitString(disabled_extensions, ", ;", base::KEEP_WHITESPACE,
545 base::SPLIT_WANT_NONEMPTY);
546 DCHECK(disabled_exts_.size());
547 }
548
ClearCachedGLExtensions()549 void RealGLApi::ClearCachedGLExtensions() {
550 filtered_exts_.clear();
551 filtered_exts_str_.clear();
552 }
553
set_gl_workarounds(const GLWorkarounds & workarounds)554 void RealGLApi::set_gl_workarounds(const GLWorkarounds& workarounds) {
555 gl_workarounds_ = workarounds;
556 }
557
set_version(std::unique_ptr<GLVersionInfo> version)558 void RealGLApi::set_version(std::unique_ptr<GLVersionInfo> version) {
559 version_ = std::move(version);
560 }
561
~TraceGLApi()562 TraceGLApi::~TraceGLApi() {
563 }
564
LogGLApi(GLApi * gl_api)565 LogGLApi::LogGLApi(GLApi* gl_api) : gl_api_(gl_api) {}
566
~LogGLApi()567 LogGLApi::~LogGLApi() {}
568
NoContextGLApi()569 NoContextGLApi::NoContextGLApi() {
570 }
571
~NoContextGLApi()572 NoContextGLApi::~NoContextGLApi() {
573 }
574
575 } // namespace gl
576