ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / ui / gl / gl_surface_ozone.cc
blob47ea8d6dd9b6c1e63b22febcfc364cd6b5d71039
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/logging.h"
9 #include "base/memory/ref_counted.h"
10 #include "ui/gfx/native_widget_types.h"
11 #include "ui/gl/gl_context.h"
12 #include "ui/gl/gl_image.h"
13 #include "ui/gl/gl_image_linux_dma_buffer.h"
14 #include "ui/gl/gl_implementation.h"
15 #include "ui/gl/gl_surface_egl.h"
16 #include "ui/gl/gl_surface_osmesa.h"
17 #include "ui/gl/gl_surface_stub.h"
18 #include "ui/gl/scoped_binders.h"
19 #include "ui/gl/scoped_make_current.h"
20 #include "ui/ozone/public/native_pixmap.h"
21 #include "ui/ozone/public/surface_factory_ozone.h"
22 #include "ui/ozone/public/surface_ozone_egl.h"
24 namespace gfx {
26 namespace {
28 // A thin wrapper around GLSurfaceEGL that owns the EGLNativeWindow
29 class GL_EXPORT GLSurfaceOzoneEGL : public NativeViewGLSurfaceEGL {
30 public:
31 GLSurfaceOzoneEGL(scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
32 AcceleratedWidget widget)
33 : NativeViewGLSurfaceEGL(ozone_surface->GetNativeWindow()),
34 ozone_surface_(ozone_surface.Pass()),
35 widget_(widget) {}
37 bool Initialize() override {
38 return Initialize(ozone_surface_->CreateVSyncProvider());
40 bool Resize(const gfx::Size& size) override {
41 if (!ozone_surface_->ResizeNativeWindow(size)) {
42 if (!ReinitializeNativeSurface() ||
43 !ozone_surface_->ResizeNativeWindow(size))
44 return false;
47 return NativeViewGLSurfaceEGL::Resize(size);
49 bool SwapBuffers() override {
50 if (!NativeViewGLSurfaceEGL::SwapBuffers())
51 return false;
53 return ozone_surface_->OnSwapBuffers();
55 bool ScheduleOverlayPlane(int z_order,
56 OverlayTransform transform,
57 GLImage* image,
58 const Rect& bounds_rect,
59 const RectF& crop_rect) override {
60 return image->ScheduleOverlayPlane(
61 widget_, z_order, transform, bounds_rect, crop_rect);
64 private:
65 using NativeViewGLSurfaceEGL::Initialize;
67 ~GLSurfaceOzoneEGL() override {
68 Destroy(); // EGL surface must be destroyed before SurfaceOzone
71 bool ReinitializeNativeSurface() {
72 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
73 GLContext* current_context = GLContext::GetCurrent();
74 bool was_current =
75 current_context && current_context->IsCurrent(this);
76 if (was_current) {
77 scoped_make_current.reset(
78 new ui::ScopedMakeCurrent(current_context, this));
81 Destroy();
82 ozone_surface_ =
83 ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
84 widget_).Pass();
85 if (!ozone_surface_) {
86 LOG(ERROR) << "Failed to create native surface.";
87 return false;
90 window_ = ozone_surface_->GetNativeWindow();
91 if (!Initialize()) {
92 LOG(ERROR) << "Failed to initialize.";
93 return false;
96 return true;
99 // The native surface. Deleting this is allowed to free the EGLNativeWindow.
100 scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface_;
101 AcceleratedWidget widget_;
103 DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneEGL);
106 class GL_EXPORT GLSurfaceOzoneSurfaceless : public SurfacelessEGL {
107 public:
108 GLSurfaceOzoneSurfaceless(scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
109 AcceleratedWidget widget)
110 : SurfacelessEGL(gfx::Size()),
111 ozone_surface_(ozone_surface.Pass()),
112 widget_(widget),
113 has_implicit_external_sync_(
114 HasEGLExtension("EGL_ARM_implicit_external_sync")) {}
116 bool Initialize() override {
117 if (!SurfacelessEGL::Initialize())
118 return false;
119 vsync_provider_ = ozone_surface_->CreateVSyncProvider();
120 if (!vsync_provider_)
121 return false;
122 return true;
124 bool Resize(const gfx::Size& size) override {
125 if (!ozone_surface_->ResizeNativeWindow(size))
126 return false;
128 return SurfacelessEGL::Resize(size);
130 bool SwapBuffers() override {
131 if (!Flush())
132 return false;
133 return ozone_surface_->OnSwapBuffers();
135 bool ScheduleOverlayPlane(int z_order,
136 OverlayTransform transform,
137 GLImage* image,
138 const Rect& bounds_rect,
139 const RectF& crop_rect) override {
140 return image->ScheduleOverlayPlane(
141 widget_, z_order, transform, bounds_rect, crop_rect);
143 bool IsOffscreen() override { return false; }
144 VSyncProvider* GetVSyncProvider() override { return vsync_provider_.get(); }
145 bool SupportsPostSubBuffer() override { return true; }
146 bool PostSubBuffer(int x, int y, int width, int height) override {
147 // The actual sub buffer handling is handled at higher layers.
148 SwapBuffers();
149 return true;
151 bool SwapBuffersAsync(const SwapCompletionCallback& callback) override {
152 if (!Flush())
153 return false;
154 return ozone_surface_->OnSwapBuffersAsync(callback);
156 bool PostSubBufferAsync(int x,
157 int y,
158 int width,
159 int height,
160 const SwapCompletionCallback& callback) override {
161 return SwapBuffersAsync(callback);
164 protected:
165 ~GLSurfaceOzoneSurfaceless() override {
166 Destroy(); // EGL surface must be destroyed before SurfaceOzone
169 bool Flush() {
170 glFlush();
171 // TODO: crbug.com/462360 the following should be replaced by a per surface
172 // flush as it gets implemented in GL drivers.
173 if (has_implicit_external_sync_) {
174 const EGLint attrib_list[] = {
175 EGL_SYNC_CONDITION_KHR,
176 EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM,
177 EGL_NONE};
178 EGLSyncKHR fence =
179 eglCreateSyncKHR(GetDisplay(), EGL_SYNC_FENCE_KHR, attrib_list);
180 if (fence) {
181 // TODO(dbehr): piman@ suggests we could improve here by moving
182 // following wait to right before drmModePageFlip crbug.com/456417.
183 eglClientWaitSyncKHR(GetDisplay(), fence,
184 EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR);
185 eglDestroySyncKHR(GetDisplay(), fence);
186 } else {
187 return false;
189 } else if (ozone_surface_->IsUniversalDisplayLinkDevice()) {
190 glFinish();
192 return true;
195 // The native surface. Deleting this is allowed to free the EGLNativeWindow.
196 scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface_;
197 AcceleratedWidget widget_;
198 scoped_ptr<VSyncProvider> vsync_provider_;
199 bool has_implicit_external_sync_;
200 DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfaceless);
203 // This provides surface-like semantics implemented through surfaceless.
204 // A framebuffer is bound automatically.
205 class GL_EXPORT GLSurfaceOzoneSurfacelessSurfaceImpl
206 : public GLSurfaceOzoneSurfaceless {
207 public:
208 GLSurfaceOzoneSurfacelessSurfaceImpl(
209 scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
210 AcceleratedWidget widget)
211 : GLSurfaceOzoneSurfaceless(ozone_surface.Pass(), widget),
212 fbo_(0),
213 current_surface_(0) {
214 for (auto& texture : textures_)
215 texture = 0;
218 unsigned int GetBackingFrameBufferObject() override { return fbo_; }
220 bool OnMakeCurrent(GLContext* context) override {
221 if (!fbo_) {
222 glGenFramebuffersEXT(1, &fbo_);
223 if (!fbo_)
224 return false;
225 glGenTextures(arraysize(textures_), textures_);
226 if (!CreatePixmaps())
227 return false;
229 BindFramebuffer();
230 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo_);
231 return SurfacelessEGL::OnMakeCurrent(context);
234 bool Resize(const gfx::Size& size) override {
235 if (size == GetSize())
236 return true;
237 return GLSurfaceOzoneSurfaceless::Resize(size) && CreatePixmaps();
240 bool SupportsPostSubBuffer() override { return false; }
242 bool SwapBuffers() override {
243 if (!images_[current_surface_]->ScheduleOverlayPlane(
244 widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE,
245 gfx::Rect(GetSize()), gfx::RectF(1, 1)))
246 return false;
247 if (!GLSurfaceOzoneSurfaceless::SwapBuffers())
248 return false;
249 current_surface_ ^= 1;
250 BindFramebuffer();
251 return true;
254 bool SwapBuffersAsync(const SwapCompletionCallback& callback) override {
255 if (!images_[current_surface_]->ScheduleOverlayPlane(
256 widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE,
257 gfx::Rect(GetSize()), gfx::RectF(1, 1)))
258 return false;
259 if (!GLSurfaceOzoneSurfaceless::SwapBuffersAsync(callback))
260 return false;
261 current_surface_ ^= 1;
262 BindFramebuffer();
263 return true;
266 void Destroy() override {
267 GLContext* current_context = GLContext::GetCurrent();
268 DCHECK(current_context && current_context->IsCurrent(this));
269 glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
270 if (fbo_) {
271 glDeleteTextures(arraysize(textures_), textures_);
272 for (auto& texture : textures_)
273 texture = 0;
274 glDeleteFramebuffersEXT(1, &fbo_);
275 fbo_ = 0;
277 for (auto image : images_) {
278 if (image)
279 image->Destroy(true);
283 private:
284 class SurfaceImage : public GLImageLinuxDMABuffer {
285 public:
286 SurfaceImage(const gfx::Size& size, unsigned internalformat)
287 : GLImageLinuxDMABuffer(size, internalformat) {}
289 bool Initialize(scoped_refptr<ui::NativePixmap> pixmap,
290 gfx::GpuMemoryBuffer::Format format) {
291 base::FileDescriptor handle(pixmap->GetDmaBufFd(), false);
292 if (!GLImageLinuxDMABuffer::Initialize(handle, format,
293 pixmap->GetDmaBufPitch()))
294 return false;
295 pixmap_ = pixmap;
296 return true;
298 bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
299 int z_order,
300 gfx::OverlayTransform transform,
301 const gfx::Rect& bounds_rect,
302 const gfx::RectF& crop_rect) override {
303 return ui::SurfaceFactoryOzone::GetInstance()->ScheduleOverlayPlane(
304 widget, z_order, transform, pixmap_, bounds_rect, crop_rect);
307 private:
308 ~SurfaceImage() override {}
310 scoped_refptr<ui::NativePixmap> pixmap_;
313 ~GLSurfaceOzoneSurfacelessSurfaceImpl() override {
314 DCHECK(!fbo_);
315 for (size_t i = 0; i < arraysize(textures_); i++)
316 DCHECK(!textures_[i]) << "texture " << i << " not released";
319 void BindFramebuffer() {
320 ScopedFrameBufferBinder fb(fbo_);
321 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
322 GL_TEXTURE_2D, textures_[current_surface_], 0);
325 bool CreatePixmaps() {
326 if (!fbo_)
327 return true;
328 for (size_t i = 0; i < arraysize(textures_); i++) {
329 scoped_refptr<ui::NativePixmap> pixmap =
330 ui::SurfaceFactoryOzone::GetInstance()->CreateNativePixmap(
331 widget_, GetSize(), ui::SurfaceFactoryOzone::RGBA_8888,
332 ui::SurfaceFactoryOzone::SCANOUT);
333 if (!pixmap)
334 return false;
335 scoped_refptr<SurfaceImage> image = new SurfaceImage(GetSize(), GL_RGBA);
336 if (!image->Initialize(pixmap, gfx::GpuMemoryBuffer::Format::BGRA_8888))
337 return false;
338 images_[i] = image;
339 // Bind image to texture.
340 ScopedTextureBinder binder(GL_TEXTURE_2D, textures_[i]);
341 if (!images_[i]->BindTexImage(GL_TEXTURE_2D))
342 return false;
344 return true;
347 GLuint fbo_;
348 GLuint textures_[2];
349 scoped_refptr<GLImage> images_[2];
350 int current_surface_;
351 DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfacelessSurfaceImpl);
354 } // namespace
356 // static
357 bool GLSurface::InitializeOneOffInternal() {
358 switch (GetGLImplementation()) {
359 case kGLImplementationEGLGLES2:
360 if (!GLSurfaceEGL::InitializeOneOff()) {
361 LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
362 return false;
365 return true;
366 case kGLImplementationOSMesaGL:
367 case kGLImplementationMockGL:
368 return true;
369 default:
370 return false;
374 // static
375 scoped_refptr<GLSurface> GLSurface::CreateSurfacelessViewGLSurface(
376 gfx::AcceleratedWidget window) {
377 if (GetGLImplementation() == kGLImplementationEGLGLES2 &&
378 window != kNullAcceleratedWidget &&
379 GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
380 ui::SurfaceFactoryOzone::GetInstance()->CanShowPrimaryPlaneAsOverlay()) {
381 scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
382 ui::SurfaceFactoryOzone::GetInstance()
383 ->CreateSurfacelessEGLSurfaceForWidget(window);
384 if (!surface_ozone)
385 return nullptr;
386 scoped_refptr<GLSurface> surface;
387 surface = new GLSurfaceOzoneSurfaceless(surface_ozone.Pass(), window);
388 if (surface->Initialize())
389 return surface;
392 return nullptr;
395 // static
396 scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
397 gfx::AcceleratedWidget window) {
398 if (GetGLImplementation() == kGLImplementationOSMesaGL) {
399 scoped_refptr<GLSurface> surface(new GLSurfaceOSMesaHeadless());
400 if (!surface->Initialize())
401 return NULL;
402 return surface;
404 DCHECK(GetGLImplementation() == kGLImplementationEGLGLES2);
405 if (window != kNullAcceleratedWidget) {
406 scoped_refptr<GLSurface> surface;
407 if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
408 ui::SurfaceFactoryOzone::GetInstance()
409 ->CanShowPrimaryPlaneAsOverlay()) {
410 scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
411 ui::SurfaceFactoryOzone::GetInstance()
412 ->CreateSurfacelessEGLSurfaceForWidget(window);
413 if (!surface_ozone)
414 return NULL;
415 surface = new GLSurfaceOzoneSurfacelessSurfaceImpl(surface_ozone.Pass(),
416 window);
417 } else {
418 scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
419 ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
420 window);
421 if (!surface_ozone)
422 return NULL;
424 surface = new GLSurfaceOzoneEGL(surface_ozone.Pass(), window);
426 if (!surface->Initialize())
427 return NULL;
428 return surface;
429 } else {
430 scoped_refptr<GLSurface> surface = new GLSurfaceStub();
431 if (surface->Initialize())
432 return surface;
434 return NULL;
437 // static
438 scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
439 const gfx::Size& size) {
440 switch (GetGLImplementation()) {
441 case kGLImplementationOSMesaGL: {
442 scoped_refptr<GLSurface> surface(
443 new GLSurfaceOSMesa(OSMesaSurfaceFormatBGRA, size));
444 if (!surface->Initialize())
445 return NULL;
447 return surface;
449 case kGLImplementationEGLGLES2: {
450 scoped_refptr<GLSurface> surface;
451 if (GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
452 (size.width() == 0 && size.height() == 0)) {
453 surface = new SurfacelessEGL(size);
454 } else
455 surface = new PbufferGLSurfaceEGL(size);
457 if (!surface->Initialize())
458 return NULL;
459 return surface;
461 default:
462 NOTREACHED();
463 return NULL;
467 EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
468 return ui::SurfaceFactoryOzone::GetInstance()->GetNativeDisplay();
471 } // namespace gfx