Fix WindowAndroid leak in Android WebView
[chromium-blink-merge.git] / ui / gl / gl_surface_ozone.cc
blob800be1759fe96331573944463123e00ce19968f2
1 // Copyright 2014 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.h"
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/threading/worker_pool.h"
14 #include "ui/gfx/native_widget_types.h"
15 #include "ui/gl/gl_context.h"
16 #include "ui/gl/gl_image.h"
17 #include "ui/gl/gl_image_linux_dma_buffer.h"
18 #include "ui/gl/gl_implementation.h"
19 #include "ui/gl/gl_surface_egl.h"
20 #include "ui/gl/gl_surface_osmesa.h"
21 #include "ui/gl/gl_surface_stub.h"
22 #include "ui/gl/scoped_binders.h"
23 #include "ui/gl/scoped_make_current.h"
24 #include "ui/ozone/public/native_pixmap.h"
25 #include "ui/ozone/public/surface_factory_ozone.h"
26 #include "ui/ozone/public/surface_ozone_egl.h"
28 namespace gfx {
30 namespace {
32 void WaitForFence(EGLDisplay display, EGLSyncKHR fence) {
33 eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
34 EGL_FOREVER_KHR);
37 // A thin wrapper around GLSurfaceEGL that owns the EGLNativeWindow
38 class GL_EXPORT GLSurfaceOzoneEGL : public NativeViewGLSurfaceEGL {
39 public:
40 GLSurfaceOzoneEGL(scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
41 AcceleratedWidget widget)
42 : NativeViewGLSurfaceEGL(ozone_surface->GetNativeWindow()),
43 ozone_surface_(ozone_surface.Pass()),
44 widget_(widget) {}
46 bool Initialize() override {
47 return Initialize(ozone_surface_->CreateVSyncProvider());
49 bool Resize(const gfx::Size& size) override {
50 if (!ozone_surface_->ResizeNativeWindow(size)) {
51 if (!ReinitializeNativeSurface() ||
52 !ozone_surface_->ResizeNativeWindow(size))
53 return false;
56 return NativeViewGLSurfaceEGL::Resize(size);
58 bool SwapBuffers() override {
59 if (!NativeViewGLSurfaceEGL::SwapBuffers())
60 return false;
62 return ozone_surface_->OnSwapBuffers();
64 bool ScheduleOverlayPlane(int z_order,
65 OverlayTransform transform,
66 GLImage* image,
67 const Rect& bounds_rect,
68 const RectF& crop_rect) override {
69 return image->ScheduleOverlayPlane(
70 widget_, z_order, transform, bounds_rect, crop_rect);
73 private:
74 using NativeViewGLSurfaceEGL::Initialize;
76 ~GLSurfaceOzoneEGL() override {
77 Destroy(); // EGL surface must be destroyed before SurfaceOzone
80 bool ReinitializeNativeSurface() {
81 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
82 GLContext* current_context = GLContext::GetCurrent();
83 bool was_current =
84 current_context && current_context->IsCurrent(this);
85 if (was_current) {
86 scoped_make_current.reset(
87 new ui::ScopedMakeCurrent(current_context, this));
90 Destroy();
91 ozone_surface_ =
92 ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
93 widget_).Pass();
94 if (!ozone_surface_) {
95 LOG(ERROR) << "Failed to create native surface.";
96 return false;
99 window_ = ozone_surface_->GetNativeWindow();
100 if (!Initialize()) {
101 LOG(ERROR) << "Failed to initialize.";
102 return false;
105 return true;
108 // The native surface. Deleting this is allowed to free the EGLNativeWindow.
109 scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface_;
110 AcceleratedWidget widget_;
112 DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneEGL);
115 class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL {
116 public:
117 GLSurfaceOzoneSurfaceless(scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
118 AcceleratedWidget widget)
119 : SurfacelessEGL(gfx::Size()),
120 ozone_surface_(ozone_surface.Pass()),
121 widget_(widget),
122 has_implicit_external_sync_(
123 HasEGLExtension("EGL_ARM_implicit_external_sync")),
124 last_swap_buffers_result_(true),
125 weak_factory_(this) {}
127 bool Initialize() override {
128 if (!SurfacelessEGL::Initialize())
129 return false;
130 vsync_provider_ = ozone_surface_->CreateVSyncProvider();
131 if (!vsync_provider_)
132 return false;
133 return true;
135 bool Resize(const gfx::Size& size) override {
136 if (!ozone_surface_->ResizeNativeWindow(size))
137 return false;
139 return SurfacelessEGL::Resize(size);
141 bool SwapBuffers() override {
142 glFlush();
143 // TODO: the following should be replaced by a per surface flush as it gets
144 // implemented in GL drivers.
145 if (has_implicit_external_sync_) {
146 EGLSyncKHR fence = InsertFence();
147 if (!fence)
148 return false;
150 EGLDisplay display = GetDisplay();
151 WaitForFence(display, fence);
152 eglDestroySyncKHR(display, fence);
153 } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) {
154 glFinish();
157 return ozone_surface_->OnSwapBuffers();
159 bool ScheduleOverlayPlane(int z_order,
160 OverlayTransform transform,
161 GLImage* image,
162 const Rect& bounds_rect,
163 const RectF& crop_rect) override {
164 return image->ScheduleOverlayPlane(
165 widget_, z_order, transform, bounds_rect, crop_rect);
167 bool IsOffscreen() override { return false; }
168 VSyncProvider* GetVSyncProvider() override { return vsync_provider_.get(); }
169 bool SupportsPostSubBuffer() override { return true; }
170 bool PostSubBuffer(int x, int y, int width, int height) override {
171 // The actual sub buffer handling is handled at higher layers.
172 SwapBuffers();
173 return true;
175 bool SwapBuffersAsync(const SwapCompletionCallback& callback) override {
176 glFlush();
177 // TODO: the following should be replaced by a per surface flush as it gets
178 // implemented in GL drivers.
179 if (has_implicit_external_sync_) {
180 // If last swap failed, don't try to schedule new ones.
181 if (!last_swap_buffers_result_) {
182 last_swap_buffers_result_ = true;
183 return false;
186 EGLSyncKHR fence = InsertFence();
187 if (!fence)
188 return false;
190 base::Closure fence_wait_task =
191 base::Bind(&WaitForFence, GetDisplay(), fence);
193 base::Closure fence_retired_callback =
194 base::Bind(&GLSurfaceOzoneSurfaceless::FenceRetired,
195 weak_factory_.GetWeakPtr(), fence, callback);
197 base::WorkerPool::PostTaskAndReply(FROM_HERE, fence_wait_task,
198 fence_retired_callback, false);
199 return true;
200 } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) {
201 glFinish();
203 return ozone_surface_->OnSwapBuffersAsync(callback);
205 bool PostSubBufferAsync(int x,
206 int y,
207 int width,
208 int height,
209 const SwapCompletionCallback& callback) override {
210 return SwapBuffersAsync(callback);
213 protected:
214 ~GLSurfaceOzoneSurfaceless() override {
215 Destroy(); // EGL surface must be destroyed before SurfaceOzone
218 EGLSyncKHR InsertFence() {
219 const EGLint attrib_list[] = {EGL_SYNC_CONDITION_KHR,
220 EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM,
221 EGL_NONE};
222 return eglCreateSyncKHR(GetDisplay(), EGL_SYNC_FENCE_KHR, attrib_list);
225 void FenceRetired(EGLSyncKHR fence, const SwapCompletionCallback& callback) {
226 eglDestroySyncKHR(GetDisplay(), fence);
227 last_swap_buffers_result_ = ozone_surface_->OnSwapBuffersAsync(callback);
230 // The native surface. Deleting this is allowed to free the EGLNativeWindow.
231 scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface_;
232 AcceleratedWidget widget_;
233 scoped_ptr<VSyncProvider> vsync_provider_;
234 bool has_implicit_external_sync_;
235 bool last_swap_buffers_result_;
237 base::WeakPtrFactory<GLSurfaceOzoneSurfaceless> weak_factory_;
239 DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfaceless);
242 // This provides surface-like semantics implemented through surfaceless.
243 // A framebuffer is bound automatically.
244 class GL_EXPORT GLSurfaceOzoneSurfacelessSurfaceImpl
245 : public GLSurfaceOzoneSurfaceless {
246 public:
247 GLSurfaceOzoneSurfacelessSurfaceImpl(
248 scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
249 AcceleratedWidget widget)
250 : GLSurfaceOzoneSurfaceless(ozone_surface.Pass(), widget),
251 fbo_(0),
252 current_surface_(0) {
253 for (auto& texture : textures_)
254 texture = 0;
257 unsigned int GetBackingFrameBufferObject() override { return fbo_; }
259 bool OnMakeCurrent(GLContext* context) override {
260 if (!fbo_) {
261 glGenFramebuffersEXT(1, &fbo_);
262 if (!fbo_)
263 return false;
264 glGenTextures(arraysize(textures_), textures_);
265 if (!CreatePixmaps())
266 return false;
268 BindFramebuffer();
269 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo_);
270 return SurfacelessEGL::OnMakeCurrent(context);
273 bool Resize(const gfx::Size& size) override {
274 if (size == GetSize())
275 return true;
276 return GLSurfaceOzoneSurfaceless::Resize(size) && CreatePixmaps();
279 bool SupportsPostSubBuffer() override { return false; }
281 bool SwapBuffers() override {
282 if (!images_[current_surface_]->ScheduleOverlayPlane(
283 widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE,
284 gfx::Rect(GetSize()), gfx::RectF(1, 1)))
285 return false;
286 if (!GLSurfaceOzoneSurfaceless::SwapBuffers())
287 return false;
288 current_surface_ ^= 1;
289 BindFramebuffer();
290 return true;
293 bool SwapBuffersAsync(const SwapCompletionCallback& callback) override {
294 if (!images_[current_surface_]->ScheduleOverlayPlane(
295 widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE,
296 gfx::Rect(GetSize()), gfx::RectF(1, 1)))
297 return false;
298 if (!GLSurfaceOzoneSurfaceless::SwapBuffersAsync(callback))
299 return false;
300 current_surface_ ^= 1;
301 BindFramebuffer();
302 return true;
305 void Destroy() override {
306 GLContext* current_context = GLContext::GetCurrent();
307 DCHECK(current_context && current_context->IsCurrent(this));
308 glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
309 if (fbo_) {
310 glDeleteTextures(arraysize(textures_), textures_);
311 for (auto& texture : textures_)
312 texture = 0;
313 glDeleteFramebuffersEXT(1, &fbo_);
314 fbo_ = 0;
316 for (auto image : images_) {
317 if (image)
318 image->Destroy(true);
322 private:
323 class SurfaceImage : public GLImageLinuxDMABuffer {
324 public:
325 SurfaceImage(const gfx::Size& size, unsigned internalformat)
326 : GLImageLinuxDMABuffer(size, internalformat) {}
328 bool Initialize(scoped_refptr<ui::NativePixmap> pixmap,
329 gfx::GpuMemoryBuffer::Format format) {
330 base::FileDescriptor handle(pixmap->GetDmaBufFd(), false);
331 if (!GLImageLinuxDMABuffer::Initialize(handle, format,
332 pixmap->GetDmaBufPitch()))
333 return false;
334 pixmap_ = pixmap;
335 return true;
337 bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
338 int z_order,
339 gfx::OverlayTransform transform,
340 const gfx::Rect& bounds_rect,
341 const gfx::RectF& crop_rect) override {
342 return ui::SurfaceFactoryOzone::GetInstance()->ScheduleOverlayPlane(
343 widget, z_order, transform, pixmap_, bounds_rect, crop_rect);
346 private:
347 ~SurfaceImage() override {}
349 scoped_refptr<ui::NativePixmap> pixmap_;
352 ~GLSurfaceOzoneSurfacelessSurfaceImpl() override {
353 DCHECK(!fbo_);
354 for (size_t i = 0; i < arraysize(textures_); i++)
355 DCHECK(!textures_[i]) << "texture " << i << " not released";
358 void BindFramebuffer() {
359 ScopedFrameBufferBinder fb(fbo_);
360 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
361 GL_TEXTURE_2D, textures_[current_surface_], 0);
364 bool CreatePixmaps() {
365 if (!fbo_)
366 return true;
367 for (size_t i = 0; i < arraysize(textures_); i++) {
368 scoped_refptr<ui::NativePixmap> pixmap =
369 ui::SurfaceFactoryOzone::GetInstance()->CreateNativePixmap(
370 widget_, GetSize(), ui::SurfaceFactoryOzone::RGBA_8888,
371 ui::SurfaceFactoryOzone::SCANOUT);
372 if (!pixmap)
373 return false;
374 scoped_refptr<SurfaceImage> image = new SurfaceImage(GetSize(), GL_RGBA);
375 if (!image->Initialize(pixmap, gfx::GpuMemoryBuffer::Format::BGRA_8888))
376 return false;
377 images_[i] = image;
378 // Bind image to texture.
379 ScopedTextureBinder binder(GL_TEXTURE_2D, textures_[i]);
380 if (!images_[i]->BindTexImage(GL_TEXTURE_2D))
381 return false;
383 return true;
386 GLuint fbo_;
387 GLuint textures_[2];
388 scoped_refptr<GLImage> images_[2];
389 int current_surface_;
390 DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfacelessSurfaceImpl);
393 } // namespace
395 // static
396 bool GLSurface::InitializeOneOffInternal() {
397 switch (GetGLImplementation()) {
398 case kGLImplementationEGLGLES2:
399 if (!GLSurfaceEGL::InitializeOneOff()) {
400 LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
401 return false;
404 return true;
405 case kGLImplementationOSMesaGL:
406 case kGLImplementationMockGL:
407 return true;
408 default:
409 return false;
413 // static
414 scoped_refptr<GLSurface> GLSurface::CreateSurfacelessViewGLSurface(
415 gfx::AcceleratedWidget window) {
416 if (GetGLImplementation() == kGLImplementationEGLGLES2 &&
417 window != kNullAcceleratedWidget &&
418 GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
419 ui::SurfaceFactoryOzone::GetInstance()->CanShowPrimaryPlaneAsOverlay()) {
420 scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
421 ui::SurfaceFactoryOzone::GetInstance()
422 ->CreateSurfacelessEGLSurfaceForWidget(window);
423 if (!surface_ozone)
424 return nullptr;
425 scoped_refptr<GLSurface> surface;
426 surface = new GLSurfaceOzoneSurfaceless(surface_ozone.Pass(), window);
427 if (surface->Initialize())
428 return surface;
431 return nullptr;
434 // static
435 scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
436 gfx::AcceleratedWidget window) {
437 if (GetGLImplementation() == kGLImplementationOSMesaGL) {
438 scoped_refptr<GLSurface> surface(new GLSurfaceOSMesaHeadless());
439 if (!surface->Initialize())
440 return NULL;
441 return surface;
443 DCHECK(GetGLImplementation() == kGLImplementationEGLGLES2);
444 if (window != kNullAcceleratedWidget) {
445 scoped_refptr<GLSurface> surface;
446 if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
447 ui::SurfaceFactoryOzone::GetInstance()
448 ->CanShowPrimaryPlaneAsOverlay()) {
449 scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
450 ui::SurfaceFactoryOzone::GetInstance()
451 ->CreateSurfacelessEGLSurfaceForWidget(window);
452 if (!surface_ozone)
453 return NULL;
454 surface = new GLSurfaceOzoneSurfacelessSurfaceImpl(surface_ozone.Pass(),
455 window);
456 } else {
457 scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
458 ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
459 window);
460 if (!surface_ozone)
461 return NULL;
463 surface = new GLSurfaceOzoneEGL(surface_ozone.Pass(), window);
465 if (!surface->Initialize())
466 return NULL;
467 return surface;
468 } else {
469 scoped_refptr<GLSurface> surface = new GLSurfaceStub();
470 if (surface->Initialize())
471 return surface;
473 return NULL;
476 // static
477 scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
478 const gfx::Size& size) {
479 switch (GetGLImplementation()) {
480 case kGLImplementationOSMesaGL: {
481 scoped_refptr<GLSurface> surface(
482 new GLSurfaceOSMesa(OSMesaSurfaceFormatBGRA, size));
483 if (!surface->Initialize())
484 return NULL;
486 return surface;
488 case kGLImplementationEGLGLES2: {
489 scoped_refptr<GLSurface> surface;
490 if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
491 (size.width() == 0 && size.height() == 0)) {
492 surface = new SurfacelessEGL(size);
493 } else
494 surface = new PbufferGLSurfaceEGL(size);
496 if (!surface->Initialize())
497 return NULL;
498 return surface;
500 default:
501 NOTREACHED();
502 return NULL;
506 EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
507 return ui::SurfaceFactoryOzone::GetInstance()->GetNativeDisplay();
510 } // namespace gfx