/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gralloc_common.h" #include "goldfish_address_space.h" #include "HostConnection.h" #include "FormatConversions.h" #include #define CRASH(MSG) \ do { \ ALOGE("%s:%d crashed with '%s'", __func__, __LINE__, MSG); \ ::abort(); \ } while (false) #define CRASH_IF(COND, MSG) \ do { \ if ((COND)) { \ ALOGE("%s:%d crashed on '%s' with '%s'", __func__, __LINE__, #COND, MSG); \ ::abort(); \ } \ } while (false) #define RETURN_ERROR_CODE(X) \ do { \ ALOGE("%s:%d failed with '%s' (%d)", \ __func__, __LINE__, strerror(-(X)), -(X)); \ return (X); \ } while (false) #define RETURN_ERROR(X) \ do { \ ALOGE("%s:%d failed with '%s'", __func__, __LINE__, #X); \ return (X); \ } while (false) #define OMX_COLOR_FormatYUV420Planar 19 namespace { const char GOLDFISH_GRALLOC_MODULE_NAME[] = "Graphics Memory Allocator Module"; hw_device_t make_hw_device(hw_module_t* module, int (*close)(hw_device_t*)) { hw_device_t result = {}; result.tag = HARDWARE_DEVICE_TAG; result.version = 0; result.module = module; result.close = close; return result; } size_t align(const size_t v, const size_t a) { return (v + a - 1) & ~(a - 1); } class HostConnectionSession { public: explicit HostConnectionSession(HostConnection* hc) : conn(hc) { hc->lock(); } ~HostConnectionSession() { if (conn) { conn->unlock(); } } HostConnectionSession(HostConnectionSession&& rhs) : conn(rhs.conn) { rhs.conn = nullptr; } HostConnectionSession& operator=(HostConnectionSession&& rhs) { if (this != &rhs) { std::swap(conn, rhs.conn); } return *this; } HostConnectionSession(const HostConnectionSession&) = delete; HostConnectionSession& operator=(const HostConnectionSession&) = delete; ExtendedRCEncoderContext* getRcEncoder() const { return conn->rcEncoder(); } private: HostConnection* conn; }; class goldfish_gralloc30_module_t; class goldfish_gralloc30_device_t; class goldfish_fb30_device_t; class buffer_manager_t { public: buffer_manager_t() = default; buffer_manager_t(const buffer_manager_t&) = delete; buffer_manager_t& operator=(const buffer_manager_t&) = delete; buffer_manager_t(buffer_manager_t&&) = delete; buffer_manager_t& operator=(buffer_manager_t&&) = delete; virtual ~buffer_manager_t() {} virtual uint64_t getMmapedPhysAddr(uint64_t offset) const = 0; virtual int alloc_buffer(int usage, int width, int height, int format, EmulatorFrameworkFormat emulatorFrameworkFormat, int glFormat, int glType, size_t bufferSize, buffer_handle_t* pHandle) = 0; virtual int free_buffer(buffer_handle_t h) = 0; virtual int register_buffer(buffer_handle_t h) = 0; virtual int unregister_buffer(buffer_handle_t h) = 0; }; std::unique_ptr create_buffer_manager(goldfish_gralloc30_module_t*); class goldfish_gralloc30_module_t { public: // TODO(b/142677230): Use unique pointers instead. goldfish_gralloc30_module_t() : m_hostConn(HostConnection::createUnique().release()) { CRASH_IF(!m_hostConn, "m_hostConn cannot be nullptr"); m_bufferManager = create_buffer_manager(this); CRASH_IF(!m_bufferManager, "m_bufferManager cannot be nullptr"); } HostConnectionSession getHostConnectionSession() const { return HostConnectionSession(m_hostConn /*.get()*/); } int alloc_buffer(int usage, int width, int height, int format, EmulatorFrameworkFormat emulatorFrameworkFormat, int glFormat, int glType, size_t bufferSize, buffer_handle_t* pHandle) { return m_bufferManager->alloc_buffer(usage, width, height, format, emulatorFrameworkFormat, glFormat, glType, bufferSize, pHandle); } int free_buffer(buffer_handle_t h) { return m_bufferManager->free_buffer(h); } int register_buffer(buffer_handle_t h) { return m_bufferManager->register_buffer(h); } int unregister_buffer(buffer_handle_t h) { return m_bufferManager->unregister_buffer(h); } int lock(cb_handle_t& handle, const int usage, const int left, const int top, const int width, const int height, void** vaddr) { if (!handle.bufferSize) { RETURN_ERROR_CODE(-EINVAL); } char* const bufferBits = static_cast(handle.getBufferPtr()); if (!bufferBits) { RETURN_ERROR_CODE(-EINVAL); } if (handle.hostHandle) { const int res = lock_impl(handle, usage, left, top, width, height, bufferBits); if (res) { return res; } } *vaddr = bufferBits; return 0; } int unlock(cb_handle_t& handle) { if (!handle.bufferSize) { RETURN_ERROR_CODE(-EINVAL); } char* const bufferBits = static_cast(handle.getBufferPtr()); if (!bufferBits) { RETURN_ERROR_CODE(-EINVAL); } if (handle.hostHandle) { unlock_impl(handle, bufferBits); } return 0; } int lock_ycbcr(cb_handle_t& handle, const int usage, const int left, const int top, const int width, const int height, android_ycbcr* ycbcr) { if (!ycbcr) { RETURN_ERROR_CODE(-EINVAL); } if (!handle.bufferSize) { RETURN_ERROR_CODE(-EINVAL); } char* const bufferBits = static_cast(handle.getBufferPtr()); if (!bufferBits) { RETURN_ERROR_CODE(-EINVAL); } size_t uOffset; size_t vOffset; size_t yStride; size_t cStride; size_t cStep; switch (handle.format) { case HAL_PIXEL_FORMAT_YCrCb_420_SP: yStride = handle.width; cStride = yStride; vOffset = yStride * handle.height; uOffset = vOffset + 1; cStep = 2; break; case HAL_PIXEL_FORMAT_YV12: // https://developer.android.com/reference/android/graphics/ImageFormat.html#YV12 yStride = align(handle.width, 16); cStride = align(yStride / 2, 16); vOffset = yStride * handle.height; uOffset = vOffset + (cStride * handle.height / 2); cStep = 1; break; case HAL_PIXEL_FORMAT_YCbCr_420_888: yStride = handle.width; cStride = yStride / 2; uOffset = handle.height * yStride; vOffset = uOffset + cStride * handle.height / 2; cStep = 1; break; default: ALOGE("%s:%d unexpected format (%d)", __func__, __LINE__, handle.format); RETURN_ERROR_CODE(-EINVAL); } if (handle.hostHandle) { const int res = lock_impl(handle, usage, left, top, width, height, bufferBits); if (res) { return res; } } memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved)); char* const vaddr1 = static_cast(bufferBits); ycbcr->y = vaddr1; ycbcr->cb = vaddr1 + uOffset; ycbcr->cr = vaddr1 + vOffset; ycbcr->ystride = yStride; ycbcr->cstride = cStride; ycbcr->chroma_step = cStep; return 0; } private: int lock_impl(cb_handle_t& handle, const int usage, const int left, const int top, const int width, const int height, char* const bufferBits) { const bool usageSwRead = usage & GRALLOC_USAGE_SW_READ_MASK; const bool usageSwWrite = usage & GRALLOC_USAGE_SW_WRITE_MASK; const bool usageHwCamera = usage & GRALLOC_USAGE_HW_CAMERA_MASK; const bool usageHwCameraWrite = usage & GRALLOC_USAGE_HW_CAMERA_WRITE; const HostConnectionSession conn = getHostConnectionSession(); ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder(); const int res = rcEnc->rcColorBufferCacheFlush( rcEnc, handle.hostHandle, 0, usageSwRead); if (res < 0) { RETURN_ERROR_CODE(-EBUSY); } // camera delivers bits to the buffer directly and does not require // an explicit read. if (usageSwRead && !usageHwCamera) { if (gralloc_is_yuv_format(handle.format)) { if (rcEnc->hasYUVCache()) { uint32_t bufferSize; switch (handle.format) { case HAL_PIXEL_FORMAT_YV12: get_yv12_offsets(handle.width, handle.height, nullptr, nullptr, &bufferSize); break; case HAL_PIXEL_FORMAT_YCbCr_420_888: get_yuv420p_offsets(handle.width, handle.height, nullptr, nullptr, &bufferSize); break; default: CRASH("Unexpected format, switch is out of sync with gralloc_is_yuv_format"); break; } rcEnc->rcReadColorBufferYUV(rcEnc, handle.hostHandle, 0, 0, handle.width, handle.height, bufferBits, bufferSize); } else { // We are using RGB888 std::vector tmpBuf(handle.width * handle.height * 3); rcEnc->rcReadColorBuffer(rcEnc, handle.hostHandle, 0, 0, handle.width, handle.height, handle.glFormat, handle.glType, tmpBuf.data()); switch (handle.format) { case HAL_PIXEL_FORMAT_YV12: rgb888_to_yv12(bufferBits, tmpBuf.data(), handle.width, handle.height, left, top, left + width - 1, top + height - 1); break; case HAL_PIXEL_FORMAT_YCbCr_420_888: rgb888_to_yuv420p(bufferBits, tmpBuf.data(), handle.width, handle.height, left, top, left + width - 1, top + height - 1); break; default: CRASH("Unexpected format, switch is out of sync with gralloc_is_yuv_format"); break; } } } else { rcEnc->rcReadColorBuffer(rcEnc, handle.hostHandle, 0, 0, handle.width, handle.height, handle.glFormat, handle.glType, bufferBits); } } if (usageSwWrite || usageHwCameraWrite) { handle.lockedLeft = left; handle.lockedTop = top; handle.lockedWidth = width; handle.lockedHeight = height; } else { handle.lockedLeft = 0; handle.lockedTop = 0; handle.lockedWidth = handle.width; handle.lockedHeight = handle.height; } return 0; } void unlock_impl(cb_handle_t& handle, char* const bufferBits) { const int bpp = glUtilsPixelBitSize(handle.glFormat, handle.glType) >> 3; const int left = handle.lockedLeft; const int top = handle.lockedTop; const int width = handle.lockedWidth; const int height = handle.lockedHeight; const uint32_t rgbSize = width * height * bpp; std::vector convertedBuf; const char* bitsToSend; uint32_t sizeToSend; if (gralloc_is_yuv_format(handle.format)) { bitsToSend = bufferBits; switch (handle.format) { case HAL_PIXEL_FORMAT_YV12: get_yv12_offsets(width, height, nullptr, nullptr, &sizeToSend); break; case HAL_PIXEL_FORMAT_YCbCr_420_888: get_yuv420p_offsets(width, height, nullptr, nullptr, &sizeToSend); break; default: CRASH("Unexpected format, switch is out of sync with gralloc_is_yuv_format"); break; } } else { convertedBuf.resize(rgbSize); copy_rgb_buffer_from_unlocked( convertedBuf.data(), bufferBits, handle.width, width, height, top, left, bpp); bitsToSend = convertedBuf.data(); sizeToSend = rgbSize; } { const HostConnectionSession conn = getHostConnectionSession(); ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder(); rcEnc->bindDmaDirectly(bufferBits, m_bufferManager->getMmapedPhysAddr(handle.getMmapedOffset())); rcEnc->rcUpdateColorBufferDMA(rcEnc, handle.hostHandle, left, top, width, height, handle.glFormat, handle.glType, const_cast(bitsToSend), sizeToSend); } handle.lockedLeft = 0; handle.lockedTop = 0; handle.lockedWidth = 0; handle.lockedHeight = 0; } //std::unique_ptr m_hostConn; // b/142677230 HostConnection* m_hostConn; std::unique_ptr m_bufferManager; }; // no ctor/dctor here struct private_module_t { goldfish_gralloc30_module_t* impl() { return &gralloc30; } hw_module_t* to_hw_module() { return &base.common; } static private_module_t* from_hw_module(const hw_module_t* m) { if (!m) { RETURN_ERROR(nullptr); } if ((m->id == GRALLOC_HARDWARE_MODULE_ID) && (m->name == GOLDFISH_GRALLOC_MODULE_NAME)) { return reinterpret_cast(const_cast(m)); } else { RETURN_ERROR(nullptr); } } static private_module_t* from_gralloc_module(const gralloc_module_t* m) { if (!m) { RETURN_ERROR(nullptr); } return from_hw_module(&m->common); } gralloc_module_t base; goldfish_gralloc30_module_t gralloc30; }; class goldfish_gralloc30_device_t { alloc_device_t device; goldfish_gralloc30_module_t* gralloc_module; public: goldfish_gralloc30_device_t(private_module_t* module) : gralloc_module(module->impl()) { memset(&device, 0, sizeof(device)); device.common = make_hw_device(module->to_hw_module(), &s_goldfish_gralloc30_device_close); device.alloc = &s_gralloc_alloc; device.free = &s_gralloc_free; } hw_device_t* get_hw_device_ptr() { return &device.common; } private: static int get_buffer_format(const int frameworkFormat, const int usage) { if (frameworkFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) { if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) { if (usage & GRALLOC_USAGE_HW_TEXTURE) { // Camera-to-display is RGBA return HAL_PIXEL_FORMAT_RGBA_8888; } else if (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER) { // Camera-to-encoder is NV21 return HAL_PIXEL_FORMAT_YCrCb_420_SP; } } RETURN_ERROR_CODE(-EINVAL); } else if (frameworkFormat == OMX_COLOR_FormatYUV420Planar && (usage & GOLDFISH_GRALLOC_USAGE_GPU_DATA_BUFFER)) { ALOGW("gralloc_alloc: Requested OMX_COLOR_FormatYUV420Planar, given " "YCbCr_420_888, taking experimental path. " "usage=%x", usage); return HAL_PIXEL_FORMAT_YCbCr_420_888; } else { return frameworkFormat; } } int gralloc_alloc(const int width, const int height, const int frameworkFormat, const int usage, buffer_handle_t* pHandle, int* pStride) { const bool usageSwWrite = usage & GRALLOC_USAGE_SW_WRITE_MASK; const bool usageSwRead = usage & GRALLOC_USAGE_SW_READ_MASK; const bool usageHwTexture = usage & GRALLOC_USAGE_HW_TEXTURE; const bool usageHwRender = usage & GRALLOC_USAGE_HW_RENDER; const bool usageHw2d = usage & GRALLOC_USAGE_HW_2D; const bool usageHwComposer = usage & GRALLOC_USAGE_HW_COMPOSER; const bool usageHwFb = usage & GRALLOC_USAGE_HW_FB; const bool usageHwCamWrite = usage & GRALLOC_USAGE_HW_CAMERA_WRITE; const bool usageHwCamRead = usage & GRALLOC_USAGE_HW_CAMERA_READ; const bool usageRGB888Unsupported = usageHwTexture || usageHwRender ||usageHw2d || usageHwComposer || usageHwFb; int bpp = 1; int glFormat = 0; int glType = 0; int align = 1; bool yuv_format = false; EmulatorFrameworkFormat emulatorFrameworkFormat = FRAMEWORK_FORMAT_GL_COMPATIBLE; const int format = get_buffer_format(frameworkFormat, usage); if (format < 0) { ALOGE("%s:%d Unsupported format: frameworkFormat=%d, usage=%x", __func__, __LINE__, frameworkFormat, usage); return format; } switch (format) { case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: case HAL_PIXEL_FORMAT_BGRA_8888: bpp = 4; glFormat = GL_RGBA; glType = GL_UNSIGNED_BYTE; break; case HAL_PIXEL_FORMAT_RGB_888: if (usageRGB888Unsupported) { RETURN_ERROR_CODE(-EINVAL); // we dont support RGB_888 for HW usage } else { bpp = 3; glFormat = GL_RGB; glType = GL_UNSIGNED_BYTE; } break; case HAL_PIXEL_FORMAT_RGB_565: bpp = 2; glFormat = GL_RGB565; glType = GL_UNSIGNED_SHORT_5_6_5; break; case HAL_PIXEL_FORMAT_RGBA_FP16: bpp = 8; glFormat = GL_RGBA16F; glType = GL_HALF_FLOAT; break; case HAL_PIXEL_FORMAT_RGBA_1010102: bpp = 4; glFormat = GL_RGB10_A2; glType = GL_UNSIGNED_INT_2_10_10_10_REV; break; case HAL_PIXEL_FORMAT_RAW16: case HAL_PIXEL_FORMAT_Y16: bpp = 2; align = 16 * bpp; if (!((usageSwRead || usageHwCamRead) && (usageSwWrite || usageHwCamWrite))) { // Raw sensor data or Y16 only goes between camera and CPU RETURN_ERROR_CODE(-EINVAL); } // Not expecting to actually create any GL surfaces for this glFormat = GL_LUMINANCE; glType = GL_UNSIGNED_SHORT; break; case HAL_PIXEL_FORMAT_BLOB: if (!usageSwRead) { // Blob data cannot be used by HW other than camera emulator // But there is a CTS test trying to have access to it // BUG: https://buganizer.corp.google.com/issues/37719518 RETURN_ERROR_CODE(-EINVAL); } // Not expecting to actually create any GL surfaces for this glFormat = GL_LUMINANCE; glType = GL_UNSIGNED_BYTE; break; case HAL_PIXEL_FORMAT_YCrCb_420_SP: yuv_format = true; // Not expecting to actually create any GL surfaces for this break; case HAL_PIXEL_FORMAT_YV12: align = 16; yuv_format = true; // We are going to use RGB8888 on the host for Vulkan glFormat = GL_RGBA; glType = GL_UNSIGNED_BYTE; emulatorFrameworkFormat = FRAMEWORK_FORMAT_YV12; break; case HAL_PIXEL_FORMAT_YCbCr_420_888: yuv_format = true; // We are going to use RGB888 on the host glFormat = GL_RGB; glType = GL_UNSIGNED_BYTE; emulatorFrameworkFormat = FRAMEWORK_FORMAT_YUV_420_888; break; default: ALOGE("%s:%d Unsupported format: format=%d, frameworkFormat=%d, usage=%x", __func__, __LINE__, format, frameworkFormat, usage); RETURN_ERROR_CODE(-EINVAL); } const size_t align1 = align - 1; int stride; size_t bufferSize; if (yuv_format) { const size_t yStride = (width * bpp + align1) & ~align1; const size_t uvStride = (yStride / 2 + align1) & ~align1; const size_t uvHeight = height / 2; bufferSize = yStride * height + 2 * (uvHeight * uvStride); stride = yStride / bpp; } else { const size_t bpr = (width * bpp + align1) & ~align1; bufferSize = bpr * height; stride = bpr / bpp; } const int res = gralloc_module->alloc_buffer( usage, width, height, format, emulatorFrameworkFormat, glFormat, glType, bufferSize, pHandle); if (res) { return res; } *pStride = stride; return 0; } int gralloc_free(buffer_handle_t h) { return gralloc_module->free_buffer(h); } static int s_goldfish_gralloc30_device_close(hw_device_t* d) { goldfish_gralloc30_device_t* gd = from_hw_device(d); if (!gd) { RETURN_ERROR_CODE(-EINVAL); } std::unique_ptr deleter(gd); return 0; } static int s_gralloc_alloc(alloc_device_t* ad, int w, int h, int format, int usage, buffer_handle_t* pHandle, int* pStride) { goldfish_gralloc30_device_t* gd = from_alloc_device(ad); if (!gd) { RETURN_ERROR_CODE(-EINVAL); } return gd->gralloc_alloc(w, h, format, usage, pHandle, pStride); } static int s_gralloc_free(alloc_device_t* ad, buffer_handle_t h) { goldfish_gralloc30_device_t* gd = from_alloc_device(ad); if (!gd) { RETURN_ERROR_CODE(-EINVAL); } return gd->gralloc_free(h); } static goldfish_gralloc30_device_t* from_hw_device(hw_device_t* d) { if (!d) { RETURN_ERROR(nullptr); } if (d->close == &s_goldfish_gralloc30_device_close) { return reinterpret_cast(d); } else { RETURN_ERROR(nullptr); } } static goldfish_gralloc30_device_t* from_alloc_device(alloc_device_t* d) { if (!d) { RETURN_ERROR(nullptr); } return from_hw_device(&d->common); } }; template T& unconst(const T& x) { return const_cast(x); } const uint32_t CB_HANDLE_MAGIC_30 = CB_HANDLE_MAGIC_BASE | 0x2; struct cb_handle_30_t : public cb_handle_t { cb_handle_30_t(address_space_handle_t p_bufferFd, QEMU_PIPE_HANDLE p_hostHandleRefCountFd, uint32_t p_hostHandle, int32_t p_usage, int32_t p_width, int32_t p_height, int32_t p_format, int32_t p_glFormat, int32_t p_glType, uint32_t p_bufSize, void* p_bufPtr, int32_t p_bufferPtrPid, uint32_t p_mmapedSize, uint64_t p_mmapedOffset) : cb_handle_t(p_bufferFd, p_hostHandleRefCountFd, CB_HANDLE_MAGIC_30, p_hostHandle, p_usage, p_width, p_height, p_format, p_glFormat, p_glType, p_bufSize, p_bufPtr, p_mmapedOffset), bufferFdAsInt(p_bufferFd), bufferPtrPid(p_bufferPtrPid), mmapedSize(p_mmapedSize) { numInts = CB_HANDLE_NUM_INTS(numFds); } bool isValid() const { return (version == sizeof(native_handle_t)) && (magic == CB_HANDLE_MAGIC_30); } static cb_handle_30_t* from(void* p) { if (!p) { return nullptr; } cb_handle_30_t* cb = static_cast(p); return cb->isValid() ? cb : nullptr; } static const cb_handle_30_t* from(const void* p) { return from(const_cast(p)); } static cb_handle_30_t* from_unconst(const void* p) { return from(const_cast(p)); } int32_t bufferFdAsInt; // int copy of bufferFd, to check if fd was duped int32_t bufferPtrPid; // pid where bufferPtr belongs to uint32_t mmapedSize; // real allocation side }; // goldfish_address_space_host_malloc_handle_manager_t uses // GoldfishAddressSpaceHostMemoryAllocator and GoldfishAddressSpaceBlock // to allocate buffers on the host. // It keeps track of usage of host handles allocated by rcCreateColorBufferDMA // on the guest by qemu_pipe_open("refcount"). class goldfish_address_space_host_malloc_buffer_manager_t : public buffer_manager_t { public: goldfish_address_space_host_malloc_buffer_manager_t(goldfish_gralloc30_module_t* gr): m_gr(gr) { GoldfishAddressSpaceHostMemoryAllocator host_memory_allocator(false); CRASH_IF(!host_memory_allocator.is_opened(), "GoldfishAddressSpaceHostMemoryAllocator failed to open"); GoldfishAddressSpaceBlock bufferBits; CRASH_IF(host_memory_allocator.hostMalloc(&bufferBits, 256), "hostMalloc failed"); m_physAddrToOffset = bufferBits.physAddr() - bufferBits.offset(); } uint64_t getMmapedPhysAddr(uint64_t offset) const override { return m_physAddrToOffset + offset; } int alloc_buffer(int usage, int width, int height, int format, EmulatorFrameworkFormat emulatorFrameworkFormat, int glFormat, int glType, size_t bufferSize, buffer_handle_t* pHandle) override { const HostConnectionSession conn = m_gr->getHostConnectionSession(); ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder(); GoldfishAddressSpaceHostMemoryAllocator host_memory_allocator( rcEnc->featureInfo_const()->hasSharedSlotsHostMemoryAllocator); if (!host_memory_allocator.is_opened()) { RETURN_ERROR_CODE(-EIO); } GoldfishAddressSpaceBlock bufferBits; if (host_memory_allocator.hostMalloc(&bufferBits, bufferSize)) { RETURN_ERROR_CODE(-EIO); } uint32_t hostHandle = 0; QEMU_PIPE_HANDLE hostHandleRefCountFd = QEMU_PIPE_INVALID_HANDLE; if (need_host_cb(usage, format)) { hostHandleRefCountFd = qemu_pipe_open("refcount"); if (!qemu_pipe_valid(hostHandleRefCountFd)) { RETURN_ERROR_CODE(-EIO); } const GLenum allocFormat = (HAL_PIXEL_FORMAT_RGBX_8888 == format) ? GL_RGB : glFormat; hostHandle = rcEnc->rcCreateColorBufferDMA( rcEnc, width, height, allocFormat, emulatorFrameworkFormat); if (!hostHandle) { qemu_pipe_close(hostHandleRefCountFd); RETURN_ERROR_CODE(-EIO); } if (qemu_pipe_write(hostHandleRefCountFd, &hostHandle, sizeof(hostHandle)) != sizeof(hostHandle)) { rcEnc->rcCloseColorBuffer(rcEnc, hostHandle); qemu_pipe_close(hostHandleRefCountFd); RETURN_ERROR_CODE(-EIO); } } std::unique_ptr handle = std::make_unique( host_memory_allocator.release(), hostHandleRefCountFd, hostHandle, usage, width, height, format, glFormat, glType, bufferSize, bufferBits.guestPtr(), getpid(), bufferBits.size(), bufferBits.offset()); bufferBits.release(); *pHandle = handle.release(); return 0; } int free_buffer(buffer_handle_t h) override { std::unique_ptr handle(cb_handle_30_t::from_unconst(h)); if (!handle) { RETURN_ERROR_CODE(-EINVAL); } if (handle->bufferPtrPid != getpid()) { RETURN_ERROR_CODE(-EACCES); } if (handle->bufferFd != handle->bufferFdAsInt) { RETURN_ERROR_CODE(-EACCES); } if (qemu_pipe_valid(handle->hostHandleRefCountFd)) { qemu_pipe_close(handle->hostHandleRefCountFd); } // We can't recycle the address block and host resources because this // fd could be duped. The kernel will take care of it when the last fd // will be closed. if (handle->mmapedSize > 0) { GoldfishAddressSpaceBlock::memoryUnmap(handle->getBufferPtr(), handle->mmapedSize); } GoldfishAddressSpaceHostMemoryAllocator::closeHandle(handle->bufferFd); return 0; } int register_buffer(buffer_handle_t h) override { #ifndef HOST_BUILD cb_handle_30_t *handle = cb_handle_30_t::from_unconst(h); if (!handle) { RETURN_ERROR_CODE(-EINVAL); } if (handle->mmapedSize > 0) { void* ptr; const int res = GoldfishAddressSpaceBlock::memoryMap( handle->getBufferPtr(), handle->mmapedSize, handle->bufferFd, handle->getMmapedOffset(), &ptr); if (res) { RETURN_ERROR_CODE(-res); } handle->setBufferPtr(ptr); } if (handle->hostHandle) { const HostConnectionSession conn = m_gr->getHostConnectionSession(); ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder(); rcEnc->rcOpenColorBuffer2(rcEnc, handle->hostHandle); } handle->bufferFdAsInt = handle->bufferFd; handle->bufferPtrPid = getpid(); #endif // HOST_BUILD return 0; } int unregister_buffer(buffer_handle_t h) override { #ifndef HOST_BUILD cb_handle_30_t *handle = cb_handle_30_t::from_unconst(h); if (!handle) { RETURN_ERROR_CODE(-EINVAL); } if (handle->bufferPtrPid != getpid()) { RETURN_ERROR_CODE(-EACCES); } if (handle->bufferFd != handle->bufferFdAsInt) { RETURN_ERROR_CODE(-EACCES); } if (handle->hostHandle) { const HostConnectionSession conn = m_gr->getHostConnectionSession(); ExtendedRCEncoderContext *const rcEnc = conn.getRcEncoder(); rcEnc->rcCloseColorBuffer(rcEnc, handle->hostHandle); } if (handle->mmapedSize > 0) { GoldfishAddressSpaceBlock::memoryUnmap(handle->getBufferPtr(), handle->mmapedSize); } handle->bufferFdAsInt = -1; handle->bufferPtrPid = -1; #endif // HOST_BUILD return 0; } static bool need_host_cb(const int usage, const int format) { return ((usage & GOLDFISH_GRALLOC_USAGE_GPU_DATA_BUFFER) || (format != HAL_PIXEL_FORMAT_BLOB && format != HAL_PIXEL_FORMAT_RAW16 && format != HAL_PIXEL_FORMAT_Y16)) && (usage & (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_2D | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_SW_READ_MASK)); } private: goldfish_gralloc30_module_t* m_gr; uint64_t m_physAddrToOffset; }; std::unique_ptr create_buffer_manager(goldfish_gralloc30_module_t* gr) { if (!gr) { RETURN_ERROR(nullptr); } // TODO: negotiate with the host the best way to allocate memory. return std::make_unique(gr); } int gralloc_register_buffer(const gralloc_module_t* gralloc_module, buffer_handle_t h) { private_module_t* module = private_module_t::from_gralloc_module(gralloc_module); if (!module) { RETURN_ERROR_CODE(-EINVAL); } return module->impl()->register_buffer(h); } int gralloc_unregister_buffer(const gralloc_module_t* gralloc_module, buffer_handle_t h) { private_module_t* module = private_module_t::from_gralloc_module(gralloc_module); if (!module) { RETURN_ERROR_CODE(-EINVAL); } return module->impl()->unregister_buffer(h); } int gralloc_lock(const gralloc_module_t* gralloc_module, buffer_handle_t bh, int usage, int l, int t, int w, int h, void** vaddr) { private_module_t* module = private_module_t::from_gralloc_module(gralloc_module); if (!module) { RETURN_ERROR_CODE(-EINVAL); } cb_handle_t* handle = cb_handle_t::from_unconst(bh); if (!handle) { RETURN_ERROR_CODE(-EINVAL); } return module->impl()->lock(*handle, usage, l, t, w, h, vaddr); } int gralloc_unlock(const gralloc_module_t* gralloc_module, buffer_handle_t bh) { private_module_t* module = private_module_t::from_gralloc_module(gralloc_module); if (!module) { RETURN_ERROR_CODE(-EINVAL); } cb_handle_t* handle = cb_handle_t::from_unconst(bh); if (!handle) { RETURN_ERROR_CODE(-EINVAL); } return module->impl()->unlock(*handle); } int gralloc_lock_ycbcr(const gralloc_module_t* gralloc_module, buffer_handle_t bh, int usage, int l, int t, int w, int h, android_ycbcr *ycbcr) { private_module_t* module = private_module_t::from_gralloc_module(gralloc_module); if (!module) { RETURN_ERROR_CODE(-EINVAL); } cb_handle_t* handle = cb_handle_t::from_unconst(bh); if (!handle) { RETURN_ERROR_CODE(-EINVAL); } return module->impl()->lock_ycbcr(*handle, usage, l, t, w, h, ycbcr); } int gralloc_device_open_gpu0(private_module_t* module, hw_device_t** device) { std::unique_ptr gralloc_device = std::make_unique(module); if (!gralloc_device) { RETURN_ERROR_CODE(-ENOMEM); } *device = gralloc_device->get_hw_device_ptr(); gralloc_device.release(); return 0; } int gralloc_device_open(const hw_module_t* hw_module, const char* name, hw_device_t** device) { private_module_t* module = private_module_t::from_hw_module(hw_module); if (!module) { RETURN_ERROR_CODE(-EINVAL); } if (!name) { RETURN_ERROR_CODE(-EINVAL); } if (!device) { RETURN_ERROR_CODE(-EINVAL); } if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) { return gralloc_device_open_gpu0(module, device); } RETURN_ERROR_CODE(-EINVAL); } struct hw_module_methods_t gralloc_module_methods = { .open = &gralloc_device_open }; } // namespace extern "C" __attribute__((visibility("default"))) struct private_module_t HAL_MODULE_INFO_SYM = { .base = { .common = { .tag = HARDWARE_MODULE_TAG, .module_api_version = GRALLOC_MODULE_API_VERSION_0_2, .hal_api_version = 0, .id = GRALLOC_HARDWARE_MODULE_ID, .name = GOLDFISH_GRALLOC_MODULE_NAME, .author = "The Android Open Source Project", .methods = &gralloc_module_methods, .dso = nullptr, .reserved = {0} }, .registerBuffer = &gralloc_register_buffer, .unregisterBuffer = &gralloc_unregister_buffer, .lock = &gralloc_lock, .unlock = &gralloc_unlock, .perform = nullptr, /* reserved for future use */ .lock_ycbcr = &gralloc_lock_ycbcr, }, };