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/hardware/graphics/allocator/3.0/IAllocator.h>
18 #include <android/hardware/graphics/mapper/3.0/IMapper.h>
19 #include <hidl/LegacySupport.h>
20 #include <qemu_pipe_bp.h>
21
22 #include "glUtils.h"
23 #include "cb_handle_30.h"
24 #include "host_connection_session.h"
25 #include "types.h"
26 #include "debug.h"
27
28 const int kOMX_COLOR_FormatYUV420Planar = 19;
29
30 using ::android::hardware::hidl_handle;
31 using ::android::hardware::hidl_vec;
32 using ::android::hardware::hidl_bitfield;
33 using ::android::hardware::Return;
34 using ::android::hardware::Void;
35
36 using ::android::hardware::graphics::common::V1_2::PixelFormat;
37 using ::android::hardware::graphics::common::V1_0::BufferUsage;
38
39 namespace AllocatorV3 = ::android::hardware::graphics::allocator::V3_0;
40 namespace MapperV3 = ::android::hardware::graphics::mapper::V3_0;
41
42 using IAllocator3 = AllocatorV3::IAllocator;
43 using IMapper3 = MapperV3::IMapper;
44 using Error3 = MapperV3::Error;
45 using BufferDescriptorInfo = IMapper3::BufferDescriptorInfo;
46
47 class GoldfishAllocator : public IAllocator3 {
48 public:
GoldfishAllocator()49 GoldfishAllocator() : m_hostConn(HostConnection::createUnique()) {}
50
dumpDebugInfo(dumpDebugInfo_cb hidl_cb)51 Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
52 hidl_cb("GoldfishAllocator::dumpDebugInfo is not implemented");
53 return {};
54 }
55
allocate(const hidl_vec<uint32_t> & rawDescriptor,uint32_t count,allocate_cb hidl_cb)56 Return<void> allocate(const hidl_vec<uint32_t>& rawDescriptor,
57 uint32_t count,
58 allocate_cb hidl_cb) {
59 uint32_t stride = 0;
60 std::vector<cb_handle_30_t*> cbs;
61 cbs.reserve(count);
62
63 const Error3 e = allocateImpl(rawDescriptor, count, &stride, &cbs);
64 if (e == Error3::NONE) {
65 hidl_vec<hidl_handle> handles(cbs.cbegin(), cbs.cend());
66 hidl_cb(Error3::NONE, stride, handles);
67 } else {
68 hidl_cb(e, 0, {});
69 }
70
71 for (cb_handle_30_t* cb : cbs) {
72 freeCb(std::unique_ptr<cb_handle_30_t>(cb));
73 }
74
75 return {};
76 }
77
78 private:
79 // 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)80 Error3 allocateImpl(const hidl_vec<uint32_t>& rawDescriptor,
81 uint32_t count,
82 uint32_t* pStride,
83 std::vector<cb_handle_30_t*>* cbs) {
84 BufferDescriptorInfo descriptor;
85 if (!decodeBufferDescriptorInfo(rawDescriptor, &descriptor)) {
86 RETURN_ERROR(Error3::BAD_DESCRIPTOR);
87 }
88
89 if (!descriptor.width) { RETURN_ERROR(Error3::UNSUPPORTED); }
90 if (!descriptor.height) { RETURN_ERROR(Error3::UNSUPPORTED); }
91 if (descriptor.layerCount != 1) { RETURN_ERROR(Error3::UNSUPPORTED); }
92
93 const uint32_t usage = descriptor.usage;
94 const bool usageSwWrite = usage & BufferUsage::CPU_WRITE_MASK;
95 const bool usageSwRead = usage & BufferUsage::CPU_READ_MASK;
96 const bool usageHwCamWrite = usage & BufferUsage::CAMERA_OUTPUT;
97 const bool usageHwCamRead = usage & BufferUsage::CAMERA_INPUT;
98
99 int bpp = 1;
100 int glFormat = 0;
101 int glType = 0;
102 int align = 1;
103 bool yuv_format = false;
104 EmulatorFrameworkFormat emulatorFrameworkFormat =
105 EmulatorFrameworkFormat::GL_COMPATIBLE;
106
107 PixelFormat format;
108 Error3 e = getBufferFormat(descriptor.format, usage, &format);
109 if (e != Error3::NONE) {
110 ALOGE("%s:%d Unsupported format: frameworkFormat=%d, usage=%x",
111 __func__, __LINE__, descriptor.format, usage);
112 return e;
113 }
114
115 switch (format) {
116 case PixelFormat::RGBA_8888:
117 case PixelFormat::RGBX_8888:
118 case PixelFormat::BGRA_8888:
119 bpp = 4;
120 glFormat = GL_RGBA;
121 glType = GL_UNSIGNED_BYTE;
122 break;
123
124 case PixelFormat::RGB_888:
125 if (usage & (BufferUsage::GPU_TEXTURE |
126 BufferUsage::GPU_RENDER_TARGET |
127 BufferUsage::COMPOSER_OVERLAY |
128 BufferUsage::COMPOSER_CLIENT_TARGET)) {
129 RETURN_ERROR(Error3::UNSUPPORTED);
130 } else {
131 bpp = 3;
132 glFormat = GL_RGB;
133 glType = GL_UNSIGNED_BYTE;
134 }
135 break;
136
137 case PixelFormat::RGB_565:
138 bpp = 2;
139 glFormat = GL_RGB565;
140 glType = GL_UNSIGNED_SHORT_5_6_5;
141 break;
142
143 case PixelFormat::RGBA_FP16:
144 bpp = 8;
145 glFormat = GL_RGBA16F;
146 glType = GL_HALF_FLOAT;
147 break;
148
149 case PixelFormat::RGBA_1010102:
150 bpp = 4;
151 glFormat = GL_RGB10_A2;
152 glType = GL_UNSIGNED_INT_2_10_10_10_REV;
153 break;
154
155 case PixelFormat::RAW16:
156 case PixelFormat::Y16:
157 bpp = 2;
158 align = 16 * bpp;
159 if (!((usageSwRead || usageHwCamRead) && (usageSwWrite || usageHwCamWrite))) {
160 // Raw sensor data or Y16 only goes between camera and CPU
161 RETURN_ERROR(Error3::UNSUPPORTED);
162 }
163 // Not expecting to actually create any GL surfaces for this
164 glFormat = GL_LUMINANCE;
165 glType = GL_UNSIGNED_SHORT;
166 break;
167
168 case PixelFormat::BLOB:
169 if (!usageSwRead) {
170 // Blob data cannot be used by HW other than camera emulator
171 // But there is a CTS test trying to have access to it
172 // BUG: https://buganizer.corp.google.com/issues/37719518
173 RETURN_ERROR(Error3::UNSUPPORTED);
174 }
175 // Not expecting to actually create any GL surfaces for this
176 glFormat = GL_LUMINANCE;
177 glType = GL_UNSIGNED_BYTE;
178 break;
179
180 case PixelFormat::YCRCB_420_SP:
181 yuv_format = true;
182 // Not expecting to actually create any GL surfaces for this
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 default:
203 ALOGE("%s:%d Unsupported format: format=%d, frameworkFormat=%d, usage=%x",
204 __func__, __LINE__, format, descriptor.format, usage);
205 RETURN_ERROR(Error3::UNSUPPORTED);
206 }
207
208 const size_t align1 = align - 1;
209 const uint32_t width = descriptor.width;
210 const uint32_t height = descriptor.height;
211 uint32_t stride;
212 size_t bufferSize;
213
214 if (yuv_format) {
215 const size_t yStride = (width * bpp + align1) & ~align1;
216 const size_t uvStride = (yStride / 2 + align1) & ~align1;
217 const size_t uvHeight = height / 2;
218 bufferSize = yStride * height + 2 * (uvHeight * uvStride);
219 stride = yStride / bpp;
220 } else {
221 const size_t bpr = (width * bpp + align1) & ~align1;
222 bufferSize = bpr * height;
223 stride = bpr / bpp;
224 }
225
226 *pStride = stride;
227
228 return allocateImpl2(usage,
229 width, height,
230 format, emulatorFrameworkFormat,
231 glFormat, glType,
232 bufferSize,
233 bpp, stride,
234 count, cbs);
235 }
236
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)237 Error3 allocateImpl2(const uint32_t usage,
238 const uint32_t width, const uint32_t height,
239 const PixelFormat format,
240 const EmulatorFrameworkFormat emulatorFrameworkFormat,
241 const int glFormat, const int glType,
242 const size_t bufferSize,
243 const uint32_t bytesPerPixel,
244 const uint32_t stride,
245 const uint32_t count,
246 std::vector<cb_handle_30_t*>* cbs) {
247 for (uint32_t i = 0; i < count; ++i) {
248 cb_handle_30_t* cb;
249 Error3 e = allocateCb(usage,
250 width, height,
251 format, emulatorFrameworkFormat,
252 glFormat, glType,
253 bufferSize,
254 bytesPerPixel, stride,
255 &cb);
256 if (e == Error3::NONE) {
257 cbs->push_back(cb);
258 } else {
259 return e;
260 }
261 }
262
263 RETURN(Error3::NONE);
264 }
265
266 // see GoldfishMapper::encodeBufferDescriptorInfo
decodeBufferDescriptorInfo(const hidl_vec<uint32_t> & raw,BufferDescriptorInfo * d)267 static bool decodeBufferDescriptorInfo(const hidl_vec<uint32_t>& raw,
268 BufferDescriptorInfo* d) {
269 if (raw.size() == 5) {
270 d->width = raw[0];
271 d->height = raw[1];
272 d->layerCount = raw[2];
273 d->format = static_cast<PixelFormat>(raw[3]);
274 d->usage = raw[4];
275
276 RETURN(true);
277 } else {
278 RETURN_ERROR(false);
279 }
280 }
281
getBufferFormat(const PixelFormat frameworkFormat,const uint32_t usage,PixelFormat * format)282 static Error3 getBufferFormat(const PixelFormat frameworkFormat,
283 const uint32_t usage,
284 PixelFormat* format) {
285 if (frameworkFormat == PixelFormat::IMPLEMENTATION_DEFINED) {
286 if (usage & BufferUsage::CAMERA_OUTPUT) {
287 if (usage & BufferUsage::GPU_TEXTURE) {
288 // Camera-to-display is RGBA
289 *format = PixelFormat::RGBA_8888;
290 RETURN(Error3::NONE);
291 } else if (usage & BufferUsage::VIDEO_ENCODER) {
292 // Camera-to-encoder is NV21
293 *format = PixelFormat::YCRCB_420_SP;
294 RETURN(Error3::NONE);
295 }
296 }
297 RETURN_ERROR(Error3::UNSUPPORTED);
298 } else if (static_cast<int>(frameworkFormat) == kOMX_COLOR_FormatYUV420Planar &&
299 (usage & BufferUsage::GPU_DATA_BUFFER)) {
300 ALOGW("gralloc_alloc: Requested OMX_COLOR_FormatYUV420Planar, given "
301 "YCbCr_420_888, taking experimental path. "
302 "usage=%x", usage);
303 *format = PixelFormat::YCBCR_420_888;
304 RETURN(Error3::NONE);
305 } else {
306 *format = frameworkFormat;
307 RETURN(Error3::NONE);
308 }
309 }
310
needHostCb(const uint32_t usage,const PixelFormat format)311 static bool needHostCb(const uint32_t usage, const PixelFormat format) {
312 return ((usage & BufferUsage::GPU_DATA_BUFFER)
313 || (format != PixelFormat::BLOB &&
314 format != PixelFormat::RAW16 &&
315 format != PixelFormat::Y16))
316 && (usage & (BufferUsage::GPU_TEXTURE
317 | BufferUsage::GPU_RENDER_TARGET
318 | BufferUsage::COMPOSER_OVERLAY
319 | BufferUsage::VIDEO_ENCODER
320 | BufferUsage::COMPOSER_CLIENT_TARGET
321 | BufferUsage::CPU_READ_MASK));
322 }
323
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)324 Error3 allocateCb(const uint32_t usage,
325 const uint32_t width, const uint32_t height,
326 const PixelFormat format,
327 const EmulatorFrameworkFormat emulatorFrameworkFormat,
328 const int glFormat, const int glType,
329 const size_t bufferSize,
330 const int32_t bytesPerPixel,
331 const int32_t stride,
332 cb_handle_30_t** cb) {
333 const HostConnectionSession conn = getHostConnectionSession();
334 ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder();
335 CRASH_IF(!rcEnc, "conn.getRcEncoder() failed");
336
337 GoldfishAddressSpaceHostMemoryAllocator host_memory_allocator(
338 rcEnc->featureInfo_const()->hasSharedSlotsHostMemoryAllocator);
339 if (!host_memory_allocator.is_opened()) {
340 RETURN_ERROR(Error3::NO_RESOURCES);
341 }
342
343 GoldfishAddressSpaceBlock bufferBits;
344 if (host_memory_allocator.hostMalloc(&bufferBits, bufferSize)) {
345 RETURN_ERROR(Error3::NO_RESOURCES);
346 }
347
348 uint32_t hostHandle = 0;
349 QEMU_PIPE_HANDLE hostHandleRefCountFd = QEMU_PIPE_INVALID_HANDLE;
350 if (needHostCb(usage, format)) {
351 hostHandleRefCountFd = qemu_pipe_open("refcount");
352 if (!qemu_pipe_valid(hostHandleRefCountFd)) {
353 RETURN_ERROR(Error3::NO_RESOURCES);
354 }
355
356 const GLenum allocFormat =
357 (PixelFormat::RGBX_8888 == format) ? GL_RGB : glFormat;
358
359 hostHandle = rcEnc->rcCreateColorBufferDMA(
360 rcEnc,
361 width, height,
362 allocFormat, static_cast<int>(emulatorFrameworkFormat));
363
364 if (!hostHandle) {
365 qemu_pipe_close(hostHandleRefCountFd);
366 RETURN_ERROR(Error3::NO_RESOURCES);
367 }
368
369 if (qemu_pipe_write(hostHandleRefCountFd,
370 &hostHandle,
371 sizeof(hostHandle)) != sizeof(hostHandle)) {
372 rcEnc->rcCloseColorBuffer(rcEnc, hostHandle);
373 qemu_pipe_close(hostHandleRefCountFd);
374 RETURN_ERROR(Error3::NO_RESOURCES);
375 }
376 }
377
378 std::unique_ptr<cb_handle_30_t> handle =
379 std::make_unique<cb_handle_30_t>(
380 host_memory_allocator.release(),
381 hostHandleRefCountFd,
382 hostHandle,
383 usage,
384 width,
385 height,
386 static_cast<int>(format),
387 glFormat,
388 glType,
389 bufferSize,
390 bufferBits.guestPtr(),
391 bufferBits.size(),
392 bufferBits.offset(),
393 bytesPerPixel,
394 stride);
395
396 bufferBits.release();
397 *cb = handle.release();
398 RETURN(Error3::NONE);
399 }
400
freeCb(std::unique_ptr<cb_handle_30_t> cb)401 void freeCb(std::unique_ptr<cb_handle_30_t> cb) {
402 // no need to undo .hostMalloc: the kernel will take care of it once the
403 // last bufferFd (duped) is closed.
404
405 if (qemu_pipe_valid(cb->hostHandleRefCountFd)) {
406 qemu_pipe_close(cb->hostHandleRefCountFd);
407 }
408 GoldfishAddressSpaceBlock::memoryUnmap(cb->getBufferPtr(), cb->mmapedSize);
409 GoldfishAddressSpaceHostMemoryAllocator::closeHandle(cb->bufferFd);
410 }
411
getHostConnectionSession() const412 HostConnectionSession getHostConnectionSession() const {
413 return HostConnectionSession(m_hostConn.get());
414 }
415
416 std::unique_ptr<HostConnection> m_hostConn;
417 };
418
main(int,char **)419 int main(int, char**) {
420 using ::android::sp;
421
422 ::android::hardware::configureRpcThreadpool(4, true /* callerWillJoin */);
423
424 sp<IAllocator3> allocator(new GoldfishAllocator());
425 if (allocator->registerAsService() != ::android::NO_ERROR) {
426 ALOGE("failed to register graphics IAllocator@3.0 service");
427 return -EINVAL;
428 }
429
430 ALOGI("graphics IAllocator@3.0 service is initialized");
431 ::android::hardware::joinRpcThreadpool();
432
433 ALOGI("graphics IAllocator@3.0 service is terminating");
434 return 0;
435 }
436