1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17 #include <android-base/unique_fd.h>
18 #include <android/hardware/graphics/allocator/3.0/IAllocator.h>
19 #include <android/hardware/graphics/mapper/3.0/IMapper.h>
20 #include <hidl/LegacySupport.h>
21 #include <qemu_pipe_bp.h>
22 #include <drm_fourcc.h>
23 
24 #include "glUtils.h"
25 #include "cb_handle_30.h"
26 #include "host_connection_session.h"
27 #include "types.h"
28 #include "debug.h"
29 
30 const int kOMX_COLOR_FormatYUV420Planar = 19;
31 
32 using ::android::hardware::hidl_handle;
33 using ::android::hardware::hidl_vec;
34 using ::android::hardware::hidl_bitfield;
35 using ::android::hardware::Return;
36 using ::android::hardware::Void;
37 
38 using ::android::hardware::graphics::common::V1_2::PixelFormat;
39 using ::android::hardware::graphics::common::V1_0::BufferUsage;
40 
41 namespace AllocatorV3 = ::android::hardware::graphics::allocator::V3_0;
42 namespace MapperV3 = ::android::hardware::graphics::mapper::V3_0;
43 
44 using IAllocator3 = AllocatorV3::IAllocator;
45 using IMapper3 = MapperV3::IMapper;
46 using Error3 = MapperV3::Error;
47 using BufferDescriptorInfo = IMapper3::BufferDescriptorInfo;
48 
49 namespace {
needGpuBuffer(const uint32_t usage)50 bool needGpuBuffer(const uint32_t usage) {
51     return usage & (BufferUsage::GPU_TEXTURE
52                     | BufferUsage::GPU_RENDER_TARGET
53                     | BufferUsage::COMPOSER_OVERLAY
54                     | BufferUsage::COMPOSER_CLIENT_TARGET
55                     | BufferUsage::GPU_DATA_BUFFER);
56 }
57 }  // namespace
58 
59 class GoldfishAllocator : public IAllocator3 {
60 public:
GoldfishAllocator()61     GoldfishAllocator() : m_hostConn(HostConnection::createUnique()) {}
62 
dumpDebugInfo(dumpDebugInfo_cb hidl_cb)63     Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
64         hidl_cb("GoldfishAllocator::dumpDebugInfo is not implemented");
65         return {};
66     }
67 
allocate(const hidl_vec<uint32_t> & rawDescriptor,uint32_t count,allocate_cb hidl_cb)68     Return<void> allocate(const hidl_vec<uint32_t>& rawDescriptor,
69                           uint32_t count,
70                           allocate_cb hidl_cb) {
71         uint32_t stride = 0;
72         std::vector<cb_handle_30_t*> cbs;
73         cbs.reserve(count);
74 
75         const Error3 e = allocateImpl(rawDescriptor, count, &stride, &cbs);
76         if (e == Error3::NONE) {
77             hidl_vec<hidl_handle> handles(cbs.cbegin(), cbs.cend());
78             hidl_cb(Error3::NONE, stride, handles);
79         } else {
80             hidl_cb(e, 0, {});
81         }
82 
83         for (cb_handle_30_t* cb : cbs) {
84             freeCb(std::unique_ptr<cb_handle_30_t>(cb));
85         }
86 
87         return {};
88     }
89 
90 private:
91     // this function should be in sync with GoldfishMapper::isSupportedImpl
allocateImpl(const hidl_vec<uint32_t> & rawDescriptor,uint32_t count,uint32_t * pStride,std::vector<cb_handle_30_t * > * cbs)92     Error3 allocateImpl(const hidl_vec<uint32_t>& rawDescriptor,
93                         uint32_t count,
94                         uint32_t* pStride,
95                         std::vector<cb_handle_30_t*>* cbs) {
96         BufferDescriptorInfo descriptor;
97         if (!decodeBufferDescriptorInfo(rawDescriptor, &descriptor)) {
98             RETURN_ERROR(Error3::BAD_DESCRIPTOR);
99         }
100 
101         if (!descriptor.width) { RETURN_ERROR(Error3::UNSUPPORTED); }
102         if (!descriptor.height) { RETURN_ERROR(Error3::UNSUPPORTED); }
103         if (descriptor.layerCount != 1) { RETURN_ERROR(Error3::UNSUPPORTED); }
104 
105         const uint32_t usage = descriptor.usage;
106 
107         int bpp = 1;
108         int glFormat = 0;
109         int glType = 0;
110         int align = 1;
111         bool yuv_format = false;
112         EmulatorFrameworkFormat emulatorFrameworkFormat =
113             EmulatorFrameworkFormat::GL_COMPATIBLE;
114 
115         PixelFormat format;
116         Error3 e = getBufferFormat(descriptor.format, usage, &format);
117         if (e != Error3::NONE) {
118             ALOGE("%s:%d Unsupported format: frameworkFormat=%d, usage=%x",
119                   __func__, __LINE__, descriptor.format, usage);
120             return e;
121         }
122 
123         switch (format) {
124         case PixelFormat::RGBA_8888:
125         case PixelFormat::RGBX_8888:
126         case PixelFormat::BGRA_8888:
127             bpp = 4;
128             glFormat = GL_RGBA;
129             glType = GL_UNSIGNED_BYTE;
130             break;
131 
132         case PixelFormat::RGB_888:
133             if (needGpuBuffer(usage)) {
134                 RETURN_ERROR(Error3::UNSUPPORTED);
135             }
136             bpp = 3;
137             glFormat = GL_RGB;
138             glType = GL_UNSIGNED_BYTE;
139             break;
140 
141         case PixelFormat::RGB_565:
142             bpp = 2;
143             glFormat = GL_RGB565;
144             glType = GL_UNSIGNED_SHORT_5_6_5;
145             break;
146 
147         case PixelFormat::RGBA_FP16:
148             bpp = 8;
149             glFormat = GL_RGBA16F;
150             glType = GL_HALF_FLOAT;
151             break;
152 
153         case PixelFormat::RGBA_1010102:
154             bpp = 4;
155             glFormat = GL_RGB10_A2;
156             glType = GL_UNSIGNED_INT_2_10_10_10_REV;
157             break;
158 
159         case PixelFormat::RAW16:
160         case PixelFormat::Y16:
161             if (needGpuBuffer(usage)) {
162                 RETURN_ERROR(Error3::UNSUPPORTED);
163             }
164             bpp = 2;
165             align = 16 * bpp;
166             glFormat = GL_LUMINANCE;
167             glType = GL_UNSIGNED_SHORT;
168             break;
169 
170         case PixelFormat::BLOB:
171             if (needGpuBuffer(usage)) {
172                 RETURN_ERROR(Error3::UNSUPPORTED);
173             }
174             glFormat = GL_LUMINANCE;
175             glType = GL_UNSIGNED_BYTE;
176             break;
177 
178         case PixelFormat::YCRCB_420_SP:
179             if (needGpuBuffer(usage)) {
180                 RETURN_ERROR(Error3::UNSUPPORTED);
181             }
182             yuv_format = true;
183             break;
184 
185         case PixelFormat::YV12:
186             align = 16;
187             yuv_format = true;
188             // We are going to use RGB8888 on the host for Vulkan
189             glFormat = GL_RGBA;
190             glType = GL_UNSIGNED_BYTE;
191             emulatorFrameworkFormat = EmulatorFrameworkFormat::YV12;
192             break;
193 
194         case PixelFormat::YCBCR_420_888:
195             yuv_format = true;
196             // We are going to use RGBA 8888 on the host
197             glFormat = GL_RGBA;
198             glType = GL_UNSIGNED_BYTE;
199             emulatorFrameworkFormat = EmulatorFrameworkFormat::YUV_420_888;
200             break;
201 
202         case PixelFormat::YCBCR_P010:
203             yuv_format = true;
204             glFormat = GL_RGBA;
205             glType = GL_UNSIGNED_BYTE;
206             bpp = 2;
207             break;
208 
209         default:
210             ALOGE("%s:%d Unsupported format: format=%d, frameworkFormat=%d, usage=%x",
211                   __func__, __LINE__, format, descriptor.format, usage);
212             RETURN_ERROR(Error3::UNSUPPORTED);
213         }
214 
215         const uint32_t width = descriptor.width;
216         const uint32_t height = descriptor.height;
217         size_t bufferSize;
218         uint32_t stride;
219 
220         if (usage & (BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK)) {
221             const size_t align1 = align - 1;
222             if (yuv_format) {
223                 const size_t yStride = (width * bpp + align1) & ~align1;
224                 const size_t uvStride = (yStride / 2 + align1) & ~align1;
225                 const size_t uvHeight = height / 2;
226                 bufferSize = yStride * height + 2 * (uvHeight * uvStride);
227                 stride = yStride / bpp;
228             } else {
229                 const size_t bpr = (width * bpp + align1) & ~align1;
230                 bufferSize = bpr * height;
231                 stride = bpr / bpp;
232             }
233         } else {
234             bufferSize = 0;
235             stride = 0;
236         }
237 
238         *pStride = stride;
239 
240         return allocateImpl2(usage,
241                              width, height,
242                              format, emulatorFrameworkFormat,
243                              glFormat, glType,
244                              bufferSize,
245                              bpp, stride,
246                              count, cbs);
247     }
248 
allocateImpl2(const uint32_t usage,const uint32_t width,const uint32_t height,const PixelFormat format,const EmulatorFrameworkFormat emulatorFrameworkFormat,const int glFormat,const int glType,const size_t bufferSize,const uint32_t bytesPerPixel,const uint32_t stride,const uint32_t count,std::vector<cb_handle_30_t * > * cbs)249     Error3 allocateImpl2(const uint32_t usage,
250                          const uint32_t width, const uint32_t height,
251                          const PixelFormat format,
252                          const EmulatorFrameworkFormat emulatorFrameworkFormat,
253                          const int glFormat, const int glType,
254                          const size_t bufferSize,
255                          const uint32_t bytesPerPixel,
256                          const uint32_t stride,
257                          const uint32_t count,
258                          std::vector<cb_handle_30_t*>* cbs) {
259         for (uint32_t i = 0; i < count; ++i) {
260             cb_handle_30_t* cb;
261             Error3 e = allocateCb(usage,
262                                   width, height,
263                                   format, emulatorFrameworkFormat,
264                                   glFormat, glType,
265                                   bufferSize,
266                                   bytesPerPixel, stride,
267                                   &cb);
268             if (e == Error3::NONE) {
269                 cbs->push_back(cb);
270             } else {
271                 return e;
272             }
273         }
274 
275         RETURN(Error3::NONE);
276     }
277 
278     // see GoldfishMapper::encodeBufferDescriptorInfo
decodeBufferDescriptorInfo(const hidl_vec<uint32_t> & raw,BufferDescriptorInfo * d)279     static bool decodeBufferDescriptorInfo(const hidl_vec<uint32_t>& raw,
280                                            BufferDescriptorInfo* d) {
281         if (raw.size() == 5) {
282             d->width = raw[0];
283             d->height = raw[1];
284             d->layerCount = raw[2];
285             d->format = static_cast<PixelFormat>(raw[3]);
286             d->usage = raw[4];
287 
288             RETURN(true);
289         } else {
290             RETURN_ERROR(false);
291         }
292     }
293 
getBufferFormat(const PixelFormat frameworkFormat,const uint32_t usage,PixelFormat * format)294     static Error3 getBufferFormat(const PixelFormat frameworkFormat,
295                                   const uint32_t usage,
296                                   PixelFormat* format) {
297         if (frameworkFormat == PixelFormat::IMPLEMENTATION_DEFINED) {
298             RETURN_ERROR(Error3::UNSUPPORTED);
299         } else if (static_cast<int>(frameworkFormat) == kOMX_COLOR_FormatYUV420Planar &&
300                (usage & BufferUsage::VIDEO_DECODER)) {
301             ALOGW("gralloc_alloc: Requested OMX_COLOR_FormatYUV420Planar, given "
302               "YCbCr_420_888, taking experimental path. "
303               "usage=%x", usage);
304             *format = PixelFormat::YCBCR_420_888;
305             RETURN(Error3::NONE);
306         } else  {
307             *format = frameworkFormat;
308             RETURN(Error3::NONE);
309         }
310     }
311 
allocateCb(const uint32_t usage,const uint32_t width,const uint32_t height,const PixelFormat format,const EmulatorFrameworkFormat emulatorFrameworkFormat,const int glFormat,const int glType,const size_t bufferSize,const int32_t bytesPerPixel,const int32_t stride,cb_handle_30_t ** cb)312     Error3 allocateCb(const uint32_t usage,
313                       const uint32_t width, const uint32_t height,
314                       const PixelFormat format,
315                       const EmulatorFrameworkFormat emulatorFrameworkFormat,
316                       const int glFormat, const int glType,
317                       const size_t bufferSize,
318                       const int32_t bytesPerPixel,
319                       const int32_t stride,
320                       cb_handle_30_t** cb) {
321         const HostConnectionSession conn = getHostConnectionSession();
322         ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
323         CRASH_IF(!rcEnc, "conn.getRcEncoder() failed");
324 
325         android::base::unique_fd cpuAlocatorFd;
326         GoldfishAddressSpaceBlock bufferBits;
327         if (bufferSize > 0) {
328             GoldfishAddressSpaceHostMemoryAllocator host_memory_allocator(
329                 rcEnc->featureInfo_const()->hasSharedSlotsHostMemoryAllocator);
330             if (!host_memory_allocator.is_opened()) {
331                 RETURN_ERROR(Error3::NO_RESOURCES);
332             }
333 
334             if (host_memory_allocator.hostMalloc(&bufferBits, bufferSize)) {
335                 RETURN_ERROR(Error3::NO_RESOURCES);
336             }
337 
338             cpuAlocatorFd.reset(host_memory_allocator.release());
339         }
340 
341         uint32_t hostHandle = 0;
342         android::base::unique_fd hostHandleRefCountFd;
343         if (needGpuBuffer(usage)) {
344             hostHandleRefCountFd.reset(qemu_pipe_open("refcount"));
345             if (!hostHandleRefCountFd.ok()) {
346                 RETURN_ERROR(Error3::NO_RESOURCES);
347             }
348 
349             const GLenum allocFormat =
350                 (PixelFormat::RGBX_8888 == format) ? GL_RGB : glFormat;
351 
352             hostHandle = rcEnc->rcCreateColorBufferDMA(
353                 rcEnc,
354                 width, height,
355                 allocFormat, static_cast<int>(emulatorFrameworkFormat));
356 
357             if (!hostHandle) {
358                 RETURN_ERROR(Error3::NO_RESOURCES);
359             }
360 
361             if (qemu_pipe_write(hostHandleRefCountFd.get(),
362                                 &hostHandle,
363                                 sizeof(hostHandle)) != sizeof(hostHandle)) {
364                 rcEnc->rcCloseColorBuffer(rcEnc, hostHandle);
365                 RETURN_ERROR(Error3::NO_RESOURCES);
366             }
367         }
368         uint32_t drmFormat = resolve_drm_format(format);
369         std::unique_ptr<cb_handle_30_t> handle =
370             std::make_unique<cb_handle_30_t>(
371                 cpuAlocatorFd.release(),
372                 hostHandleRefCountFd.release(),
373                 hostHandle,
374                 usage,
375                 width,
376                 height,
377                 static_cast<int>(format),
378                 drmFormat,
379                 glFormat,
380                 glType,
381                 bufferSize,
382                 bufferBits.guestPtr(),
383                 bufferBits.size(),
384                 bufferBits.offset(),
385                 bytesPerPixel,
386                 stride);
387 
388         bufferBits.release();
389         *cb = handle.release();
390         RETURN(Error3::NONE);
391     }
392 
resolve_drm_format(const PixelFormat format)393     uint32_t resolve_drm_format(const PixelFormat format) {
394         /**
395          * This aims to replicate the virtgpu format handling for YUV
396          * Moving to minigbm + virtgpu should offer the same behaviour
397          * https://cs.android.com/android/platform/superproject/main/+/main:external/minigbm/virtgpu_virgl.c;l=1206?q=virtgpu&ss=android%2Fplatform%2Fsuperproject%2Fmain
398         */
399         ALOGV("Resolving drm format from PixelFormat %d", static_cast<int>(format));
400         switch (format) {
401             case PixelFormat::YCBCR_420_888:
402                 return DRM_FORMAT_YUV420;
403             default:
404                 //TODO handle new formats if needed
405                 ALOGV("Unknown DRM Format resolution. Proceeding with an "
406                       "invalid drm format. Later stages of the application "
407                       "should handle this.");
408                 return DRM_FORMAT_INVALID;
409         }
410     }
411 
freeCb(std::unique_ptr<cb_handle_30_t> cb)412     void freeCb(std::unique_ptr<cb_handle_30_t> cb) {
413         if (cb->hostHandleRefcountFdIndex >= 0) {
414             ::close(cb->fds[cb->hostHandleRefcountFdIndex]);
415         }
416 
417         if (cb->bufferFdIndex >= 0) {
418             GoldfishAddressSpaceBlock::memoryUnmap(cb->getBufferPtr(), cb->mmapedSize);
419             GoldfishAddressSpaceHostMemoryAllocator::closeHandle(cb->fds[cb->bufferFdIndex]);
420         }
421     }
422 
getHostConnectionSession() const423     HostConnectionSession getHostConnectionSession() const {
424         return HostConnectionSession(m_hostConn.get());
425     }
426 
427     std::unique_ptr<HostConnection> m_hostConn;
428 };
429 
main(int,char **)430 int main(int, char**) {
431     using ::android::sp;
432 
433     ::android::hardware::configureRpcThreadpool(4, true /* callerWillJoin */);
434 
435     sp<IAllocator3> allocator(new GoldfishAllocator());
436     if (allocator->registerAsService() != ::android::NO_ERROR) {
437         ALOGE("failed to register graphics IAllocator@3.0 service");
438         return -EINVAL;
439     }
440 
441     ALOGI("graphics IAllocator@3.0 service is initialized");
442     ::android::hardware::joinRpcThreadpool();
443 
444     ALOGI("graphics IAllocator@3.0 service is terminating");
445     return 0;
446 }
447