Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / gl / gl_surface_egl.cc
blob2e193a5d5dc2e2fcff8043065594bee13300930c
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 "ui/gl/gl_surface_egl.h"
7 #if defined(OS_ANDROID)
8 #include <android/native_window_jni.h>
9 #endif
11 #include "base/command_line.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/trace_event/trace_event.h"
16 #include "build/build_config.h"
17 #include "ui/gfx/geometry/rect.h"
18 #include "ui/gl/egl_util.h"
19 #include "ui/gl/gl_context.h"
20 #include "ui/gl/gl_implementation.h"
21 #include "ui/gl/gl_surface_stub.h"
22 #include "ui/gl/gl_switches.h"
23 #include "ui/gl/scoped_make_current.h"
24 #include "ui/gl/sync_control_vsync_provider.h"
26 #if defined(USE_X11)
27 extern "C" {
28 #include <X11/Xlib.h>
30 #endif
32 #if defined (USE_OZONE)
33 #include "ui/ozone/public/ozone_platform.h"
34 #include "ui/ozone/public/surface_factory_ozone.h"
35 #endif
37 #if !defined(EGL_FIXED_SIZE_ANGLE)
38 #define EGL_FIXED_SIZE_ANGLE 0x3201
39 #endif
41 #if !defined(EGL_OPENGL_ES3_BIT)
42 #define EGL_OPENGL_ES3_BIT 0x00000040
43 #endif
45 // From ANGLE's egl/eglext.h.
47 #ifndef EGL_ANGLE_platform_angle
48 #define EGL_ANGLE_platform_angle 1
49 #define EGL_PLATFORM_ANGLE_ANGLE 0x3202
50 #define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203
51 #define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3204
52 #define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3205
53 #define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3206
54 #endif /* EGL_ANGLE_platform_angle */
56 #ifndef EGL_ANGLE_platform_angle_d3d
57 #define EGL_ANGLE_platform_angle_d3d 1
58 #define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207
59 #define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208
60 #define EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE 0x3209
61 #define EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE 0x320A
62 #define EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE 0x320B
63 #define EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE 0x320C
64 #endif /* EGL_ANGLE_platform_angle_d3d */
66 #ifndef EGL_ANGLE_platform_angle_opengl
67 #define EGL_ANGLE_platform_angle_opengl 1
68 #define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320D
69 #define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320E
70 #endif /* EGL_ANGLE_platform_angle_opengl */
72 using ui::GetLastEGLErrorString;
74 namespace gfx {
76 #if defined(OS_WIN)
77 unsigned int NativeViewGLSurfaceEGL::current_swap_generation_ = 0;
78 unsigned int NativeViewGLSurfaceEGL::swaps_this_generation_ = 0;
79 unsigned int NativeViewGLSurfaceEGL::last_multiswap_generation_ = 0;
81 const unsigned int MULTISWAP_FRAME_VSYNC_THRESHOLD = 60;
82 #endif
84 namespace {
86 EGLConfig g_config;
87 EGLDisplay g_display;
88 EGLNativeDisplayType g_native_display_type;
90 // In the Cast environment, we need to destroy the EGLNativeDisplayType and
91 // EGLDisplay returned by the GPU platform when we switch to an external app
92 // which will temporarily own all screen and GPU resources.
93 // Even though Chromium is still in the background.
94 // As such, it must be reinitialized each time we come back to the foreground.
95 bool g_initialized = false;
96 int g_num_surfaces = 0;
97 bool g_terminate_pending = false;
99 const char* g_egl_extensions = NULL;
100 bool g_egl_create_context_robustness_supported = false;
101 bool g_egl_sync_control_supported = false;
102 bool g_egl_window_fixed_size_supported = false;
103 bool g_egl_surfaceless_context_supported = false;
105 class EGLSyncControlVSyncProvider
106 : public gfx::SyncControlVSyncProvider {
107 public:
108 explicit EGLSyncControlVSyncProvider(EGLSurface surface)
109 : SyncControlVSyncProvider(),
110 surface_(surface) {
113 ~EGLSyncControlVSyncProvider() override {}
115 protected:
116 bool GetSyncValues(int64* system_time,
117 int64* media_stream_counter,
118 int64* swap_buffer_counter) override {
119 uint64 u_system_time, u_media_stream_counter, u_swap_buffer_counter;
120 bool result = eglGetSyncValuesCHROMIUM(
121 g_display, surface_, &u_system_time,
122 &u_media_stream_counter, &u_swap_buffer_counter) == EGL_TRUE;
123 if (result) {
124 *system_time = static_cast<int64>(u_system_time);
125 *media_stream_counter = static_cast<int64>(u_media_stream_counter);
126 *swap_buffer_counter = static_cast<int64>(u_swap_buffer_counter);
128 return result;
131 bool GetMscRate(int32* numerator, int32* denominator) override {
132 return false;
135 private:
136 EGLSurface surface_;
138 DISALLOW_COPY_AND_ASSIGN(EGLSyncControlVSyncProvider);
141 void DeinitializeEgl() {
142 if (g_initialized) {
143 g_initialized = false;
144 eglTerminate(g_display);
148 EGLDisplay GetPlatformANGLEDisplay(EGLNativeDisplayType native_display,
149 EGLenum platform_type,
150 bool warpDevice) {
151 std::vector<EGLint> display_attribs;
153 display_attribs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
154 display_attribs.push_back(platform_type);
156 if (warpDevice) {
157 display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
158 display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE);
161 display_attribs.push_back(EGL_NONE);
163 return eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
164 reinterpret_cast<void*>(native_display),
165 &display_attribs[0]);
168 EGLDisplay GetDisplayFromType(DisplayType display_type,
169 EGLNativeDisplayType native_display) {
170 switch (display_type) {
171 case DEFAULT:
172 case SWIFT_SHADER:
173 return eglGetDisplay(native_display);
174 case ANGLE_WARP:
175 return GetPlatformANGLEDisplay(native_display,
176 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, true);
177 case ANGLE_D3D9:
178 return GetPlatformANGLEDisplay(native_display,
179 EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, false);
180 case ANGLE_D3D11:
181 return GetPlatformANGLEDisplay(
182 native_display, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, false);
183 case ANGLE_OPENGL:
184 return GetPlatformANGLEDisplay(
185 native_display, EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, false);
186 case ANGLE_OPENGLES:
187 return GetPlatformANGLEDisplay(
188 native_display, EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE, false);
189 default:
190 NOTREACHED();
191 return EGL_NO_DISPLAY;
195 const char* DisplayTypeString(DisplayType display_type) {
196 switch (display_type) {
197 case DEFAULT:
198 return "Default";
199 case SWIFT_SHADER:
200 return "SwiftShader";
201 case ANGLE_WARP:
202 return "WARP";
203 case ANGLE_D3D9:
204 return "D3D9";
205 case ANGLE_D3D11:
206 return "D3D11";
207 case ANGLE_OPENGL:
208 return "OpenGL";
209 case ANGLE_OPENGLES:
210 return "OpenGLES";
211 default:
212 NOTREACHED();
213 return "Err";
217 } // namespace
219 void GetEGLInitDisplays(bool supports_angle_d3d,
220 bool supports_angle_opengl,
221 const base::CommandLine* command_line,
222 std::vector<DisplayType>* init_displays) {
223 // SwiftShader does not use the platform extensions
224 if (command_line->GetSwitchValueASCII(switches::kUseGL) ==
225 kGLImplementationSwiftShaderName) {
226 init_displays->push_back(SWIFT_SHADER);
227 return;
230 std::string requested_renderer =
231 command_line->GetSwitchValueASCII(switches::kUseANGLE);
233 if (supports_angle_d3d) {
234 bool use_angle_default =
235 !command_line->HasSwitch(switches::kUseANGLE) ||
236 requested_renderer == kANGLEImplementationDefaultName;
238 if (use_angle_default) {
239 // Default mode for ANGLE - try D3D11, else try D3D9
240 if (!command_line->HasSwitch(switches::kDisableD3D11)) {
241 init_displays->push_back(ANGLE_D3D11);
243 init_displays->push_back(ANGLE_D3D9);
244 } else {
245 if (requested_renderer == kANGLEImplementationD3D11Name) {
246 init_displays->push_back(ANGLE_D3D11);
248 if (requested_renderer == kANGLEImplementationD3D9Name) {
249 init_displays->push_back(ANGLE_D3D9);
251 if (requested_renderer == kANGLEImplementationWARPName) {
252 init_displays->push_back(ANGLE_WARP);
257 if (supports_angle_opengl) {
258 if (requested_renderer == kANGLEImplementationOpenGLName) {
259 init_displays->push_back(ANGLE_OPENGL);
261 if (requested_renderer == kANGLEImplementationOpenGLESName) {
262 init_displays->push_back(ANGLE_OPENGLES);
266 // If no displays are available due to missing angle extensions or invalid
267 // flags, request the default display.
268 if (init_displays->empty()) {
269 init_displays->push_back(DEFAULT);
273 GLSurfaceEGL::GLSurfaceEGL() {
274 ++g_num_surfaces;
275 if (!g_initialized) {
276 bool result = GLSurfaceEGL::InitializeOneOff();
277 DCHECK(result);
278 DCHECK(g_initialized);
282 bool GLSurfaceEGL::InitializeOneOff() {
283 if (g_initialized)
284 return true;
286 InitializeDisplay();
287 if (g_display == EGL_NO_DISPLAY)
288 return false;
290 // Choose an EGL configuration.
291 // On X this is only used for PBuffer surfaces.
292 EGLint renderable_type = EGL_OPENGL_ES2_BIT;
293 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
294 switches::kEnableUnsafeES3APIs)) {
295 renderable_type = EGL_OPENGL_ES3_BIT;
297 const EGLint kConfigAttribs[] = {
298 EGL_BUFFER_SIZE, 32,
299 EGL_ALPHA_SIZE, 8,
300 EGL_BLUE_SIZE, 8,
301 EGL_GREEN_SIZE, 8,
302 EGL_RED_SIZE, 8,
303 EGL_RENDERABLE_TYPE, renderable_type,
304 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
305 EGL_NONE
308 #if defined(USE_OZONE)
309 const EGLint* config_attribs = ui::OzonePlatform::GetInstance()
310 ->GetSurfaceFactoryOzone()
311 ->GetEGLSurfaceProperties(kConfigAttribs);
312 #else
313 const EGLint* config_attribs = kConfigAttribs;
314 #endif
316 EGLint num_configs;
317 if (!eglChooseConfig(g_display,
318 config_attribs,
319 NULL,
321 &num_configs)) {
322 LOG(ERROR) << "eglChooseConfig failed with error "
323 << GetLastEGLErrorString();
324 return false;
327 if (num_configs == 0) {
328 LOG(ERROR) << "No suitable EGL configs found.";
329 return false;
332 if (!eglChooseConfig(g_display,
333 config_attribs,
334 &g_config,
336 &num_configs)) {
337 LOG(ERROR) << "eglChooseConfig failed with error "
338 << GetLastEGLErrorString();
339 return false;
342 g_egl_extensions = eglQueryString(g_display, EGL_EXTENSIONS);
343 g_egl_create_context_robustness_supported =
344 HasEGLExtension("EGL_EXT_create_context_robustness");
345 g_egl_sync_control_supported =
346 HasEGLExtension("EGL_CHROMIUM_sync_control");
347 g_egl_window_fixed_size_supported =
348 HasEGLExtension("EGL_ANGLE_window_fixed_size");
350 // We always succeed beyond this point so set g_initialized here to avoid
351 // infinite recursion through CreateGLContext and GetDisplay
352 // if g_egl_surfaceless_context_supported.
353 g_initialized = true;
354 g_terminate_pending = false;
356 // TODO(oetuaho@nvidia.com): Surfaceless is disabled on Android as a temporary
357 // workaround, since code written for Android WebView takes different paths
358 // based on whether GL surface objects have underlying EGL surface handles,
359 // conflicting with the use of surfaceless. See https://crbug.com/382349
360 #if defined(OS_ANDROID)
361 DCHECK(!g_egl_surfaceless_context_supported);
362 #else
363 // Check if SurfacelessEGL is supported.
364 g_egl_surfaceless_context_supported =
365 HasEGLExtension("EGL_KHR_surfaceless_context");
366 if (g_egl_surfaceless_context_supported) {
367 // EGL_KHR_surfaceless_context is supported but ensure
368 // GL_OES_surfaceless_context is also supported. We need a current context
369 // to query for supported GL extensions.
370 scoped_refptr<GLSurface> surface = new SurfacelessEGL(Size(1, 1));
371 scoped_refptr<GLContext> context = GLContext::CreateGLContext(
372 NULL, surface.get(), PreferIntegratedGpu);
373 if (!context->MakeCurrent(surface.get()))
374 g_egl_surfaceless_context_supported = false;
376 // Ensure context supports GL_OES_surfaceless_context.
377 if (g_egl_surfaceless_context_supported) {
378 g_egl_surfaceless_context_supported = context->HasExtension(
379 "GL_OES_surfaceless_context");
380 context->ReleaseCurrent(surface.get());
383 #endif
385 return true;
388 EGLDisplay GLSurfaceEGL::GetDisplay() {
389 DCHECK(g_initialized);
390 return g_display;
393 // static
394 EGLDisplay GLSurfaceEGL::GetHardwareDisplay() {
395 if (!g_initialized) {
396 bool result = GLSurfaceEGL::InitializeOneOff();
397 DCHECK(result);
399 return g_display;
402 // static
403 EGLNativeDisplayType GLSurfaceEGL::GetNativeDisplay() {
404 if (!g_initialized) {
405 bool result = GLSurfaceEGL::InitializeOneOff();
406 DCHECK(result);
408 return g_native_display_type;
411 const char* GLSurfaceEGL::GetEGLExtensions() {
412 // No need for InitializeOneOff. Assume that extensions will not change
413 // after the first initialization.
414 return g_egl_extensions;
417 bool GLSurfaceEGL::HasEGLExtension(const char* name) {
418 return ExtensionsContain(GetEGLExtensions(), name);
421 bool GLSurfaceEGL::IsCreateContextRobustnessSupported() {
422 return g_egl_create_context_robustness_supported;
425 bool GLSurfaceEGL::IsEGLSurfacelessContextSupported() {
426 return g_egl_surfaceless_context_supported;
429 void GLSurfaceEGL::DestroyAndTerminateDisplay() {
430 DCHECK(g_initialized);
431 DCHECK_EQ(g_num_surfaces, 1);
432 Destroy();
433 g_terminate_pending = true;
436 GLSurfaceEGL::~GLSurfaceEGL() {
437 DCHECK_GT(g_num_surfaces, 0) << "Bad surface count";
438 if (--g_num_surfaces == 0 && g_terminate_pending) {
439 DeinitializeEgl();
440 g_terminate_pending = false;
444 // InitializeDisplay is necessary because the static binding code
445 // needs a full Display init before it can query the Display extensions.
446 // static
447 EGLDisplay GLSurfaceEGL::InitializeDisplay() {
448 if (g_display != EGL_NO_DISPLAY) {
449 return g_display;
452 g_native_display_type = GetPlatformDefaultEGLNativeDisplay();
454 // If EGL_EXT_client_extensions not supported this call to eglQueryString
455 // will return NULL.
456 const char* client_extensions =
457 eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
459 bool supports_angle_d3d = false;
460 bool supports_angle_opengl = false;
461 // Check for availability of ANGLE extensions.
462 if (client_extensions &&
463 ExtensionsContain(client_extensions, "EGL_ANGLE_platform_angle")) {
464 supports_angle_d3d =
465 ExtensionsContain(client_extensions, "EGL_ANGLE_platform_angle_d3d");
466 supports_angle_opengl =
467 ExtensionsContain(client_extensions, "EGL_ANGLE_platform_angle_opengl");
470 std::vector<DisplayType> init_displays;
471 GetEGLInitDisplays(supports_angle_d3d, supports_angle_opengl,
472 base::CommandLine::ForCurrentProcess(), &init_displays);
474 for (size_t disp_index = 0; disp_index < init_displays.size(); ++disp_index) {
475 DisplayType display_type = init_displays[disp_index];
476 EGLDisplay display =
477 GetDisplayFromType(display_type, g_native_display_type);
478 if (display == EGL_NO_DISPLAY) {
479 LOG(ERROR) << "EGL display query failed with error "
480 << GetLastEGLErrorString();
483 if (!eglInitialize(display, nullptr, nullptr)) {
484 bool is_last = disp_index == init_displays.size() - 1;
486 LOG(ERROR) << "eglInitialize " << DisplayTypeString(display_type)
487 << " failed with error " << GetLastEGLErrorString()
488 << (is_last ? "" : ", trying next display type");
489 } else {
490 g_display = display;
491 break;
495 return g_display;
498 NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(EGLNativeWindowType window)
499 : window_(window),
500 surface_(NULL),
501 supports_post_sub_buffer_(false),
502 config_(NULL),
503 size_(1, 1),
504 swap_interval_(1) {
505 #if defined(OS_ANDROID)
506 if (window)
507 ANativeWindow_acquire(window);
508 #endif
510 #if defined(OS_WIN)
511 vsync_override_ = false;
512 swap_generation_ = 0;
513 RECT windowRect;
514 if (GetClientRect(window_, &windowRect))
515 size_ = gfx::Rect(windowRect).size();
516 #endif
519 bool NativeViewGLSurfaceEGL::Initialize() {
520 return Initialize(nullptr);
523 bool NativeViewGLSurfaceEGL::Initialize(
524 scoped_ptr<VSyncProvider> sync_provider) {
525 DCHECK(!surface_);
527 if (!GetDisplay()) {
528 LOG(ERROR) << "Trying to create surface with invalid display.";
529 return false;
532 std::vector<EGLint> egl_window_attributes;
534 if (g_egl_window_fixed_size_supported) {
535 egl_window_attributes.push_back(EGL_FIXED_SIZE_ANGLE);
536 egl_window_attributes.push_back(EGL_TRUE);
537 egl_window_attributes.push_back(EGL_WIDTH);
538 egl_window_attributes.push_back(size_.width());
539 egl_window_attributes.push_back(EGL_HEIGHT);
540 egl_window_attributes.push_back(size_.height());
543 if (gfx::g_driver_egl.ext.b_EGL_NV_post_sub_buffer) {
544 egl_window_attributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
545 egl_window_attributes.push_back(EGL_TRUE);
548 egl_window_attributes.push_back(EGL_NONE);
549 // Create a surface for the native window.
550 surface_ = eglCreateWindowSurface(
551 GetDisplay(), GetConfig(), window_, &egl_window_attributes[0]);
553 if (!surface_) {
554 LOG(ERROR) << "eglCreateWindowSurface failed with error "
555 << GetLastEGLErrorString();
556 Destroy();
557 return false;
560 if (gfx::g_driver_egl.ext.b_EGL_NV_post_sub_buffer) {
561 EGLint surfaceVal;
562 EGLBoolean retVal = eglQuerySurface(
563 GetDisplay(), surface_, EGL_POST_SUB_BUFFER_SUPPORTED_NV, &surfaceVal);
564 supports_post_sub_buffer_ = (surfaceVal && retVal) == EGL_TRUE;
567 if (sync_provider)
568 vsync_provider_.reset(sync_provider.release());
569 else if (g_egl_sync_control_supported)
570 vsync_provider_.reset(new EGLSyncControlVSyncProvider(surface_));
571 return true;
574 void NativeViewGLSurfaceEGL::Destroy() {
575 if (surface_) {
576 if (!eglDestroySurface(GetDisplay(), surface_)) {
577 LOG(ERROR) << "eglDestroySurface failed with error "
578 << GetLastEGLErrorString();
580 surface_ = NULL;
584 EGLConfig NativeViewGLSurfaceEGL::GetConfig() {
585 #if !defined(USE_X11)
586 return g_config;
587 #else
588 if (!config_) {
589 // Get a config compatible with the window
590 DCHECK(window_);
591 XWindowAttributes win_attribs;
592 if (!XGetWindowAttributes(GetNativeDisplay(), window_, &win_attribs)) {
593 return NULL;
596 // Try matching the window depth with an alpha channel,
597 // because we're worried the destination alpha width could
598 // constrain blending precision.
599 const int kBufferSizeOffset = 1;
600 const int kAlphaSizeOffset = 3;
601 EGLint config_attribs[] = {
602 EGL_BUFFER_SIZE, ~0,
603 EGL_ALPHA_SIZE, 8,
604 EGL_BLUE_SIZE, 8,
605 EGL_GREEN_SIZE, 8,
606 EGL_RED_SIZE, 8,
607 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
608 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
609 EGL_NONE
611 config_attribs[kBufferSizeOffset] = win_attribs.depth;
613 EGLint num_configs;
614 if (!eglChooseConfig(g_display,
615 config_attribs,
616 &config_,
618 &num_configs)) {
619 LOG(ERROR) << "eglChooseConfig failed with error "
620 << GetLastEGLErrorString();
621 return NULL;
624 if (num_configs) {
625 EGLint config_depth;
626 if (!eglGetConfigAttrib(g_display,
627 config_,
628 EGL_BUFFER_SIZE,
629 &config_depth)) {
630 LOG(ERROR) << "eglGetConfigAttrib failed with error "
631 << GetLastEGLErrorString();
632 return NULL;
635 if (config_depth == win_attribs.depth) {
636 return config_;
640 // Try without an alpha channel.
641 config_attribs[kAlphaSizeOffset] = 0;
642 if (!eglChooseConfig(g_display,
643 config_attribs,
644 &config_,
646 &num_configs)) {
647 LOG(ERROR) << "eglChooseConfig failed with error "
648 << GetLastEGLErrorString();
649 return NULL;
652 if (num_configs == 0) {
653 LOG(ERROR) << "No suitable EGL configs found.";
654 return NULL;
657 return config_;
658 #endif
661 bool NativeViewGLSurfaceEGL::IsOffscreen() {
662 return false;
665 gfx::SwapResult NativeViewGLSurfaceEGL::SwapBuffers() {
666 TRACE_EVENT2("gpu", "NativeViewGLSurfaceEGL:RealSwapBuffers",
667 "width", GetSize().width(),
668 "height", GetSize().height());
670 #if defined(OS_WIN)
671 if (swap_interval_ != 0) {
672 // This code is a simple way of enforcing that we only vsync if one surface
673 // is swapping per frame. This provides single window cases a stable refresh
674 // while allowing multi-window cases to not slow down due to multiple syncs
675 // on a single thread. A better way to fix this problem would be to have
676 // each surface present on its own thread.
678 if (current_swap_generation_ == swap_generation_) {
679 if (swaps_this_generation_ > 1)
680 last_multiswap_generation_ = current_swap_generation_;
681 swaps_this_generation_ = 0;
682 current_swap_generation_++;
685 swap_generation_ = current_swap_generation_;
687 if (swaps_this_generation_ != 0 ||
688 (current_swap_generation_ - last_multiswap_generation_ <
689 MULTISWAP_FRAME_VSYNC_THRESHOLD)) {
690 // Override vsync settings and switch it off
691 if (!vsync_override_) {
692 eglSwapInterval(GetDisplay(), 0);
693 vsync_override_ = true;
695 } else if (vsync_override_) {
696 // Only one window swapping, so let the normal vsync setting take over
697 eglSwapInterval(GetDisplay(), swap_interval_);
698 vsync_override_ = false;
701 swaps_this_generation_++;
703 #endif
705 if (!eglSwapBuffers(GetDisplay(), surface_)) {
706 DVLOG(1) << "eglSwapBuffers failed with error "
707 << GetLastEGLErrorString();
708 return gfx::SwapResult::SWAP_FAILED;
711 return gfx::SwapResult::SWAP_ACK;
714 gfx::Size NativeViewGLSurfaceEGL::GetSize() {
715 EGLint width;
716 EGLint height;
717 if (!eglQuerySurface(GetDisplay(), surface_, EGL_WIDTH, &width) ||
718 !eglQuerySurface(GetDisplay(), surface_, EGL_HEIGHT, &height)) {
719 NOTREACHED() << "eglQuerySurface failed with error "
720 << GetLastEGLErrorString();
721 return gfx::Size();
724 return gfx::Size(width, height);
727 bool NativeViewGLSurfaceEGL::Resize(const gfx::Size& size) {
728 if (size == GetSize())
729 return true;
731 size_ = size;
733 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
734 GLContext* current_context = GLContext::GetCurrent();
735 bool was_current =
736 current_context && current_context->IsCurrent(this);
737 if (was_current) {
738 scoped_make_current.reset(
739 new ui::ScopedMakeCurrent(current_context, this));
740 current_context->ReleaseCurrent(this);
743 Destroy();
745 if (!Initialize()) {
746 LOG(ERROR) << "Failed to resize window.";
747 return false;
750 return true;
753 bool NativeViewGLSurfaceEGL::Recreate() {
754 Destroy();
755 if (!Initialize()) {
756 LOG(ERROR) << "Failed to create surface.";
757 return false;
759 return true;
762 EGLSurface NativeViewGLSurfaceEGL::GetHandle() {
763 return surface_;
766 bool NativeViewGLSurfaceEGL::SupportsPostSubBuffer() {
767 return supports_post_sub_buffer_;
770 gfx::SwapResult NativeViewGLSurfaceEGL::PostSubBuffer(int x,
771 int y,
772 int width,
773 int height) {
774 DCHECK(supports_post_sub_buffer_);
775 if (!eglPostSubBufferNV(GetDisplay(), surface_, x, y, width, height)) {
776 DVLOG(1) << "eglPostSubBufferNV failed with error "
777 << GetLastEGLErrorString();
778 return gfx::SwapResult::SWAP_FAILED;
780 return gfx::SwapResult::SWAP_ACK;
783 VSyncProvider* NativeViewGLSurfaceEGL::GetVSyncProvider() {
784 return vsync_provider_.get();
787 void NativeViewGLSurfaceEGL::OnSetSwapInterval(int interval) {
788 swap_interval_ = interval;
791 NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() {
792 Destroy();
793 #if defined(OS_ANDROID)
794 if (window_)
795 ANativeWindow_release(window_);
796 #endif
799 PbufferGLSurfaceEGL::PbufferGLSurfaceEGL(const gfx::Size& size)
800 : size_(size),
801 surface_(NULL) {
802 // Some implementations of Pbuffer do not support having a 0 size. For such
803 // cases use a (1, 1) surface.
804 if (size_.GetArea() == 0)
805 size_.SetSize(1, 1);
808 bool PbufferGLSurfaceEGL::Initialize() {
809 EGLSurface old_surface = surface_;
811 EGLDisplay display = GetDisplay();
812 if (!display) {
813 LOG(ERROR) << "Trying to create surface with invalid display.";
814 return false;
817 // Allocate the new pbuffer surface before freeing the old one to ensure
818 // they have different addresses. If they have the same address then a
819 // future call to MakeCurrent might early out because it appears the current
820 // context and surface have not changed.
821 const EGLint pbuffer_attribs[] = {
822 EGL_WIDTH, size_.width(),
823 EGL_HEIGHT, size_.height(),
824 EGL_NONE
827 EGLSurface new_surface = eglCreatePbufferSurface(display,
828 GetConfig(),
829 pbuffer_attribs);
830 if (!new_surface) {
831 LOG(ERROR) << "eglCreatePbufferSurface failed with error "
832 << GetLastEGLErrorString();
833 return false;
836 if (old_surface)
837 eglDestroySurface(display, old_surface);
839 surface_ = new_surface;
840 return true;
843 void PbufferGLSurfaceEGL::Destroy() {
844 if (surface_) {
845 if (!eglDestroySurface(GetDisplay(), surface_)) {
846 LOG(ERROR) << "eglDestroySurface failed with error "
847 << GetLastEGLErrorString();
849 surface_ = NULL;
853 EGLConfig PbufferGLSurfaceEGL::GetConfig() {
854 return g_config;
857 bool PbufferGLSurfaceEGL::IsOffscreen() {
858 return true;
861 gfx::SwapResult PbufferGLSurfaceEGL::SwapBuffers() {
862 NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL.";
863 return gfx::SwapResult::SWAP_FAILED;
866 gfx::Size PbufferGLSurfaceEGL::GetSize() {
867 return size_;
870 bool PbufferGLSurfaceEGL::Resize(const gfx::Size& size) {
871 if (size == size_)
872 return true;
874 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
875 GLContext* current_context = GLContext::GetCurrent();
876 bool was_current =
877 current_context && current_context->IsCurrent(this);
878 if (was_current) {
879 scoped_make_current.reset(
880 new ui::ScopedMakeCurrent(current_context, this));
883 size_ = size;
885 if (!Initialize()) {
886 LOG(ERROR) << "Failed to resize pbuffer.";
887 return false;
890 return true;
893 EGLSurface PbufferGLSurfaceEGL::GetHandle() {
894 return surface_;
897 void* PbufferGLSurfaceEGL::GetShareHandle() {
898 #if defined(OS_ANDROID)
899 NOTREACHED();
900 return NULL;
901 #else
902 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_query_surface_pointer)
903 return NULL;
905 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle)
906 return NULL;
908 void* handle;
909 if (!eglQuerySurfacePointerANGLE(g_display,
910 GetHandle(),
911 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
912 &handle)) {
913 return NULL;
916 return handle;
917 #endif
920 PbufferGLSurfaceEGL::~PbufferGLSurfaceEGL() {
921 Destroy();
924 SurfacelessEGL::SurfacelessEGL(const gfx::Size& size)
925 : size_(size) {
928 bool SurfacelessEGL::Initialize() {
929 return true;
932 void SurfacelessEGL::Destroy() {
935 EGLConfig SurfacelessEGL::GetConfig() {
936 return g_config;
939 bool SurfacelessEGL::IsOffscreen() {
940 return true;
943 bool SurfacelessEGL::IsSurfaceless() const {
944 return true;
947 gfx::SwapResult SurfacelessEGL::SwapBuffers() {
948 LOG(ERROR) << "Attempted to call SwapBuffers with SurfacelessEGL.";
949 return gfx::SwapResult::SWAP_FAILED;
952 gfx::Size SurfacelessEGL::GetSize() {
953 return size_;
956 bool SurfacelessEGL::Resize(const gfx::Size& size) {
957 size_ = size;
958 return true;
961 EGLSurface SurfacelessEGL::GetHandle() {
962 return EGL_NO_SURFACE;
965 void* SurfacelessEGL::GetShareHandle() {
966 return NULL;
969 SurfacelessEGL::~SurfacelessEGL() {
972 } // namespace gfx