| Index: ui/ozone/platform/drm/gpu/intel_drm_pixmap.cc
 | 
| diff --git a/ui/ozone/platform/drm/gpu/intel_drm_pixmap.cc b/ui/ozone/platform/drm/gpu/intel_drm_pixmap.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..2923990b084de875d62ce6e76afeba93e963c61d
 | 
| --- /dev/null
 | 
| +++ b/ui/ozone/platform/drm/gpu/intel_drm_pixmap.cc
 | 
| @@ -0,0 +1,259 @@
 | 
| +// Copyright 2015 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/intel_drm_pixmap.h"
 | 
| +
 | 
| +#include <fcntl.h>
 | 
| +#include <libdrm/i915_drm.h>
 | 
| +extern "C" {
 | 
| +#include <libdrm/intel_bufmgr.h>
 | 
| +}
 | 
| +
 | 
| +#include "base/posix/eintr_wrapper.h"
 | 
| +#include "base/lazy_instance.h"
 | 
| +#include "base/numerics/safe_math.h"
 | 
| +#include "base/trace_event/trace_event.h"
 | 
| +#include "ui/ozone/platform/drm/gpu/gbm_device.h"
 | 
| +
 | 
| +#include "base/file_descriptor_posix.h"
 | 
| +#include "base/memory/scoped_ptr.h"
 | 
| +#include "ui/ozone/ozone_export.h"
 | 
| +
 | 
| +namespace ui {
 | 
| +
 | 
| +namespace {
 | 
| +
 | 
| +class DrmIntelBufferManager {
 | 
| + public:
 | 
| +  DrmIntelBufferManager() : buffer_manager_(nullptr) {}
 | 
| +  ~DrmIntelBufferManager() {
 | 
| +    if (buffer_manager_)
 | 
| +      drm_intel_bufmgr_destroy(buffer_manager_);
 | 
| +    if (device_fd_.auto_close)
 | 
| +      base::ScopedFD closing_fd(device_fd_.fd);
 | 
| +  }
 | 
| +
 | 
| +  bool Initialize(const base::FileDescriptor& device_fd) {
 | 
| +    if (buffer_manager_)
 | 
| +      return true;
 | 
| +
 | 
| +    device_fd_ = device_fd;
 | 
| +
 | 
| +    // TODO(dshwang): drm bufmgr doesn't need an execbuffer, so batch size is 0.
 | 
| +    const int kBatchSize = 16 * 4096;
 | 
| +    buffer_manager_ = drm_intel_bufmgr_gem_init(device_fd_.fd, kBatchSize);
 | 
| +    if (!buffer_manager_) {
 | 
| +      DLOG(ERROR) << "drm_intel_bufmgr_gem_init failed.";
 | 
| +      return false;
 | 
| +    }
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +  drm_intel_bufmgr* buffer_manager() const { return buffer_manager_; }
 | 
| +  int device_fd() const { return device_fd_.fd; }
 | 
| +
 | 
| + private:
 | 
| +  base::FileDescriptor device_fd_;
 | 
| +  drm_intel_bufmgr* buffer_manager_;
 | 
| +
 | 
| +  DISALLOW_COPY_AND_ASSIGN(DrmIntelBufferManager);
 | 
| +};
 | 
| +
 | 
| +int BytesPerPixel(gfx::BufferFormat format) {
 | 
| +  switch (format) {
 | 
| +    case gfx::BufferFormat::BGRA_8888:
 | 
| +    case gfx::BufferFormat::RGBX_8888:
 | 
| +      return 4;
 | 
| +    default:
 | 
| +      NOTREACHED();
 | 
| +      return 0;
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +base::LazyInstance<DrmIntelBufferManager>::Leaky g_buffer_manager =
 | 
| +    LAZY_INSTANCE_INITIALIZER;
 | 
| +
 | 
| +}  // namespace
 | 
| +
 | 
| +// static
 | 
| +scoped_refptr<IntelDrmPixmap> IntelDrmPixmap::Create(
 | 
| +    const base::FileDescriptor& device_fd,
 | 
| +    gfx::BufferFormat format,
 | 
| +    const gfx::Size& size) {
 | 
| +  TRACE_EVENT1("drm", "IntelDrmPixmap::Create", "size", size.ToString());
 | 
| +
 | 
| +  scoped_refptr<IntelDrmPixmap> pixmap(new IntelDrmPixmap());
 | 
| +  if (!pixmap->Initialize(device_fd, format, size))
 | 
| +    return nullptr;
 | 
| +
 | 
| +  return pixmap;
 | 
| +}
 | 
| +
 | 
| +IntelDrmPixmap::IntelDrmPixmap() : buffer_(nullptr), stride_(0) {}
 | 
| +
 | 
| +IntelDrmPixmap::~IntelDrmPixmap() {
 | 
| +  if (buffer_) {
 | 
| +    drm_intel_bo_unreference(buffer_);
 | 
| +    buffer_ = nullptr;
 | 
| +  }
 | 
| +}
 | 
| +bool IntelDrmPixmap::Initialize(const base::FileDescriptor& device_fd,
 | 
| +                                gfx::BufferFormat format,
 | 
| +                                const gfx::Size& size) {
 | 
| +  if (!g_buffer_manager.Pointer()->buffer_manager()) {
 | 
| +    g_buffer_manager.Pointer()->Initialize(device_fd);
 | 
| +  } else {
 | 
| +    DCHECK(g_buffer_manager.Pointer()->device_fd() == device_fd.fd);
 | 
| +  }
 | 
| +
 | 
| +  uint32_t tiling_mode = I915_TILING_NONE;
 | 
| +  unsigned long stride = 0;
 | 
| +  buffer_ = drm_intel_bo_alloc_tiled(
 | 
| +      g_buffer_manager.Pointer()->buffer_manager(),
 | 
| +      "chromium-gpu-memory-buffer", size.width(), size.height(),
 | 
| +      BytesPerPixel(format), &tiling_mode, &stride, 0);
 | 
| +  if (!buffer_) {
 | 
| +    DLOG(ERROR) << "drm_intel_bo_alloc_tiled failed.";
 | 
| +    return false;
 | 
| +  }
 | 
| +  DCHECK(stride);
 | 
| +  stride_ = stride;
 | 
| +
 | 
| +  int prime_fd = -1;
 | 
| +  drm_intel_bo_gem_export_to_prime(buffer_, &prime_fd);
 | 
| +  if (prime_fd <= 0) {
 | 
| +    DLOG(ERROR) << "Fail to export a drm buffer file descriptor";
 | 
| +    return false;
 | 
| +  }
 | 
| +  prime_fd_.reset(prime_fd);
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +void* IntelDrmPixmap::GetEGLClientBuffer() {
 | 
| +  return nullptr;
 | 
| +}
 | 
| +
 | 
| +int IntelDrmPixmap::GetDmaBufFd() {
 | 
| +  return prime_fd_.get();
 | 
| +}
 | 
| +
 | 
| +int IntelDrmPixmap::GetDmaBufPitch() {
 | 
| +  return stride_;
 | 
| +}
 | 
| +
 | 
| +bool IntelDrmPixmap::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
 | 
| +                                          int plane_z_order,
 | 
| +                                          gfx::OverlayTransform plane_transform,
 | 
| +                                          const gfx::Rect& display_bounds,
 | 
| +                                          const gfx::RectF& crop_rect) {
 | 
| +  // IntelDrmPixmap is used in Browser and Renderer, so this feature is not
 | 
| +  // needed.
 | 
| +  NOTREACHED();
 | 
| +  return false;
 | 
| +}
 | 
| +
 | 
| +void IntelDrmPixmap::SetScalingCallback(
 | 
| +    const ScalingCallback& scaling_callback) {
 | 
| +  // IntelDrmPixmap is used in Browser and Renderer, so this feature is not
 | 
| +  // needed.
 | 
| +  NOTREACHED();
 | 
| +}
 | 
| +
 | 
| +scoped_refptr<NativePixmap> IntelDrmPixmap::GetScaledPixmap(
 | 
| +    gfx::Size new_size) {
 | 
| +  // IntelDrmPixmap is used in Browser and Renderer, so this feature is not
 | 
| +  // needed.
 | 
| +  NOTREACHED();
 | 
| +  return nullptr;
 | 
| +}
 | 
| +
 | 
| +gfx::NativePixmapHandle IntelDrmPixmap::ExportHandle() {
 | 
| +  gfx::NativePixmapHandle handle;
 | 
| +
 | 
| +  int dmabuf_fd = HANDLE_EINTR(dup(prime_fd_.get()));
 | 
| +  if (dmabuf_fd < 0) {
 | 
| +    PLOG(ERROR) << "dup";
 | 
| +    return handle;
 | 
| +  }
 | 
| +
 | 
| +  handle.fd = base::FileDescriptor(base::ScopedFD(dmabuf_fd));
 | 
| +  handle.stride = stride_;
 | 
| +  return handle;
 | 
| +}
 | 
| +
 | 
| +//////////// IntelDrmClientPixmap
 | 
| +
 | 
| +// static
 | 
| +scoped_ptr<IntelDrmClientPixmap> IntelDrmClientPixmap::CreateFromHandle(
 | 
| +    const gfx::NativePixmapHandle& handle,
 | 
| +    const base::FileDescriptor& device_fd,
 | 
| +    gfx::BufferFormat format,
 | 
| +    const gfx::Size& size) {
 | 
| +  TRACE_EVENT1("drm", "IntelDrmClientPixmap::CreateFromHandle", "size",
 | 
| +               size.ToString());
 | 
| +
 | 
| +  scoped_ptr<IntelDrmClientPixmap> pixmap(new IntelDrmClientPixmap());
 | 
| +  if (!pixmap->InitializeFromHandle(handle, device_fd, format, size))
 | 
| +    return nullptr;
 | 
| +
 | 
| +  return pixmap;
 | 
| +}
 | 
| +
 | 
| +IntelDrmClientPixmap::IntelDrmClientPixmap() : buffer_(nullptr), stride_(0) {}
 | 
| +
 | 
| +IntelDrmClientPixmap::~IntelDrmClientPixmap() {
 | 
| +  if (buffer_) {
 | 
| +    drm_intel_bo_unreference(buffer_);
 | 
| +    buffer_ = nullptr;
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +bool IntelDrmClientPixmap::InitializeFromHandle(
 | 
| +    const gfx::NativePixmapHandle& handle,
 | 
| +    const base::FileDescriptor& device_fd,
 | 
| +    gfx::BufferFormat format,
 | 
| +    const gfx::Size& size) {
 | 
| +  if (!g_buffer_manager.Pointer()->buffer_manager()) {
 | 
| +    g_buffer_manager.Pointer()->Initialize(device_fd);
 | 
| +  }
 | 
| +
 | 
| +  stride_ = handle.stride;
 | 
| +  int buffer_size = stride_ * size.height();
 | 
| +  buffer_ = drm_intel_bo_gem_create_from_prime(
 | 
| +      g_buffer_manager.Pointer()->buffer_manager(), handle.fd.fd, buffer_size);
 | 
| +  if (!buffer_) {
 | 
| +    DLOG(ERROR) << "drm_intel_bo_gem_create_from_prime failed.";
 | 
| +    return false;
 | 
| +  }
 | 
| +  DCHECK(handle.fd.auto_close);
 | 
| +  prime_fd_.reset(handle.fd.fd);
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +bool IntelDrmClientPixmap::Map(void** data) {
 | 
| +  TRACE_EVENT0("gpu", "IntelDrmClientPixmap::Map");
 | 
| +  DCHECK(buffer_);
 | 
| +  int write_enable = 1;
 | 
| +  int error = drm_intel_bo_map(buffer_, write_enable);
 | 
| +  if (error) {
 | 
| +    DLOG(ERROR) << "fail to map a drm buffer. error:" << error;
 | 
| +    return false;
 | 
| +  }
 | 
| +  DCHECK(buffer_->virt);
 | 
| +  *data = buffer_->virt;
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +void IntelDrmClientPixmap::Unmap() {
 | 
| +  TRACE_EVENT0("gpu", "IntelDrmClientPixmap::Unmap");
 | 
| +  DCHECK(buffer_);
 | 
| +  int error = drm_intel_bo_unmap(buffer_);
 | 
| +  DCHECK(!error) << error;
 | 
| +}
 | 
| +
 | 
| +void IntelDrmClientPixmap::GetStride(int* stride) const {
 | 
| +  *stride = stride_;
 | 
| +}
 | 
| +
 | 
| +}  // namespace ui
 | 
| 
 |