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"
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"
24 int GetGbmFormatFromBufferFormat(gfx::BufferFormat fmt
) {
26 case gfx::BufferFormat::BGRA_8888
:
27 return GBM_FORMAT_ARGB8888
;
28 case gfx::BufferFormat::BGRX_8888
:
29 return GBM_FORMAT_XRGB8888
;
38 GbmBuffer::GbmBuffer(const scoped_refptr
<GbmDevice
>& gbm
,
40 gfx::BufferUsage usage
)
41 : GbmBufferBase(gbm
, bo
, usage
== gfx::BufferUsage::SCANOUT
),
44 GbmBuffer::~GbmBuffer() {
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.
61 flags
|= GBM_BO_USE_SCANOUT
;
62 gbm_bo
* bo
= gbm_bo_create(gbm
->device(), size
.width(), size
.height(),
63 GetGbmFormatFromBufferFormat(format
), flags
);
67 scoped_refptr
<GbmBuffer
> buffer(new GbmBuffer(gbm
, bo
, usage
));
68 if (use_scanout
&& !buffer
->GetFramebufferId())
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());
85 PLOG(ERROR
) << "Failed to export buffer to dma_buf";
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_
));
104 PLOG(ERROR
) << "dup";
108 handle
.fd
= base::FileDescriptor(dmabuf_fd
, true /* auto_close */);
109 handle
.stride
= gbm_bo_get_stride(buffer_
->bo());
113 GbmPixmap::~GbmPixmap() {
118 void* GbmPixmap::GetEGLClientBuffer() {
122 int GbmPixmap::GetDmaBufFd() {
126 int GbmPixmap::GetDmaBufPitch() {
127 return gbm_bo_get_stride(buffer_
->bo());
130 bool GbmPixmap::ScheduleOverlayPlane(gfx::AcceleratedWidget widget
,
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
;
138 ShouldApplyScaling(display_bounds
, crop_rect
, &required_size
)) {
139 scoped_refptr
<NativePixmap
> scaled_pixmap
= GetScaledPixmap(required_size
);
141 return scaled_pixmap
->ScheduleOverlayPlane(
142 widget
, plane_z_order
, plane_transform
, display_bounds
, crop_rect
);
148 screen_manager_
->GetWindow(widget
)->QueueOverlayPlane(OverlayPlane(
149 buffer_
, plane_z_order
, plane_transform
, display_bounds
, crop_rect
));
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.";
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
;