• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <algorithm>
8 #include <vector>
9 
10 #include "base/command_line.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 
19 namespace gfx {
20 
21 // The GL Api being used. This could be g_real_gl or gl_trace_gl
22 static GLApi* g_gl = NULL;
23 // A GL Api that calls directly into the driver.
24 static RealGLApi* g_real_gl = NULL;
25 // A GL Api that does nothing but warn about illegal GL calls without a context
26 // current.
27 static NoContextGLApi* g_no_context_gl = NULL;
28 // A GL Api that calls TRACE and then calls another GL api.
29 static TraceGLApi* g_trace_gl = NULL;
30 // GL version used when initializing dynamic bindings.
31 static GLVersionInfo* g_version_info = NULL;
32 
33 namespace {
34 
GetInternalFormat(GLenum internal_format)35 static inline GLenum GetInternalFormat(GLenum internal_format) {
36   if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
37     if (internal_format == GL_BGRA_EXT || internal_format == GL_BGRA8_EXT)
38       return GL_RGBA8;
39   }
40   return internal_format;
41 }
42 
43 // TODO(epenner): Could the above function be merged into this and removed?
GetTexInternalFormat(GLenum internal_format,GLenum format,GLenum type)44 static inline GLenum GetTexInternalFormat(GLenum internal_format,
45                                           GLenum format,
46                                           GLenum type) {
47   GLenum gl_internal_format = GetInternalFormat(internal_format);
48 
49   // g_version_info must be initialized when this function is bound.
50   DCHECK(gfx::g_version_info);
51   if (type == GL_FLOAT && gfx::g_version_info->is_angle &&
52       gfx::g_version_info->is_es2) {
53     // It's possible that the texture is using a sized internal format, and
54     // ANGLE exposing GLES2 API doesn't support those.
55     // TODO(oetuaho@nvidia.com): Remove these conversions once ANGLE has the
56     // support.
57     // http://code.google.com/p/angleproject/issues/detail?id=556
58     switch (format) {
59       case GL_RGBA:
60         gl_internal_format = GL_RGBA;
61         break;
62       case GL_RGB:
63         gl_internal_format = GL_RGB;
64         break;
65       default:
66         break;
67     }
68   }
69 
70   if (gfx::g_version_info->is_es)
71     return gl_internal_format;
72 
73   if (type == GL_FLOAT) {
74     switch (format) {
75       case GL_RGBA:
76         gl_internal_format = GL_RGBA32F_ARB;
77         break;
78       case GL_RGB:
79         gl_internal_format = GL_RGB32F_ARB;
80         break;
81       case GL_LUMINANCE_ALPHA:
82         gl_internal_format = GL_LUMINANCE_ALPHA32F_ARB;
83         break;
84       case GL_LUMINANCE:
85         gl_internal_format = GL_LUMINANCE32F_ARB;
86         break;
87       case GL_ALPHA:
88         gl_internal_format = GL_ALPHA32F_ARB;
89         break;
90       default:
91         NOTREACHED();
92         break;
93     }
94   } else if (type == GL_HALF_FLOAT_OES) {
95     switch (format) {
96       case GL_RGBA:
97         gl_internal_format = GL_RGBA16F_ARB;
98         break;
99       case GL_RGB:
100         gl_internal_format = GL_RGB16F_ARB;
101         break;
102       case GL_LUMINANCE_ALPHA:
103         gl_internal_format = GL_LUMINANCE_ALPHA16F_ARB;
104         break;
105       case GL_LUMINANCE:
106         gl_internal_format = GL_LUMINANCE16F_ARB;
107         break;
108       case GL_ALPHA:
109         gl_internal_format = GL_ALPHA16F_ARB;
110         break;
111       default:
112         NOTREACHED();
113         break;
114     }
115   }
116   return gl_internal_format;
117 }
118 
GetTexType(GLenum type)119 static inline GLenum GetTexType(GLenum type) {
120    if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
121      if (type == GL_HALF_FLOAT_OES)
122        return GL_HALF_FLOAT_ARB;
123    }
124    return type;
125 }
126 
CustomTexImage2D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const void * pixels)127 static void GL_BINDING_CALL CustomTexImage2D(
128     GLenum target, GLint level, GLint internalformat,
129     GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type,
130     const void* pixels) {
131   GLenum gl_internal_format = GetTexInternalFormat(
132       internalformat, format, type);
133   GLenum gl_type = GetTexType(type);
134   g_driver_gl.orig_fn.glTexImage2DFn(
135       target, level, gl_internal_format, width, height, border, format, gl_type,
136       pixels);
137 }
138 
CustomTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,const void * pixels)139 static void GL_BINDING_CALL CustomTexSubImage2D(
140       GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
141       GLsizei height, GLenum format, GLenum type, const void* pixels) {
142   GLenum gl_type = GetTexType(type);
143   g_driver_gl.orig_fn.glTexSubImage2DFn(
144       target, level, xoffset, yoffset, width, height, format, gl_type, pixels);
145 }
146 
CustomTexStorage2DEXT(GLenum target,GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height)147 static void GL_BINDING_CALL CustomTexStorage2DEXT(
148     GLenum target, GLsizei levels, GLenum internalformat, GLsizei width,
149     GLsizei height) {
150   GLenum gl_internal_format = GetInternalFormat(internalformat);
151   g_driver_gl.orig_fn.glTexStorage2DEXTFn(
152       target, levels, gl_internal_format, width, height);
153 }
154 
CustomRenderbufferStorageEXT(GLenum target,GLenum internalformat,GLsizei width,GLsizei height)155 static void GL_BINDING_CALL CustomRenderbufferStorageEXT(
156     GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
157   GLenum gl_internal_format = GetInternalFormat(internalformat);
158   g_driver_gl.orig_fn.glRenderbufferStorageEXTFn(
159       target, gl_internal_format, width, height);
160 }
161 
162 // The ANGLE and IMG variants of glRenderbufferStorageMultisample currently do
163 // not support BGRA render buffers so only the EXT one is customized. If
164 // GL_CHROMIUM_renderbuffer_format_BGRA8888 support is added to ANGLE then the
165 // ANGLE version should also be customized.
CustomRenderbufferStorageMultisampleEXT(GLenum target,GLsizei samples,GLenum internalformat,GLsizei width,GLsizei height)166 static void GL_BINDING_CALL CustomRenderbufferStorageMultisampleEXT(
167     GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
168     GLsizei height) {
169   GLenum gl_internal_format = GetInternalFormat(internalformat);
170   g_driver_gl.orig_fn.glRenderbufferStorageMultisampleEXTFn(
171       target, samples, gl_internal_format, width, height);
172 }
173 
174 }  // anonymous namespace
175 
InitializeCustomDynamicBindings(GLContext * context)176 void DriverGL::InitializeCustomDynamicBindings(GLContext* context) {
177   InitializeDynamicBindings(context);
178 
179   DCHECK(orig_fn.glTexImage2DFn == NULL);
180   orig_fn.glTexImage2DFn = fn.glTexImage2DFn;
181   fn.glTexImage2DFn =
182       reinterpret_cast<glTexImage2DProc>(CustomTexImage2D);
183 
184   DCHECK(orig_fn.glTexSubImage2DFn == NULL);
185   orig_fn.glTexSubImage2DFn = fn.glTexSubImage2DFn;
186   fn.glTexSubImage2DFn =
187       reinterpret_cast<glTexSubImage2DProc>(CustomTexSubImage2D);
188 
189   DCHECK(orig_fn.glTexStorage2DEXTFn == NULL);
190   orig_fn.glTexStorage2DEXTFn = fn.glTexStorage2DEXTFn;
191   fn.glTexStorage2DEXTFn =
192       reinterpret_cast<glTexStorage2DEXTProc>(CustomTexStorage2DEXT);
193 
194   DCHECK(orig_fn.glRenderbufferStorageEXTFn == NULL);
195   orig_fn.glRenderbufferStorageEXTFn = fn.glRenderbufferStorageEXTFn;
196   fn.glRenderbufferStorageEXTFn =
197       reinterpret_cast<glRenderbufferStorageEXTProc>(
198       CustomRenderbufferStorageEXT);
199 
200   DCHECK(orig_fn.glRenderbufferStorageMultisampleEXTFn == NULL);
201   orig_fn.glRenderbufferStorageMultisampleEXTFn =
202       fn.glRenderbufferStorageMultisampleEXTFn;
203   fn.glRenderbufferStorageMultisampleEXTFn =
204       reinterpret_cast<glRenderbufferStorageMultisampleEXTProc>(
205       CustomRenderbufferStorageMultisampleEXT);
206 }
207 
NullDrawClearFn(GLbitfield mask)208 static void GL_BINDING_CALL NullDrawClearFn(GLbitfield mask) {
209   if (!g_driver_gl.null_draw_bindings_enabled)
210     g_driver_gl.orig_fn.glClearFn(mask);
211 }
212 
213 static void GL_BINDING_CALL
NullDrawDrawArraysFn(GLenum mode,GLint first,GLsizei count)214 NullDrawDrawArraysFn(GLenum mode, GLint first, GLsizei count) {
215   if (!g_driver_gl.null_draw_bindings_enabled)
216     g_driver_gl.orig_fn.glDrawArraysFn(mode, first, count);
217 }
218 
NullDrawDrawElementsFn(GLenum mode,GLsizei count,GLenum type,const void * indices)219 static void GL_BINDING_CALL NullDrawDrawElementsFn(GLenum mode,
220                                                    GLsizei count,
221                                                    GLenum type,
222                                                    const void* indices) {
223   if (!g_driver_gl.null_draw_bindings_enabled)
224     g_driver_gl.orig_fn.glDrawElementsFn(mode, count, type, indices);
225 }
226 
InitializeNullDrawBindings()227 void DriverGL::InitializeNullDrawBindings() {
228   DCHECK(orig_fn.glClearFn == NULL);
229   orig_fn.glClearFn = fn.glClearFn;
230   fn.glClearFn = NullDrawClearFn;
231 
232   DCHECK(orig_fn.glDrawArraysFn == NULL);
233   orig_fn.glDrawArraysFn = fn.glDrawArraysFn;
234   fn.glDrawArraysFn = NullDrawDrawArraysFn;
235 
236   DCHECK(orig_fn.glDrawElementsFn == NULL);
237   orig_fn.glDrawElementsFn = fn.glDrawElementsFn;
238   fn.glDrawElementsFn = NullDrawDrawElementsFn;
239 
240   null_draw_bindings_enabled = true;
241 }
242 
HasInitializedNullDrawBindings()243 bool DriverGL::HasInitializedNullDrawBindings() {
244   return orig_fn.glClearFn != NULL && orig_fn.glDrawArraysFn != NULL &&
245          orig_fn.glDrawElementsFn != NULL;
246 }
247 
SetNullDrawBindingsEnabled(bool enabled)248 bool DriverGL::SetNullDrawBindingsEnabled(bool enabled) {
249   DCHECK(orig_fn.glClearFn != NULL);
250   DCHECK(orig_fn.glDrawArraysFn != NULL);
251   DCHECK(orig_fn.glDrawElementsFn != NULL);
252 
253   bool before = null_draw_bindings_enabled;
254   null_draw_bindings_enabled = enabled;
255   return before;
256 }
257 
InitializeStaticGLBindingsGL()258 void InitializeStaticGLBindingsGL() {
259   g_current_gl_context_tls = new base::ThreadLocalPointer<GLApi>;
260   g_driver_gl.InitializeStaticBindings();
261   if (!g_real_gl) {
262     g_real_gl = new RealGLApi();
263     g_trace_gl = new TraceGLApi(g_real_gl);
264     g_no_context_gl = new NoContextGLApi();
265   }
266   g_real_gl->Initialize(&g_driver_gl);
267   g_gl = g_real_gl;
268   if (CommandLine::ForCurrentProcess()->HasSwitch(
269       switches::kEnableGPUServiceTracing)) {
270     g_gl = g_trace_gl;
271   }
272   SetGLToRealGLApi();
273 }
274 
GetCurrentGLApi()275 GLApi* GetCurrentGLApi() {
276   return g_current_gl_context_tls->Get();
277 }
278 
SetGLApi(GLApi * api)279 void SetGLApi(GLApi* api) {
280   g_current_gl_context_tls->Set(api);
281 }
282 
SetGLToRealGLApi()283 void SetGLToRealGLApi() {
284   SetGLApi(g_gl);
285 }
286 
SetGLApiToNoContext()287 void SetGLApiToNoContext() {
288   SetGLApi(g_no_context_gl);
289 }
290 
GetGLVersionInfo()291 const GLVersionInfo* GetGLVersionInfo() {
292   return g_version_info;
293 }
294 
InitializeDynamicGLBindingsGL(GLContext * context)295 void InitializeDynamicGLBindingsGL(GLContext* context) {
296   g_driver_gl.InitializeCustomDynamicBindings(context);
297   DCHECK(context && context->IsCurrent(NULL) && !g_version_info);
298   g_version_info = new GLVersionInfo(context->GetGLVersion().c_str(),
299       context->GetGLRenderer().c_str());
300 }
301 
InitializeDebugGLBindingsGL()302 void InitializeDebugGLBindingsGL() {
303   g_driver_gl.InitializeDebugBindings();
304 }
305 
InitializeNullDrawGLBindingsGL()306 void InitializeNullDrawGLBindingsGL() {
307   g_driver_gl.InitializeNullDrawBindings();
308 }
309 
HasInitializedNullDrawGLBindingsGL()310 bool HasInitializedNullDrawGLBindingsGL() {
311   return g_driver_gl.HasInitializedNullDrawBindings();
312 }
313 
SetNullDrawGLBindingsEnabledGL(bool enabled)314 bool SetNullDrawGLBindingsEnabledGL(bool enabled) {
315   return g_driver_gl.SetNullDrawBindingsEnabled(enabled);
316 }
317 
ClearGLBindingsGL()318 void ClearGLBindingsGL() {
319   if (g_real_gl) {
320     delete g_real_gl;
321     g_real_gl = NULL;
322   }
323   if (g_trace_gl) {
324     delete g_trace_gl;
325     g_trace_gl = NULL;
326   }
327   if (g_no_context_gl) {
328     delete g_no_context_gl;
329     g_no_context_gl = NULL;
330   }
331   g_gl = NULL;
332   g_driver_gl.ClearBindings();
333   if (g_current_gl_context_tls) {
334     delete g_current_gl_context_tls;
335     g_current_gl_context_tls = NULL;
336   }
337   if (g_version_info) {
338     delete g_version_info;
339     g_version_info = NULL;
340   }
341 }
342 
GLApi()343 GLApi::GLApi() {
344 }
345 
~GLApi()346 GLApi::~GLApi() {
347   if (GetCurrentGLApi() == this)
348     SetGLApi(NULL);
349 }
350 
GLApiBase()351 GLApiBase::GLApiBase()
352     : driver_(NULL) {
353 }
354 
~GLApiBase()355 GLApiBase::~GLApiBase() {
356 }
357 
InitializeBase(DriverGL * driver)358 void GLApiBase::InitializeBase(DriverGL* driver) {
359   driver_ = driver;
360 }
361 
SignalFlush()362 void GLApiBase::SignalFlush() {
363   DCHECK(GLContext::GetCurrent());
364   GLContext::GetCurrent()->OnFlush();
365 }
366 
RealGLApi()367 RealGLApi::RealGLApi() {
368 }
369 
~RealGLApi()370 RealGLApi::~RealGLApi() {
371 }
372 
Initialize(DriverGL * driver)373 void RealGLApi::Initialize(DriverGL* driver) {
374   InitializeBase(driver);
375 }
376 
glFlushFn()377 void RealGLApi::glFlushFn() {
378   GLApiBase::glFlushFn();
379   GLApiBase::SignalFlush();
380 }
381 
glFinishFn()382 void RealGLApi::glFinishFn() {
383   GLApiBase::glFinishFn();
384   GLApiBase::SignalFlush();
385 }
386 
~TraceGLApi()387 TraceGLApi::~TraceGLApi() {
388 }
389 
NoContextGLApi()390 NoContextGLApi::NoContextGLApi() {
391 }
392 
~NoContextGLApi()393 NoContextGLApi::~NoContextGLApi() {
394 }
395 
VirtualGLApi()396 VirtualGLApi::VirtualGLApi()
397     : real_context_(NULL),
398       current_context_(NULL) {
399 }
400 
~VirtualGLApi()401 VirtualGLApi::~VirtualGLApi() {
402 }
403 
Initialize(DriverGL * driver,GLContext * real_context)404 void VirtualGLApi::Initialize(DriverGL* driver, GLContext* real_context) {
405   InitializeBase(driver);
406   real_context_ = real_context;
407 
408   DCHECK(real_context->IsCurrent(NULL));
409   std::string ext_string(
410       reinterpret_cast<const char*>(driver_->fn.glGetStringFn(GL_EXTENSIONS)));
411   std::vector<std::string> ext;
412   Tokenize(ext_string, " ", &ext);
413 
414   std::vector<std::string>::iterator it;
415   // We can't support GL_EXT_occlusion_query_boolean which is
416   // based on GL_ARB_occlusion_query without a lot of work virtualizing
417   // queries.
418   it = std::find(ext.begin(), ext.end(), "GL_EXT_occlusion_query_boolean");
419   if (it != ext.end())
420     ext.erase(it);
421 
422   extensions_ = JoinString(ext, " ");
423 }
424 
MakeCurrent(GLContext * virtual_context,GLSurface * surface)425 bool VirtualGLApi::MakeCurrent(GLContext* virtual_context, GLSurface* surface) {
426   bool switched_contexts = g_current_gl_context_tls->Get() != this;
427   GLSurface* current_surface = GLSurface::GetCurrent();
428   if (switched_contexts || surface != current_surface) {
429     // MakeCurrent 'lite' path that avoids potentially expensive MakeCurrent()
430     // calls if the GLSurface uses the same underlying surface or renders to
431     // an FBO.
432     if (switched_contexts || !current_surface ||
433         !virtual_context->IsCurrent(surface)) {
434       if (!real_context_->MakeCurrent(surface)) {
435         return false;
436       }
437     }
438   }
439 
440   DCHECK_EQ(real_context_, GLContext::GetRealCurrent());
441   DCHECK(real_context_->IsCurrent(NULL));
442   DCHECK(virtual_context->IsCurrent(surface));
443 
444   if (switched_contexts || virtual_context != current_context_) {
445     // There should be no errors from the previous context leaking into the
446     // new context.
447     DCHECK_EQ(glGetErrorFn(), static_cast<GLenum>(GL_NO_ERROR));
448 
449     // Set all state that is different from the real state
450     GLApi* temp = GetCurrentGLApi();
451     SetGLToRealGLApi();
452     if (virtual_context->GetGLStateRestorer()->IsInitialized()) {
453       virtual_context->GetGLStateRestorer()->RestoreState(
454           (current_context_ && !switched_contexts)
455               ? current_context_->GetGLStateRestorer()
456               : NULL);
457     }
458     SetGLApi(temp);
459     current_context_ = virtual_context;
460   }
461   SetGLApi(this);
462 
463   virtual_context->SetCurrent(surface);
464   if (!surface->OnMakeCurrent(virtual_context)) {
465     LOG(ERROR) << "Could not make GLSurface current.";
466     return false;
467   }
468   return true;
469 }
470 
OnReleaseVirtuallyCurrent(GLContext * virtual_context)471 void VirtualGLApi::OnReleaseVirtuallyCurrent(GLContext* virtual_context) {
472   if (current_context_ == virtual_context)
473     current_context_ = NULL;
474 }
475 
glGetStringFn(GLenum name)476 const GLubyte* VirtualGLApi::glGetStringFn(GLenum name) {
477   switch (name) {
478     case GL_EXTENSIONS:
479       return reinterpret_cast<const GLubyte*>(extensions_.c_str());
480     default:
481       return driver_->fn.glGetStringFn(name);
482   }
483 }
484 
glFlushFn()485 void VirtualGLApi::glFlushFn() {
486   GLApiBase::glFlushFn();
487   GLApiBase::SignalFlush();
488 }
489 
glFinishFn()490 void VirtualGLApi::glFinishFn() {
491   GLApiBase::glFinishFn();
492   GLApiBase::SignalFlush();
493 }
494 
495 }  // namespace gfx
496