WebSocket header continuations test case.
[chromium-blink-merge.git] / ui / gl / gl_implementation_win.cc
blob49ffa891e32d188bf5e191e367e6072ae2fc69e6
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 const unsigned char* AngleGetTraceCategoryEnabledFlag(const char* name) {
65 return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name);
68 void AngleAddTraceEvent(char phase,
69 const unsigned char* category_group_enabled,
70 const char* name,
71 unsigned long long id,
72 int num_args,
73 const char** arg_names,
74 const unsigned char* arg_types,
75 const unsigned long long* arg_values,
76 unsigned char flags) {
77 TRACE_EVENT_API_ADD_TRACE_EVENT(phase,
78 category_group_enabled,
79 name,
80 id,
81 num_args,
82 arg_names,
83 arg_types,
84 arg_values,
85 NULL,
86 flags);
89 typedef const unsigned char* (*GetCategoryEnabledFlagFunc)(const char* name);
90 typedef void (*AddTraceEventFunc)(char phase,
91 const unsigned char* categoryGroupEnabled,
92 const char* name,
93 unsigned long long id,
94 int numArgs,
95 const char** argNames,
96 const unsigned char* argTypes,
97 const unsigned long long* argValues,
98 unsigned char flags);
99 typedef void (__stdcall *SetTraceFunctionPointersFunc)(
100 GetCategoryEnabledFlagFunc get_category_enabled_flag,
101 AddTraceEventFunc add_trace_event_func);
103 // TODO(jmadill): Apply to all platforms eventually
104 base::LazyInstance<ANGLEPlatformImpl> g_angle_platform_impl =
105 LAZY_INSTANCE_INITIALIZER;
107 ANGLEPlatformShutdownFunc g_angle_platform_shutdown = nullptr;
109 } // namespace
111 void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
112 impls->push_back(kGLImplementationEGLGLES2);
113 impls->push_back(kGLImplementationDesktopGL);
114 impls->push_back(kGLImplementationOSMesaGL);
117 bool InitializeStaticGLBindings(GLImplementation implementation) {
118 // Prevent reinitialization with a different implementation. Once the gpu
119 // unit tests have initialized with kGLImplementationMock, we don't want to
120 // later switch to another GL implementation.
121 DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
123 // Allow the main thread or another to initialize these bindings
124 // after instituting restrictions on I/O. Going forward they will
125 // likely be used in the browser process on most platforms. The
126 // one-time initialization cost is small, between 2 and 5 ms.
127 base::ThreadRestrictions::ScopedAllowIO allow_io;
129 switch (implementation) {
130 case kGLImplementationOSMesaGL: {
131 base::FilePath module_path;
132 if (!PathService::Get(base::DIR_MODULE, &module_path)) {
133 LOG(ERROR) << "PathService::Get failed.";
134 return false;
137 base::NativeLibrary library = base::LoadNativeLibrary(
138 module_path.Append(L"osmesa.dll"), NULL);
139 if (!library) {
140 DVLOG(1) << "osmesa.dll not found";
141 return false;
144 GLGetProcAddressProc get_proc_address =
145 reinterpret_cast<GLGetProcAddressProc>(
146 base::GetFunctionPointerFromNativeLibrary(
147 library, "OSMesaGetProcAddress"));
148 if (!get_proc_address) {
149 DLOG(ERROR) << "OSMesaGetProcAddress not found.";
150 base::UnloadNativeLibrary(library);
151 return false;
154 SetGLGetProcAddressProc(get_proc_address);
155 AddGLNativeLibrary(library);
156 SetGLImplementation(kGLImplementationOSMesaGL);
158 InitializeStaticGLBindingsGL();
159 InitializeStaticGLBindingsOSMESA();
160 break;
162 case kGLImplementationEGLGLES2: {
163 base::FilePath module_path;
164 if (!PathService::Get(base::DIR_MODULE, &module_path))
165 return false;
167 // Attempt to load the D3DX shader compiler using the default search path
168 // and if that fails, using an absolute path. This is to ensure these DLLs
169 // are loaded before ANGLE is loaded in case they are not in the default
170 // search path.
171 LoadD3DXLibrary(module_path, kD3DCompiler);
173 base::FilePath gles_path;
174 const base::CommandLine* command_line =
175 base::CommandLine::ForCurrentProcess();
176 bool using_swift_shader =
177 command_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader";
178 if (using_swift_shader) {
179 if (!command_line->HasSwitch(switches::kSwiftShaderPath))
180 return false;
181 gles_path =
182 command_line->GetSwitchValuePath(switches::kSwiftShaderPath);
183 // Preload library
184 LoadLibrary(L"ddraw.dll");
185 } else {
186 gles_path = module_path;
189 // Load libglesv2.dll before libegl.dll because the latter is dependent on
190 // the former and if there is another version of libglesv2.dll in the dll
191 // search path, it will get loaded instead.
192 base::NativeLibrary gles_library = base::LoadNativeLibrary(
193 gles_path.Append(L"libglesv2.dll"), NULL);
194 if (!gles_library) {
195 DVLOG(1) << "libglesv2.dll not found";
196 return false;
199 // When using EGL, first try eglGetProcAddress and then Windows
200 // GetProcAddress on both the EGL and GLES2 DLLs.
201 base::NativeLibrary egl_library = base::LoadNativeLibrary(
202 gles_path.Append(L"libegl.dll"), NULL);
203 if (!egl_library) {
204 DVLOG(1) << "libegl.dll not found.";
205 base::UnloadNativeLibrary(gles_library);
206 return false;
209 #if defined(ENABLE_SWIFTSHADER)
210 if (using_swift_shader) {
211 SetupSoftwareRenderer(gles_library);
213 #endif
215 if (!using_swift_shader) {
216 // TODO(jmadill): remove when platform impl supports tracing
217 SetTraceFunctionPointersFunc set_trace_function_pointers =
218 reinterpret_cast<SetTraceFunctionPointersFunc>(
219 base::GetFunctionPointerFromNativeLibrary(
220 gles_library, "SetTraceFunctionPointers"));
221 if (set_trace_function_pointers) {
222 set_trace_function_pointers(&AngleGetTraceCategoryEnabledFlag,
223 &AngleAddTraceEvent);
226 // Init ANGLE platform here, before we call GetPlatformDisplay().
227 // TODO(jmadill): Apply to all platforms eventually
228 ANGLEPlatformInitializeFunc angle_platform_init =
229 reinterpret_cast<ANGLEPlatformInitializeFunc>(
230 base::GetFunctionPointerFromNativeLibrary(
231 gles_library,
232 "ANGLEPlatformInitialize"));
233 if (angle_platform_init) {
234 angle_platform_init(&g_angle_platform_impl.Get());
236 g_angle_platform_shutdown =
237 reinterpret_cast<ANGLEPlatformShutdownFunc>(
238 base::GetFunctionPointerFromNativeLibrary(
239 gles_library,
240 "ANGLEPlatformShutdown"));
244 GLGetProcAddressProc get_proc_address =
245 reinterpret_cast<GLGetProcAddressProc>(
246 base::GetFunctionPointerFromNativeLibrary(
247 egl_library, "eglGetProcAddress"));
248 if (!get_proc_address) {
249 LOG(ERROR) << "eglGetProcAddress not found.";
250 base::UnloadNativeLibrary(egl_library);
251 base::UnloadNativeLibrary(gles_library);
252 return false;
255 SetGLGetProcAddressProc(get_proc_address);
256 AddGLNativeLibrary(egl_library);
257 AddGLNativeLibrary(gles_library);
258 SetGLImplementation(kGLImplementationEGLGLES2);
260 InitializeStaticGLBindingsGL();
261 InitializeStaticGLBindingsEGL();
263 // These two functions take single precision float rather than double
264 // precision float parameters in GLES.
265 ::gfx::g_driver_gl.fn.glClearDepthFn = MarshalClearDepthToClearDepthf;
266 ::gfx::g_driver_gl.fn.glDepthRangeFn = MarshalDepthRangeToDepthRangef;
267 break;
269 case kGLImplementationDesktopGL: {
270 base::NativeLibrary library = base::LoadNativeLibrary(
271 base::FilePath(L"opengl32.dll"), NULL);
272 if (!library) {
273 DVLOG(1) << "opengl32.dll not found";
274 return false;
277 GLGetProcAddressProc get_proc_address =
278 reinterpret_cast<GLGetProcAddressProc>(
279 base::GetFunctionPointerFromNativeLibrary(
280 library, "wglGetProcAddress"));
281 if (!get_proc_address) {
282 LOG(ERROR) << "wglGetProcAddress not found.";
283 base::UnloadNativeLibrary(library);
284 return false;
287 SetGLGetProcAddressProc(get_proc_address);
288 AddGLNativeLibrary(library);
289 SetGLImplementation(kGLImplementationDesktopGL);
291 // Initialize GL surface and get some functions needed for the context
292 // creation below.
293 if (!GLSurfaceWGL::InitializeOneOff()) {
294 LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed.";
295 return false;
297 wglCreateContextProc wglCreateContextFn =
298 reinterpret_cast<wglCreateContextProc>(
299 GetGLProcAddress("wglCreateContext"));
300 wglDeleteContextProc wglDeleteContextFn =
301 reinterpret_cast<wglDeleteContextProc>(
302 GetGLProcAddress("wglDeleteContext"));
303 wglMakeCurrentProc wglMakeCurrentFn =
304 reinterpret_cast<wglMakeCurrentProc>(
305 GetGLProcAddress("wglMakeCurrent"));
307 // Create a temporary GL context to bind to entry points. This is needed
308 // because wglGetProcAddress is specified to return NULL for all queries
309 // if a context is not current in MSDN documentation, and the static
310 // bindings may contain functions that need to be queried with
311 // wglGetProcAddress. OpenGL wiki further warns that other error values
312 // than NULL could also be returned from wglGetProcAddress on some
313 // implementations, so we need to clear the WGL bindings and reinitialize
314 // them after the context creation.
315 HGLRC gl_context = wglCreateContextFn(GLSurfaceWGL::GetDisplayDC());
316 if (!gl_context) {
317 LOG(ERROR) << "Failed to create temporary context.";
318 return false;
320 if (!wglMakeCurrentFn(GLSurfaceWGL::GetDisplayDC(), gl_context)) {
321 LOG(ERROR) << "Failed to make temporary GL context current.";
322 wglDeleteContextFn(gl_context);
323 return false;
326 InitializeStaticGLBindingsGL();
327 InitializeStaticGLBindingsWGL();
329 wglMakeCurrent(NULL, NULL);
330 wglDeleteContext(gl_context);
332 break;
334 case kGLImplementationMockGL: {
335 SetGLImplementation(kGLImplementationMockGL);
336 InitializeStaticGLBindingsGL();
337 break;
339 default:
340 return false;
343 return true;
346 bool InitializeDynamicGLBindings(GLImplementation implementation,
347 GLContext* context) {
348 switch (implementation) {
349 case kGLImplementationOSMesaGL:
350 case kGLImplementationEGLGLES2:
351 case kGLImplementationDesktopGL:
352 InitializeDynamicGLBindingsGL(context);
353 break;
354 case kGLImplementationMockGL:
355 if (!context) {
356 scoped_refptr<GLContextStubWithExtensions> mock_context(
357 new GLContextStubWithExtensions());
358 mock_context->SetGLVersionString("3.0");
359 InitializeDynamicGLBindingsGL(mock_context.get());
360 } else
361 InitializeDynamicGLBindingsGL(context);
362 break;
363 default:
364 return false;
367 return true;
370 void InitializeDebugGLBindings() {
371 InitializeDebugGLBindingsEGL();
372 InitializeDebugGLBindingsGL();
373 InitializeDebugGLBindingsOSMESA();
374 InitializeDebugGLBindingsWGL();
377 void ClearGLBindings() {
378 // TODO(jmadill): Apply to all platforms eventually
379 if (g_angle_platform_shutdown) {
380 g_angle_platform_shutdown();
383 ClearGLBindingsEGL();
384 ClearGLBindingsGL();
385 ClearGLBindingsOSMESA();
386 ClearGLBindingsWGL();
387 SetGLImplementation(kGLImplementationNone);
388 UnloadGLNativeLibraries();
391 bool GetGLWindowSystemBindingInfo(GLWindowSystemBindingInfo* info) {
392 switch (GetGLImplementation()) {
393 case kGLImplementationDesktopGL:
394 return GetGLWindowSystemBindingInfoWGL(info);
395 case kGLImplementationEGLGLES2:
396 return GetGLWindowSystemBindingInfoEGL(info);
397 default:
398 return false;
402 } // namespace gfx