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_egl_api_implementation.h" 21 #include "ui/gl/gl_gl_api_implementation.h" 22 #include "ui/gl/gl_implementation.h" 23 #include "ui/gl/gl_osmesa_api_implementation.h" 24 #include "ui/gl/gl_wgl_api_implementation.h" 25 26 #if defined(ENABLE_SWIFTSHADER) 27 #include "software_renderer.h" 28 #endif 29 30 namespace gfx { 31 32 namespace { 33 34 // Version 43 is the latest version of D3DCompiler_nn.dll that works prior to 35 // Windows Vista. 36 const wchar_t kPreVistaD3DCompiler[] = L"D3DCompiler_43.dll"; 37 const wchar_t kPostVistaD3DCompiler[] = L"D3DCompiler_46.dll"; 38 39 void GL_BINDING_CALL MarshalClearDepthToClearDepthf(GLclampd depth) { 40 glClearDepthf(static_cast<GLclampf>(depth)); 41 } 42 43 void GL_BINDING_CALL MarshalDepthRangeToDepthRangef(GLclampd z_near, 44 GLclampd z_far) { 45 glDepthRangef(static_cast<GLclampf>(z_near), static_cast<GLclampf>(z_far)); 46 } 47 48 bool LoadD3DXLibrary(const base::FilePath& module_path, 49 const base::FilePath::StringType& name) { 50 base::NativeLibrary library = 51 base::LoadNativeLibrary(base::FilePath(name), NULL); 52 if (!library) { 53 library = base::LoadNativeLibrary(module_path.Append(name), NULL); 54 if (!library) { 55 DVLOG(1) << name << " not found."; 56 return false; 57 } 58 } 59 return true; 60 } 61 62 const unsigned char* AngleGetTraceCategoryEnabledFlag(const char* name) { 63 return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name); 64 } 65 66 void AngleAddTraceEvent(char phase, 67 const unsigned char* category_group_enabled, 68 const char* name, 69 unsigned long long id, 70 int num_args, 71 const char** arg_names, 72 const unsigned char* arg_types, 73 const unsigned long long* arg_values, 74 unsigned char flags) { 75 TRACE_EVENT_API_ADD_TRACE_EVENT(phase, 76 category_group_enabled, 77 name, 78 id, 79 num_args, 80 arg_names, 81 arg_types, 82 arg_values, 83 NULL, 84 flags); 85 } 86 87 typedef const unsigned char* (*GetCategoryEnabledFlagFunc)(const char* name); 88 typedef void (*AddTraceEventFunc)(char phase, 89 const unsigned char* categoryGroupEnabled, 90 const char* name, 91 unsigned long long id, 92 int numArgs, 93 const char** argNames, 94 const unsigned char* argTypes, 95 const unsigned long long* argValues, 96 unsigned char flags); 97 typedef void (__stdcall *SetTraceFunctionPointersFunc)( 98 GetCategoryEnabledFlagFunc get_category_enabled_flag, 99 AddTraceEventFunc add_trace_event_func); 100 101 } // namespace 102 103 void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) { 104 impls->push_back(kGLImplementationEGLGLES2); 105 impls->push_back(kGLImplementationDesktopGL); 106 impls->push_back(kGLImplementationOSMesaGL); 107 } 108 109 bool InitializeGLBindings(GLImplementation implementation) { 110 // Prevent reinitialization with a different implementation. Once the gpu 111 // unit tests have initialized with kGLImplementationMock, we don't want to 112 // later switch to another GL implementation. 113 if (GetGLImplementation() != kGLImplementationNone) 114 return true; 115 116 // Allow the main thread or another to initialize these bindings 117 // after instituting restrictions on I/O. Going forward they will 118 // likely be used in the browser process on most platforms. The 119 // one-time initialization cost is small, between 2 and 5 ms. 120 base::ThreadRestrictions::ScopedAllowIO allow_io; 121 122 switch (implementation) { 123 case kGLImplementationOSMesaGL: { 124 base::FilePath module_path; 125 if (!PathService::Get(base::DIR_MODULE, &module_path)) { 126 LOG(ERROR) << "PathService::Get failed."; 127 return false; 128 } 129 130 base::NativeLibrary library = base::LoadNativeLibrary( 131 module_path.Append(L"osmesa.dll"), NULL); 132 if (!library) { 133 DVLOG(1) << "osmesa.dll not found"; 134 return false; 135 } 136 137 GLGetProcAddressProc get_proc_address = 138 reinterpret_cast<GLGetProcAddressProc>( 139 base::GetFunctionPointerFromNativeLibrary( 140 library, "OSMesaGetProcAddress")); 141 if (!get_proc_address) { 142 DLOG(ERROR) << "OSMesaGetProcAddress not found."; 143 base::UnloadNativeLibrary(library); 144 return false; 145 } 146 147 SetGLGetProcAddressProc(get_proc_address); 148 AddGLNativeLibrary(library); 149 SetGLImplementation(kGLImplementationOSMesaGL); 150 151 InitializeGLBindingsGL(); 152 InitializeGLBindingsOSMESA(); 153 break; 154 } 155 case kGLImplementationEGLGLES2: { 156 base::FilePath module_path; 157 if (!PathService::Get(base::DIR_MODULE, &module_path)) 158 return false; 159 160 // Attempt to load the D3DX shader compiler using the default search path 161 // and if that fails, using an absolute path. This is to ensure these DLLs 162 // are loaded before ANGLE is loaded in case they are not in the default 163 // search path. Prefer the post vista version. 164 if (base::win::GetVersion() < base::win::VERSION_VISTA || 165 !LoadD3DXLibrary(module_path, kPostVistaD3DCompiler)) { 166 LoadD3DXLibrary(module_path, kPreVistaD3DCompiler); 167 } 168 169 base::FilePath gles_path; 170 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 171 bool using_swift_shader = 172 command_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader"; 173 if (using_swift_shader) { 174 if (!command_line->HasSwitch(switches::kSwiftShaderPath)) 175 return false; 176 gles_path = 177 command_line->GetSwitchValuePath(switches::kSwiftShaderPath); 178 // Preload library 179 LoadLibrary(L"ddraw.dll"); 180 } else { 181 gles_path = module_path; 182 } 183 184 // Load libglesv2.dll before libegl.dll because the latter is dependent on 185 // the former and if there is another version of libglesv2.dll in the dll 186 // search path, it will get loaded instead. 187 base::NativeLibrary gles_library = base::LoadNativeLibrary( 188 gles_path.Append(L"libglesv2.dll"), NULL); 189 if (!gles_library) { 190 DVLOG(1) << "libglesv2.dll not found"; 191 return false; 192 } 193 194 // When using EGL, first try eglGetProcAddress and then Windows 195 // GetProcAddress on both the EGL and GLES2 DLLs. 196 base::NativeLibrary egl_library = base::LoadNativeLibrary( 197 gles_path.Append(L"libegl.dll"), NULL); 198 if (!egl_library) { 199 DVLOG(1) << "libegl.dll not found."; 200 base::UnloadNativeLibrary(gles_library); 201 return false; 202 } 203 204 #if defined(ENABLE_SWIFTSHADER) 205 if (using_swift_shader) { 206 SetupSoftwareRenderer(gles_library); 207 } 208 #endif 209 210 if (!using_swift_shader) { 211 SetTraceFunctionPointersFunc set_trace_function_pointers = 212 reinterpret_cast<SetTraceFunctionPointersFunc>( 213 base::GetFunctionPointerFromNativeLibrary( 214 gles_library, "SetTraceFunctionPointers")); 215 if (set_trace_function_pointers) { 216 set_trace_function_pointers(&AngleGetTraceCategoryEnabledFlag, 217 &AngleAddTraceEvent); 218 } 219 } 220 221 GLGetProcAddressProc get_proc_address = 222 reinterpret_cast<GLGetProcAddressProc>( 223 base::GetFunctionPointerFromNativeLibrary( 224 egl_library, "eglGetProcAddress")); 225 if (!get_proc_address) { 226 LOG(ERROR) << "eglGetProcAddress not found."; 227 base::UnloadNativeLibrary(egl_library); 228 base::UnloadNativeLibrary(gles_library); 229 return false; 230 } 231 232 SetGLGetProcAddressProc(get_proc_address); 233 AddGLNativeLibrary(egl_library); 234 AddGLNativeLibrary(gles_library); 235 SetGLImplementation(kGLImplementationEGLGLES2); 236 237 InitializeGLBindingsGL(); 238 InitializeGLBindingsEGL(); 239 240 // These two functions take single precision float rather than double 241 // precision float parameters in GLES. 242 ::gfx::g_driver_gl.fn.glClearDepthFn = MarshalClearDepthToClearDepthf; 243 ::gfx::g_driver_gl.fn.glDepthRangeFn = MarshalDepthRangeToDepthRangef; 244 break; 245 } 246 case kGLImplementationDesktopGL: { 247 // When using Windows OpenGL, first try wglGetProcAddress and then 248 // Windows GetProcAddress. 249 base::NativeLibrary library = base::LoadNativeLibrary( 250 base::FilePath(L"opengl32.dll"), NULL); 251 if (!library) { 252 DVLOG(1) << "opengl32.dll not found"; 253 return false; 254 } 255 256 GLGetProcAddressProc get_proc_address = 257 reinterpret_cast<GLGetProcAddressProc>( 258 base::GetFunctionPointerFromNativeLibrary( 259 library, "wglGetProcAddress")); 260 if (!get_proc_address) { 261 LOG(ERROR) << "wglGetProcAddress not found."; 262 base::UnloadNativeLibrary(library); 263 return false; 264 } 265 266 SetGLGetProcAddressProc(get_proc_address); 267 AddGLNativeLibrary(library); 268 SetGLImplementation(kGLImplementationDesktopGL); 269 270 InitializeGLBindingsGL(); 271 InitializeGLBindingsWGL(); 272 break; 273 } 274 case kGLImplementationMockGL: { 275 SetGLGetProcAddressProc(GetMockGLProcAddress); 276 SetGLImplementation(kGLImplementationMockGL); 277 InitializeGLBindingsGL(); 278 break; 279 } 280 default: 281 return false; 282 } 283 284 return true; 285 } 286 287 bool InitializeGLExtensionBindings(GLImplementation implementation, 288 GLContext* context) { 289 switch (implementation) { 290 case kGLImplementationOSMesaGL: 291 InitializeGLExtensionBindingsGL(context); 292 InitializeGLExtensionBindingsOSMESA(context); 293 break; 294 case kGLImplementationEGLGLES2: 295 InitializeGLExtensionBindingsGL(context); 296 InitializeGLExtensionBindingsEGL(context); 297 break; 298 case kGLImplementationDesktopGL: 299 InitializeGLExtensionBindingsGL(context); 300 InitializeGLExtensionBindingsWGL(context); 301 break; 302 case kGLImplementationMockGL: 303 InitializeGLExtensionBindingsGL(context); 304 break; 305 default: 306 return false; 307 } 308 309 return true; 310 } 311 312 void InitializeDebugGLBindings() { 313 InitializeDebugGLBindingsEGL(); 314 InitializeDebugGLBindingsGL(); 315 InitializeDebugGLBindingsOSMESA(); 316 InitializeDebugGLBindingsWGL(); 317 } 318 319 void ClearGLBindings() { 320 ClearGLBindingsEGL(); 321 ClearGLBindingsGL(); 322 ClearGLBindingsOSMESA(); 323 ClearGLBindingsWGL(); 324 SetGLImplementation(kGLImplementationNone); 325 UnloadGLNativeLibraries(); 326 } 327 328 bool GetGLWindowSystemBindingInfo(GLWindowSystemBindingInfo* info) { 329 switch (GetGLImplementation()) { 330 case kGLImplementationDesktopGL: 331 return GetGLWindowSystemBindingInfoWGL(info); 332 case kGLImplementationEGLGLES2: 333 return GetGLWindowSystemBindingInfoEGL(info); 334 default: 335 return false; 336 } 337 return false; 338 } 339 340 } // namespace gfx 341