Update metrics verification for dev-proxy.
[chromium-blink-merge.git] / ui / gl / gl_implementation_win.cc
blobb4dd38c416b001d1f8744a543ea7974e0726d747
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/debug/trace_event.h"
12 #include "base/files/file_path.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/win/windows_version.h"
19 #include "ui/gl/gl_bindings.h"
20 #include "ui/gl/gl_context_stub_with_extensions.h"
21 #include "ui/gl/gl_egl_api_implementation.h"
22 #include "ui/gl/gl_gl_api_implementation.h"
23 #include "ui/gl/gl_implementation.h"
24 #include "ui/gl/gl_osmesa_api_implementation.h"
25 #include "ui/gl/gl_surface_wgl.h"
26 #include "ui/gl/gl_wgl_api_implementation.h"
28 #if defined(ENABLE_SWIFTSHADER)
29 #include "software_renderer.h"
30 #endif
32 namespace gfx {
34 namespace {
36 const wchar_t kD3DCompiler[] = L"D3DCompiler_46.dll";
38 void GL_BINDING_CALL MarshalClearDepthToClearDepthf(GLclampd depth) {
39 glClearDepthf(static_cast<GLclampf>(depth));
42 void GL_BINDING_CALL MarshalDepthRangeToDepthRangef(GLclampd z_near,
43 GLclampd z_far) {
44 glDepthRangef(static_cast<GLclampf>(z_near), static_cast<GLclampf>(z_far));
47 bool LoadD3DXLibrary(const base::FilePath& module_path,
48 const base::FilePath::StringType& name) {
49 base::NativeLibrary library =
50 base::LoadNativeLibrary(base::FilePath(name), NULL);
51 if (!library) {
52 library = base::LoadNativeLibrary(module_path.Append(name), NULL);
53 if (!library) {
54 DVLOG(1) << name << " not found.";
55 return false;
58 return true;
61 const unsigned char* AngleGetTraceCategoryEnabledFlag(const char* name) {
62 return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name);
65 void AngleAddTraceEvent(char phase,
66 const unsigned char* category_group_enabled,
67 const char* name,
68 unsigned long long id,
69 int num_args,
70 const char** arg_names,
71 const unsigned char* arg_types,
72 const unsigned long long* arg_values,
73 unsigned char flags) {
74 TRACE_EVENT_API_ADD_TRACE_EVENT(phase,
75 category_group_enabled,
76 name,
77 id,
78 num_args,
79 arg_names,
80 arg_types,
81 arg_values,
82 NULL,
83 flags);
86 typedef const unsigned char* (*GetCategoryEnabledFlagFunc)(const char* name);
87 typedef void (*AddTraceEventFunc)(char phase,
88 const unsigned char* categoryGroupEnabled,
89 const char* name,
90 unsigned long long id,
91 int numArgs,
92 const char** argNames,
93 const unsigned char* argTypes,
94 const unsigned long long* argValues,
95 unsigned char flags);
96 typedef void (__stdcall *SetTraceFunctionPointersFunc)(
97 GetCategoryEnabledFlagFunc get_category_enabled_flag,
98 AddTraceEventFunc add_trace_event_func);
100 } // namespace
102 void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
103 impls->push_back(kGLImplementationEGLGLES2);
104 impls->push_back(kGLImplementationDesktopGL);
105 impls->push_back(kGLImplementationOSMesaGL);
108 bool InitializeStaticGLBindings(GLImplementation implementation) {
109 // Prevent reinitialization with a different implementation. Once the gpu
110 // unit tests have initialized with kGLImplementationMock, we don't want to
111 // later switch to another GL implementation.
112 DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
114 // Allow the main thread or another to initialize these bindings
115 // after instituting restrictions on I/O. Going forward they will
116 // likely be used in the browser process on most platforms. The
117 // one-time initialization cost is small, between 2 and 5 ms.
118 base::ThreadRestrictions::ScopedAllowIO allow_io;
120 switch (implementation) {
121 case kGLImplementationOSMesaGL: {
122 base::FilePath module_path;
123 if (!PathService::Get(base::DIR_MODULE, &module_path)) {
124 LOG(ERROR) << "PathService::Get failed.";
125 return false;
128 base::NativeLibrary library = base::LoadNativeLibrary(
129 module_path.Append(L"osmesa.dll"), NULL);
130 if (!library) {
131 DVLOG(1) << "osmesa.dll not found";
132 return false;
135 GLGetProcAddressProc get_proc_address =
136 reinterpret_cast<GLGetProcAddressProc>(
137 base::GetFunctionPointerFromNativeLibrary(
138 library, "OSMesaGetProcAddress"));
139 if (!get_proc_address) {
140 DLOG(ERROR) << "OSMesaGetProcAddress not found.";
141 base::UnloadNativeLibrary(library);
142 return false;
145 SetGLGetProcAddressProc(get_proc_address);
146 AddGLNativeLibrary(library);
147 SetGLImplementation(kGLImplementationOSMesaGL);
149 InitializeStaticGLBindingsGL();
150 InitializeStaticGLBindingsOSMESA();
151 break;
153 case kGLImplementationEGLGLES2: {
154 base::FilePath module_path;
155 if (!PathService::Get(base::DIR_MODULE, &module_path))
156 return false;
158 // Attempt to load the D3DX shader compiler using the default search path
159 // and if that fails, using an absolute path. This is to ensure these DLLs
160 // are loaded before ANGLE is loaded in case they are not in the default
161 // search path.
162 LoadD3DXLibrary(module_path, kD3DCompiler);
164 base::FilePath gles_path;
165 const CommandLine* command_line = CommandLine::ForCurrentProcess();
166 bool using_swift_shader =
167 command_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader";
168 if (using_swift_shader) {
169 if (!command_line->HasSwitch(switches::kSwiftShaderPath))
170 return false;
171 gles_path =
172 command_line->GetSwitchValuePath(switches::kSwiftShaderPath);
173 // Preload library
174 LoadLibrary(L"ddraw.dll");
175 } else {
176 gles_path = module_path;
179 // Load libglesv2.dll before libegl.dll because the latter is dependent on
180 // the former and if there is another version of libglesv2.dll in the dll
181 // search path, it will get loaded instead.
182 base::NativeLibrary gles_library = base::LoadNativeLibrary(
183 gles_path.Append(L"libglesv2.dll"), NULL);
184 if (!gles_library) {
185 DVLOG(1) << "libglesv2.dll not found";
186 return false;
189 // When using EGL, first try eglGetProcAddress and then Windows
190 // GetProcAddress on both the EGL and GLES2 DLLs.
191 base::NativeLibrary egl_library = base::LoadNativeLibrary(
192 gles_path.Append(L"libegl.dll"), NULL);
193 if (!egl_library) {
194 DVLOG(1) << "libegl.dll not found.";
195 base::UnloadNativeLibrary(gles_library);
196 return false;
199 #if defined(ENABLE_SWIFTSHADER)
200 if (using_swift_shader) {
201 SetupSoftwareRenderer(gles_library);
203 #endif
205 if (!using_swift_shader) {
206 SetTraceFunctionPointersFunc set_trace_function_pointers =
207 reinterpret_cast<SetTraceFunctionPointersFunc>(
208 base::GetFunctionPointerFromNativeLibrary(
209 gles_library, "SetTraceFunctionPointers"));
210 if (set_trace_function_pointers) {
211 set_trace_function_pointers(&AngleGetTraceCategoryEnabledFlag,
212 &AngleAddTraceEvent);
216 GLGetProcAddressProc get_proc_address =
217 reinterpret_cast<GLGetProcAddressProc>(
218 base::GetFunctionPointerFromNativeLibrary(
219 egl_library, "eglGetProcAddress"));
220 if (!get_proc_address) {
221 LOG(ERROR) << "eglGetProcAddress not found.";
222 base::UnloadNativeLibrary(egl_library);
223 base::UnloadNativeLibrary(gles_library);
224 return false;
227 SetGLGetProcAddressProc(get_proc_address);
228 AddGLNativeLibrary(egl_library);
229 AddGLNativeLibrary(gles_library);
230 SetGLImplementation(kGLImplementationEGLGLES2);
232 InitializeStaticGLBindingsGL();
233 InitializeStaticGLBindingsEGL();
235 // These two functions take single precision float rather than double
236 // precision float parameters in GLES.
237 ::gfx::g_driver_gl.fn.glClearDepthFn = MarshalClearDepthToClearDepthf;
238 ::gfx::g_driver_gl.fn.glDepthRangeFn = MarshalDepthRangeToDepthRangef;
239 break;
241 case kGLImplementationDesktopGL: {
242 base::NativeLibrary library = base::LoadNativeLibrary(
243 base::FilePath(L"opengl32.dll"), NULL);
244 if (!library) {
245 DVLOG(1) << "opengl32.dll not found";
246 return false;
249 GLGetProcAddressProc get_proc_address =
250 reinterpret_cast<GLGetProcAddressProc>(
251 base::GetFunctionPointerFromNativeLibrary(
252 library, "wglGetProcAddress"));
253 if (!get_proc_address) {
254 LOG(ERROR) << "wglGetProcAddress not found.";
255 base::UnloadNativeLibrary(library);
256 return false;
259 SetGLGetProcAddressProc(get_proc_address);
260 AddGLNativeLibrary(library);
261 SetGLImplementation(kGLImplementationDesktopGL);
263 // Initialize GL surface and get some functions needed for the context
264 // creation below.
265 if (!GLSurfaceWGL::InitializeOneOff()) {
266 LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed.";
267 return false;
269 wglCreateContextProc wglCreateContextFn =
270 reinterpret_cast<wglCreateContextProc>(
271 GetGLProcAddress("wglCreateContext"));
272 wglDeleteContextProc wglDeleteContextFn =
273 reinterpret_cast<wglDeleteContextProc>(
274 GetGLProcAddress("wglDeleteContext"));
275 wglMakeCurrentProc wglMakeCurrentFn =
276 reinterpret_cast<wglMakeCurrentProc>(
277 GetGLProcAddress("wglMakeCurrent"));
279 // Create a temporary GL context to bind to entry points. This is needed
280 // because wglGetProcAddress is specified to return NULL for all queries
281 // if a context is not current in MSDN documentation, and the static
282 // bindings may contain functions that need to be queried with
283 // wglGetProcAddress. OpenGL wiki further warns that other error values
284 // than NULL could also be returned from wglGetProcAddress on some
285 // implementations, so we need to clear the WGL bindings and reinitialize
286 // them after the context creation.
287 HGLRC gl_context = wglCreateContextFn(GLSurfaceWGL::GetDisplayDC());
288 if (!gl_context) {
289 LOG(ERROR) << "Failed to create temporary context.";
290 return false;
292 if (!wglMakeCurrentFn(GLSurfaceWGL::GetDisplayDC(), gl_context)) {
293 LOG(ERROR) << "Failed to make temporary GL context current.";
294 wglDeleteContextFn(gl_context);
295 return false;
298 InitializeStaticGLBindingsGL();
299 InitializeStaticGLBindingsWGL();
301 wglMakeCurrent(NULL, NULL);
302 wglDeleteContext(gl_context);
304 break;
306 case kGLImplementationMockGL: {
307 SetGLImplementation(kGLImplementationMockGL);
308 InitializeStaticGLBindingsGL();
309 break;
311 default:
312 return false;
315 return true;
318 bool InitializeDynamicGLBindings(GLImplementation implementation,
319 GLContext* context) {
320 switch (implementation) {
321 case kGLImplementationOSMesaGL:
322 InitializeDynamicGLBindingsGL(context);
323 InitializeDynamicGLBindingsOSMESA(context);
324 break;
325 case kGLImplementationEGLGLES2:
326 InitializeDynamicGLBindingsGL(context);
327 InitializeDynamicGLBindingsEGL(context);
328 break;
329 case kGLImplementationDesktopGL:
330 InitializeDynamicGLBindingsGL(context);
331 InitializeDynamicGLBindingsWGL(context);
332 break;
333 case kGLImplementationMockGL:
334 if (!context) {
335 scoped_refptr<GLContextStubWithExtensions> mock_context(
336 new GLContextStubWithExtensions());
337 mock_context->SetGLVersionString("3.0");
338 InitializeDynamicGLBindingsGL(mock_context.get());
339 } else
340 InitializeDynamicGLBindingsGL(context);
341 break;
342 default:
343 return false;
346 return true;
349 void InitializeDebugGLBindings() {
350 InitializeDebugGLBindingsEGL();
351 InitializeDebugGLBindingsGL();
352 InitializeDebugGLBindingsOSMESA();
353 InitializeDebugGLBindingsWGL();
356 void ClearGLBindings() {
357 ClearGLBindingsEGL();
358 ClearGLBindingsGL();
359 ClearGLBindingsOSMESA();
360 ClearGLBindingsWGL();
361 SetGLImplementation(kGLImplementationNone);
362 UnloadGLNativeLibraries();
365 bool GetGLWindowSystemBindingInfo(GLWindowSystemBindingInfo* info) {
366 switch (GetGLImplementation()) {
367 case kGLImplementationDesktopGL:
368 return GetGLWindowSystemBindingInfoWGL(info);
369 case kGLImplementationEGLGLES2:
370 return GetGLWindowSystemBindingInfoEGL(info);
371 default:
372 return false;
376 } // namespace gfx