ion_buffer.cpp revision 4fe60582f314e381098f8f3bc2e39c5880e9243a
1#include <private/dvr/ion_buffer.h>
2
3#include <log/log.h>
4#define ATRACE_TAG ATRACE_TAG_GRAPHICS
5#include <utils/Trace.h>
6
7#include <mutex>
8
9namespace android {
10namespace dvr {
11
12gralloc_module_t const* IonBuffer::gralloc_module_ = nullptr;
13alloc_device_t* IonBuffer::gralloc_device_ = nullptr;
14
15IonBuffer::IonBuffer() : IonBuffer(nullptr, 0, 0, 0, 0, 0, 0, 0) {}
16
17IonBuffer::IonBuffer(int width, int height, int format, int usage)
18    : IonBuffer() {
19  Alloc(width, height, format, usage);
20}
21
22IonBuffer::IonBuffer(buffer_handle_t handle, int width, int height, int stride,
23                     int format, int usage)
24    : IonBuffer(handle, width, height, 1, stride, 0, format, usage) {}
25
26IonBuffer::IonBuffer(buffer_handle_t handle, int width, int height,
27                     int layer_count, int stride, int layer_stride, int format,
28                     int usage)
29    : handle_(handle),
30      width_(width),
31      height_(height),
32      layer_count_(layer_count),
33      stride_(stride),
34      layer_stride_(layer_stride),
35      format_(format),
36      usage_(usage),
37      locked_(false),
38      needs_unregister_(false) {
39  ALOGD_IF(TRACE,
40           "IonBuffer::IonBuffer: handle=%p width=%d height=%d layer_count=%d "
41           "stride=%d layer stride=%d format=%d usage=%d",
42           handle_, width_, height_, layer_count_, stride_, layer_stride_,
43           format_, usage_);
44  GrallocInit();
45}
46
47IonBuffer::~IonBuffer() {
48  ALOGD_IF(TRACE,
49           "IonBuffer::~IonBuffer: handle=%p width=%d height=%d stride=%d "
50           "format=%d usage=%d",
51           handle_, width_, height_, stride_, format_, usage_);
52
53  FreeHandle();
54}
55
56IonBuffer::IonBuffer(IonBuffer&& other) : IonBuffer() {
57  *this = std::move(other);
58}
59
60IonBuffer& IonBuffer::operator=(IonBuffer&& other) {
61  ALOGD_IF(TRACE, "IonBuffer::operator=: handle_=%p other.handle_=%p", handle_,
62           other.handle_);
63
64  if (this != &other) {
65    Replace(other.handle_, other.width_, other.height_, other.layer_count_,
66            other.stride_, other.layer_stride_, other.format_, other.usage_,
67            other.needs_unregister_);
68    locked_ = other.locked_;
69    other.handle_ = nullptr;
70    other.FreeHandle();
71  }
72
73  return *this;
74}
75
76void IonBuffer::FreeHandle() {
77  if (handle_) {
78    // Lock/Unlock don't need to be balanced, but one Unlock is needed to
79    // clean/unmap the buffer. Warn if this didn't happen before freeing the
80    // native handle.
81    ALOGW_IF(locked_,
82             "IonBuffer::FreeHandle: freeing a locked handle!!! handle=%p",
83             handle_);
84
85    if (needs_unregister_) {
86      int ret = gralloc_module_->unregisterBuffer(gralloc_module_, handle_);
87      ALOGE_IF(ret < 0,
88               "IonBuffer::FreeHandle: Failed to unregister handle: %s",
89               strerror(-ret));
90
91      native_handle_close(const_cast<native_handle_t*>(handle_));
92      native_handle_delete(const_cast<native_handle_t*>(handle_));
93    } else {
94      int ret = gralloc_device_->free(gralloc_device_, handle_);
95      if (ret < 0) {
96        ALOGE("IonBuffer::FreeHandle: failed to free buffer: %s",
97              strerror(-ret));
98
99        // Not sure if this is the right thing to do. Attempting to prevent a
100        // memory leak of the native handle.
101        native_handle_close(const_cast<native_handle_t*>(handle_));
102        native_handle_delete(const_cast<native_handle_t*>(handle_));
103      }
104    }
105  }
106
107  // Always re-initialize these members, even if handle_ was nullptr, in case
108  // someone was dumb enough to pass a nullptr handle to the constructor or
109  // Reset.
110  handle_ = nullptr;
111  width_ = 0;
112  height_ = 0;
113  layer_count_ = 0;
114  stride_ = 0;
115  layer_stride_ = 0;
116  format_ = 0;
117  usage_ = 0;
118  locked_ = false;
119  needs_unregister_ = false;
120}
121
122int IonBuffer::Alloc(int width, int height, int format, int usage) {
123  ATRACE_NAME("IonBuffer::Alloc");
124  ALOGD_IF(TRACE, "IonBuffer::Alloc: width=%d height=%d format=%d usage=%d",
125           width, height, format, usage);
126
127  int stride;
128  buffer_handle_t handle;
129
130  int ret = gralloc_device_->alloc(gralloc_device_, width, height, format,
131                                   usage, &handle, &stride);
132  if (ret < 0) {
133    ALOGE("IonBuffer::Alloc: failed to allocate gralloc buffer: %s",
134          strerror(-ret));
135    return ret;
136  }
137
138  Replace(handle, width, height, 1, stride, 0, format, usage, false);
139  return 0;
140}
141
142void IonBuffer::Replace(buffer_handle_t handle, int width, int height,
143                        int layer_count, int stride, int layer_stride,
144                        int format, int usage, bool needs_unregister) {
145  FreeHandle();
146
147  handle_ = handle;
148  width_ = width;
149  height_ = height;
150  layer_count_ = layer_count;
151  stride_ = stride;
152  layer_stride_ = layer_stride;
153  format_ = format;
154  usage_ = usage;
155  needs_unregister_ = needs_unregister;
156}
157
158void IonBuffer::Reset(buffer_handle_t handle, int width, int height, int stride,
159                      int format, int usage) {
160  ALOGD_IF(TRACE,
161           "IonBuffer::Reset: handle=%p width=%d height=%d stride=%d format=%d "
162           "usage=%d",
163           handle, width, height, stride, format, usage);
164
165  Replace(handle, width, height, 1, stride, 0, format, usage, false);
166}
167
168int IonBuffer::Import(buffer_handle_t handle, int width, int height, int stride,
169                      int format, int usage) {
170  ATRACE_NAME("IonBuffer::Import1");
171  ALOGD_IF(
172      TRACE,
173      "IonBuffer::Import: handle=%p width=%d height=%d stride=%d format=%d "
174      "usage=%d",
175      handle, width, height, stride, format, usage);
176
177  int ret = gralloc_module_->registerBuffer(gralloc_module_, handle);
178  if (ret < 0) {
179    ALOGE("IonBuffer::Import: failed to import handle: %s", strerror(-ret));
180    return ret;
181  }
182
183  Replace(handle, width, height, 1, stride, 0, format, usage, true);
184  return 0;
185}
186
187int IonBuffer::Import(const int* fd_array, int fd_count, const int* int_array,
188                      int int_count, int width, int height, int stride,
189                      int format, int usage) {
190  ATRACE_NAME("IonBuffer::Import2");
191  ALOGD_IF(TRACE,
192           "IonBuffer::Import: fd_count=%d int_count=%d width=%d height=%d "
193           "stride=%d format=%d usage=%d",
194           fd_count, int_count, width, height, stride, format, usage);
195
196  if (fd_count < 0 || int_count < 0) {
197    ALOGE("IonBuffer::Import: invalid arguments.");
198    return -EINVAL;
199  }
200
201  native_handle_t* handle = native_handle_create(fd_count, int_count);
202  if (!handle) {
203    ALOGE("IonBuffer::Import: failed to create new native handle.");
204    return -ENOMEM;
205  }
206
207  // Copy fd_array into the first part of handle->data and int_array right
208  // after it.
209  memcpy(handle->data, fd_array, sizeof(int) * fd_count);
210  memcpy(handle->data + fd_count, int_array, sizeof(int) * int_count);
211
212  int ret = Import(handle, width, height, stride, format, usage);
213  if (ret < 0) {
214    ALOGE("IonBuffer::Import: failed to import raw native handle: %s",
215          strerror(-ret));
216    native_handle_close(handle);
217    native_handle_delete(handle);
218  }
219
220  return ret;
221}
222
223int IonBuffer::Duplicate(const IonBuffer* other) {
224  if (!other->handle())
225    return -EINVAL;
226
227  const int fd_count = other->handle()->numFds;
228  const int int_count = other->handle()->numInts;
229
230  if (fd_count < 0 || int_count < 0)
231    return -EINVAL;
232
233  native_handle_t* handle = native_handle_create(fd_count, int_count);
234  if (!handle) {
235    ALOGE("IonBuffer::Duplicate: Failed to create new native handle.");
236    return -ENOMEM;
237  }
238
239  // Duplicate the file descriptors from the other native handle.
240  for (int i = 0; i < fd_count; i++)
241    handle->data[i] = dup(other->handle()->data[i]);
242
243  // Copy the ints after the file descriptors.
244  memcpy(handle->data + fd_count, other->handle()->data + fd_count,
245         sizeof(int) * int_count);
246
247  const int ret = Import(handle, other->width(), other->height(),
248                         other->stride(), other->format(), other->usage());
249  if (ret < 0) {
250    ALOGE("IonBuffer::Duplicate: Failed to import duplicate native handle: %s",
251          strerror(-ret));
252    native_handle_close(handle);
253    native_handle_delete(handle);
254  }
255
256  return ret;
257}
258
259int IonBuffer::Lock(int usage, int x, int y, int width, int height,
260                    void** address) {
261  ATRACE_NAME("IonBuffer::Lock");
262  ALOGD_IF(TRACE,
263           "IonBuffer::Lock: handle=%p usage=%d x=%d y=%d width=%d height=%d "
264           "address=%p",
265           handle_, usage, x, y, width, height, address);
266
267  // Lock may be called multiple times; but only one Unlock is required.
268  const int err = gralloc_module_->lock(gralloc_module_, handle_, usage, x, y,
269                                        width, height, address);
270  if (!err)
271    locked_ = true;
272
273  return err;
274}
275
276int IonBuffer::LockYUV(int usage, int x, int y, int width, int height,
277                       struct android_ycbcr* yuv) {
278  ATRACE_NAME("IonBuffer::LockYUV");
279  ALOGD_IF(TRACE,
280           "IonBuffer::Lock: handle=%p usage=%d x=%d y=%d width=%d height=%d",
281           handle_, usage, x, y, width, height);
282  const int err = gralloc_module_->lock_ycbcr(gralloc_module_, handle_, usage,
283                                              x, y, width, height, yuv);
284  if (!err)
285    locked_ = true;
286
287  return err;
288}
289
290int IonBuffer::Unlock() {
291  ATRACE_NAME("IonBuffer::Unlock");
292  ALOGD_IF(TRACE, "IonBuffer::Unlock: handle=%p", handle_);
293
294  // Lock may be called multiple times; but only one Unlock is required.
295  const int err = gralloc_module_->unlock(gralloc_module_, handle_);
296  if (!err)
297    locked_ = false;
298
299  return err;
300}
301
302void IonBuffer::GrallocInit() {
303  static std::once_flag gralloc_flag;
304  std::call_once(gralloc_flag, []() {
305    hw_module_t const* module = nullptr;
306    alloc_device_t* device = nullptr;
307
308    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
309    ALOGE_IF(err, "IonBuffer::GrallocInit: failed to find the %s module: %s",
310             GRALLOC_HARDWARE_MODULE_ID, strerror(-err));
311
312    err = gralloc_open(module, &device);
313    ALOGE_IF(err, "IonBuffer::GrallocInit: failed to open gralloc device: %s",
314             strerror(-err));
315
316    gralloc_module_ = reinterpret_cast<gralloc_module_t const*>(module);
317    gralloc_device_ = device;
318  });
319}
320
321}  // namespace dvr
322}  // namespace android
323