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_surface.h"
10 #include "base/logging.h"
11 #include "ui/ozone/platform/drm/gpu/drm_buffer.h"
12 #include "ui/ozone/platform/drm/gpu/drm_window.h"
13 #include "ui/ozone/platform/drm/gpu/gbm_buffer_base.h"
14 #include "ui/ozone/platform/drm/gpu/gbm_device.h"
15 #include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
16 #include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
22 void DoNothing(gfx::SwapResult
) {
25 class GbmSurfaceBuffer
: public GbmBufferBase
{
27 static scoped_refptr
<GbmSurfaceBuffer
> CreateBuffer(
28 const scoped_refptr
<DrmDevice
>& drm
,
30 static scoped_refptr
<GbmSurfaceBuffer
> GetBuffer(gbm_bo
* buffer
);
33 GbmSurfaceBuffer(const scoped_refptr
<DrmDevice
>& drm
, gbm_bo
* bo
);
34 ~GbmSurfaceBuffer() override
;
36 static void Destroy(gbm_bo
* buffer
, void* data
);
38 // This buffer is special and is released by GBM at any point in time (as
39 // long as it isn't being used). Since GBM should be the only one to
40 // release this buffer, keep a self-reference in order to keep this alive.
41 // When GBM calls Destroy(..) the self-reference will dissapear and this will
43 scoped_refptr
<GbmSurfaceBuffer
> self_
;
45 DISALLOW_COPY_AND_ASSIGN(GbmSurfaceBuffer
);
48 GbmSurfaceBuffer::GbmSurfaceBuffer(const scoped_refptr
<DrmDevice
>& drm
,
50 : GbmBufferBase(drm
, bo
, true) {
51 if (GetFramebufferId()) {
53 gbm_bo_set_user_data(bo
, this, GbmSurfaceBuffer::Destroy
);
57 GbmSurfaceBuffer::~GbmSurfaceBuffer() {
61 scoped_refptr
<GbmSurfaceBuffer
> GbmSurfaceBuffer::CreateBuffer(
62 const scoped_refptr
<DrmDevice
>& drm
,
64 scoped_refptr
<GbmSurfaceBuffer
> scoped_buffer(
65 new GbmSurfaceBuffer(drm
, buffer
));
66 if (!scoped_buffer
->GetFramebufferId())
73 scoped_refptr
<GbmSurfaceBuffer
> GbmSurfaceBuffer::GetBuffer(gbm_bo
* buffer
) {
74 return scoped_refptr
<GbmSurfaceBuffer
>(
75 static_cast<GbmSurfaceBuffer
*>(gbm_bo_get_user_data(buffer
)));
79 void GbmSurfaceBuffer::Destroy(gbm_bo
* buffer
, void* data
) {
80 GbmSurfaceBuffer
* scoped_buffer
= static_cast<GbmSurfaceBuffer
*>(data
);
81 scoped_buffer
->self_
= NULL
;
86 GbmSurface::GbmSurface(DrmWindow
* window
, const scoped_refptr
<GbmDevice
>& gbm
)
87 : GbmSurfaceless(window
, NULL
),
89 native_surface_(NULL
),
90 current_buffer_(NULL
),
94 GbmSurface::~GbmSurface() {
96 gbm_surface_release_buffer(native_surface_
, current_buffer_
);
99 gbm_surface_destroy(native_surface_
);
102 bool GbmSurface::Initialize() {
103 // If we're initializing the surface without a controller (possible on startup
104 // where the surface creation can happen before the native window
105 // IPCs arrive), initialize the size to a valid value such that surface
106 // creation doesn't fail.
107 gfx::Size
size(1, 1);
108 if (window_
->GetController()) {
109 size
= window_
->GetController()->GetModeSize();
111 // TODO(dnicoara) Check underlying system support for pixel format.
112 native_surface_
= gbm_surface_create(
113 gbm_
->device(), size
.width(), size
.height(), GBM_BO_FORMAT_XRGB8888
,
114 GBM_BO_USE_SCANOUT
| GBM_BO_USE_RENDERING
);
116 if (!native_surface_
)
123 intptr_t GbmSurface::GetNativeWindow() {
124 DCHECK(native_surface_
);
125 return reinterpret_cast<intptr_t>(native_surface_
);
128 bool GbmSurface::ResizeNativeWindow(const gfx::Size
& viewport_size
) {
129 if (size_
== viewport_size
)
135 bool GbmSurface::OnSwapBuffers() {
136 return OnSwapBuffersAsync(base::Bind(&DoNothing
));
139 bool GbmSurface::OnSwapBuffersAsync(const SwapCompletionCallback
& callback
) {
140 DCHECK(native_surface_
);
142 gbm_bo
* pending_buffer
= gbm_surface_lock_front_buffer(native_surface_
);
143 scoped_refptr
<GbmSurfaceBuffer
> primary
=
144 GbmSurfaceBuffer::GetBuffer(pending_buffer
);
145 if (!primary
.get()) {
146 primary
= GbmSurfaceBuffer::CreateBuffer(gbm_
, pending_buffer
);
147 if (!primary
.get()) {
148 LOG(ERROR
) << "Failed to associate the buffer with the controller";
149 callback
.Run(gfx::SwapResult::SWAP_FAILED
);
154 // The primary buffer is a special case.
155 window_
->QueueOverlayPlane(OverlayPlane(primary
));
157 if (!GbmSurfaceless::OnSwapBuffersAsync(
158 base::Bind(&GbmSurface::OnSwapBuffersCallback
,
159 weak_factory_
.GetWeakPtr(), callback
, pending_buffer
))) {
160 callback
.Run(gfx::SwapResult::SWAP_FAILED
);
167 void GbmSurface::OnSwapBuffersCallback(const SwapCompletionCallback
& callback
,
168 gbm_bo
* pending_buffer
,
169 gfx::SwapResult result
) {
170 // If there was a frontbuffer, it is no longer active. Release it back to GBM.
172 gbm_surface_release_buffer(native_surface_
, current_buffer_
);
174 current_buffer_
= pending_buffer
;
175 callback
.Run(result
);