| Index: ui/ozone/platform/drm/gpu/gbm_surface.cc | 
| diff --git a/ui/ozone/platform/drm/gpu/gbm_surface.cc b/ui/ozone/platform/drm/gpu/gbm_surface.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..566d0c7c0742a53455406317745a24bde950ddfa | 
| --- /dev/null | 
| +++ b/ui/ozone/platform/drm/gpu/gbm_surface.cc | 
| @@ -0,0 +1,148 @@ | 
| +// Copyright 2016 The Chromium Authors. All rights reserved. | 
| +// Use of this source code is governed by a BSD-style license that can be | 
| +// found in the LICENSE file. | 
| + | 
| +#include "ui/ozone/platform/drm/gpu/gbm_surface.h" | 
| + | 
| +#include <utility> | 
| + | 
| +#include "base/logging.h" | 
| +#include "ui/gl/gl_surface_egl.h" | 
| +#include "ui/ozone/gl/gl_image_ozone_native_pixmap.h" | 
| +#include "ui/ozone/platform/drm/gpu/drm_window_proxy.h" | 
| +#include "ui/ozone/platform/drm/gpu/gbm_surface_factory.h" | 
| +#include "ui/ozone/public/native_pixmap.h" | 
| + | 
| +namespace ui { | 
| + | 
| +GbmSurface::GbmSurface(GbmSurfaceFactory* surface_factory, | 
| +                       std::unique_ptr<DrmWindowProxy> window, | 
| +                       gfx::AcceleratedWidget widget) | 
| +    : GbmSurfaceless(surface_factory, std::move(window), widget) { | 
| +  for (auto& texture : textures_) | 
| +    texture = 0; | 
| +} | 
| + | 
| +unsigned int GbmSurface::GetBackingFrameBufferObject() { | 
| +  return fbo_; | 
| +} | 
| + | 
| +bool GbmSurface::OnMakeCurrent(gl::GLContext* context) { | 
| +  DCHECK(!context_ || context == context_); | 
| +  context_ = context; | 
| +  if (!fbo_) { | 
| +    glGenFramebuffersEXT(1, &fbo_); | 
| +    if (!fbo_) | 
| +      return false; | 
| +    glGenTextures(arraysize(textures_), textures_); | 
| +    if (!CreatePixmaps()) | 
| +      return false; | 
| +  } | 
| +  BindFramebuffer(); | 
| +  glBindFramebufferEXT(GL_FRAMEBUFFER, fbo_); | 
| +  return SurfacelessEGL::OnMakeCurrent(context); | 
| +} | 
| + | 
| +bool GbmSurface::Resize(const gfx::Size& size, | 
| +                        float scale_factor, | 
| +                        bool has_alpha) { | 
| +  if (size == GetSize()) | 
| +    return true; | 
| +  // Alpha value isn't actually used in allocating buffers yet, so always use | 
| +  // true instead. | 
| +  return GbmSurfaceless::Resize(size, scale_factor, true) && CreatePixmaps(); | 
| +} | 
| + | 
| +bool GbmSurface::SupportsPostSubBuffer() { | 
| +  return false; | 
| +} | 
| + | 
| +void GbmSurface::SwapBuffersAsync(const SwapCompletionCallback& callback) { | 
| +  if (!images_[current_surface_]->ScheduleOverlayPlane( | 
| +          widget(), 0, gfx::OverlayTransform::OVERLAY_TRANSFORM_NONE, | 
| +          gfx::Rect(GetSize()), gfx::RectF(1, 1))) { | 
| +    callback.Run(gfx::SwapResult::SWAP_FAILED); | 
| +    return; | 
| +  } | 
| +  GbmSurfaceless::SwapBuffersAsync(callback); | 
| +  current_surface_ ^= 1; | 
| +  BindFramebuffer(); | 
| +} | 
| + | 
| +void GbmSurface::Destroy() { | 
| +  if (!context_) | 
| +    return; | 
| +  scoped_refptr<gl::GLContext> previous_context = gl::GLContext::GetCurrent(); | 
| +  scoped_refptr<GLSurface> previous_surface; | 
| + | 
| +  bool was_current = previous_context && previous_context->IsCurrent(nullptr) && | 
| +                     GLSurface::GetCurrent() == this; | 
| +  if (!was_current) { | 
| +    // Only take a reference to previous surface if it's not |this| | 
| +    // because otherwise we can take a self reference from our own dtor. | 
| +    previous_surface = GLSurface::GetCurrent(); | 
| +    context_->MakeCurrent(this); | 
| +  } | 
| + | 
| +  glBindFramebufferEXT(GL_FRAMEBUFFER, 0); | 
| +  if (fbo_) { | 
| +    glDeleteTextures(arraysize(textures_), textures_); | 
| +    for (auto& texture : textures_) | 
| +      texture = 0; | 
| +    glDeleteFramebuffersEXT(1, &fbo_); | 
| +    fbo_ = 0; | 
| +  } | 
| +  for (auto image : images_) { | 
| +    if (image) | 
| +      image->Destroy(true); | 
| +  } | 
| + | 
| +  if (!was_current) { | 
| +    if (previous_context) { | 
| +      previous_context->MakeCurrent(previous_surface.get()); | 
| +    } else { | 
| +      context_->ReleaseCurrent(this); | 
| +    } | 
| +  } | 
| +} | 
| + | 
| +bool GbmSurface::IsSurfaceless() const { | 
| +  return false; | 
| +} | 
| + | 
| +GbmSurface::~GbmSurface() { | 
| +  Destroy(); | 
| +} | 
| + | 
| +void GbmSurface::BindFramebuffer() { | 
| +  gl::ScopedFrameBufferBinder fb(fbo_); | 
| +  glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | 
| +                            textures_[current_surface_], 0); | 
| +} | 
| + | 
| +bool GbmSurface::CreatePixmaps() { | 
| +  if (!fbo_) | 
| +    return true; | 
| +  for (size_t i = 0; i < arraysize(textures_); i++) { | 
| +    scoped_refptr<NativePixmap> pixmap = surface_factory()->CreateNativePixmap( | 
| +        widget(), GetSize(), gfx::BufferFormat::BGRA_8888, | 
| +        gfx::BufferUsage::SCANOUT); | 
| +    if (!pixmap) | 
| +      return false; | 
| +    scoped_refptr<GLImageOzoneNativePixmap> image = | 
| +        new GLImageOzoneNativePixmap(GetSize(), GL_BGRA_EXT); | 
| +    if (!image->Initialize(pixmap.get(), gfx::BufferFormat::BGRA_8888)) | 
| +      return false; | 
| +    // GLImage must have Destroy() called before destructor is called. | 
| +    if (images_[i]) | 
| +      images_[i]->Destroy(true); | 
| +    images_[i] = image; | 
| +    // Bind image to texture. | 
| +    gl::ScopedTextureBinder binder(GL_TEXTURE_2D, textures_[i]); | 
| +    if (!images_[i]->BindTexImage(GL_TEXTURE_2D)) | 
| +      return false; | 
| +  } | 
| +  return true; | 
| +} | 
| + | 
| +}  // namespace ui | 
|  |