Add ICU message format support
[chromium-blink-merge.git] / ui / gl / gl_surface_egl.cc
blobf85258ff8b876e276aed88706849a1a179131e0a
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;
90 const char* g_egl_extensions = NULL;
91 bool g_egl_create_context_robustness_supported = false;
92 bool g_egl_sync_control_supported = false;
93 bool g_egl_window_fixed_size_supported = false;
94 bool g_egl_surfaceless_context_supported = false;
96 class EGLSyncControlVSyncProvider
97 : public gfx::SyncControlVSyncProvider {
98 public:
99 explicit EGLSyncControlVSyncProvider(EGLSurface surface)
100 : SyncControlVSyncProvider(),
101 surface_(surface) {
104 ~EGLSyncControlVSyncProvider() override {}
106 protected:
107 bool GetSyncValues(int64* system_time,
108 int64* media_stream_counter,
109 int64* swap_buffer_counter) override {
110 uint64 u_system_time, u_media_stream_counter, u_swap_buffer_counter;
111 bool result = eglGetSyncValuesCHROMIUM(
112 g_display, surface_, &u_system_time,
113 &u_media_stream_counter, &u_swap_buffer_counter) == EGL_TRUE;
114 if (result) {
115 *system_time = static_cast<int64>(u_system_time);
116 *media_stream_counter = static_cast<int64>(u_media_stream_counter);
117 *swap_buffer_counter = static_cast<int64>(u_swap_buffer_counter);
119 return result;
122 bool GetMscRate(int32* numerator, int32* denominator) override {
123 return false;
126 private:
127 EGLSurface surface_;
129 DISALLOW_COPY_AND_ASSIGN(EGLSyncControlVSyncProvider);
132 EGLDisplay GetPlatformANGLEDisplay(EGLNativeDisplayType native_display,
133 EGLenum platform_type,
134 bool warpDevice) {
135 std::vector<EGLint> display_attribs;
137 display_attribs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
138 display_attribs.push_back(platform_type);
140 if (warpDevice) {
141 display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
142 display_attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE);
145 display_attribs.push_back(EGL_NONE);
147 return eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
148 reinterpret_cast<void*>(native_display),
149 &display_attribs[0]);
152 EGLDisplay GetDisplayFromType(DisplayType display_type,
153 EGLNativeDisplayType native_display) {
154 switch (display_type) {
155 case DEFAULT:
156 case SWIFT_SHADER:
157 return eglGetDisplay(native_display);
158 case ANGLE_WARP:
159 return GetPlatformANGLEDisplay(native_display,
160 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, true);
161 case ANGLE_D3D9:
162 return GetPlatformANGLEDisplay(native_display,
163 EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, false);
164 case ANGLE_D3D11:
165 return GetPlatformANGLEDisplay(
166 native_display, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, false);
167 case ANGLE_OPENGL:
168 return GetPlatformANGLEDisplay(
169 native_display, EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE, false);
170 case ANGLE_OPENGLES:
171 return GetPlatformANGLEDisplay(
172 native_display, EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE, false);
173 default:
174 NOTREACHED();
175 return EGL_NO_DISPLAY;
179 const char* DisplayTypeString(DisplayType display_type) {
180 switch (display_type) {
181 case DEFAULT:
182 return "Default";
183 case SWIFT_SHADER:
184 return "SwiftShader";
185 case ANGLE_WARP:
186 return "WARP";
187 case ANGLE_D3D9:
188 return "D3D9";
189 case ANGLE_D3D11:
190 return "D3D11";
191 case ANGLE_OPENGL:
192 return "OpenGL";
193 case ANGLE_OPENGLES:
194 return "OpenGLES";
195 default:
196 NOTREACHED();
197 return "Err";
201 } // namespace
203 void GetEGLInitDisplays(bool supports_angle_d3d,
204 bool supports_angle_opengl,
205 const base::CommandLine* command_line,
206 std::vector<DisplayType>* init_displays) {
207 // SwiftShader does not use the platform extensions
208 if (command_line->GetSwitchValueASCII(switches::kUseGL) ==
209 kGLImplementationSwiftShaderName) {
210 init_displays->push_back(SWIFT_SHADER);
211 return;
214 std::string requested_renderer =
215 command_line->GetSwitchValueASCII(switches::kUseANGLE);
217 if (supports_angle_d3d) {
218 bool use_angle_default =
219 !command_line->HasSwitch(switches::kUseANGLE) ||
220 requested_renderer == kANGLEImplementationDefaultName;
222 if (use_angle_default) {
223 // Default mode for ANGLE - try D3D11, else try D3D9
224 if (!command_line->HasSwitch(switches::kDisableD3D11)) {
225 init_displays->push_back(ANGLE_D3D11);
227 init_displays->push_back(ANGLE_D3D9);
228 } else {
229 if (requested_renderer == kANGLEImplementationD3D11Name) {
230 init_displays->push_back(ANGLE_D3D11);
232 if (requested_renderer == kANGLEImplementationD3D9Name) {
233 init_displays->push_back(ANGLE_D3D9);
235 if (requested_renderer == kANGLEImplementationWARPName) {
236 init_displays->push_back(ANGLE_WARP);
241 if (supports_angle_opengl) {
242 if (requested_renderer == kANGLEImplementationOpenGLName) {
243 init_displays->push_back(ANGLE_OPENGL);
245 if (requested_renderer == kANGLEImplementationOpenGLESName) {
246 init_displays->push_back(ANGLE_OPENGLES);
250 // If no displays are available due to missing angle extensions or invalid
251 // flags, request the default display.
252 if (init_displays->empty()) {
253 init_displays->push_back(DEFAULT);
257 GLSurfaceEGL::GLSurfaceEGL() {}
259 bool GLSurfaceEGL::InitializeOneOff() {
260 static bool initialized = false;
261 if (initialized)
262 return true;
264 InitializeDisplay();
265 if (g_display == EGL_NO_DISPLAY)
266 return false;
268 // Choose an EGL configuration.
269 // On X this is only used for PBuffer surfaces.
270 EGLint renderable_type = EGL_OPENGL_ES2_BIT;
271 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
272 switches::kEnableUnsafeES3APIs)) {
273 renderable_type = EGL_OPENGL_ES3_BIT;
275 const EGLint kConfigAttribs[] = {
276 EGL_BUFFER_SIZE, 32,
277 EGL_ALPHA_SIZE, 8,
278 EGL_BLUE_SIZE, 8,
279 EGL_GREEN_SIZE, 8,
280 EGL_RED_SIZE, 8,
281 EGL_RENDERABLE_TYPE, renderable_type,
282 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
283 EGL_NONE
286 #if defined(USE_OZONE)
287 const EGLint* config_attribs = ui::OzonePlatform::GetInstance()
288 ->GetSurfaceFactoryOzone()
289 ->GetEGLSurfaceProperties(kConfigAttribs);
290 #else
291 const EGLint* config_attribs = kConfigAttribs;
292 #endif
294 EGLint num_configs;
295 if (!eglChooseConfig(g_display,
296 config_attribs,
297 NULL,
299 &num_configs)) {
300 LOG(ERROR) << "eglChooseConfig failed with error "
301 << GetLastEGLErrorString();
302 return false;
305 if (num_configs == 0) {
306 LOG(ERROR) << "No suitable EGL configs found.";
307 return false;
310 if (!eglChooseConfig(g_display,
311 config_attribs,
312 &g_config,
314 &num_configs)) {
315 LOG(ERROR) << "eglChooseConfig failed with error "
316 << GetLastEGLErrorString();
317 return false;
320 g_egl_extensions = eglQueryString(g_display, EGL_EXTENSIONS);
321 g_egl_create_context_robustness_supported =
322 HasEGLExtension("EGL_EXT_create_context_robustness");
323 g_egl_sync_control_supported =
324 HasEGLExtension("EGL_CHROMIUM_sync_control");
325 g_egl_window_fixed_size_supported =
326 HasEGLExtension("EGL_ANGLE_window_fixed_size");
328 // TODO(oetuaho@nvidia.com): Surfaceless is disabled on Android as a temporary
329 // workaround, since code written for Android WebView takes different paths
330 // based on whether GL surface objects have underlying EGL surface handles,
331 // conflicting with the use of surfaceless. See https://crbug.com/382349
332 #if defined(OS_ANDROID)
333 DCHECK(!g_egl_surfaceless_context_supported);
334 #else
335 // Check if SurfacelessEGL is supported.
336 g_egl_surfaceless_context_supported =
337 HasEGLExtension("EGL_KHR_surfaceless_context");
338 if (g_egl_surfaceless_context_supported) {
339 // EGL_KHR_surfaceless_context is supported but ensure
340 // GL_OES_surfaceless_context is also supported. We need a current context
341 // to query for supported GL extensions.
342 scoped_refptr<GLSurface> surface = new SurfacelessEGL(Size(1, 1));
343 scoped_refptr<GLContext> context = GLContext::CreateGLContext(
344 NULL, surface.get(), PreferIntegratedGpu);
345 if (!context->MakeCurrent(surface.get()))
346 g_egl_surfaceless_context_supported = false;
348 // Ensure context supports GL_OES_surfaceless_context.
349 if (g_egl_surfaceless_context_supported) {
350 g_egl_surfaceless_context_supported = context->HasExtension(
351 "GL_OES_surfaceless_context");
352 context->ReleaseCurrent(surface.get());
355 #endif
357 initialized = true;
359 return true;
362 EGLDisplay GLSurfaceEGL::GetDisplay() {
363 return g_display;
366 EGLDisplay GLSurfaceEGL::GetHardwareDisplay() {
367 return g_display;
370 EGLNativeDisplayType GLSurfaceEGL::GetNativeDisplay() {
371 return g_native_display;
374 const char* GLSurfaceEGL::GetEGLExtensions() {
375 return g_egl_extensions;
378 bool GLSurfaceEGL::HasEGLExtension(const char* name) {
379 return ExtensionsContain(GetEGLExtensions(), name);
382 bool GLSurfaceEGL::IsCreateContextRobustnessSupported() {
383 return g_egl_create_context_robustness_supported;
386 bool GLSurfaceEGL::IsEGLSurfacelessContextSupported() {
387 return g_egl_surfaceless_context_supported;
390 GLSurfaceEGL::~GLSurfaceEGL() {}
392 // InitializeDisplay is necessary because the static binding code
393 // needs a full Display init before it can query the Display extensions.
394 // static
395 EGLDisplay GLSurfaceEGL::InitializeDisplay() {
396 if (g_display != EGL_NO_DISPLAY) {
397 return g_display;
400 g_native_display = GetPlatformDefaultEGLNativeDisplay();
402 // If EGL_EXT_client_extensions not supported this call to eglQueryString
403 // will return NULL.
404 const char* client_extensions =
405 eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
407 bool supports_angle_d3d = false;
408 bool supports_angle_opengl = false;
409 // Check for availability of ANGLE extensions.
410 if (client_extensions &&
411 ExtensionsContain(client_extensions, "EGL_ANGLE_platform_angle")) {
412 supports_angle_d3d =
413 ExtensionsContain(client_extensions, "EGL_ANGLE_platform_angle_d3d");
414 supports_angle_opengl =
415 ExtensionsContain(client_extensions, "EGL_ANGLE_platform_angle_opengl");
418 std::vector<DisplayType> init_displays;
419 GetEGLInitDisplays(supports_angle_d3d, supports_angle_opengl,
420 base::CommandLine::ForCurrentProcess(), &init_displays);
422 for (size_t disp_index = 0; disp_index < init_displays.size(); ++disp_index) {
423 DisplayType display_type = init_displays[disp_index];
424 EGLDisplay display =
425 GetDisplayFromType(display_type, g_native_display);
426 if (display == EGL_NO_DISPLAY) {
427 LOG(ERROR) << "EGL display query failed with error "
428 << GetLastEGLErrorString();
431 if (!eglInitialize(display, nullptr, nullptr)) {
432 bool is_last = disp_index == init_displays.size() - 1;
434 LOG(ERROR) << "eglInitialize " << DisplayTypeString(display_type)
435 << " failed with error " << GetLastEGLErrorString()
436 << (is_last ? "" : ", trying next display type");
437 } else {
438 g_display = display;
439 break;
443 return g_display;
446 NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(EGLNativeWindowType window)
447 : window_(window),
448 surface_(NULL),
449 supports_post_sub_buffer_(false),
450 config_(NULL),
451 size_(1, 1),
452 swap_interval_(1) {
453 #if defined(OS_ANDROID)
454 if (window)
455 ANativeWindow_acquire(window);
456 #endif
458 #if defined(OS_WIN)
459 vsync_override_ = false;
460 swap_generation_ = 0;
461 RECT windowRect;
462 if (GetClientRect(window_, &windowRect))
463 size_ = gfx::Rect(windowRect).size();
464 #endif
467 bool NativeViewGLSurfaceEGL::Initialize() {
468 return Initialize(nullptr);
471 bool NativeViewGLSurfaceEGL::Initialize(
472 scoped_ptr<VSyncProvider> sync_provider) {
473 DCHECK(!surface_);
475 if (!GetDisplay()) {
476 LOG(ERROR) << "Trying to create surface with invalid display.";
477 return false;
480 std::vector<EGLint> egl_window_attributes;
482 if (g_egl_window_fixed_size_supported) {
483 egl_window_attributes.push_back(EGL_FIXED_SIZE_ANGLE);
484 egl_window_attributes.push_back(EGL_TRUE);
485 egl_window_attributes.push_back(EGL_WIDTH);
486 egl_window_attributes.push_back(size_.width());
487 egl_window_attributes.push_back(EGL_HEIGHT);
488 egl_window_attributes.push_back(size_.height());
491 if (gfx::g_driver_egl.ext.b_EGL_NV_post_sub_buffer) {
492 egl_window_attributes.push_back(EGL_POST_SUB_BUFFER_SUPPORTED_NV);
493 egl_window_attributes.push_back(EGL_TRUE);
496 egl_window_attributes.push_back(EGL_NONE);
497 // Create a surface for the native window.
498 surface_ = eglCreateWindowSurface(
499 GetDisplay(), GetConfig(), window_, &egl_window_attributes[0]);
501 if (!surface_) {
502 LOG(ERROR) << "eglCreateWindowSurface failed with error "
503 << GetLastEGLErrorString();
504 Destroy();
505 return false;
508 if (gfx::g_driver_egl.ext.b_EGL_NV_post_sub_buffer) {
509 EGLint surfaceVal;
510 EGLBoolean retVal = eglQuerySurface(
511 GetDisplay(), surface_, EGL_POST_SUB_BUFFER_SUPPORTED_NV, &surfaceVal);
512 supports_post_sub_buffer_ = (surfaceVal && retVal) == EGL_TRUE;
515 if (sync_provider)
516 vsync_provider_.reset(sync_provider.release());
517 else if (g_egl_sync_control_supported)
518 vsync_provider_.reset(new EGLSyncControlVSyncProvider(surface_));
519 return true;
522 void NativeViewGLSurfaceEGL::Destroy() {
523 if (surface_) {
524 if (!eglDestroySurface(GetDisplay(), surface_)) {
525 LOG(ERROR) << "eglDestroySurface failed with error "
526 << GetLastEGLErrorString();
528 surface_ = NULL;
532 EGLConfig NativeViewGLSurfaceEGL::GetConfig() {
533 #if !defined(USE_X11)
534 return g_config;
535 #else
536 if (!config_) {
537 // Get a config compatible with the window
538 DCHECK(window_);
539 XWindowAttributes win_attribs;
540 if (!XGetWindowAttributes(GetNativeDisplay(), window_, &win_attribs)) {
541 return NULL;
544 // Try matching the window depth with an alpha channel,
545 // because we're worried the destination alpha width could
546 // constrain blending precision.
547 const int kBufferSizeOffset = 1;
548 const int kAlphaSizeOffset = 3;
549 EGLint config_attribs[] = {
550 EGL_BUFFER_SIZE, ~0,
551 EGL_ALPHA_SIZE, 8,
552 EGL_BLUE_SIZE, 8,
553 EGL_GREEN_SIZE, 8,
554 EGL_RED_SIZE, 8,
555 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
556 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
557 EGL_NONE
559 config_attribs[kBufferSizeOffset] = win_attribs.depth;
561 EGLint num_configs;
562 if (!eglChooseConfig(g_display,
563 config_attribs,
564 &config_,
566 &num_configs)) {
567 LOG(ERROR) << "eglChooseConfig failed with error "
568 << GetLastEGLErrorString();
569 return NULL;
572 if (num_configs) {
573 EGLint config_depth;
574 if (!eglGetConfigAttrib(g_display,
575 config_,
576 EGL_BUFFER_SIZE,
577 &config_depth)) {
578 LOG(ERROR) << "eglGetConfigAttrib failed with error "
579 << GetLastEGLErrorString();
580 return NULL;
583 if (config_depth == win_attribs.depth) {
584 return config_;
588 // Try without an alpha channel.
589 config_attribs[kAlphaSizeOffset] = 0;
590 if (!eglChooseConfig(g_display,
591 config_attribs,
592 &config_,
594 &num_configs)) {
595 LOG(ERROR) << "eglChooseConfig failed with error "
596 << GetLastEGLErrorString();
597 return NULL;
600 if (num_configs == 0) {
601 LOG(ERROR) << "No suitable EGL configs found.";
602 return NULL;
605 return config_;
606 #endif
609 bool NativeViewGLSurfaceEGL::IsOffscreen() {
610 return false;
613 gfx::SwapResult NativeViewGLSurfaceEGL::SwapBuffers() {
614 TRACE_EVENT2("gpu", "NativeViewGLSurfaceEGL:RealSwapBuffers",
615 "width", GetSize().width(),
616 "height", GetSize().height());
618 #if defined(OS_WIN)
619 if (swap_interval_ != 0) {
620 // This code is a simple way of enforcing that we only vsync if one surface
621 // is swapping per frame. This provides single window cases a stable refresh
622 // while allowing multi-window cases to not slow down due to multiple syncs
623 // on a single thread. A better way to fix this problem would be to have
624 // each surface present on its own thread.
626 if (current_swap_generation_ == swap_generation_) {
627 if (swaps_this_generation_ > 1)
628 last_multiswap_generation_ = current_swap_generation_;
629 swaps_this_generation_ = 0;
630 current_swap_generation_++;
633 swap_generation_ = current_swap_generation_;
635 if (swaps_this_generation_ != 0 ||
636 (current_swap_generation_ - last_multiswap_generation_ <
637 MULTISWAP_FRAME_VSYNC_THRESHOLD)) {
638 // Override vsync settings and switch it off
639 if (!vsync_override_) {
640 eglSwapInterval(GetDisplay(), 0);
641 vsync_override_ = true;
643 } else if (vsync_override_) {
644 // Only one window swapping, so let the normal vsync setting take over
645 eglSwapInterval(GetDisplay(), swap_interval_);
646 vsync_override_ = false;
649 swaps_this_generation_++;
651 #endif
653 if (!eglSwapBuffers(GetDisplay(), surface_)) {
654 DVLOG(1) << "eglSwapBuffers failed with error "
655 << GetLastEGLErrorString();
656 return gfx::SwapResult::SWAP_FAILED;
659 return gfx::SwapResult::SWAP_ACK;
662 gfx::Size NativeViewGLSurfaceEGL::GetSize() {
663 EGLint width;
664 EGLint height;
665 if (!eglQuerySurface(GetDisplay(), surface_, EGL_WIDTH, &width) ||
666 !eglQuerySurface(GetDisplay(), surface_, EGL_HEIGHT, &height)) {
667 NOTREACHED() << "eglQuerySurface failed with error "
668 << GetLastEGLErrorString();
669 return gfx::Size();
672 return gfx::Size(width, height);
675 bool NativeViewGLSurfaceEGL::Resize(const gfx::Size& size) {
676 if (size == GetSize())
677 return true;
679 size_ = size;
681 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
682 GLContext* current_context = GLContext::GetCurrent();
683 bool was_current =
684 current_context && current_context->IsCurrent(this);
685 if (was_current) {
686 scoped_make_current.reset(
687 new ui::ScopedMakeCurrent(current_context, this));
688 current_context->ReleaseCurrent(this);
691 Destroy();
693 if (!Initialize()) {
694 LOG(ERROR) << "Failed to resize window.";
695 return false;
698 return true;
701 bool NativeViewGLSurfaceEGL::Recreate() {
702 Destroy();
703 if (!Initialize()) {
704 LOG(ERROR) << "Failed to create surface.";
705 return false;
707 return true;
710 EGLSurface NativeViewGLSurfaceEGL::GetHandle() {
711 return surface_;
714 bool NativeViewGLSurfaceEGL::SupportsPostSubBuffer() {
715 return supports_post_sub_buffer_;
718 gfx::SwapResult NativeViewGLSurfaceEGL::PostSubBuffer(int x,
719 int y,
720 int width,
721 int height) {
722 DCHECK(supports_post_sub_buffer_);
723 if (!eglPostSubBufferNV(GetDisplay(), surface_, x, y, width, height)) {
724 DVLOG(1) << "eglPostSubBufferNV failed with error "
725 << GetLastEGLErrorString();
726 return gfx::SwapResult::SWAP_FAILED;
728 return gfx::SwapResult::SWAP_ACK;
731 VSyncProvider* NativeViewGLSurfaceEGL::GetVSyncProvider() {
732 return vsync_provider_.get();
735 void NativeViewGLSurfaceEGL::OnSetSwapInterval(int interval) {
736 swap_interval_ = interval;
739 NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() {
740 Destroy();
741 #if defined(OS_ANDROID)
742 if (window_)
743 ANativeWindow_release(window_);
744 #endif
747 PbufferGLSurfaceEGL::PbufferGLSurfaceEGL(const gfx::Size& size)
748 : size_(size),
749 surface_(NULL) {
750 // Some implementations of Pbuffer do not support having a 0 size. For such
751 // cases use a (1, 1) surface.
752 if (size_.GetArea() == 0)
753 size_.SetSize(1, 1);
756 bool PbufferGLSurfaceEGL::Initialize() {
757 EGLSurface old_surface = surface_;
759 EGLDisplay display = GetDisplay();
760 if (!display) {
761 LOG(ERROR) << "Trying to create surface with invalid display.";
762 return false;
765 // Allocate the new pbuffer surface before freeing the old one to ensure
766 // they have different addresses. If they have the same address then a
767 // future call to MakeCurrent might early out because it appears the current
768 // context and surface have not changed.
769 const EGLint pbuffer_attribs[] = {
770 EGL_WIDTH, size_.width(),
771 EGL_HEIGHT, size_.height(),
772 EGL_NONE
775 EGLSurface new_surface = eglCreatePbufferSurface(display,
776 GetConfig(),
777 pbuffer_attribs);
778 if (!new_surface) {
779 LOG(ERROR) << "eglCreatePbufferSurface failed with error "
780 << GetLastEGLErrorString();
781 return false;
784 if (old_surface)
785 eglDestroySurface(display, old_surface);
787 surface_ = new_surface;
788 return true;
791 void PbufferGLSurfaceEGL::Destroy() {
792 if (surface_) {
793 if (!eglDestroySurface(GetDisplay(), surface_)) {
794 LOG(ERROR) << "eglDestroySurface failed with error "
795 << GetLastEGLErrorString();
797 surface_ = NULL;
801 EGLConfig PbufferGLSurfaceEGL::GetConfig() {
802 return g_config;
805 bool PbufferGLSurfaceEGL::IsOffscreen() {
806 return true;
809 gfx::SwapResult PbufferGLSurfaceEGL::SwapBuffers() {
810 NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL.";
811 return gfx::SwapResult::SWAP_FAILED;
814 gfx::Size PbufferGLSurfaceEGL::GetSize() {
815 return size_;
818 bool PbufferGLSurfaceEGL::Resize(const gfx::Size& size) {
819 if (size == size_)
820 return true;
822 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
823 GLContext* current_context = GLContext::GetCurrent();
824 bool was_current =
825 current_context && current_context->IsCurrent(this);
826 if (was_current) {
827 scoped_make_current.reset(
828 new ui::ScopedMakeCurrent(current_context, this));
831 size_ = size;
833 if (!Initialize()) {
834 LOG(ERROR) << "Failed to resize pbuffer.";
835 return false;
838 return true;
841 EGLSurface PbufferGLSurfaceEGL::GetHandle() {
842 return surface_;
845 void* PbufferGLSurfaceEGL::GetShareHandle() {
846 #if defined(OS_ANDROID)
847 NOTREACHED();
848 return NULL;
849 #else
850 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_query_surface_pointer)
851 return NULL;
853 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle)
854 return NULL;
856 void* handle;
857 if (!eglQuerySurfacePointerANGLE(g_display,
858 GetHandle(),
859 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
860 &handle)) {
861 return NULL;
864 return handle;
865 #endif
868 PbufferGLSurfaceEGL::~PbufferGLSurfaceEGL() {
869 Destroy();
872 SurfacelessEGL::SurfacelessEGL(const gfx::Size& size)
873 : size_(size) {
876 bool SurfacelessEGL::Initialize() {
877 return true;
880 void SurfacelessEGL::Destroy() {
883 EGLConfig SurfacelessEGL::GetConfig() {
884 return g_config;
887 bool SurfacelessEGL::IsOffscreen() {
888 return true;
891 bool SurfacelessEGL::IsSurfaceless() const {
892 return true;
895 gfx::SwapResult SurfacelessEGL::SwapBuffers() {
896 LOG(ERROR) << "Attempted to call SwapBuffers with SurfacelessEGL.";
897 return gfx::SwapResult::SWAP_FAILED;
900 gfx::Size SurfacelessEGL::GetSize() {
901 return size_;
904 bool SurfacelessEGL::Resize(const gfx::Size& size) {
905 size_ = size;
906 return true;
909 EGLSurface SurfacelessEGL::GetHandle() {
910 return EGL_NO_SURFACE;
913 void* SurfacelessEGL::GetShareHandle() {
914 return NULL;
917 SurfacelessEGL::~SurfacelessEGL() {
920 } // namespace gfx