/*
* Copyright (C) 2016 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 <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <cutils/ashmem.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <utils/String8.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
#include <guest/libs/platform_support/api_level_fixes.h>
#include "common/libs/auto_resources/auto_resources.h"
#include "common/vsoc/lib/screen_region_view.h"
#include "gralloc_vsoc_priv.h"
#include "region_registry.h"
using vsoc::screen::ScreenRegionView;
/*****************************************************************************/
static inline size_t roundUpToPageSize(size_t x) {
return (x + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
}
static int gralloc_alloc_buffer(
alloc_device_t* /*dev*/, int format, int w, int h,
buffer_handle_t* pHandle, int* pStrideInPixels) {
int err = 0;
int fd = -1;
static int sequence = 0;
int bytes_per_pixel = formatToBytesPerPixel(format);
int bytes_per_line;
int stride_in_pixels;
int size = 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 = ScreenRegionView::align(bytes_per_pixel * w, 16);
} else {
bytes_per_line = ScreenRegionView::align(bytes_per_pixel * w);
}
size = roundUpToPageSize(size + formatToBytesPerFrame(format, w, h));
size += PAGE_SIZE;
fd = ashmem_create_region(
android::String8::format(
"gralloc-%d.%d", getpid(), sequence++).string(),
size);
if (fd < 0) {
ALOGE("couldn't create ashmem (%s)", strerror(-errno));
err = -errno;
}
if (err == 0) {
stride_in_pixels = bytes_per_line / bytes_per_pixel;
private_handle_t* hnd =
new private_handle_t(fd, size, format, w, h, stride_in_pixels, 0);
void* base = reference_region(__FUNCTION__, hnd);
if (base) {
*pHandle = hnd;
*pStrideInPixels = stride_in_pixels;
} else {
err = -EIO;
}
}
ALOGE_IF(err, "gralloc failed err=%s", strerror(-err));
return err;
}
/*****************************************************************************/
static int gralloc_alloc(alloc_device_t* dev, int w, int h, int format,
int /*usage*/, buffer_handle_t* pHandle,
int* pStrideInPixels) {
if (!pHandle || !pStrideInPixels)
return -EINVAL;
int err = gralloc_alloc_buffer(dev, format, w, h, pHandle, pStrideInPixels);
if (err < 0) {
return err;
}
return 0;
}
static int gralloc_free(alloc_device_t* /*dev*/, buffer_handle_t handle) {
if (private_handle_t::validate(handle) < 0) {
return -EINVAL;
}
private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(
handle);
int retval = unreference_region(__FUNCTION__, hnd);
close(hnd->fd);
delete hnd;
return retval;
}
/*****************************************************************************/
static int gralloc_close(struct hw_device_t *dev) {
priv_alloc_device_t* ctx = reinterpret_cast<priv_alloc_device_t*>(dev);
if (ctx) {
/* TODO: keep a list of all buffer_handle_t created, and free them
* all here.
*/
free(ctx);
}
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)) {
priv_alloc_device_t *dev;
dev = (priv_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;
dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = gralloc_close;
dev->device.alloc = gralloc_alloc;
dev->device.free = gralloc_free;
*device = &dev->device.common;
status = 0;
} else {
status = fb_device_open(module, name, device);
}
return status;
}
/*****************************************************************************/
static struct hw_module_methods_t gralloc_module_methods = {
VSOC_STATIC_INITIALIZER(open) gralloc_device_open
};
struct private_module_t HAL_MODULE_INFO_SYM = {
VSOC_STATIC_INITIALIZER(base) {
VSOC_STATIC_INITIALIZER(common) {
VSOC_STATIC_INITIALIZER(tag) HARDWARE_MODULE_TAG,
#ifdef GRALLOC_MODULE_API_VERSION_0_2
VSOC_STATIC_INITIALIZER(version_major) GRALLOC_MODULE_API_VERSION_0_2,
#else
VSOC_STATIC_INITIALIZER(version_major) 1,
#endif
VSOC_STATIC_INITIALIZER(version_minor) 0,
VSOC_STATIC_INITIALIZER(id) GRALLOC_HARDWARE_MODULE_ID,
VSOC_STATIC_INITIALIZER(name) "VSOC X86 Graphics Memory Allocator Module",
VSOC_STATIC_INITIALIZER(author) "The Android Open Source Project",
VSOC_STATIC_INITIALIZER(methods) &gralloc_module_methods,
VSOC_STATIC_INITIALIZER(dso) NULL,
VSOC_STATIC_INITIALIZER(reserved) {0},
},
VSOC_STATIC_INITIALIZER(registerBuffer) gralloc_register_buffer,
VSOC_STATIC_INITIALIZER(unregisterBuffer) gralloc_unregister_buffer,
VSOC_STATIC_INITIALIZER(lock) gralloc_lock,
VSOC_STATIC_INITIALIZER(unlock) gralloc_unlock,
#ifdef GRALLOC_MODULE_API_VERSION_0_2
VSOC_STATIC_INITIALIZER(perform) NULL,
VSOC_STATIC_INITIALIZER(lock_ycbcr) gralloc_lock_ycbcr,
#endif
},
};