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 {
10
11constexpr uint32_t kDefaultGraphicBufferLayerCount = 1;
12
13}  // anonymous namespace
14
15namespace android {
16namespace dvr {
17
18IonBuffer::IonBuffer() : IonBuffer(nullptr, 0, 0, 0, 0, 0, 0) {}
19
20IonBuffer::IonBuffer(uint32_t width, uint32_t height, uint32_t format,
21                     uint64_t usage)
22    : IonBuffer() {
23  Alloc(width, height, kDefaultGraphicBufferLayerCount, format, usage);
24}
25
26IonBuffer::IonBuffer(buffer_handle_t handle, uint32_t width, uint32_t height,
27                     uint32_t stride, uint32_t format, uint64_t usage)
28    : IonBuffer(handle, width, height, kDefaultGraphicBufferLayerCount, stride,
29                format, usage) {}
30
31IonBuffer::IonBuffer(buffer_handle_t handle, uint32_t width, uint32_t height,
32                     uint32_t layer_count, uint32_t stride, uint32_t format,
33                     uint64_t usage)
34    : buffer_(nullptr) {
35  ALOGD_IF(TRACE,
36           "IonBuffer::IonBuffer: handle=%p width=%u height=%u layer_count=%u "
37           "stride=%u format=%u usage=%" PRIx64,
38           handle, width, height, layer_count, stride, format, usage);
39  if (handle != 0) {
40    Import(handle, width, height, layer_count, stride, format, usage);
41  }
42}
43
44IonBuffer::~IonBuffer() {
45  ALOGD_IF(TRACE,
46           "IonBuffer::~IonBuffer: handle=%p width=%u height=%u stride=%u "
47           "format=%u usage=%" PRIx64,
48           handle(), width(), height(), stride(), format(), usage());
49  FreeHandle();
50}
51
52IonBuffer::IonBuffer(IonBuffer&& other) : IonBuffer() {
53  *this = std::move(other);
54}
55
56IonBuffer& IonBuffer::operator=(IonBuffer&& other) {
57  ALOGD_IF(TRACE, "IonBuffer::operator=: handle_=%p other.handle_=%p", handle(),
58           other.handle());
59
60  if (this != &other) {
61    buffer_ = other.buffer_;
62    other.FreeHandle();
63  }
64  return *this;
65}
66
67void IonBuffer::FreeHandle() {
68  if (buffer_.get()) {
69    // GraphicBuffer unregisters and cleans up the handle if needed
70    buffer_ = nullptr;
71  }
72}
73
74int IonBuffer::Alloc(uint32_t width, uint32_t height, uint32_t layer_count,
75                     uint32_t format, uint64_t usage) {
76  ALOGD_IF(TRACE,
77           "IonBuffer::Alloc: width=%u height=%u layer_count=%u format=%u "
78           "usage=%" PRIx64, width, height, layer_count, format, usage);
79
80  sp<GraphicBuffer> buffer =
81      new GraphicBuffer(width, height, format, layer_count, usage);
82  if (buffer->initCheck() != OK) {
83    ALOGE("IonBuffer::Aloc: Failed to allocate buffer");
84    return -EINVAL;
85  } else {
86    buffer_ = buffer;
87    return 0;
88  }
89}
90
91void IonBuffer::Reset(buffer_handle_t handle, uint32_t width, uint32_t height,
92                      uint32_t layer_count, uint32_t stride, uint32_t format,
93                      uint64_t usage) {
94  ALOGD_IF(TRACE,
95           "IonBuffer::Reset: handle=%p width=%u height=%u layer_count=%u "
96           "stride=%u format=%u usage=%" PRIx64,
97           handle, width, height, layer_count, stride, format, usage);
98  Import(handle, width, height, layer_count, stride, format, usage);
99}
100
101int IonBuffer::Import(buffer_handle_t handle, uint32_t width, uint32_t height,
102                      uint32_t layer_count, uint32_t stride, uint32_t format,
103                      uint64_t usage) {
104  ATRACE_NAME("IonBuffer::Import1");
105  ALOGD_IF(TRACE,
106           "IonBuffer::Import: handle=%p width=%u height=%u layer_count=%u "
107           "stride=%u format=%u usage=%" PRIx64,
108           handle, width, height, layer_count, stride, format, usage);
109  FreeHandle();
110  sp<GraphicBuffer> buffer =
111      new GraphicBuffer(handle, GraphicBuffer::TAKE_UNREGISTERED_HANDLE, width,
112                        height, format, layer_count, usage, stride);
113  if (buffer->initCheck() != OK) {
114    ALOGE("IonBuffer::Import: Failed to import buffer");
115    return -EINVAL;
116  } else {
117    buffer_ = buffer;
118    return 0;
119  }
120}
121
122int IonBuffer::Import(const int* fd_array, int fd_count, const int* int_array,
123                      int int_count, uint32_t width, uint32_t height,
124                      uint32_t layer_count, uint32_t stride, uint32_t format,
125                      uint64_t usage) {
126  ATRACE_NAME("IonBuffer::Import2");
127  ALOGD_IF(TRACE,
128           "IonBuffer::Import: fd_count=%d int_count=%d width=%u height=%u "
129           "layer_count=%u stride=%u format=%u usage=%" PRIx64,
130           fd_count, int_count, width, height, layer_count, stride, format,
131           usage);
132
133  if (fd_count < 0 || int_count < 0) {
134    ALOGE("IonBuffer::Import: invalid arguments.");
135    return -EINVAL;
136  }
137
138  native_handle_t* handle = native_handle_create(fd_count, int_count);
139  if (!handle) {
140    ALOGE("IonBuffer::Import: failed to create new native handle.");
141    return -ENOMEM;
142  }
143
144  // Copy fd_array into the first part of handle->data and int_array right
145  // after it.
146  memcpy(handle->data, fd_array, sizeof(int) * fd_count);
147  memcpy(handle->data + fd_count, int_array, sizeof(int) * int_count);
148
149  const int ret =
150      Import(handle, width, height, layer_count, stride, format, usage);
151  if (ret < 0) {
152    ALOGE("IonBuffer::Import: failed to import raw native handle: %s",
153          strerror(-ret));
154    native_handle_close(handle);
155    native_handle_delete(handle);
156  }
157
158  return ret;
159}
160
161int IonBuffer::Duplicate(const IonBuffer* other) {
162  if (!other->handle())
163    return -EINVAL;
164
165  const int fd_count = other->handle()->numFds;
166  const int int_count = other->handle()->numInts;
167
168  if (fd_count < 0 || int_count < 0)
169    return -EINVAL;
170
171  native_handle_t* handle = native_handle_create(fd_count, int_count);
172  if (!handle) {
173    ALOGE("IonBuffer::Duplicate: Failed to create new native handle.");
174    return -ENOMEM;
175  }
176
177  // Duplicate the file descriptors from the other native handle.
178  for (int i = 0; i < fd_count; i++)
179    handle->data[i] = dup(other->handle()->data[i]);
180
181  // Copy the ints after the file descriptors.
182  memcpy(handle->data + fd_count, other->handle()->data + fd_count,
183         sizeof(int) * int_count);
184
185  const int ret =
186      Import(handle, other->width(), other->height(), other->layer_count(),
187             other->stride(), other->format(), other->usage());
188  if (ret < 0) {
189    ALOGE("IonBuffer::Duplicate: Failed to import duplicate native handle: %s",
190          strerror(-ret));
191    native_handle_close(handle);
192    native_handle_delete(handle);
193  }
194
195  return ret;
196}
197
198int IonBuffer::Lock(uint32_t usage, int x, int y, int width, int height,
199                    void** address) {
200  ATRACE_NAME("IonBuffer::Lock");
201  ALOGD_IF(TRACE,
202           "IonBuffer::Lock: handle=%p usage=%d x=%d y=%d width=%d height=%d "
203           "address=%p",
204           handle(), usage, x, y, width, height, address);
205
206  status_t err =
207      buffer_->lock(usage, Rect(x, y, x + width, y + height), address);
208  if (err != NO_ERROR)
209    return -EINVAL;
210  else
211    return 0;
212}
213
214int IonBuffer::LockYUV(uint32_t usage, int x, int y, int width, int height,
215                       struct android_ycbcr* yuv) {
216  ATRACE_NAME("IonBuffer::LockYUV");
217  ALOGD_IF(TRACE,
218           "IonBuffer::Lock: handle=%p usage=%d x=%d y=%d width=%d height=%d",
219           handle(), usage, x, y, width, height);
220
221  status_t err =
222      buffer_->lockYCbCr(usage, Rect(x, y, x + width, y + height), yuv);
223  if (err != NO_ERROR)
224    return -EINVAL;
225  else
226    return 0;
227}
228
229int IonBuffer::Unlock() {
230  ATRACE_NAME("IonBuffer::Unlock");
231  ALOGD_IF(TRACE, "IonBuffer::Unlock: handle=%p", handle());
232
233  status_t err = buffer_->unlock();
234  if (err != NO_ERROR)
235    return -EINVAL;
236  else
237    return 0;
238}
239}  // namespace dvr
240}  // namespace android
241