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.
5 #include "ui/gl/gl_gl_api_implementation.h"
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"
20 // The GL Api being used. This could be g_real_gl or gl_trace_gl
22 // A GL Api that calls directly into the driver.
23 static RealGLApi
* g_real_gl
;
24 // A GL Api that calls TRACE and then calls another GL api.
25 static TraceGLApi
* g_trace_gl
;
29 static inline GLenum
GetTexInternalFormat(GLenum internal_format
) {
30 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2
) {
31 if (internal_format
== GL_BGRA_EXT
|| internal_format
== GL_BGRA8_EXT
)
34 return internal_format
;
37 // TODO(epenner): Could the above function be merged into this and removed?
38 static inline GLenum
GetTexInternalFormat(GLenum internal_format
,
41 GLenum gl_internal_format
= GetTexInternalFormat(internal_format
);
43 if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2
)
44 return gl_internal_format
;
46 if (type
== GL_FLOAT
) {
49 gl_internal_format
= GL_RGBA32F_ARB
;
52 gl_internal_format
= GL_RGB32F_ARB
;
54 case GL_LUMINANCE_ALPHA
:
55 gl_internal_format
= GL_LUMINANCE_ALPHA32F_ARB
;
58 gl_internal_format
= GL_LUMINANCE32F_ARB
;
61 gl_internal_format
= GL_ALPHA32F_ARB
;
67 } else if (type
== GL_HALF_FLOAT_OES
) {
70 gl_internal_format
= GL_RGBA16F_ARB
;
73 gl_internal_format
= GL_RGB16F_ARB
;
75 case GL_LUMINANCE_ALPHA
:
76 gl_internal_format
= GL_LUMINANCE_ALPHA16F_ARB
;
79 gl_internal_format
= GL_LUMINANCE16F_ARB
;
82 gl_internal_format
= GL_ALPHA16F_ARB
;
89 return gl_internal_format
;
92 static inline GLenum
GetTexType(GLenum type
) {
93 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2
) {
94 if (type
== GL_HALF_FLOAT_OES
)
95 return GL_HALF_FLOAT_ARB
;
100 static void GL_BINDING_CALL
CustomTexImage2D(
101 GLenum target
, GLint level
, GLint internalformat
,
102 GLsizei width
, GLsizei height
, GLint border
, GLenum format
, GLenum type
,
103 const void* pixels
) {
104 GLenum gl_internal_format
= GetTexInternalFormat(
105 internalformat
, format
, type
);
106 GLenum gl_type
= GetTexType(type
);
107 return g_driver_gl
.orig_fn
.glTexImage2DFn(
108 target
, level
, gl_internal_format
, width
, height
, border
, format
, gl_type
,
112 static void GL_BINDING_CALL
CustomTexSubImage2D(
113 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
114 GLsizei height
, GLenum format
, GLenum type
, const void* pixels
) {
115 GLenum gl_type
= GetTexType(type
);
116 return g_driver_gl
.orig_fn
.glTexSubImage2DFn(
117 target
, level
, xoffset
, yoffset
, width
, height
, format
, gl_type
, pixels
);
120 static void GL_BINDING_CALL
CustomTexStorage2DEXT(
121 GLenum target
, GLsizei levels
, GLenum internalformat
, GLsizei width
,
123 GLenum gl_internal_format
= GetTexInternalFormat(internalformat
);
124 return g_driver_gl
.orig_fn
.glTexStorage2DEXTFn(
125 target
, levels
, gl_internal_format
, width
, height
);
128 } // anonymous namespace
130 void DriverGL::Initialize() {
131 InitializeBindings();
134 void DriverGL::InitializeExtensions(GLContext
* context
) {
135 InitializeExtensionBindings(context
);
138 reinterpret_cast<glTexImage2DProc
>(CustomTexImage2D
);
139 fn
.glTexSubImage2DFn
=
140 reinterpret_cast<glTexSubImage2DProc
>(CustomTexSubImage2D
);
141 fn
.glTexStorage2DEXTFn
=
142 reinterpret_cast<glTexStorage2DEXTProc
>(CustomTexStorage2DEXT
);
145 void InitializeGLBindingsGL() {
146 g_driver_gl
.Initialize();
148 g_real_gl
= new RealGLApi();
149 g_trace_gl
= new TraceGLApi(g_real_gl
);
151 g_real_gl
->Initialize(&g_driver_gl
);
153 if (CommandLine::ForCurrentProcess()->HasSwitch(
154 switches::kEnableGPUServiceTracing
)) {
160 GLApi
* GetCurrentGLApi() {
161 return g_current_gl_context
;
164 void SetGLApi(GLApi
* api
) {
165 g_current_gl_context
= api
;
168 void SetGLToRealGLApi() {
172 void InitializeGLExtensionBindingsGL(GLContext
* context
) {
173 g_driver_gl
.InitializeExtensions(context
);
176 void InitializeDebugGLBindingsGL() {
177 g_driver_gl
.InitializeDebugBindings();
180 void ClearGLBindingsGL() {
190 g_current_gl_context
= NULL
;
191 g_driver_gl
.ClearBindings();
198 if (GetCurrentGLApi() == this)
202 GLApiBase::GLApiBase()
206 GLApiBase::~GLApiBase() {
209 void GLApiBase::InitializeBase(DriverGL
* driver
) {
213 RealGLApi::RealGLApi() {
216 RealGLApi::~RealGLApi() {
219 void RealGLApi::Initialize(DriverGL
* driver
) {
220 InitializeBase(driver
);
223 TraceGLApi::~TraceGLApi() {
226 VirtualGLApi::VirtualGLApi()
227 : real_context_(NULL
),
228 current_context_(NULL
) {
231 VirtualGLApi::~VirtualGLApi() {
234 void VirtualGLApi::Initialize(DriverGL
* driver
, GLContext
* real_context
) {
235 InitializeBase(driver
);
236 real_context_
= real_context
;
238 DCHECK(real_context
->IsCurrent(NULL
));
239 std::string
ext_string(
240 reinterpret_cast<const char*>(driver_
->fn
.glGetStringFn(GL_EXTENSIONS
)));
241 std::vector
<std::string
> ext
;
242 Tokenize(ext_string
, " ", &ext
);
244 std::vector
<std::string
>::iterator it
;
245 // We can't support GL_EXT_occlusion_query_boolean which is
246 // based on GL_ARB_occlusion_query without a lot of work virtualizing
248 it
= std::find(ext
.begin(), ext
.end(), "GL_EXT_occlusion_query_boolean");
252 extensions_
= JoinString(ext
, " ");
255 bool VirtualGLApi::MakeCurrent(GLContext
* virtual_context
, GLSurface
* surface
) {
256 bool switched_contexts
= g_current_gl_context
!= this;
257 GLSurface
* current_surface
= GLSurface::GetCurrent();
258 if (switched_contexts
|| surface
!= current_surface
) {
259 // MakeCurrent 'lite' path that avoids potentially expensive MakeCurrent()
260 // calls if the GLSurface uses the same underlying surface or renders to
262 if (switched_contexts
|| !current_surface
||
263 !virtual_context
->IsCurrent(surface
)) {
264 if (!real_context_
->MakeCurrent(surface
)) {
270 DCHECK_EQ(real_context_
, GLContext::GetRealCurrent());
271 DCHECK(real_context_
->IsCurrent(NULL
));
272 DCHECK(virtual_context
->IsCurrent(surface
));
274 if (switched_contexts
|| virtual_context
!= current_context_
) {
275 // There should be no errors from the previous context leaking into the
277 DCHECK_EQ(glGetErrorFn(), static_cast<GLenum
>(GL_NO_ERROR
));
279 current_context_
= virtual_context
;
280 // Set all state that is different from the real state
281 // NOTE: !!! This is a temporary implementation that just restores all
282 // state to let us test that it works.
283 // TODO: ASAP, change this to something that only restores the state
284 // needed for individual GL calls.
285 GLApi
* temp
= GetCurrentGLApi();
287 if (virtual_context
->GetGLStateRestorer()->IsInitialized())
288 virtual_context
->GetGLStateRestorer()->RestoreState();
293 virtual_context
->SetCurrent(surface
);
294 if (!surface
->OnMakeCurrent(virtual_context
)) {
295 LOG(ERROR
) << "Could not make GLSurface current.";
301 void VirtualGLApi::OnReleaseVirtuallyCurrent(GLContext
* virtual_context
) {
302 if (current_context_
== virtual_context
)
303 current_context_
= NULL
;
306 const GLubyte
* VirtualGLApi::glGetStringFn(GLenum name
) {
309 return reinterpret_cast<const GLubyte
*>(extensions_
.c_str());
311 return driver_
->fn
.glGetStringFn(name
);