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/files/file_path.h" 12#include "base/logging.h" 13#include "base/native_library.h" 14#include "base/path_service.h" 15#include "base/strings/stringprintf.h" 16#include "base/threading/thread_restrictions.h" 17#include "base/win/windows_version.h" 18#include "ui/gl/gl_bindings.h" 19#include "ui/gl/gl_egl_api_implementation.h" 20#include "ui/gl/gl_gl_api_implementation.h" 21#include "ui/gl/gl_implementation.h" 22#include "ui/gl/gl_osmesa_api_implementation.h" 23#include "ui/gl/gl_wgl_api_implementation.h" 24 25#if defined(ENABLE_SWIFTSHADER) 26#include "software_renderer.h" 27#endif 28 29namespace gfx { 30 31namespace { 32 33// Version 43 is the latest version of D3DCompiler_nn.dll that works prior to 34// Windows Vista. 35const wchar_t kPreVistaD3DCompiler[] = L"D3DCompiler_43.dll"; 36const wchar_t kPostVistaD3DCompiler[] = 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 61} // namespace 62 63void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) { 64 impls->push_back(kGLImplementationEGLGLES2); 65 impls->push_back(kGLImplementationDesktopGL); 66 impls->push_back(kGLImplementationOSMesaGL); 67} 68 69bool InitializeGLBindings(GLImplementation implementation) { 70 // Prevent reinitialization with a different implementation. Once the gpu 71 // unit tests have initialized with kGLImplementationMock, we don't want to 72 // later switch to another GL implementation. 73 if (GetGLImplementation() != kGLImplementationNone) 74 return true; 75 76 // Allow the main thread or another to initialize these bindings 77 // after instituting restrictions on I/O. Going forward they will 78 // likely be used in the browser process on most platforms. The 79 // one-time initialization cost is small, between 2 and 5 ms. 80 base::ThreadRestrictions::ScopedAllowIO allow_io; 81 82 switch (implementation) { 83 case kGLImplementationOSMesaGL: { 84 base::FilePath module_path; 85 if (!PathService::Get(base::DIR_MODULE, &module_path)) { 86 LOG(ERROR) << "PathService::Get failed."; 87 return false; 88 } 89 90 base::NativeLibrary library = base::LoadNativeLibrary( 91 module_path.Append(L"osmesa.dll"), NULL); 92 if (!library) { 93 DVLOG(1) << "osmesa.dll not found"; 94 return false; 95 } 96 97 GLGetProcAddressProc get_proc_address = 98 reinterpret_cast<GLGetProcAddressProc>( 99 base::GetFunctionPointerFromNativeLibrary( 100 library, "OSMesaGetProcAddress")); 101 if (!get_proc_address) { 102 DLOG(ERROR) << "OSMesaGetProcAddress not found."; 103 base::UnloadNativeLibrary(library); 104 return false; 105 } 106 107 SetGLGetProcAddressProc(get_proc_address); 108 AddGLNativeLibrary(library); 109 SetGLImplementation(kGLImplementationOSMesaGL); 110 111 InitializeGLBindingsGL(); 112 InitializeGLBindingsOSMESA(); 113 break; 114 } 115 case kGLImplementationEGLGLES2: { 116 base::FilePath module_path; 117 if (!PathService::Get(base::DIR_MODULE, &module_path)) 118 return false; 119 120 // Attempt to load the D3DX shader compiler using the default search path 121 // and if that fails, using an absolute path. This is to ensure these DLLs 122 // are loaded before ANGLE is loaded in case they are not in the default 123 // search path. Prefer the post vista version. 124 if (base::win::GetVersion() < base::win::VERSION_VISTA || 125 !LoadD3DXLibrary(module_path, kPostVistaD3DCompiler)) { 126 LoadD3DXLibrary(module_path, kPreVistaD3DCompiler); 127 } 128 129 base::FilePath gles_path; 130 const CommandLine* command_line = CommandLine::ForCurrentProcess(); 131 bool using_swift_shader = 132 command_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader"; 133 if (using_swift_shader) { 134 if (!command_line->HasSwitch(switches::kSwiftShaderPath)) 135 return false; 136 gles_path = 137 command_line->GetSwitchValuePath(switches::kSwiftShaderPath); 138 // Preload library 139 LoadLibrary(L"ddraw.dll"); 140 } else { 141 gles_path = module_path; 142 } 143 144 // Load libglesv2.dll before libegl.dll because the latter is dependent on 145 // the former and if there is another version of libglesv2.dll in the dll 146 // search path, it will get loaded instead. 147 base::NativeLibrary gles_library = base::LoadNativeLibrary( 148 gles_path.Append(L"libglesv2.dll"), NULL); 149 if (!gles_library) { 150 DVLOG(1) << "libglesv2.dll not found"; 151 return false; 152 } 153 154 // When using EGL, first try eglGetProcAddress and then Windows 155 // GetProcAddress on both the EGL and GLES2 DLLs. 156 base::NativeLibrary egl_library = base::LoadNativeLibrary( 157 gles_path.Append(L"libegl.dll"), NULL); 158 if (!egl_library) { 159 DVLOG(1) << "libegl.dll not found."; 160 base::UnloadNativeLibrary(gles_library); 161 return false; 162 } 163 164#if defined(ENABLE_SWIFTSHADER) 165 if (using_swift_shader) { 166 SetupSoftwareRenderer(gles_library); 167 } 168#endif 169 170 GLGetProcAddressProc get_proc_address = 171 reinterpret_cast<GLGetProcAddressProc>( 172 base::GetFunctionPointerFromNativeLibrary( 173 egl_library, "eglGetProcAddress")); 174 if (!get_proc_address) { 175 LOG(ERROR) << "eglGetProcAddress not found."; 176 base::UnloadNativeLibrary(egl_library); 177 base::UnloadNativeLibrary(gles_library); 178 return false; 179 } 180 181 SetGLGetProcAddressProc(get_proc_address); 182 AddGLNativeLibrary(egl_library); 183 AddGLNativeLibrary(gles_library); 184 SetGLImplementation(kGLImplementationEGLGLES2); 185 186 InitializeGLBindingsGL(); 187 InitializeGLBindingsEGL(); 188 189 // These two functions take single precision float rather than double 190 // precision float parameters in GLES. 191 ::gfx::g_driver_gl.fn.glClearDepthFn = MarshalClearDepthToClearDepthf; 192 ::gfx::g_driver_gl.fn.glDepthRangeFn = MarshalDepthRangeToDepthRangef; 193 break; 194 } 195 case kGLImplementationDesktopGL: { 196 // When using Windows OpenGL, first try wglGetProcAddress and then 197 // Windows GetProcAddress. 198 base::NativeLibrary library = base::LoadNativeLibrary( 199 base::FilePath(L"opengl32.dll"), NULL); 200 if (!library) { 201 DVLOG(1) << "opengl32.dll not found"; 202 return false; 203 } 204 205 GLGetProcAddressProc get_proc_address = 206 reinterpret_cast<GLGetProcAddressProc>( 207 base::GetFunctionPointerFromNativeLibrary( 208 library, "wglGetProcAddress")); 209 if (!get_proc_address) { 210 LOG(ERROR) << "wglGetProcAddress not found."; 211 base::UnloadNativeLibrary(library); 212 return false; 213 } 214 215 SetGLGetProcAddressProc(get_proc_address); 216 AddGLNativeLibrary(library); 217 SetGLImplementation(kGLImplementationDesktopGL); 218 219 InitializeGLBindingsGL(); 220 InitializeGLBindingsWGL(); 221 break; 222 } 223 case kGLImplementationMockGL: { 224 SetGLGetProcAddressProc(GetMockGLProcAddress); 225 SetGLImplementation(kGLImplementationMockGL); 226 InitializeGLBindingsGL(); 227 break; 228 } 229 default: 230 return false; 231 } 232 233 return true; 234} 235 236bool InitializeGLExtensionBindings(GLImplementation implementation, 237 GLContext* context) { 238 switch (implementation) { 239 case kGLImplementationOSMesaGL: 240 InitializeGLExtensionBindingsGL(context); 241 InitializeGLExtensionBindingsOSMESA(context); 242 break; 243 case kGLImplementationEGLGLES2: 244 InitializeGLExtensionBindingsGL(context); 245 InitializeGLExtensionBindingsEGL(context); 246 break; 247 case kGLImplementationDesktopGL: 248 InitializeGLExtensionBindingsGL(context); 249 InitializeGLExtensionBindingsWGL(context); 250 break; 251 case kGLImplementationMockGL: 252 InitializeGLExtensionBindingsGL(context); 253 break; 254 default: 255 return false; 256 } 257 258 return true; 259} 260 261void InitializeDebugGLBindings() { 262 InitializeDebugGLBindingsEGL(); 263 InitializeDebugGLBindingsGL(); 264 InitializeDebugGLBindingsOSMESA(); 265 InitializeDebugGLBindingsWGL(); 266} 267 268void ClearGLBindings() { 269 ClearGLBindingsEGL(); 270 ClearGLBindingsGL(); 271 ClearGLBindingsOSMESA(); 272 ClearGLBindingsWGL(); 273 SetGLImplementation(kGLImplementationNone); 274 UnloadGLNativeLibraries(); 275} 276 277bool GetGLWindowSystemBindingInfo(GLWindowSystemBindingInfo* info) { 278 switch (GetGLImplementation()) { 279 case kGLImplementationDesktopGL: 280 return GetGLWindowSystemBindingInfoWGL(info); 281 case kGLImplementationEGLGLES2: 282 return GetGLWindowSystemBindingInfoEGL(info); 283 default: 284 return false; 285 } 286 return false; 287} 288 289} // namespace gfx 290