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