Add ICU message format support
[chromium-blink-merge.git] / ui / gl / gl_implementation_win.cc
blob6a4e61298a71ea231190462ecf669f643df0d7f7
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 <vector>
7 #include "base/at_exit.h"
8 #include "base/base_paths.h"
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/files/file_path.h"
12 #include "base/lazy_instance.h"
13 #include "base/logging.h"
14 #include "base/native_library.h"
15 #include "base/path_service.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/threading/thread_restrictions.h"
18 #include "base/trace_event/trace_event.h"
19 #include "base/win/windows_version.h"
20 // TODO(jmadill): Apply to all platforms eventually
21 #include "ui/gl/angle_platform_impl.h"
22 #include "ui/gl/gl_bindings.h"
23 #include "ui/gl/gl_context_stub_with_extensions.h"
24 #include "ui/gl/gl_egl_api_implementation.h"
25 #include "ui/gl/gl_gl_api_implementation.h"
26 #include "ui/gl/gl_implementation.h"
27 #include "ui/gl/gl_osmesa_api_implementation.h"
28 #include "ui/gl/gl_surface_wgl.h"
29 #include "ui/gl/gl_wgl_api_implementation.h"
31 #if defined(ENABLE_SWIFTSHADER)
32 #include "software_renderer.h"
33 #endif
35 namespace gfx {
37 namespace {
39 const wchar_t kD3DCompiler[] = L"D3DCompiler_47.dll";
41 void GL_BINDING_CALL MarshalClearDepthToClearDepthf(GLclampd depth) {
42 glClearDepthf(static_cast<GLclampf>(depth));
45 void GL_BINDING_CALL MarshalDepthRangeToDepthRangef(GLclampd z_near,
46 GLclampd z_far) {
47 glDepthRangef(static_cast<GLclampf>(z_near), static_cast<GLclampf>(z_far));
50 bool LoadD3DXLibrary(const base::FilePath& module_path,
51 const base::FilePath::StringType& name) {
52 base::NativeLibrary library =
53 base::LoadNativeLibrary(base::FilePath(name), NULL);
54 if (!library) {
55 library = base::LoadNativeLibrary(module_path.Append(name), NULL);
56 if (!library) {
57 DVLOG(1) << name << " not found.";
58 return false;
61 return true;
64 // TODO(jmadill): Apply to all platforms eventually
65 base::LazyInstance<ANGLEPlatformImpl> g_angle_platform_impl =
66 LAZY_INSTANCE_INITIALIZER;
68 ANGLEPlatformShutdownFunc g_angle_platform_shutdown = nullptr;
70 } // namespace
72 void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
73 impls->push_back(kGLImplementationEGLGLES2);
74 impls->push_back(kGLImplementationDesktopGL);
75 impls->push_back(kGLImplementationOSMesaGL);
78 bool InitializeStaticGLBindings(GLImplementation implementation) {
79 // Prevent reinitialization with a different implementation. Once the gpu
80 // unit tests have initialized with kGLImplementationMock, we don't want to
81 // later switch to another GL implementation.
82 DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
84 // Allow the main thread or another to initialize these bindings
85 // after instituting restrictions on I/O. Going forward they will
86 // likely be used in the browser process on most platforms. The
87 // one-time initialization cost is small, between 2 and 5 ms.
88 base::ThreadRestrictions::ScopedAllowIO allow_io;
90 switch (implementation) {
91 case kGLImplementationOSMesaGL: {
92 base::FilePath module_path;
93 PathService::Get(base::DIR_MODULE, &module_path);
94 base::NativeLibrary library = base::LoadNativeLibrary(
95 module_path.Append(L"osmesa.dll"), NULL);
96 if (!library) {
97 PathService::Get(base::DIR_EXE, &module_path);
98 library = base::LoadNativeLibrary(
99 module_path.Append(L"osmesa.dll"), NULL);
100 if (!library) {
101 DVLOG(1) << "osmesa.dll not found";
102 return false;
106 GLGetProcAddressProc get_proc_address =
107 reinterpret_cast<GLGetProcAddressProc>(
108 base::GetFunctionPointerFromNativeLibrary(
109 library, "OSMesaGetProcAddress"));
110 if (!get_proc_address) {
111 DLOG(ERROR) << "OSMesaGetProcAddress not found.";
112 base::UnloadNativeLibrary(library);
113 return false;
116 SetGLGetProcAddressProc(get_proc_address);
117 AddGLNativeLibrary(library);
118 SetGLImplementation(kGLImplementationOSMesaGL);
120 InitializeStaticGLBindingsGL();
121 InitializeStaticGLBindingsOSMESA();
122 break;
124 case kGLImplementationEGLGLES2: {
125 base::FilePath module_path;
126 if (!PathService::Get(base::DIR_MODULE, &module_path))
127 return false;
129 // Attempt to load the D3DX shader compiler using the default search path
130 // and if that fails, using an absolute path. This is to ensure these DLLs
131 // are loaded before ANGLE is loaded in case they are not in the default
132 // search path.
133 LoadD3DXLibrary(module_path, kD3DCompiler);
135 base::FilePath gles_path;
136 const base::CommandLine* command_line =
137 base::CommandLine::ForCurrentProcess();
138 bool using_swift_shader =
139 command_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader";
140 if (using_swift_shader) {
141 if (!command_line->HasSwitch(switches::kSwiftShaderPath))
142 return false;
143 gles_path =
144 command_line->GetSwitchValuePath(switches::kSwiftShaderPath);
145 // Preload library
146 LoadLibrary(L"ddraw.dll");
147 } else {
148 gles_path = module_path;
151 // Load libglesv2.dll before libegl.dll because the latter is dependent on
152 // the former and if there is another version of libglesv2.dll in the dll
153 // search path, it will get loaded instead.
154 base::NativeLibrary gles_library = base::LoadNativeLibrary(
155 gles_path.Append(L"libglesv2.dll"), NULL);
156 if (!gles_library) {
157 DVLOG(1) << "libglesv2.dll not found";
158 return false;
161 // When using EGL, first try eglGetProcAddress and then Windows
162 // GetProcAddress on both the EGL and GLES2 DLLs.
163 base::NativeLibrary egl_library = base::LoadNativeLibrary(
164 gles_path.Append(L"libegl.dll"), NULL);
165 if (!egl_library) {
166 DVLOG(1) << "libegl.dll not found.";
167 base::UnloadNativeLibrary(gles_library);
168 return false;
171 #if defined(ENABLE_SWIFTSHADER)
172 if (using_swift_shader) {
173 SetupSoftwareRenderer(gles_library);
175 #endif
177 if (!using_swift_shader) {
178 // Init ANGLE platform here, before we call GetPlatformDisplay().
179 // TODO(jmadill): Apply to all platforms eventually
180 ANGLEPlatformInitializeFunc angle_platform_init =
181 reinterpret_cast<ANGLEPlatformInitializeFunc>(
182 base::GetFunctionPointerFromNativeLibrary(
183 gles_library,
184 "ANGLEPlatformInitialize"));
185 if (angle_platform_init) {
186 angle_platform_init(&g_angle_platform_impl.Get());
188 g_angle_platform_shutdown =
189 reinterpret_cast<ANGLEPlatformShutdownFunc>(
190 base::GetFunctionPointerFromNativeLibrary(
191 gles_library,
192 "ANGLEPlatformShutdown"));
196 GLGetProcAddressProc get_proc_address =
197 reinterpret_cast<GLGetProcAddressProc>(
198 base::GetFunctionPointerFromNativeLibrary(
199 egl_library, "eglGetProcAddress"));
200 if (!get_proc_address) {
201 LOG(ERROR) << "eglGetProcAddress not found.";
202 base::UnloadNativeLibrary(egl_library);
203 base::UnloadNativeLibrary(gles_library);
204 return false;
207 SetGLGetProcAddressProc(get_proc_address);
208 AddGLNativeLibrary(egl_library);
209 AddGLNativeLibrary(gles_library);
210 SetGLImplementation(kGLImplementationEGLGLES2);
212 InitializeStaticGLBindingsGL();
213 InitializeStaticGLBindingsEGL();
215 // These two functions take single precision float rather than double
216 // precision float parameters in GLES.
217 ::gfx::g_driver_gl.fn.glClearDepthFn = MarshalClearDepthToClearDepthf;
218 ::gfx::g_driver_gl.fn.glDepthRangeFn = MarshalDepthRangeToDepthRangef;
219 break;
221 case kGLImplementationDesktopGL: {
222 base::NativeLibrary library = base::LoadNativeLibrary(
223 base::FilePath(L"opengl32.dll"), NULL);
224 if (!library) {
225 DVLOG(1) << "opengl32.dll not found";
226 return false;
229 GLGetProcAddressProc get_proc_address =
230 reinterpret_cast<GLGetProcAddressProc>(
231 base::GetFunctionPointerFromNativeLibrary(
232 library, "wglGetProcAddress"));
233 if (!get_proc_address) {
234 LOG(ERROR) << "wglGetProcAddress not found.";
235 base::UnloadNativeLibrary(library);
236 return false;
239 SetGLGetProcAddressProc(get_proc_address);
240 AddGLNativeLibrary(library);
241 SetGLImplementation(kGLImplementationDesktopGL);
243 // Initialize GL surface and get some functions needed for the context
244 // creation below.
245 if (!GLSurfaceWGL::InitializeOneOff()) {
246 LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed.";
247 return false;
249 wglCreateContextProc wglCreateContextFn =
250 reinterpret_cast<wglCreateContextProc>(
251 GetGLProcAddress("wglCreateContext"));
252 wglDeleteContextProc wglDeleteContextFn =
253 reinterpret_cast<wglDeleteContextProc>(
254 GetGLProcAddress("wglDeleteContext"));
255 wglMakeCurrentProc wglMakeCurrentFn =
256 reinterpret_cast<wglMakeCurrentProc>(
257 GetGLProcAddress("wglMakeCurrent"));
259 // Create a temporary GL context to bind to entry points. This is needed
260 // because wglGetProcAddress is specified to return NULL for all queries
261 // if a context is not current in MSDN documentation, and the static
262 // bindings may contain functions that need to be queried with
263 // wglGetProcAddress. OpenGL wiki further warns that other error values
264 // than NULL could also be returned from wglGetProcAddress on some
265 // implementations, so we need to clear the WGL bindings and reinitialize
266 // them after the context creation.
267 HGLRC gl_context = wglCreateContextFn(GLSurfaceWGL::GetDisplayDC());
268 if (!gl_context) {
269 LOG(ERROR) << "Failed to create temporary context.";
270 return false;
272 if (!wglMakeCurrentFn(GLSurfaceWGL::GetDisplayDC(), gl_context)) {
273 LOG(ERROR) << "Failed to make temporary GL context current.";
274 wglDeleteContextFn(gl_context);
275 return false;
278 InitializeStaticGLBindingsGL();
279 InitializeStaticGLBindingsWGL();
281 wglMakeCurrent(NULL, NULL);
282 wglDeleteContext(gl_context);
284 break;
286 case kGLImplementationMockGL: {
287 SetGLImplementation(kGLImplementationMockGL);
288 InitializeStaticGLBindingsGL();
289 break;
291 default:
292 return false;
295 return true;
298 bool InitializeDynamicGLBindings(GLImplementation implementation,
299 GLContext* context) {
300 switch (implementation) {
301 case kGLImplementationOSMesaGL:
302 case kGLImplementationEGLGLES2:
303 case kGLImplementationDesktopGL:
304 InitializeDynamicGLBindingsGL(context);
305 break;
306 case kGLImplementationMockGL:
307 if (!context) {
308 scoped_refptr<GLContextStubWithExtensions> mock_context(
309 new GLContextStubWithExtensions());
310 mock_context->SetGLVersionString("3.0");
311 InitializeDynamicGLBindingsGL(mock_context.get());
312 } else
313 InitializeDynamicGLBindingsGL(context);
314 break;
315 default:
316 return false;
319 return true;
322 void InitializeDebugGLBindings() {
323 InitializeDebugGLBindingsEGL();
324 InitializeDebugGLBindingsGL();
325 InitializeDebugGLBindingsOSMESA();
326 InitializeDebugGLBindingsWGL();
329 void ClearGLBindings() {
330 // TODO(jmadill): Apply to all platforms eventually
331 if (g_angle_platform_shutdown) {
332 g_angle_platform_shutdown();
335 ClearGLBindingsEGL();
336 ClearGLBindingsGL();
337 ClearGLBindingsOSMESA();
338 ClearGLBindingsWGL();
339 SetGLImplementation(kGLImplementationNone);
340 UnloadGLNativeLibraries();
343 bool GetGLWindowSystemBindingInfo(GLWindowSystemBindingInfo* info) {
344 switch (GetGLImplementation()) {
345 case kGLImplementationDesktopGL:
346 return GetGLWindowSystemBindingInfoWGL(info);
347 case kGLImplementationEGLGLES2:
348 return GetGLWindowSystemBindingInfoEGL(info);
349 default:
350 return false;
354 } // namespace gfx