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/scoped_vector.h"
13 #include "base/memory/weak_ptr.h"
14 #include "base/threading/worker_pool.h"
15 #include "ui/gfx/native_widget_types.h"
16 #include "ui/gl/gl_context.h"
17 #include "ui/gl/gl_image.h"
18 #include "ui/gl/gl_image_linux_dma_buffer.h"
19 #include "ui/gl/gl_implementation.h"
20 #include "ui/gl/gl_surface_egl.h"
21 #include "ui/gl/gl_surface_osmesa.h"
22 #include "ui/gl/gl_surface_stub.h"
23 #include "ui/gl/scoped_binders.h"
24 #include "ui/gl/scoped_make_current.h"
25 #include "ui/ozone/public/native_pixmap.h"
26 #include "ui/ozone/public/surface_factory_ozone.h"
27 #include "ui/ozone/public/surface_ozone_egl.h"
33 void WaitForFence(EGLDisplay display
, EGLSyncKHR fence
) {
34 eglClientWaitSyncKHR(display
, fence
, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR
,
38 // A thin wrapper around GLSurfaceEGL that owns the EGLNativeWindow
39 class GL_EXPORT GLSurfaceOzoneEGL
: public NativeViewGLSurfaceEGL
{
41 GLSurfaceOzoneEGL(scoped_ptr
<ui::SurfaceOzoneEGL
> ozone_surface
,
42 AcceleratedWidget widget
)
43 : NativeViewGLSurfaceEGL(ozone_surface
->GetNativeWindow()),
44 ozone_surface_(ozone_surface
.Pass()),
47 bool Initialize() override
{
48 return Initialize(ozone_surface_
->CreateVSyncProvider());
50 bool Resize(const gfx::Size
& size
) override
{
51 if (!ozone_surface_
->ResizeNativeWindow(size
)) {
52 if (!ReinitializeNativeSurface() ||
53 !ozone_surface_
->ResizeNativeWindow(size
))
57 return NativeViewGLSurfaceEGL::Resize(size
);
59 bool SwapBuffers() override
{
60 if (!NativeViewGLSurfaceEGL::SwapBuffers())
63 return ozone_surface_
->OnSwapBuffers();
65 bool ScheduleOverlayPlane(int z_order
,
66 OverlayTransform transform
,
68 const Rect
& bounds_rect
,
69 const RectF
& crop_rect
) override
{
70 return image
->ScheduleOverlayPlane(
71 widget_
, z_order
, transform
, bounds_rect
, crop_rect
);
75 using NativeViewGLSurfaceEGL::Initialize
;
77 ~GLSurfaceOzoneEGL() override
{
78 Destroy(); // EGL surface must be destroyed before SurfaceOzone
81 bool ReinitializeNativeSurface() {
82 scoped_ptr
<ui::ScopedMakeCurrent
> scoped_make_current
;
83 GLContext
* current_context
= GLContext::GetCurrent();
85 current_context
&& current_context
->IsCurrent(this);
87 scoped_make_current
.reset(
88 new ui::ScopedMakeCurrent(current_context
, this));
93 ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
95 if (!ozone_surface_
) {
96 LOG(ERROR
) << "Failed to create native surface.";
100 window_
= ozone_surface_
->GetNativeWindow();
102 LOG(ERROR
) << "Failed to initialize.";
109 // The native surface. Deleting this is allowed to free the EGLNativeWindow.
110 scoped_ptr
<ui::SurfaceOzoneEGL
> ozone_surface_
;
111 AcceleratedWidget widget_
;
113 DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneEGL
);
116 class GL_EXPORT GLSurfaceOzoneSurfaceless
: public SurfacelessEGL
{
118 GLSurfaceOzoneSurfaceless(scoped_ptr
<ui::SurfaceOzoneEGL
> ozone_surface
,
119 AcceleratedWidget widget
)
120 : SurfacelessEGL(gfx::Size()),
121 ozone_surface_(ozone_surface
.Pass()),
123 has_implicit_external_sync_(
124 HasEGLExtension("EGL_ARM_implicit_external_sync")),
125 last_swap_buffers_result_(true),
126 weak_factory_(this) {
127 unsubmitted_frames_
.push_back(new PendingFrame());
130 bool Initialize() override
{
131 if (!SurfacelessEGL::Initialize())
133 vsync_provider_
= ozone_surface_
->CreateVSyncProvider();
134 if (!vsync_provider_
)
138 bool Resize(const gfx::Size
& size
) override
{
139 if (!ozone_surface_
->ResizeNativeWindow(size
))
142 return SurfacelessEGL::Resize(size
);
144 bool SwapBuffers() override
{
146 // TODO: the following should be replaced by a per surface flush as it gets
147 // implemented in GL drivers.
148 if (has_implicit_external_sync_
) {
149 EGLSyncKHR fence
= InsertFence();
153 EGLDisplay display
= GetDisplay();
154 WaitForFence(display
, fence
);
155 eglDestroySyncKHR(display
, fence
);
156 } else if (ozone_surface_
->IsUniversalDisplayLinkDevice()) {
160 unsubmitted_frames_
.back()->ScheduleOverlayPlanes(widget_
);
161 unsubmitted_frames_
.back()->overlays
.clear();
163 return ozone_surface_
->OnSwapBuffers();
165 bool ScheduleOverlayPlane(int z_order
,
166 OverlayTransform transform
,
168 const Rect
& bounds_rect
,
169 const RectF
& crop_rect
) override
{
170 unsubmitted_frames_
.back()->overlays
.push_back(PendingFrame::Overlay(
171 z_order
, transform
, image
, bounds_rect
, crop_rect
));
174 bool IsOffscreen() override
{ return false; }
175 VSyncProvider
* GetVSyncProvider() override
{ return vsync_provider_
.get(); }
176 bool SupportsPostSubBuffer() override
{ return true; }
177 bool PostSubBuffer(int x
, int y
, int width
, int height
) override
{
178 // The actual sub buffer handling is handled at higher layers.
182 bool SwapBuffersAsync(const SwapCompletionCallback
& callback
) override
{
184 // TODO: the following should be replaced by a per surface flush as it gets
185 // implemented in GL drivers.
186 if (has_implicit_external_sync_
) {
187 // If last swap failed, don't try to schedule new ones.
188 if (!last_swap_buffers_result_
) {
189 last_swap_buffers_result_
= true;
193 EGLSyncKHR fence
= InsertFence();
197 base::Closure fence_wait_task
=
198 base::Bind(&WaitForFence
, GetDisplay(), fence
);
200 PendingFrame
* frame
= unsubmitted_frames_
.back();
201 frame
->callback
= callback
;
202 base::Closure fence_retired_callback
=
203 base::Bind(&GLSurfaceOzoneSurfaceless::FenceRetired
,
204 weak_factory_
.GetWeakPtr(), fence
, frame
);
206 base::WorkerPool::PostTaskAndReply(FROM_HERE
, fence_wait_task
,
207 fence_retired_callback
, false);
208 unsubmitted_frames_
.push_back(new PendingFrame());
210 } else if (ozone_surface_
->IsUniversalDisplayLinkDevice()) {
213 unsubmitted_frames_
.back()->ScheduleOverlayPlanes(widget_
);
214 unsubmitted_frames_
.back()->overlays
.clear();
215 return ozone_surface_
->OnSwapBuffersAsync(callback
);
217 bool PostSubBufferAsync(int x
,
221 const SwapCompletionCallback
& callback
) override
{
222 return SwapBuffersAsync(callback
);
226 struct PendingFrame
{
229 OverlayTransform transform
,
231 const Rect
& bounds_rect
,
232 const RectF
& crop_rect
)
234 transform(transform
),
236 bounds_rect(bounds_rect
),
237 crop_rect(crop_rect
) {}
239 bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget
) const {
240 return image
->ScheduleOverlayPlane(widget
, z_order
, transform
,
241 bounds_rect
, crop_rect
);
245 OverlayTransform transform
;
246 scoped_refptr
<GLImage
> image
;
251 PendingFrame() : ready(false) {}
253 bool ScheduleOverlayPlanes(gfx::AcceleratedWidget widget
) {
254 for (const auto& overlay
: overlays
)
255 if (!overlay
.ScheduleOverlayPlane(widget
))
260 std::vector
<Overlay
> overlays
;
261 SwapCompletionCallback callback
;
264 ~GLSurfaceOzoneSurfaceless() override
{
265 Destroy(); // EGL surface must be destroyed before SurfaceOzone
268 void SubmitFrames() {
269 while (!unsubmitted_frames_
.empty() && unsubmitted_frames_
.front()->ready
) {
270 PendingFrame
* frame
= unsubmitted_frames_
.front();
271 last_swap_buffers_result_
=
272 last_swap_buffers_result_
&& frame
->ScheduleOverlayPlanes(widget_
) &&
273 ozone_surface_
->OnSwapBuffersAsync(frame
->callback
);
274 unsubmitted_frames_
.erase(unsubmitted_frames_
.begin());
278 EGLSyncKHR
InsertFence() {
279 const EGLint attrib_list
[] = {EGL_SYNC_CONDITION_KHR
,
280 EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM
,
282 return eglCreateSyncKHR(GetDisplay(), EGL_SYNC_FENCE_KHR
, attrib_list
);
285 void FenceRetired(EGLSyncKHR fence
, PendingFrame
* frame
) {
286 eglDestroySyncKHR(GetDisplay(), fence
);
291 // The native surface. Deleting this is allowed to free the EGLNativeWindow.
292 scoped_ptr
<ui::SurfaceOzoneEGL
> ozone_surface_
;
293 AcceleratedWidget widget_
;
294 scoped_ptr
<VSyncProvider
> vsync_provider_
;
295 ScopedVector
<PendingFrame
> unsubmitted_frames_
;
296 bool has_implicit_external_sync_
;
297 bool last_swap_buffers_result_
;
299 base::WeakPtrFactory
<GLSurfaceOzoneSurfaceless
> weak_factory_
;
301 DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfaceless
);
304 // This provides surface-like semantics implemented through surfaceless.
305 // A framebuffer is bound automatically.
306 class GL_EXPORT GLSurfaceOzoneSurfacelessSurfaceImpl
307 : public GLSurfaceOzoneSurfaceless
{
309 GLSurfaceOzoneSurfacelessSurfaceImpl(
310 scoped_ptr
<ui::SurfaceOzoneEGL
> ozone_surface
,
311 AcceleratedWidget widget
)
312 : GLSurfaceOzoneSurfaceless(ozone_surface
.Pass(), widget
),
314 current_surface_(0) {
315 for (auto& texture
: textures_
)
319 unsigned int GetBackingFrameBufferObject() override
{ return fbo_
; }
321 bool OnMakeCurrent(GLContext
* context
) override
{
323 glGenFramebuffersEXT(1, &fbo_
);
326 glGenTextures(arraysize(textures_
), textures_
);
327 if (!CreatePixmaps())
331 glBindFramebufferEXT(GL_FRAMEBUFFER
, fbo_
);
332 return SurfacelessEGL::OnMakeCurrent(context
);
335 bool Resize(const gfx::Size
& size
) override
{
336 if (size
== GetSize())
338 return GLSurfaceOzoneSurfaceless::Resize(size
) && CreatePixmaps();
341 bool SupportsPostSubBuffer() override
{ return false; }
343 bool SwapBuffers() override
{
344 if (!images_
[current_surface_
]->ScheduleOverlayPlane(
345 widget_
, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE
,
346 gfx::Rect(GetSize()), gfx::RectF(1, 1)))
348 if (!GLSurfaceOzoneSurfaceless::SwapBuffers())
350 current_surface_
^= 1;
355 bool SwapBuffersAsync(const SwapCompletionCallback
& callback
) override
{
356 if (!images_
[current_surface_
]->ScheduleOverlayPlane(
357 widget_
, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE
,
358 gfx::Rect(GetSize()), gfx::RectF(1, 1)))
360 if (!GLSurfaceOzoneSurfaceless::SwapBuffersAsync(callback
))
362 current_surface_
^= 1;
367 void Destroy() override
{
368 GLContext
* current_context
= GLContext::GetCurrent();
369 DCHECK(current_context
&& current_context
->IsCurrent(this));
370 glBindFramebufferEXT(GL_FRAMEBUFFER
, 0);
372 glDeleteTextures(arraysize(textures_
), textures_
);
373 for (auto& texture
: textures_
)
375 glDeleteFramebuffersEXT(1, &fbo_
);
378 for (auto image
: images_
) {
380 image
->Destroy(true);
385 class SurfaceImage
: public GLImageLinuxDMABuffer
{
387 SurfaceImage(const gfx::Size
& size
, unsigned internalformat
)
388 : GLImageLinuxDMABuffer(size
, internalformat
) {}
390 bool Initialize(scoped_refptr
<ui::NativePixmap
> pixmap
,
391 gfx::GpuMemoryBuffer::Format format
) {
392 base::FileDescriptor
handle(pixmap
->GetDmaBufFd(), false);
393 if (!GLImageLinuxDMABuffer::Initialize(handle
, format
,
394 pixmap
->GetDmaBufPitch()))
399 bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget
,
401 gfx::OverlayTransform transform
,
402 const gfx::Rect
& bounds_rect
,
403 const gfx::RectF
& crop_rect
) override
{
404 return ui::SurfaceFactoryOzone::GetInstance()->ScheduleOverlayPlane(
405 widget
, z_order
, transform
, pixmap_
, bounds_rect
, crop_rect
);
409 ~SurfaceImage() override
{}
411 scoped_refptr
<ui::NativePixmap
> pixmap_
;
414 ~GLSurfaceOzoneSurfacelessSurfaceImpl() override
{
416 for (size_t i
= 0; i
< arraysize(textures_
); i
++)
417 DCHECK(!textures_
[i
]) << "texture " << i
<< " not released";
420 void BindFramebuffer() {
421 ScopedFrameBufferBinder
fb(fbo_
);
422 glFramebufferTexture2DEXT(GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
423 GL_TEXTURE_2D
, textures_
[current_surface_
], 0);
426 bool CreatePixmaps() {
429 for (size_t i
= 0; i
< arraysize(textures_
); i
++) {
430 scoped_refptr
<ui::NativePixmap
> pixmap
=
431 ui::SurfaceFactoryOzone::GetInstance()->CreateNativePixmap(
432 widget_
, GetSize(), ui::SurfaceFactoryOzone::RGBA_8888
,
433 ui::SurfaceFactoryOzone::SCANOUT
);
436 scoped_refptr
<SurfaceImage
> image
= new SurfaceImage(GetSize(), GL_RGBA
);
437 if (!image
->Initialize(pixmap
, gfx::GpuMemoryBuffer::Format::BGRA_8888
))
440 // Bind image to texture.
441 ScopedTextureBinder
binder(GL_TEXTURE_2D
, textures_
[i
]);
442 if (!images_
[i
]->BindTexImage(GL_TEXTURE_2D
))
450 scoped_refptr
<GLImage
> images_
[2];
451 int current_surface_
;
452 DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfacelessSurfaceImpl
);
458 bool GLSurface::InitializeOneOffInternal() {
459 switch (GetGLImplementation()) {
460 case kGLImplementationEGLGLES2
:
461 if (!GLSurfaceEGL::InitializeOneOff()) {
462 LOG(ERROR
) << "GLSurfaceEGL::InitializeOneOff failed.";
467 case kGLImplementationOSMesaGL
:
468 case kGLImplementationMockGL
:
476 scoped_refptr
<GLSurface
> GLSurface::CreateSurfacelessViewGLSurface(
477 gfx::AcceleratedWidget window
) {
478 if (GetGLImplementation() == kGLImplementationEGLGLES2
&&
479 window
!= kNullAcceleratedWidget
&&
480 GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
481 ui::SurfaceFactoryOzone::GetInstance()->CanShowPrimaryPlaneAsOverlay()) {
482 scoped_ptr
<ui::SurfaceOzoneEGL
> surface_ozone
=
483 ui::SurfaceFactoryOzone::GetInstance()
484 ->CreateSurfacelessEGLSurfaceForWidget(window
);
487 scoped_refptr
<GLSurface
> surface
;
488 surface
= new GLSurfaceOzoneSurfaceless(surface_ozone
.Pass(), window
);
489 if (surface
->Initialize())
497 scoped_refptr
<GLSurface
> GLSurface::CreateViewGLSurface(
498 gfx::AcceleratedWidget window
) {
499 if (GetGLImplementation() == kGLImplementationOSMesaGL
) {
500 scoped_refptr
<GLSurface
> surface(new GLSurfaceOSMesaHeadless());
501 if (!surface
->Initialize())
505 DCHECK(GetGLImplementation() == kGLImplementationEGLGLES2
);
506 if (window
!= kNullAcceleratedWidget
) {
507 scoped_refptr
<GLSurface
> surface
;
508 if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
509 ui::SurfaceFactoryOzone::GetInstance()
510 ->CanShowPrimaryPlaneAsOverlay()) {
511 scoped_ptr
<ui::SurfaceOzoneEGL
> surface_ozone
=
512 ui::SurfaceFactoryOzone::GetInstance()
513 ->CreateSurfacelessEGLSurfaceForWidget(window
);
516 surface
= new GLSurfaceOzoneSurfacelessSurfaceImpl(surface_ozone
.Pass(),
519 scoped_ptr
<ui::SurfaceOzoneEGL
> surface_ozone
=
520 ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
525 surface
= new GLSurfaceOzoneEGL(surface_ozone
.Pass(), window
);
527 if (!surface
->Initialize())
531 scoped_refptr
<GLSurface
> surface
= new GLSurfaceStub();
532 if (surface
->Initialize())
539 scoped_refptr
<GLSurface
> GLSurface::CreateOffscreenGLSurface(
540 const gfx::Size
& size
) {
541 switch (GetGLImplementation()) {
542 case kGLImplementationOSMesaGL
: {
543 scoped_refptr
<GLSurface
> surface(
544 new GLSurfaceOSMesa(OSMesaSurfaceFormatBGRA
, size
));
545 if (!surface
->Initialize())
550 case kGLImplementationEGLGLES2
: {
551 scoped_refptr
<GLSurface
> surface
;
552 if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
553 (size
.width() == 0 && size
.height() == 0)) {
554 surface
= new SurfacelessEGL(size
);
556 surface
= new PbufferGLSurfaceEGL(size
);
558 if (!surface
->Initialize())
568 EGLNativeDisplayType
GetPlatformDefaultEGLNativeDisplay() {
569 return ui::SurfaceFactoryOzone::GetInstance()->GetNativeDisplay();