/* * Copyright (C) 2017 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 <hardware/gralloc.h> #include <hardware/hardware.h> #include <log/log.h> #include <stdlib.h> #include "guest/libs/platform_support/api_level_fixes.h" #include "guest/hals/gralloc/gralloc_vsoc_priv.h" #include "guest/vsoc/lib/gralloc_region_view.h" using vsoc::gralloc::GrallocRegionView; namespace { static const int kSwiftShaderPadding = 4; inline void formatToYcbcr( int format, int width, int height, void* base_v, android_ycbcr* ycbcr) { uintptr_t it = reinterpret_cast<uintptr_t>(base_v); // Clear reserved fields; memset(ycbcr, 0, sizeof(*ycbcr)); switch (format) { case HAL_PIXEL_FORMAT_YV12: case HAL_PIXEL_FORMAT_YCbCr_420_888: ycbcr->ystride = align(width, 16); ycbcr->cstride = align(ycbcr->ystride / 2, 16); ycbcr->chroma_step = 1; ycbcr->y = reinterpret_cast<void*>(it); it += ycbcr->ystride * height; ycbcr->cr = reinterpret_cast<void*>(it); it += ycbcr->cstride * height / 2; ycbcr->cb = reinterpret_cast<void*>(it); break; default: ALOGE("%s: can't deal with format=0x%x", __FUNCTION__, format); } } inline int formatToBytesPerPixel(int format) { switch (format) { #if VSOC_PLATFORM_SDK_AFTER(N_MR1) case HAL_PIXEL_FORMAT_RGBA_FP16: return 8; #endif case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: case HAL_PIXEL_FORMAT_BGRA_8888: // The camera 3.0 implementation assumes that IMPLEMENTATION_DEFINED // means HAL_PIXEL_FORMAT_RGBA_8888 case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: return 4; case HAL_PIXEL_FORMAT_RGB_888: return 3; case HAL_PIXEL_FORMAT_RGB_565: case HAL_PIXEL_FORMAT_YV12: case HAL_PIXEL_FORMAT_YCbCr_420_888: return 2; case HAL_PIXEL_FORMAT_BLOB: return 1; default: ALOGE("%s: unknown format=%d", __FUNCTION__, format); return 8; } } inline int formatToBytesPerFrame(int format, int w, int h) { int bytes_per_pixel = formatToBytesPerPixel(format); int w16, h16; int y_size, c_size; switch (format) { // BLOB is used to allocate buffers for JPEG formatted data. Bytes per pixel // is 1, the desired buffer size is in w, and h should be 1. We refrain from // adding additional padding, although the caller is likely to round // up to a page size. case HAL_PIXEL_FORMAT_BLOB: return bytes_per_pixel * w * h; case HAL_PIXEL_FORMAT_YV12: case HAL_PIXEL_FORMAT_YCbCr_420_888: android_ycbcr strides; formatToYcbcr(format, w, h, NULL, &strides); y_size = strides.ystride * h; c_size = strides.cstride * h / 2; return (y_size + 2 * c_size + kSwiftShaderPadding); /*case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_RGBX_8888: case HAL_PIXEL_FORMAT_BGRA_8888: case HAL_PIXEL_FORMAT_RGB_888: case HAL_PIXEL_FORMAT_RGB_565:*/ default: w16 = align(w, 16); h16 = align(h, 16); return bytes_per_pixel * w16 * h16 + kSwiftShaderPadding; } } } /******************************************************************************/ void dump(struct alloc_device_t */*dev*/, char */*buff*/, int /*buff_len*/) {} /******************************************************************************/ int lock(struct gralloc_module_t const* /*module*/, buffer_handle_t handle, int /*usage*/, int /*l*/, int /*t*/, int /*w*/, int /*h*/, void** vaddr) { if (!vaddr || vsoc_buffer_handle_t::validate(handle)) { return -EINVAL; } // TODO(jemoreira): Check allocation usage flags against requested usage. const vsoc_buffer_handle_t* hnd = reinterpret_cast<const vsoc_buffer_handle_t*>(handle); void* mapped = reference_buffer(hnd); if (mapped == NULL) { ALOGE("Unable to reference buffer, %s", __FUNCTION__); return -1; } *vaddr = mapped; return 0; } int unlock(struct gralloc_module_t const* /*module*/, buffer_handle_t handle) { if (vsoc_buffer_handle_t::validate(handle)) { return -EINVAL; } return unreference_buffer( reinterpret_cast<const vsoc_buffer_handle_t*>(handle)); } int lock_ycbcr(struct gralloc_module_t const* module, buffer_handle_t handle, int usage, int l, int t, int w, int h, struct android_ycbcr* ycbcr) { void* mapped; int retval = lock(module, handle, usage, l, t, w, h, &mapped); if (retval) { return retval; } const vsoc_buffer_handle_t* hnd = reinterpret_cast<const vsoc_buffer_handle_t*>(handle); formatToYcbcr(hnd->format, w, h, mapped, ycbcr); return 0; } /******************************************************************************/ static int gralloc_alloc(alloc_device_t* /*dev*/, int w, int h, int format, int /*usage*/, buffer_handle_t* pHandle, int* pStrideInPixels) { int fd = -1; int bytes_per_pixel = formatToBytesPerPixel(format); int bytes_per_line; int stride_in_pixels; int size = 0; uint32_t offset = 0; // SwiftShader can't handle RGB_888, so fail fast and hard if we try to create // a gralloc buffer in this format. ALOG_ASSERT(format != HAL_PIXEL_FORMAT_RGB_888); if (format == HAL_PIXEL_FORMAT_YV12) { bytes_per_line = align(bytes_per_pixel * w, 16); } else { bytes_per_line = align(bytes_per_pixel * w, 8); } size = align(size + formatToBytesPerFrame(format, w, h), PAGE_SIZE); size += PAGE_SIZE; fd = GrallocRegionView::GetInstance()->AllocateBuffer(size, &offset); if (fd < 0) { ALOGE("Unable to allocate buffer (%s)", strerror(-fd)); return fd; } stride_in_pixels = bytes_per_line / bytes_per_pixel; vsoc_buffer_handle_t* hnd = new vsoc_buffer_handle_t(fd, offset, size, format, w, h, stride_in_pixels); void* addr = reference_buffer(reinterpret_cast<const vsoc_buffer_handle_t*>(hnd)); if (!addr) { ALOGE("Unable to reference buffer, %s", __FUNCTION__); return -EIO; } *pHandle = hnd; *pStrideInPixels = stride_in_pixels; return 0; } static int gralloc_free(alloc_device_t* /*dev*/, buffer_handle_t handle) { // No need to do anything else, the buffer will be atomatically deallocated // when the handle is closed. return unreference_buffer( reinterpret_cast<const vsoc_buffer_handle_t*>(handle)); } static int register_buffer(struct gralloc_module_t const* /*module*/, buffer_handle_t handle) { if (vsoc_buffer_handle_t::validate(handle)) { return -EINVAL; } void* addr = reference_buffer(reinterpret_cast<const vsoc_buffer_handle_t*>(handle)); if (!addr) { ALOGE("Unable to reference buffer, %s", __FUNCTION__); return -EIO; } return 0; } int unregister_buffer(struct gralloc_module_t const* /*module*/, buffer_handle_t handle) { if (vsoc_buffer_handle_t::validate(handle)) { return -EINVAL; } return unreference_buffer( reinterpret_cast<const vsoc_buffer_handle_t*>(handle)); } /******************************************************************************/ static int gralloc_device_close(struct hw_device_t *dev) { vsoc_alloc_device_t* pdev = reinterpret_cast<vsoc_alloc_device_t*>(dev); if (pdev) { free(pdev); } return 0; } static int gralloc_device_open( const hw_module_t* module, const char* name, hw_device_t** device) { int status = -EINVAL; if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) { vsoc_alloc_device_t *dev; dev = (vsoc_alloc_device_t*) malloc(sizeof(*dev)); LOG_FATAL_IF(!dev, "%s: malloc returned NULL.", __FUNCTION__); /* initialize our state here */ memset(dev, 0, sizeof(*dev)); /* initialize the procs */ dev->device.common.tag = HARDWARE_DEVICE_TAG; dev->device.common.version = 0; // TODO(jemoreira): Bump to 0_2 when stable dev->device.common.module = const_cast<hw_module_t*>(module); dev->device.common.close = gralloc_device_close; dev->device.alloc = gralloc_alloc; dev->device.free = gralloc_free; if (!GrallocRegionView::GetInstance()) { LOG_FATAL("Unable to instantiate the gralloc region"); free(dev); return -EIO; } *device = &dev->device.common; status = 0; } // TODO(jemoreira): Consider opening other type of devices (framebuffer) return status; } /******************************************************************************/ static struct hw_module_methods_t gralloc_module_methods = { .open = gralloc_device_open }; struct vsoc_gralloc_module_t HAL_MODULE_INFO_SYM = { .base = { .common = { .tag = HARDWARE_MODULE_TAG, .version_major = GRALLOC_MODULE_API_VERSION_0_2, .version_minor = 0, .id = GRALLOC_HARDWARE_MODULE_ID, .name = "VSoC X86 Graphics Memory Allocator Module", .author = "The Android Open Source Project", .methods = &gralloc_module_methods, .dso = NULL, .reserved = {0}, }, .registerBuffer = register_buffer, .unregisterBuffer = unregister_buffer, .lock = lock, .unlock = unlock, .lock_ycbcr = lock_ycbcr, .perform = NULL, }, };