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"
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"
32 void WaitForFence(EGLDisplay display
, EGLSyncKHR fence
) {
33 eglClientWaitSyncKHR(display
, fence
, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR
,
37 // A thin wrapper around GLSurfaceEGL that owns the EGLNativeWindow
38 class GL_EXPORT GLSurfaceOzoneEGL
: public NativeViewGLSurfaceEGL
{
40 GLSurfaceOzoneEGL(scoped_ptr
<ui::SurfaceOzoneEGL
> ozone_surface
,
41 AcceleratedWidget widget
)
42 : NativeViewGLSurfaceEGL(ozone_surface
->GetNativeWindow()),
43 ozone_surface_(ozone_surface
.Pass()),
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
))
56 return NativeViewGLSurfaceEGL::Resize(size
);
58 bool SwapBuffers() override
{
59 if (!NativeViewGLSurfaceEGL::SwapBuffers())
62 return ozone_surface_
->OnSwapBuffers();
64 bool ScheduleOverlayPlane(int z_order
,
65 OverlayTransform transform
,
67 const Rect
& bounds_rect
,
68 const RectF
& crop_rect
) override
{
69 return image
->ScheduleOverlayPlane(
70 widget_
, z_order
, transform
, bounds_rect
, crop_rect
);
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();
84 current_context
&& current_context
->IsCurrent(this);
86 scoped_make_current
.reset(
87 new ui::ScopedMakeCurrent(current_context
, this));
92 ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
94 if (!ozone_surface_
) {
95 LOG(ERROR
) << "Failed to create native surface.";
99 window_
= ozone_surface_
->GetNativeWindow();
101 LOG(ERROR
) << "Failed to initialize.";
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
{
117 GLSurfaceOzoneSurfaceless(scoped_ptr
<ui::SurfaceOzoneEGL
> ozone_surface
,
118 AcceleratedWidget widget
)
119 : SurfacelessEGL(gfx::Size()),
120 ozone_surface_(ozone_surface
.Pass()),
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())
130 vsync_provider_
= ozone_surface_
->CreateVSyncProvider();
131 if (!vsync_provider_
)
135 bool Resize(const gfx::Size
& size
) override
{
136 if (!ozone_surface_
->ResizeNativeWindow(size
))
139 return SurfacelessEGL::Resize(size
);
141 bool SwapBuffers() override
{
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();
150 EGLDisplay display
= GetDisplay();
151 WaitForFence(display
, fence
);
152 eglDestroySyncKHR(display
, fence
);
153 } else if (ozone_surface_
->IsUniversalDisplayLinkDevice()) {
157 return ozone_surface_
->OnSwapBuffers();
159 bool ScheduleOverlayPlane(int z_order
,
160 OverlayTransform transform
,
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.
175 bool SwapBuffersAsync(const SwapCompletionCallback
& callback
) override
{
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;
186 EGLSyncKHR fence
= InsertFence();
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);
200 } else if (ozone_surface_
->IsUniversalDisplayLinkDevice()) {
203 return ozone_surface_
->OnSwapBuffersAsync(callback
);
205 bool PostSubBufferAsync(int x
,
209 const SwapCompletionCallback
& callback
) override
{
210 return SwapBuffersAsync(callback
);
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
,
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
{
247 GLSurfaceOzoneSurfacelessSurfaceImpl(
248 scoped_ptr
<ui::SurfaceOzoneEGL
> ozone_surface
,
249 AcceleratedWidget widget
)
250 : GLSurfaceOzoneSurfaceless(ozone_surface
.Pass(), widget
),
252 current_surface_(0) {
253 for (auto& texture
: textures_
)
257 unsigned int GetBackingFrameBufferObject() override
{ return fbo_
; }
259 bool OnMakeCurrent(GLContext
* context
) override
{
261 glGenFramebuffersEXT(1, &fbo_
);
264 glGenTextures(arraysize(textures_
), textures_
);
265 if (!CreatePixmaps())
269 glBindFramebufferEXT(GL_FRAMEBUFFER
, fbo_
);
270 return SurfacelessEGL::OnMakeCurrent(context
);
273 bool Resize(const gfx::Size
& size
) override
{
274 if (size
== GetSize())
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)))
286 if (!GLSurfaceOzoneSurfaceless::SwapBuffers())
288 current_surface_
^= 1;
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)))
298 if (!GLSurfaceOzoneSurfaceless::SwapBuffersAsync(callback
))
300 current_surface_
^= 1;
305 void Destroy() override
{
306 GLContext
* current_context
= GLContext::GetCurrent();
307 DCHECK(current_context
&& current_context
->IsCurrent(this));
308 glBindFramebufferEXT(GL_FRAMEBUFFER
, 0);
310 glDeleteTextures(arraysize(textures_
), textures_
);
311 for (auto& texture
: textures_
)
313 glDeleteFramebuffersEXT(1, &fbo_
);
316 for (auto image
: images_
) {
318 image
->Destroy(true);
323 class SurfaceImage
: public GLImageLinuxDMABuffer
{
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()))
337 bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget
,
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
);
347 ~SurfaceImage() override
{}
349 scoped_refptr
<ui::NativePixmap
> pixmap_
;
352 ~GLSurfaceOzoneSurfacelessSurfaceImpl() override
{
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() {
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
);
374 scoped_refptr
<SurfaceImage
> image
= new SurfaceImage(GetSize(), GL_RGBA
);
375 if (!image
->Initialize(pixmap
, gfx::GpuMemoryBuffer::Format::BGRA_8888
))
378 // Bind image to texture.
379 ScopedTextureBinder
binder(GL_TEXTURE_2D
, textures_
[i
]);
380 if (!images_
[i
]->BindTexImage(GL_TEXTURE_2D
))
388 scoped_refptr
<GLImage
> images_
[2];
389 int current_surface_
;
390 DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfacelessSurfaceImpl
);
396 bool GLSurface::InitializeOneOffInternal() {
397 switch (GetGLImplementation()) {
398 case kGLImplementationEGLGLES2
:
399 if (!GLSurfaceEGL::InitializeOneOff()) {
400 LOG(ERROR
) << "GLSurfaceEGL::InitializeOneOff failed.";
405 case kGLImplementationOSMesaGL
:
406 case kGLImplementationMockGL
:
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
);
425 scoped_refptr
<GLSurface
> surface
;
426 surface
= new GLSurfaceOzoneSurfaceless(surface_ozone
.Pass(), window
);
427 if (surface
->Initialize())
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())
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
);
454 surface
= new GLSurfaceOzoneSurfacelessSurfaceImpl(surface_ozone
.Pass(),
457 scoped_ptr
<ui::SurfaceOzoneEGL
> surface_ozone
=
458 ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
463 surface
= new GLSurfaceOzoneEGL(surface_ozone
.Pass(), window
);
465 if (!surface
->Initialize())
469 scoped_refptr
<GLSurface
> surface
= new GLSurfaceStub();
470 if (surface
->Initialize())
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())
488 case kGLImplementationEGLGLES2
: {
489 scoped_refptr
<GLSurface
> surface
;
490 if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
491 (size
.width() == 0 && size
.height() == 0)) {
492 surface
= new SurfacelessEGL(size
);
494 surface
= new PbufferGLSurfaceEGL(size
);
496 if (!surface
->Initialize())
506 EGLNativeDisplayType
GetPlatformDefaultEGLNativeDisplay() {
507 return ui::SurfaceFactoryOzone::GetInstance()->GetNativeDisplay();