Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / ui / gl / gl_surface_ozone.cc
blobba7b02b036814056100705915fcd4bd4033603a5
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/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"
29 namespace gfx {
31 namespace {
33 void WaitForFence(EGLDisplay display, EGLSyncKHR fence) {
34 eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
35 EGL_FOREVER_KHR);
38 // A thin wrapper around GLSurfaceEGL that owns the EGLNativeWindow
39 class GL_EXPORT GLSurfaceOzoneEGL : public NativeViewGLSurfaceEGL {
40 public:
41 GLSurfaceOzoneEGL(scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
42 AcceleratedWidget widget)
43 : NativeViewGLSurfaceEGL(ozone_surface->GetNativeWindow()),
44 ozone_surface_(ozone_surface.Pass()),
45 widget_(widget) {}
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))
54 return false;
57 return NativeViewGLSurfaceEGL::Resize(size);
59 bool SwapBuffers() override {
60 if (!NativeViewGLSurfaceEGL::SwapBuffers())
61 return false;
63 return ozone_surface_->OnSwapBuffers();
65 bool ScheduleOverlayPlane(int z_order,
66 OverlayTransform transform,
67 GLImage* image,
68 const Rect& bounds_rect,
69 const RectF& crop_rect) override {
70 return image->ScheduleOverlayPlane(
71 widget_, z_order, transform, bounds_rect, crop_rect);
74 private:
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();
84 bool was_current =
85 current_context && current_context->IsCurrent(this);
86 if (was_current) {
87 scoped_make_current.reset(
88 new ui::ScopedMakeCurrent(current_context, this));
91 Destroy();
92 ozone_surface_ =
93 ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
94 widget_).Pass();
95 if (!ozone_surface_) {
96 LOG(ERROR) << "Failed to create native surface.";
97 return false;
100 window_ = ozone_surface_->GetNativeWindow();
101 if (!Initialize()) {
102 LOG(ERROR) << "Failed to initialize.";
103 return false;
106 return true;
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 {
117 public:
118 GLSurfaceOzoneSurfaceless(scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
119 AcceleratedWidget widget)
120 : SurfacelessEGL(gfx::Size()),
121 ozone_surface_(ozone_surface.Pass()),
122 widget_(widget),
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())
132 return false;
133 vsync_provider_ = ozone_surface_->CreateVSyncProvider();
134 if (!vsync_provider_)
135 return false;
136 return true;
138 bool Resize(const gfx::Size& size) override {
139 if (!ozone_surface_->ResizeNativeWindow(size))
140 return false;
142 return SurfacelessEGL::Resize(size);
144 bool SwapBuffers() override {
145 glFlush();
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();
150 if (!fence)
151 return false;
153 EGLDisplay display = GetDisplay();
154 WaitForFence(display, fence);
155 eglDestroySyncKHR(display, fence);
156 } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) {
157 glFinish();
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,
167 GLImage* image,
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));
172 return true;
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.
179 SwapBuffers();
180 return true;
182 bool SwapBuffersAsync(const SwapCompletionCallback& callback) override {
183 glFlush();
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;
190 return false;
193 EGLSyncKHR fence = InsertFence();
194 if (!fence)
195 return false;
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());
209 return true;
210 } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) {
211 glFinish();
213 unsubmitted_frames_.back()->ScheduleOverlayPlanes(widget_);
214 unsubmitted_frames_.back()->overlays.clear();
215 return ozone_surface_->OnSwapBuffersAsync(callback);
217 bool PostSubBufferAsync(int x,
218 int y,
219 int width,
220 int height,
221 const SwapCompletionCallback& callback) override {
222 return SwapBuffersAsync(callback);
225 protected:
226 struct PendingFrame {
227 struct Overlay {
228 Overlay(int z_order,
229 OverlayTransform transform,
230 GLImage* image,
231 const Rect& bounds_rect,
232 const RectF& crop_rect)
233 : z_order(z_order),
234 transform(transform),
235 image(image),
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);
244 int z_order;
245 OverlayTransform transform;
246 scoped_refptr<GLImage> image;
247 Rect bounds_rect;
248 RectF crop_rect;
251 PendingFrame() : ready(false) {}
253 bool ScheduleOverlayPlanes(gfx::AcceleratedWidget widget) {
254 for (const auto& overlay : overlays)
255 if (!overlay.ScheduleOverlayPlane(widget))
256 return false;
257 return true;
259 bool ready;
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,
281 EGL_NONE};
282 return eglCreateSyncKHR(GetDisplay(), EGL_SYNC_FENCE_KHR, attrib_list);
285 void FenceRetired(EGLSyncKHR fence, PendingFrame* frame) {
286 eglDestroySyncKHR(GetDisplay(), fence);
287 frame->ready = true;
288 SubmitFrames();
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 {
308 public:
309 GLSurfaceOzoneSurfacelessSurfaceImpl(
310 scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
311 AcceleratedWidget widget)
312 : GLSurfaceOzoneSurfaceless(ozone_surface.Pass(), widget),
313 fbo_(0),
314 current_surface_(0) {
315 for (auto& texture : textures_)
316 texture = 0;
319 unsigned int GetBackingFrameBufferObject() override { return fbo_; }
321 bool OnMakeCurrent(GLContext* context) override {
322 if (!fbo_) {
323 glGenFramebuffersEXT(1, &fbo_);
324 if (!fbo_)
325 return false;
326 glGenTextures(arraysize(textures_), textures_);
327 if (!CreatePixmaps())
328 return false;
330 BindFramebuffer();
331 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo_);
332 return SurfacelessEGL::OnMakeCurrent(context);
335 bool Resize(const gfx::Size& size) override {
336 if (size == GetSize())
337 return true;
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)))
347 return false;
348 if (!GLSurfaceOzoneSurfaceless::SwapBuffers())
349 return false;
350 current_surface_ ^= 1;
351 BindFramebuffer();
352 return true;
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)))
359 return false;
360 if (!GLSurfaceOzoneSurfaceless::SwapBuffersAsync(callback))
361 return false;
362 current_surface_ ^= 1;
363 BindFramebuffer();
364 return true;
367 void Destroy() override {
368 GLContext* current_context = GLContext::GetCurrent();
369 DCHECK(current_context && current_context->IsCurrent(this));
370 glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
371 if (fbo_) {
372 glDeleteTextures(arraysize(textures_), textures_);
373 for (auto& texture : textures_)
374 texture = 0;
375 glDeleteFramebuffersEXT(1, &fbo_);
376 fbo_ = 0;
378 for (auto image : images_) {
379 if (image)
380 image->Destroy(true);
384 private:
385 class SurfaceImage : public GLImageLinuxDMABuffer {
386 public:
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()))
395 return false;
396 pixmap_ = pixmap;
397 return true;
399 bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
400 int z_order,
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);
408 private:
409 ~SurfaceImage() override {}
411 scoped_refptr<ui::NativePixmap> pixmap_;
414 ~GLSurfaceOzoneSurfacelessSurfaceImpl() override {
415 DCHECK(!fbo_);
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() {
427 if (!fbo_)
428 return true;
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);
434 if (!pixmap)
435 return false;
436 scoped_refptr<SurfaceImage> image = new SurfaceImage(GetSize(), GL_RGBA);
437 if (!image->Initialize(pixmap, gfx::GpuMemoryBuffer::Format::BGRA_8888))
438 return false;
439 images_[i] = image;
440 // Bind image to texture.
441 ScopedTextureBinder binder(GL_TEXTURE_2D, textures_[i]);
442 if (!images_[i]->BindTexImage(GL_TEXTURE_2D))
443 return false;
445 return true;
448 GLuint fbo_;
449 GLuint textures_[2];
450 scoped_refptr<GLImage> images_[2];
451 int current_surface_;
452 DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfacelessSurfaceImpl);
455 } // namespace
457 // static
458 bool GLSurface::InitializeOneOffInternal() {
459 switch (GetGLImplementation()) {
460 case kGLImplementationEGLGLES2:
461 if (!GLSurfaceEGL::InitializeOneOff()) {
462 LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
463 return false;
466 return true;
467 case kGLImplementationOSMesaGL:
468 case kGLImplementationMockGL:
469 return true;
470 default:
471 return false;
475 // static
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);
485 if (!surface_ozone)
486 return nullptr;
487 scoped_refptr<GLSurface> surface;
488 surface = new GLSurfaceOzoneSurfaceless(surface_ozone.Pass(), window);
489 if (surface->Initialize())
490 return surface;
493 return nullptr;
496 // static
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())
502 return NULL;
503 return surface;
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);
514 if (!surface_ozone)
515 return NULL;
516 surface = new GLSurfaceOzoneSurfacelessSurfaceImpl(surface_ozone.Pass(),
517 window);
518 } else {
519 scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
520 ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
521 window);
522 if (!surface_ozone)
523 return NULL;
525 surface = new GLSurfaceOzoneEGL(surface_ozone.Pass(), window);
527 if (!surface->Initialize())
528 return NULL;
529 return surface;
530 } else {
531 scoped_refptr<GLSurface> surface = new GLSurfaceStub();
532 if (surface->Initialize())
533 return surface;
535 return NULL;
538 // static
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())
546 return NULL;
548 return surface;
550 case kGLImplementationEGLGLES2: {
551 scoped_refptr<GLSurface> surface;
552 if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
553 (size.width() == 0 && size.height() == 0)) {
554 surface = new SurfacelessEGL(size);
555 } else
556 surface = new PbufferGLSurfaceEGL(size);
558 if (!surface->Initialize())
559 return NULL;
560 return surface;
562 default:
563 NOTREACHED();
564 return NULL;
568 EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
569 return ui::SurfaceFactoryOzone::GetInstance()->GetNativeDisplay();
572 } // namespace gfx