- add sources.
[platform/framework/web/crosswalk.git] / src / ui / gl / gl_gl_api_implementation.cc
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
18 namespace gfx {
19
20 // The GL Api being used. This could be g_real_gl or gl_trace_gl
21 static GLApi* g_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;
26
27 namespace {
28
29 static inline GLenum GetInternalFormat(GLenum internal_format) {
30   if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
31     if (internal_format == GL_BGRA_EXT || internal_format == GL_BGRA8_EXT)
32       return GL_RGBA8;
33   }
34   return internal_format;
35 }
36
37 // TODO(epenner): Could the above function be merged into this and removed?
38 static inline GLenum GetTexInternalFormat(GLenum internal_format,
39                                           GLenum format,
40                                           GLenum type) {
41   GLenum gl_internal_format = GetInternalFormat(internal_format);
42
43   if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2)
44     return gl_internal_format;
45
46   if (type == GL_FLOAT) {
47     switch (format) {
48       case GL_RGBA:
49         gl_internal_format = GL_RGBA32F_ARB;
50         break;
51       case GL_RGB:
52         gl_internal_format = GL_RGB32F_ARB;
53         break;
54       case GL_LUMINANCE_ALPHA:
55         gl_internal_format = GL_LUMINANCE_ALPHA32F_ARB;
56         break;
57       case GL_LUMINANCE:
58         gl_internal_format = GL_LUMINANCE32F_ARB;
59         break;
60       case GL_ALPHA:
61         gl_internal_format = GL_ALPHA32F_ARB;
62         break;
63       default:
64         NOTREACHED();
65         break;
66     }
67   } else if (type == GL_HALF_FLOAT_OES) {
68     switch (format) {
69       case GL_RGBA:
70         gl_internal_format = GL_RGBA16F_ARB;
71         break;
72       case GL_RGB:
73         gl_internal_format = GL_RGB16F_ARB;
74         break;
75       case GL_LUMINANCE_ALPHA:
76         gl_internal_format = GL_LUMINANCE_ALPHA16F_ARB;
77         break;
78       case GL_LUMINANCE:
79         gl_internal_format = GL_LUMINANCE16F_ARB;
80         break;
81       case GL_ALPHA:
82         gl_internal_format = GL_ALPHA16F_ARB;
83         break;
84       default:
85         NOTREACHED();
86         break;
87     }
88   }
89   return gl_internal_format;
90 }
91
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;
96    }
97    return type;
98 }
99
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,
109       pixels);
110 }
111
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);
118 }
119
120 static void GL_BINDING_CALL CustomTexStorage2DEXT(
121     GLenum target, GLsizei levels, GLenum internalformat, GLsizei width,
122     GLsizei height) {
123   GLenum gl_internal_format = GetInternalFormat(internalformat);
124   return g_driver_gl.orig_fn.glTexStorage2DEXTFn(
125       target, levels, gl_internal_format, width, height);
126 }
127
128 static void GL_BINDING_CALL CustomRenderbufferStorageEXT(
129     GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
130   GLenum gl_internal_format = GetInternalFormat(internalformat);
131   return g_driver_gl.orig_fn.glRenderbufferStorageEXTFn(
132       target, gl_internal_format, width, height);
133 }
134
135 // The ANGLE and IMG variants of glRenderbufferStorageMultisample currently do
136 // not support BGRA render buffers so only the EXT one is customized. If
137 // GL_CHROMIUM_renderbuffer_format_BGRA8888 support is added to ANGLE then the
138 // ANGLE version should also be customized.
139 static void GL_BINDING_CALL CustomRenderbufferStorageMultisampleEXT(
140     GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
141     GLsizei height) {
142   GLenum gl_internal_format = GetInternalFormat(internalformat);
143   return g_driver_gl.orig_fn.glRenderbufferStorageMultisampleEXTFn(
144       target, samples, gl_internal_format, width, height);
145 }
146
147 }  // anonymous namespace
148
149 void DriverGL::Initialize() {
150   InitializeBindings();
151 }
152
153 void DriverGL::InitializeExtensions(GLContext* context) {
154   InitializeExtensionBindings(context);
155   orig_fn = fn;
156   fn.glTexImage2DFn =
157       reinterpret_cast<glTexImage2DProc>(CustomTexImage2D);
158   fn.glTexSubImage2DFn =
159       reinterpret_cast<glTexSubImage2DProc>(CustomTexSubImage2D);
160   fn.glTexStorage2DEXTFn =
161       reinterpret_cast<glTexStorage2DEXTProc>(CustomTexStorage2DEXT);
162   fn.glRenderbufferStorageEXTFn =
163       reinterpret_cast<glRenderbufferStorageEXTProc>(
164       CustomRenderbufferStorageEXT);
165   fn.glRenderbufferStorageMultisampleEXTFn =
166       reinterpret_cast<glRenderbufferStorageMultisampleEXTProc>(
167       CustomRenderbufferStorageMultisampleEXT);
168 }
169
170 void InitializeGLBindingsGL() {
171   g_current_gl_context_tls = new base::ThreadLocalPointer<GLApi>;
172   g_driver_gl.Initialize();
173   if (!g_real_gl) {
174     g_real_gl = new RealGLApi();
175     g_trace_gl = new TraceGLApi(g_real_gl);
176   }
177   g_real_gl->Initialize(&g_driver_gl);
178   g_gl = g_real_gl;
179   if (CommandLine::ForCurrentProcess()->HasSwitch(
180       switches::kEnableGPUServiceTracing)) {
181     g_gl = g_trace_gl;
182   }
183   SetGLToRealGLApi();
184 }
185
186 GLApi* GetCurrentGLApi() {
187   return g_current_gl_context_tls->Get();
188 }
189
190 void SetGLApi(GLApi* api) {
191   g_current_gl_context_tls->Set(api);
192 }
193
194 void SetGLToRealGLApi() {
195   SetGLApi(g_gl);
196 }
197
198 void InitializeGLExtensionBindingsGL(GLContext* context) {
199   g_driver_gl.InitializeExtensions(context);
200 }
201
202 void InitializeDebugGLBindingsGL() {
203   g_driver_gl.InitializeDebugBindings();
204 }
205
206 void ClearGLBindingsGL() {
207   if (g_real_gl) {
208     delete g_real_gl;
209     g_real_gl = NULL;
210   }
211   if (g_trace_gl) {
212     delete g_trace_gl;
213     g_trace_gl = NULL;
214   }
215   g_gl = NULL;
216   g_driver_gl.ClearBindings();
217   if (g_current_gl_context_tls) {
218     delete g_current_gl_context_tls;
219     g_current_gl_context_tls = NULL;
220   }
221 }
222
223 GLApi::GLApi() {
224 }
225
226 GLApi::~GLApi() {
227   if (GetCurrentGLApi() == this)
228     SetGLApi(NULL);
229 }
230
231 GLApiBase::GLApiBase()
232     : driver_(NULL) {
233 }
234
235 GLApiBase::~GLApiBase() {
236 }
237
238 void GLApiBase::InitializeBase(DriverGL* driver) {
239   driver_ = driver;
240 }
241
242 RealGLApi::RealGLApi() {
243 }
244
245 RealGLApi::~RealGLApi() {
246 }
247
248 void RealGLApi::Initialize(DriverGL* driver) {
249   InitializeBase(driver);
250 }
251
252 TraceGLApi::~TraceGLApi() {
253 }
254
255 VirtualGLApi::VirtualGLApi()
256     : real_context_(NULL),
257       current_context_(NULL) {
258 }
259
260 VirtualGLApi::~VirtualGLApi() {
261 }
262
263 void VirtualGLApi::Initialize(DriverGL* driver, GLContext* real_context) {
264   InitializeBase(driver);
265   real_context_ = real_context;
266
267   DCHECK(real_context->IsCurrent(NULL));
268   std::string ext_string(
269       reinterpret_cast<const char*>(driver_->fn.glGetStringFn(GL_EXTENSIONS)));
270   std::vector<std::string> ext;
271   Tokenize(ext_string, " ", &ext);
272
273   std::vector<std::string>::iterator it;
274   // We can't support GL_EXT_occlusion_query_boolean which is
275   // based on GL_ARB_occlusion_query without a lot of work virtualizing
276   // queries.
277   it = std::find(ext.begin(), ext.end(), "GL_EXT_occlusion_query_boolean");
278   if (it != ext.end())
279     ext.erase(it);
280
281   extensions_ = JoinString(ext, " ");
282 }
283
284 bool VirtualGLApi::MakeCurrent(GLContext* virtual_context, GLSurface* surface) {
285   bool switched_contexts = g_current_gl_context_tls->Get() != this;
286   GLSurface* current_surface = GLSurface::GetCurrent();
287   if (switched_contexts || surface != current_surface) {
288     // MakeCurrent 'lite' path that avoids potentially expensive MakeCurrent()
289     // calls if the GLSurface uses the same underlying surface or renders to
290     // an FBO.
291     if (switched_contexts || !current_surface ||
292         !virtual_context->IsCurrent(surface)) {
293       if (!real_context_->MakeCurrent(surface)) {
294         return false;
295       }
296     }
297   }
298
299   DCHECK_EQ(real_context_, GLContext::GetRealCurrent());
300   DCHECK(real_context_->IsCurrent(NULL));
301   DCHECK(virtual_context->IsCurrent(surface));
302
303   if (switched_contexts || virtual_context != current_context_) {
304     // There should be no errors from the previous context leaking into the
305     // new context.
306     DCHECK_EQ(glGetErrorFn(), static_cast<GLenum>(GL_NO_ERROR));
307
308     current_context_ = virtual_context;
309     // Set all state that is different from the real state
310     // NOTE: !!! This is a temporary implementation that just restores all
311     // state to let us test that it works.
312     // TODO: ASAP, change this to something that only restores the state
313     // needed for individual GL calls.
314     GLApi* temp = GetCurrentGLApi();
315     SetGLToRealGLApi();
316     if (virtual_context->GetGLStateRestorer()->IsInitialized())
317       virtual_context->GetGLStateRestorer()->RestoreState();
318     SetGLApi(temp);
319   }
320   SetGLApi(this);
321
322   virtual_context->SetCurrent(surface);
323   if (!surface->OnMakeCurrent(virtual_context)) {
324     LOG(ERROR) << "Could not make GLSurface current.";
325     return false;
326   }
327   return true;
328 }
329
330 void VirtualGLApi::OnReleaseVirtuallyCurrent(GLContext* virtual_context) {
331   if (current_context_ == virtual_context)
332     current_context_ = NULL;
333 }
334
335 const GLubyte* VirtualGLApi::glGetStringFn(GLenum name) {
336   switch (name) {
337     case GL_EXTENSIONS:
338       return reinterpret_cast<const GLubyte*>(extensions_.c_str());
339     default:
340       return driver_->fn.glGetStringFn(name);
341   }
342 }
343
344 }  // namespace gfx