Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ui / ozone / platform / drm / gpu / gbm_buffer.cc
blob3d07983a8ee5baaa4e9269684efd229b5cc01eeb
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/ozone/platform/drm/gpu/gbm_buffer.h"
7 #include <drm.h>
8 #include <fcntl.h>
9 #include <gbm.h>
10 #include <xf86drm.h>
12 #include "base/logging.h"
13 #include "base/posix/eintr_wrapper.h"
14 #include "base/trace_event/trace_event.h"
15 #include "ui/gfx/geometry/size_conversions.h"
16 #include "ui/gfx/native_pixmap_handle_ozone.h"
17 #include "ui/ozone/platform/drm/gpu/drm_window.h"
18 #include "ui/ozone/platform/drm/gpu/gbm_device.h"
20 namespace ui {
22 namespace {
24 int GetGbmFormatFromBufferFormat(gfx::BufferFormat fmt) {
25 switch (fmt) {
26 case gfx::BufferFormat::BGRA_8888:
27 return GBM_FORMAT_ARGB8888;
28 case gfx::BufferFormat::BGRX_8888:
29 return GBM_FORMAT_XRGB8888;
30 default:
31 NOTREACHED();
32 return 0;
36 } // namespace
38 GbmBuffer::GbmBuffer(const scoped_refptr<GbmDevice>& gbm,
39 gbm_bo* bo,
40 gfx::BufferUsage usage)
41 : GbmBufferBase(gbm, bo, usage == gfx::BufferUsage::SCANOUT),
42 usage_(usage) {}
44 GbmBuffer::~GbmBuffer() {
45 if (bo())
46 gbm_bo_destroy(bo());
49 // static
50 scoped_refptr<GbmBuffer> GbmBuffer::CreateBuffer(
51 const scoped_refptr<GbmDevice>& gbm,
52 gfx::BufferFormat format,
53 const gfx::Size& size,
54 gfx::BufferUsage usage) {
55 TRACE_EVENT2("drm", "GbmBuffer::CreateBuffer", "device",
56 gbm->device_path().value(), "size", size.ToString());
57 bool use_scanout = (usage == gfx::BufferUsage::SCANOUT);
58 unsigned flags = GBM_BO_USE_RENDERING;
59 // GBM_BO_USE_SCANOUT is the hint of x-tiling.
60 if (use_scanout)
61 flags |= GBM_BO_USE_SCANOUT;
62 gbm_bo* bo = gbm_bo_create(gbm->device(), size.width(), size.height(),
63 GetGbmFormatFromBufferFormat(format), flags);
64 if (!bo)
65 return nullptr;
67 scoped_refptr<GbmBuffer> buffer(new GbmBuffer(gbm, bo, usage));
68 if (use_scanout && !buffer->GetFramebufferId())
69 return nullptr;
71 return buffer;
74 GbmPixmap::GbmPixmap(const scoped_refptr<GbmBuffer>& buffer,
75 ScreenManager* screen_manager)
76 : buffer_(buffer), screen_manager_(screen_manager) {
79 bool GbmPixmap::Initialize() {
80 // We want to use the GBM API because it's going to call into libdrm
81 // which might do some optimizations on buffer allocation,
82 // especially when sharing buffers via DMABUF.
83 dma_buf_ = gbm_bo_get_fd(buffer_->bo());
84 if (dma_buf_ < 0) {
85 PLOG(ERROR) << "Failed to export buffer to dma_buf";
86 return false;
88 return true;
91 void GbmPixmap::SetScalingCallback(const ScalingCallback& scaling_callback) {
92 scaling_callback_ = scaling_callback;
95 scoped_refptr<NativePixmap> GbmPixmap::GetScaledPixmap(gfx::Size new_size) {
96 return scaling_callback_.Run(new_size);
99 gfx::NativePixmapHandle GbmPixmap::ExportHandle() {
100 gfx::NativePixmapHandle handle;
102 int dmabuf_fd = HANDLE_EINTR(dup(dma_buf_));
103 if (dmabuf_fd < 0) {
104 PLOG(ERROR) << "dup";
105 return handle;
108 handle.fd = base::FileDescriptor(dmabuf_fd, true /* auto_close */);
109 handle.stride = gbm_bo_get_stride(buffer_->bo());
110 return handle;
113 GbmPixmap::~GbmPixmap() {
114 if (dma_buf_ > 0)
115 close(dma_buf_);
118 void* GbmPixmap::GetEGLClientBuffer() {
119 return nullptr;
122 int GbmPixmap::GetDmaBufFd() {
123 return dma_buf_;
126 int GbmPixmap::GetDmaBufPitch() {
127 return gbm_bo_get_stride(buffer_->bo());
130 bool GbmPixmap::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
131 int plane_z_order,
132 gfx::OverlayTransform plane_transform,
133 const gfx::Rect& display_bounds,
134 const gfx::RectF& crop_rect) {
135 DCHECK(buffer_->GetUsage() == gfx::BufferUsage::SCANOUT);
136 gfx::Size required_size;
137 if (plane_z_order &&
138 ShouldApplyScaling(display_bounds, crop_rect, &required_size)) {
139 scoped_refptr<NativePixmap> scaled_pixmap = GetScaledPixmap(required_size);
140 if (scaled_pixmap) {
141 return scaled_pixmap->ScheduleOverlayPlane(
142 widget, plane_z_order, plane_transform, display_bounds, crop_rect);
143 } else {
144 return false;
148 screen_manager_->GetWindow(widget)->QueueOverlayPlane(OverlayPlane(
149 buffer_, plane_z_order, plane_transform, display_bounds, crop_rect));
150 return true;
153 bool GbmPixmap::ShouldApplyScaling(const gfx::Rect& display_bounds,
154 const gfx::RectF& crop_rect,
155 gfx::Size* required_size) {
156 if (crop_rect.width() == 0 || crop_rect.height() == 0) {
157 PLOG(ERROR) << "ShouldApplyScaling passed zero scaling target.";
158 return false;
161 gfx::Size pixmap_size = buffer_->GetSize();
162 // If the required size is not integer-sized, round it to the next integer.
163 *required_size = gfx::ToCeiledSize(
164 gfx::SizeF(display_bounds.width() / crop_rect.width(),
165 display_bounds.height() / crop_rect.height()));
166 return pixmap_size != *required_size;
169 } // namespace ui