Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / ui / gl / gl_surface_egl.cc
blob3b81daf83285a476768cb724f7facde9bbca8950
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/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop.h"
14 #include "build/build_config.h"
15 #include "ui/gl/egl_util.h"
16 #include "ui/gl/gl_context.h"
18 #if defined(USE_X11)
19 extern "C" {
20 #include <X11/Xlib.h>
22 #endif
24 using ui::GetLastEGLErrorString;
26 namespace gfx {
28 namespace {
30 EGLConfig g_config;
31 EGLDisplay g_display;
32 EGLNativeDisplayType g_native_display;
33 EGLConfig g_software_config;
34 EGLDisplay g_software_display;
35 EGLNativeDisplayType g_software_native_display;
37 const char* g_egl_extensions = NULL;
38 bool g_egl_create_context_robustness_supported = false;
39 bool g_egl_sync_control_supported = false;
41 class EGLSyncControlVSyncProvider
42 : public gfx::SyncControlVSyncProvider {
43 public:
44 explicit EGLSyncControlVSyncProvider(EGLSurface surface)
45 : SyncControlVSyncProvider(),
46 surface_(surface) {
49 virtual ~EGLSyncControlVSyncProvider() { }
51 protected:
52 virtual bool GetSyncValues(int64* system_time,
53 int64* media_stream_counter,
54 int64* swap_buffer_counter) OVERRIDE {
55 uint64 u_system_time, u_media_stream_counter, u_swap_buffer_counter;
56 bool result = eglGetSyncValuesCHROMIUM(
57 g_display, surface_, &u_system_time,
58 &u_media_stream_counter, &u_swap_buffer_counter) == EGL_TRUE;
59 if (result) {
60 *system_time = static_cast<int64>(u_system_time);
61 *media_stream_counter = static_cast<int64>(u_media_stream_counter);
62 *swap_buffer_counter = static_cast<int64>(u_swap_buffer_counter);
64 return result;
67 virtual bool GetMscRate(int32* numerator, int32* denominator) OVERRIDE {
68 return false;
71 private:
72 EGLSurface surface_;
74 DISALLOW_COPY_AND_ASSIGN(EGLSyncControlVSyncProvider);
77 } // namespace
79 GLSurfaceEGL::GLSurfaceEGL() : software_(false) {}
81 bool GLSurfaceEGL::InitializeOneOff() {
82 static bool initialized = false;
83 if (initialized)
84 return true;
86 #if defined(USE_X11)
87 g_native_display = base::MessagePumpForUI::GetDefaultXDisplay();
88 #else
89 g_native_display = EGL_DEFAULT_DISPLAY;
90 #endif
91 g_display = eglGetDisplay(g_native_display);
92 if (!g_display) {
93 LOG(ERROR) << "eglGetDisplay failed with error " << GetLastEGLErrorString();
94 return false;
97 if (!eglInitialize(g_display, NULL, NULL)) {
98 LOG(ERROR) << "eglInitialize failed with error " << GetLastEGLErrorString();
99 return false;
102 // Choose an EGL configuration.
103 // On X this is only used for PBuffer surfaces.
104 static const EGLint kConfigAttribs[] = {
105 EGL_BUFFER_SIZE, 32,
106 EGL_ALPHA_SIZE, 8,
107 EGL_BLUE_SIZE, 8,
108 EGL_GREEN_SIZE, 8,
109 EGL_RED_SIZE, 8,
110 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
111 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
112 EGL_NONE
115 EGLint num_configs;
116 if (!eglChooseConfig(g_display,
117 kConfigAttribs,
118 NULL,
120 &num_configs)) {
121 LOG(ERROR) << "eglChooseConfig failed with error "
122 << GetLastEGLErrorString();
123 return false;
126 if (num_configs == 0) {
127 LOG(ERROR) << "No suitable EGL configs found.";
128 return false;
131 if (!eglChooseConfig(g_display,
132 kConfigAttribs,
133 &g_config,
135 &num_configs)) {
136 LOG(ERROR) << "eglChooseConfig failed with error "
137 << GetLastEGLErrorString();
138 return false;
141 g_egl_extensions = eglQueryString(g_display, EGL_EXTENSIONS);
142 g_egl_create_context_robustness_supported =
143 HasEGLExtension("EGL_EXT_create_context_robustness");
144 g_egl_sync_control_supported =
145 HasEGLExtension("EGL_CHROMIUM_sync_control");
147 initialized = true;
149 #if defined(USE_X11) || defined(OS_ANDROID)
150 return true;
151 #else
152 g_software_native_display = EGL_SOFTWARE_DISPLAY_ANGLE;
153 #endif
154 g_software_display = eglGetDisplay(g_software_native_display);
155 if (!g_software_display) {
156 return true;
159 if (!eglInitialize(g_software_display, NULL, NULL)) {
160 return true;
163 if (!eglChooseConfig(g_software_display,
164 kConfigAttribs,
165 NULL,
167 &num_configs)) {
168 g_software_display = NULL;
169 return true;
172 if (num_configs == 0) {
173 g_software_display = NULL;
174 return true;
177 if (!eglChooseConfig(g_software_display,
178 kConfigAttribs,
179 &g_software_config,
181 &num_configs)) {
182 g_software_display = NULL;
183 return false;
186 return true;
189 EGLDisplay GLSurfaceEGL::GetDisplay() {
190 return software_ ? g_software_display : g_display;
193 EGLDisplay GLSurfaceEGL::GetHardwareDisplay() {
194 return g_display;
197 EGLDisplay GLSurfaceEGL::GetSoftwareDisplay() {
198 return g_software_display;
201 EGLNativeDisplayType GLSurfaceEGL::GetNativeDisplay() {
202 return g_native_display;
205 const char* GLSurfaceEGL::GetEGLExtensions() {
206 return g_egl_extensions;
209 bool GLSurfaceEGL::HasEGLExtension(const char* name) {
210 return ExtensionsContain(GetEGLExtensions(), name);
213 bool GLSurfaceEGL::IsCreateContextRobustnessSupported() {
214 return g_egl_create_context_robustness_supported;
217 GLSurfaceEGL::~GLSurfaceEGL() {}
219 NativeViewGLSurfaceEGL::NativeViewGLSurfaceEGL(bool software,
220 gfx::AcceleratedWidget window)
221 : window_(window),
222 surface_(NULL),
223 supports_post_sub_buffer_(false),
224 config_(NULL) {
225 software_ = software;
226 #if defined(OS_ANDROID)
227 if (window)
228 ANativeWindow_acquire(window);
229 #endif
232 bool NativeViewGLSurfaceEGL::Initialize() {
233 DCHECK(!surface_);
235 if (window_ == kNullAcceleratedWidget) {
236 LOG(ERROR) << "Trying to create surface without window.";
237 return false;
240 if (!GetDisplay()) {
241 LOG(ERROR) << "Trying to create surface with invalid display.";
242 return false;
245 static const EGLint egl_window_attributes_sub_buffer[] = {
246 EGL_POST_SUB_BUFFER_SUPPORTED_NV, EGL_TRUE,
247 EGL_NONE
250 // Create a surface for the native window.
251 surface_ = eglCreateWindowSurface(
252 GetDisplay(),
253 GetConfig(),
254 window_,
255 gfx::g_driver_egl.ext.b_EGL_NV_post_sub_buffer ?
256 egl_window_attributes_sub_buffer :
257 NULL);
259 if (!surface_) {
260 LOG(ERROR) << "eglCreateWindowSurface failed with error "
261 << GetLastEGLErrorString();
262 Destroy();
263 return false;
266 EGLint surfaceVal;
267 EGLBoolean retVal = eglQuerySurface(GetDisplay(),
268 surface_,
269 EGL_POST_SUB_BUFFER_SUPPORTED_NV,
270 &surfaceVal);
271 supports_post_sub_buffer_ = (surfaceVal && retVal) == EGL_TRUE;
273 if (g_egl_sync_control_supported)
274 vsync_provider_.reset(new EGLSyncControlVSyncProvider(surface_));
276 return true;
279 void NativeViewGLSurfaceEGL::Destroy() {
280 if (surface_) {
281 if (!eglDestroySurface(GetDisplay(), surface_)) {
282 LOG(ERROR) << "eglDestroySurface failed with error "
283 << GetLastEGLErrorString();
285 surface_ = NULL;
289 EGLConfig NativeViewGLSurfaceEGL::GetConfig() {
290 #if !defined(USE_X11)
291 return software_ ? g_software_config : g_config;
292 #else
293 if (!config_) {
294 // Get a config compatible with the window
295 DCHECK(window_);
296 XWindowAttributes win_attribs;
297 if (!XGetWindowAttributes(GetNativeDisplay(), window_, &win_attribs)) {
298 return NULL;
301 // Try matching the window depth with an alpha channel,
302 // because we're worried the destination alpha width could
303 // constrain blending precision.
304 const int kBufferSizeOffset = 1;
305 const int kAlphaSizeOffset = 3;
306 EGLint config_attribs[] = {
307 EGL_BUFFER_SIZE, ~0,
308 EGL_ALPHA_SIZE, 8,
309 EGL_BLUE_SIZE, 8,
310 EGL_GREEN_SIZE, 8,
311 EGL_RED_SIZE, 8,
312 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
313 EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT,
314 EGL_NONE
316 config_attribs[kBufferSizeOffset] = win_attribs.depth;
318 EGLint num_configs;
319 if (!eglChooseConfig(g_display,
320 config_attribs,
321 &config_,
323 &num_configs)) {
324 LOG(ERROR) << "eglChooseConfig failed with error "
325 << GetLastEGLErrorString();
326 return NULL;
329 if (num_configs) {
330 EGLint config_depth;
331 if (!eglGetConfigAttrib(g_display,
332 config_,
333 EGL_BUFFER_SIZE,
334 &config_depth)) {
335 LOG(ERROR) << "eglGetConfigAttrib failed with error "
336 << GetLastEGLErrorString();
337 return NULL;
340 if (config_depth == win_attribs.depth) {
341 return config_;
345 // Try without an alpha channel.
346 config_attribs[kAlphaSizeOffset] = 0;
347 if (!eglChooseConfig(g_display,
348 config_attribs,
349 &config_,
351 &num_configs)) {
352 LOG(ERROR) << "eglChooseConfig failed with error "
353 << GetLastEGLErrorString();
354 return NULL;
357 if (num_configs == 0) {
358 LOG(ERROR) << "No suitable EGL configs found.";
359 return NULL;
362 return config_;
363 #endif
366 bool NativeViewGLSurfaceEGL::IsOffscreen() {
367 return false;
370 bool NativeViewGLSurfaceEGL::SwapBuffers() {
371 if (!eglSwapBuffers(GetDisplay(), surface_)) {
372 DVLOG(1) << "eglSwapBuffers failed with error "
373 << GetLastEGLErrorString();
374 return false;
377 return true;
380 gfx::Size NativeViewGLSurfaceEGL::GetSize() {
381 EGLint width;
382 EGLint height;
383 if (!eglQuerySurface(GetDisplay(), surface_, EGL_WIDTH, &width) ||
384 !eglQuerySurface(GetDisplay(), surface_, EGL_HEIGHT, &height)) {
385 NOTREACHED() << "eglQuerySurface failed with error "
386 << GetLastEGLErrorString();
387 return gfx::Size();
390 return gfx::Size(width, height);
393 bool NativeViewGLSurfaceEGL::Resize(const gfx::Size& size) {
394 if (size == GetSize())
395 return true;
397 GLContext* current_context = GLContext::GetCurrent();
398 bool was_current = current_context && current_context->IsCurrent(this);
399 if (was_current)
400 current_context->ReleaseCurrent(this);
402 Destroy();
404 if (!Initialize()) {
405 LOG(ERROR) << "Failed to resize pbuffer.";
406 return false;
409 if (was_current)
410 return current_context->MakeCurrent(this);
411 return true;
414 EGLSurface NativeViewGLSurfaceEGL::GetHandle() {
415 return surface_;
418 std::string NativeViewGLSurfaceEGL::GetExtensions() {
419 std::string extensions = GLSurface::GetExtensions();
420 if (supports_post_sub_buffer_) {
421 extensions += extensions.empty() ? "" : " ";
422 extensions += "GL_CHROMIUM_post_sub_buffer";
424 return extensions;
427 bool NativeViewGLSurfaceEGL::PostSubBuffer(
428 int x, int y, int width, int height) {
429 DCHECK(supports_post_sub_buffer_);
430 if (!eglPostSubBufferNV(GetDisplay(), surface_, x, y, width, height)) {
431 DVLOG(1) << "eglPostSubBufferNV failed with error "
432 << GetLastEGLErrorString();
433 return false;
435 return true;
438 VSyncProvider* NativeViewGLSurfaceEGL::GetVSyncProvider() {
439 return vsync_provider_.get();
442 NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() {
443 Destroy();
444 #if defined(OS_ANDROID)
445 if (window_)
446 ANativeWindow_release(window_);
447 #endif
450 void NativeViewGLSurfaceEGL::SetHandle(EGLSurface surface) {
451 surface_ = surface;
454 PbufferGLSurfaceEGL::PbufferGLSurfaceEGL(bool software, const gfx::Size& size)
455 : size_(size),
456 surface_(NULL) {
457 software_ = software;
460 bool PbufferGLSurfaceEGL::Initialize() {
461 EGLSurface old_surface = surface_;
463 EGLDisplay display = GetDisplay();
464 if (!display) {
465 LOG(ERROR) << "Trying to create surface with invalid display.";
466 return false;
469 if (size_.GetArea() == 0) {
470 LOG(ERROR) << "Error: surface has zero area "
471 << size_.width() << " x " << size_.height();
472 return false;
475 // Allocate the new pbuffer surface before freeing the old one to ensure
476 // they have different addresses. If they have the same address then a
477 // future call to MakeCurrent might early out because it appears the current
478 // context and surface have not changed.
479 const EGLint pbuffer_attribs[] = {
480 EGL_WIDTH, size_.width(),
481 EGL_HEIGHT, size_.height(),
482 EGL_NONE
485 EGLSurface new_surface = eglCreatePbufferSurface(display,
486 GetConfig(),
487 pbuffer_attribs);
488 if (!new_surface) {
489 LOG(ERROR) << "eglCreatePbufferSurface failed with error "
490 << GetLastEGLErrorString();
491 return false;
494 if (old_surface)
495 eglDestroySurface(display, old_surface);
497 surface_ = new_surface;
498 return true;
501 void PbufferGLSurfaceEGL::Destroy() {
502 if (surface_) {
503 if (!eglDestroySurface(GetDisplay(), surface_)) {
504 LOG(ERROR) << "eglDestroySurface failed with error "
505 << GetLastEGLErrorString();
507 surface_ = NULL;
511 EGLConfig PbufferGLSurfaceEGL::GetConfig() {
512 return software_ ? g_software_config : g_config;
515 bool PbufferGLSurfaceEGL::IsOffscreen() {
516 return true;
519 bool PbufferGLSurfaceEGL::SwapBuffers() {
520 NOTREACHED() << "Attempted to call SwapBuffers on a PbufferGLSurfaceEGL.";
521 return false;
524 gfx::Size PbufferGLSurfaceEGL::GetSize() {
525 return size_;
528 bool PbufferGLSurfaceEGL::Resize(const gfx::Size& size) {
529 if (size == size_)
530 return true;
532 GLContext* current_context = GLContext::GetCurrent();
533 bool was_current = current_context && current_context->IsCurrent(this);
535 size_ = size;
537 if (!Initialize()) {
538 LOG(ERROR) << "Failed to resize pbuffer.";
539 return false;
542 if (was_current)
543 return current_context->MakeCurrent(this);
545 return true;
548 EGLSurface PbufferGLSurfaceEGL::GetHandle() {
549 return surface_;
552 void* PbufferGLSurfaceEGL::GetShareHandle() {
553 #if defined(OS_ANDROID)
554 NOTREACHED();
555 return NULL;
556 #else
557 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_query_surface_pointer)
558 return NULL;
560 if (!gfx::g_driver_egl.ext.b_EGL_ANGLE_surface_d3d_texture_2d_share_handle)
561 return NULL;
563 void* handle;
564 if (!eglQuerySurfacePointerANGLE(g_display,
565 GetHandle(),
566 EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE,
567 &handle)) {
568 return NULL;
571 return handle;
572 #endif
575 PbufferGLSurfaceEGL::~PbufferGLSurfaceEGL() {
576 Destroy();
579 } // namespace gfx