summaryrefslogtreecommitdiffstats
path: root/ui/ozone/platform/drm/gpu/gbm_surface.cc
blob: 8b5b167bc85a3d9eefa3e0b0ffbf59cd9af9827c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// Copyright 2014 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 <gbm.h>

#include "base/bind.h"
#include "base/logging.h"
#include "ui/ozone/platform/drm/gpu/drm_buffer.h"
#include "ui/ozone/platform/drm/gpu/drm_window.h"
#include "ui/ozone/platform/drm/gpu/gbm_buffer_base.h"
#include "ui/ozone/platform/drm/gpu/gbm_device.h"
#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"

namespace ui {

namespace {

class GbmSurfaceBuffer : public GbmBufferBase {
 public:
  static scoped_refptr<GbmSurfaceBuffer> CreateBuffer(
      const scoped_refptr<DrmDevice>& drm,
      gbm_bo* buffer);
  static scoped_refptr<GbmSurfaceBuffer> GetBuffer(gbm_bo* buffer);

 private:
  GbmSurfaceBuffer(const scoped_refptr<DrmDevice>& drm, gbm_bo* bo);
  ~GbmSurfaceBuffer() override;

  static void Destroy(gbm_bo* buffer, void* data);

  // This buffer is special and is released by GBM at any point in time (as
  // long as it isn't being used). Since GBM should be the only one to
  // release this buffer, keep a self-reference in order to keep this alive.
  // When GBM calls Destroy(..) the self-reference will dissapear and this will
  // be destroyed.
  scoped_refptr<GbmSurfaceBuffer> self_;

  DISALLOW_COPY_AND_ASSIGN(GbmSurfaceBuffer);
};

GbmSurfaceBuffer::GbmSurfaceBuffer(const scoped_refptr<DrmDevice>& drm,
                                   gbm_bo* bo)
    : GbmBufferBase(drm, bo, true) {
  if (GetFramebufferId()) {
    self_ = this;
    gbm_bo_set_user_data(bo, this, GbmSurfaceBuffer::Destroy);
  }
}

GbmSurfaceBuffer::~GbmSurfaceBuffer() {
}

// static
scoped_refptr<GbmSurfaceBuffer> GbmSurfaceBuffer::CreateBuffer(
    const scoped_refptr<DrmDevice>& drm,
    gbm_bo* buffer) {
  scoped_refptr<GbmSurfaceBuffer> scoped_buffer(
      new GbmSurfaceBuffer(drm, buffer));
  if (!scoped_buffer->GetFramebufferId())
    return NULL;

  return scoped_buffer;
}

// static
scoped_refptr<GbmSurfaceBuffer> GbmSurfaceBuffer::GetBuffer(gbm_bo* buffer) {
  return scoped_refptr<GbmSurfaceBuffer>(
      static_cast<GbmSurfaceBuffer*>(gbm_bo_get_user_data(buffer)));
}

// static
void GbmSurfaceBuffer::Destroy(gbm_bo* buffer, void* data) {
  GbmSurfaceBuffer* scoped_buffer = static_cast<GbmSurfaceBuffer*>(data);
  scoped_buffer->self_ = NULL;
}

}  // namespace

GbmSurface::GbmSurface(DrmWindow* window_delegate,
                       const scoped_refptr<GbmDevice>& gbm)
    : GbmSurfaceless(window_delegate, NULL),
      gbm_(gbm),
      native_surface_(NULL),
      current_buffer_(NULL),
      weak_factory_(this) {
}

GbmSurface::~GbmSurface() {
  if (current_buffer_)
    gbm_surface_release_buffer(native_surface_, current_buffer_);

  if (native_surface_)
    gbm_surface_destroy(native_surface_);
}

bool GbmSurface::Initialize() {
  // If we're initializing the surface without a controller (possible on startup
  // where the surface creation can happen before the native window delegate
  // IPCs arrive), initialize the size to a valid value such that surface
  // creation doesn't fail.
  gfx::Size size(1, 1);
  if (window_delegate_->GetController()) {
    size = window_delegate_->GetController()->GetModeSize();
  }
  // TODO(dnicoara) Check underlying system support for pixel format.
  native_surface_ = gbm_surface_create(
      gbm_->device(), size.width(), size.height(), GBM_BO_FORMAT_XRGB8888,
      GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);

  if (!native_surface_)
    return false;

  size_ = size;
  return true;
}

intptr_t GbmSurface::GetNativeWindow() {
  DCHECK(native_surface_);
  return reinterpret_cast<intptr_t>(native_surface_);
}

bool GbmSurface::ResizeNativeWindow(const gfx::Size& viewport_size) {
  if (size_ == viewport_size)
    return true;

  return false;
}

bool GbmSurface::OnSwapBuffers() {
  return OnSwapBuffersAsync(base::Bind(&base::DoNothing));
}

bool GbmSurface::OnSwapBuffersAsync(const SwapCompletionCallback& callback) {
  DCHECK(native_surface_);

  gbm_bo* pending_buffer = gbm_surface_lock_front_buffer(native_surface_);
  scoped_refptr<GbmSurfaceBuffer> primary =
      GbmSurfaceBuffer::GetBuffer(pending_buffer);
  if (!primary.get()) {
    primary = GbmSurfaceBuffer::CreateBuffer(gbm_, pending_buffer);
    if (!primary.get()) {
      LOG(ERROR) << "Failed to associate the buffer with the controller";
      callback.Run();
      return false;
    }
  }

  // The primary buffer is a special case.
  window_delegate_->QueueOverlayPlane(OverlayPlane(primary));

  if (!GbmSurfaceless::OnSwapBuffersAsync(
          base::Bind(&GbmSurface::OnSwapBuffersCallback,
                     weak_factory_.GetWeakPtr(), callback, pending_buffer))) {
    callback.Run();
    return false;
  }

  return true;
}

void GbmSurface::OnSwapBuffersCallback(const SwapCompletionCallback& callback,
                                       gbm_bo* pending_buffer) {
  // If there was a frontbuffer, it is no longer active. Release it back to GBM.
  if (current_buffer_)
    gbm_surface_release_buffer(native_surface_, current_buffer_);

  current_buffer_ = pending_buffer;
  callback.Run();
}

}  // namespace ui