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 <vector> 6 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" 27 28#if defined(ENABLE_SWIFTSHADER) 29#include "software_renderer.h" 30#endif 31 32namespace gfx { 33 34namespace { 35 36const wchar_t kD3DCompiler[] = L"D3DCompiler_46.dll"; 37 38void GL_BINDING_CALL MarshalClearDepthToClearDepthf(GLclampd depth) { 39 glClearDepthf(static_cast<GLclampf>(depth)); 40} 41 42void GL_BINDING_CALL MarshalDepthRangeToDepthRangef(GLclampd z_near, 43 GLclampd z_far) { 44 glDepthRangef(static_cast<GLclampf>(z_near), static_cast<GLclampf>(z_far)); 45} 46 47bool 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; 56 } 57 } 58 return true; 59} 60 61const unsigned char* AngleGetTraceCategoryEnabledFlag(const char* name) { 62 return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name); 63} 64 65void 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); 84} 85 86typedef const unsigned char* (*GetCategoryEnabledFlagFunc)(const char* name); 87typedef 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); 96typedef void (__stdcall *SetTraceFunctionPointersFunc)( 97 GetCategoryEnabledFlagFunc get_category_enabled_flag, 98 AddTraceEventFunc add_trace_event_func); 99 100} // namespace 101 102void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) { 103 impls->push_back(kGLImplementationEGLGLES2); 104 impls->push_back(kGLImplementationDesktopGL); 105 impls->push_back(kGLImplementationOSMesaGL); 106} 107 108bool 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()); 113 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; 119 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; 126 } 127 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; 133 } 134 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; 143 } 144 145 SetGLGetProcAddressProc(get_proc_address); 146 AddGLNativeLibrary(library); 147 SetGLImplementation(kGLImplementationOSMesaGL); 148 149 InitializeStaticGLBindingsGL(); 150 InitializeStaticGLBindingsOSMESA(); 151 break; 152 } 153 case kGLImplementationEGLGLES2: { 154 base::FilePath module_path; 155 if (!PathService::Get(base::DIR_MODULE, &module_path)) 156 return false; 157 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); 163 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; 177 } 178 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; 187 } 188 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; 197 } 198 199#if defined(ENABLE_SWIFTSHADER) 200 if (using_swift_shader) { 201 SetupSoftwareRenderer(gles_library); 202 } 203#endif 204 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); 213 } 214 } 215 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; 225 } 226 227 SetGLGetProcAddressProc(get_proc_address); 228 AddGLNativeLibrary(egl_library); 229 AddGLNativeLibrary(gles_library); 230 SetGLImplementation(kGLImplementationEGLGLES2); 231 232 InitializeStaticGLBindingsGL(); 233 InitializeStaticGLBindingsEGL(); 234 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; 240 } 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; 247 } 248 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; 257 } 258 259 SetGLGetProcAddressProc(get_proc_address); 260 AddGLNativeLibrary(library); 261 SetGLImplementation(kGLImplementationDesktopGL); 262 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; 268 } 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")); 278 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; 291 } 292 if (!wglMakeCurrentFn(GLSurfaceWGL::GetDisplayDC(), gl_context)) { 293 LOG(ERROR) << "Failed to make temporary GL context current."; 294 wglDeleteContextFn(gl_context); 295 return false; 296 } 297 298 InitializeStaticGLBindingsGL(); 299 InitializeStaticGLBindingsWGL(); 300 301 wglMakeCurrent(NULL, NULL); 302 wglDeleteContext(gl_context); 303 304 break; 305 } 306 case kGLImplementationMockGL: { 307 SetGLImplementation(kGLImplementationMockGL); 308 InitializeStaticGLBindingsGL(); 309 break; 310 } 311 default: 312 return false; 313 } 314 315 return true; 316} 317 318bool 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; 344 } 345 346 return true; 347} 348 349void InitializeDebugGLBindings() { 350 InitializeDebugGLBindingsEGL(); 351 InitializeDebugGLBindingsGL(); 352 InitializeDebugGLBindingsOSMESA(); 353 InitializeDebugGLBindingsWGL(); 354} 355 356void ClearGLBindings() { 357 ClearGLBindingsEGL(); 358 ClearGLBindingsGL(); 359 ClearGLBindingsOSMESA(); 360 ClearGLBindingsWGL(); 361 SetGLImplementation(kGLImplementationNone); 362 UnloadGLNativeLibraries(); 363} 364 365bool 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; 373 } 374} 375 376} // namespace gfx 377