Commit 4969f8fd by Greg Hartman

Remove gralloc

Change-Id: Iba39815f809388367d8297739c80fb5d1605900b Reviewed-on: https://swiftshader-review.googlesource.com/3011Reviewed-by: 's avatarNicolas Capens <capn@google.com> Tested-by: 's avatarGreg Hartman <ghartman@google.com>
parent 03e91f29
# Copyright (C) 2008 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.
LOCAL_PATH := $(call my-dir)
# HAL module implemenation stored in
# hw/<OVERLAY_HARDWARE_MODULE_ID>.<ro.product.board>.so
include $(CLEAR_VARS)
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_INSTALLED_MODULE_STEM := gralloc.gce_x86.so
LOCAL_SHARED_LIBRARIES := \
liblog \
libutils \
libcutils
LOCAL_STATIC_LIBRARIES := \
libgceframebufferconfig \
libgcemetadata \
libyuv_static
LOCAL_SRC_FILES := \
gralloc.cpp \
framebuffer.cpp \
mapper.cpp
LOCAL_MODULE := gralloc_swiftshader.gce_x86
LOCAL_CFLAGS:= -DLOG_TAG=\"gralloc_gce_x86\" -Wno-missing-field-initializers
LOCAL_C_INCLUDES := \
device/google/gce/include \
external/libyuv/files/include
include $(BUILD_SHARED_LIBRARY)
/*
* Copyright (C) 2008 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 <sys/mman.h>
#include <dlfcn.h>
#include <cutils/ashmem.h>
#include <cutils/log.h>
#include <cutils/properties.h>
#include <sys/system_properties.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <string.h>
#include <stdlib.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <cutils/sockets.h>
#include <private/android_filesystem_config.h>
#if HAVE_ANDROID_OS
#include <linux/fb.h>
#endif
#include "gralloc_priv.h"
#include "gr.h"
#include <GceFrameBufferConfig.h>
#include "remoter_framework_pkt.h"
/*****************************************************************************/
// numbers of buffers for page flipping
#define NUM_BUFFERS 2
enum {
PAGE_FLIP = 0x00000001,
LOCKED = 0x00000002
};
struct fb_context_t {
framebuffer_device_t device;
};
/*****************************************************************************/
static int fb_setSwapInterval(struct framebuffer_device_t* dev,
int interval)
{
fb_context_t* ctx = (fb_context_t*)dev;
if (interval < dev->minSwapInterval || interval > dev->maxSwapInterval)
return -EINVAL;
// FIXME: implement fb_setSwapInterval
return 0;
}
static int fb_setUpdateRect(struct framebuffer_device_t* dev,
int l, int t, int w, int h)
{
if (((w|h) <= 0) || ((l|t)<0))
return -EINVAL;
fb_context_t* ctx = (fb_context_t*)dev;
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
if (m->remoter_socket != -1) {
struct remoter_request_packet pkt;
remoter_request_packet_init(&pkt, REMOTER_OP_FB_UPDATE_RECT, 0);
pkt.params.fb_update_rect_params.left = l;
pkt.params.fb_update_rect_params.top = t;
pkt.params.fb_update_rect_params.width = w;
pkt.params.fb_update_rect_params.height = h;
if (write(m->remoter_socket, &pkt, sizeof(pkt)) < 0) {
ALOGE("Remoter socket write failed (%s)", strerror(errno));
}
} else
ALOGW("Remoter socket not connected!");
return 0;
}
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
{
if (private_handle_t::validate(buffer) < 0)
return -EINVAL;
fb_context_t* ctx = (fb_context_t*)dev;
private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
const size_t offset = uintptr_t(hnd->base) - uintptr_t(m->framebuffer->base);
m->info.yoffset = offset / m->finfo.line_length;
if (m->remoter_socket != -1) {
struct remoter_request_packet pkt;
remoter_request_packet_init(&pkt, REMOTER_OP_FB_POST, 0);
pkt.params.fb_post_params.y_offset = m->info.yoffset;
if (write(m->remoter_socket, &pkt, sizeof(pkt)) < 0) {
ALOGE("Remoter socket write failed (%s)", strerror(errno));
}
} else
ALOGW("Remoter socket not connected!");
m->currentBuffer = buffer;
} else {
// If we can't do the page_flip, just copy the buffer to the front
// FIXME: use copybit HAL instead of memcpy
void* fb_vaddr;
void* buffer_vaddr;
m->base.lock(&m->base, m->framebuffer,
GRALLOC_USAGE_SW_WRITE_RARELY,
0, 0, m->info.xres, m->info.yres,
&fb_vaddr);
m->base.lock(&m->base, buffer,
GRALLOC_USAGE_SW_READ_RARELY,
0, 0, m->info.xres, m->info.yres,
&buffer_vaddr);
memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);
m->base.unlock(&m->base, buffer);
m->base.unlock(&m->base, m->framebuffer);
}
return 0;
}
int wait_for_remoter() {
char prop_value[PROP_VALUE_MAX];
const char* prop_name = "ro.remoter_ready";
int retries = (60 * 5);
ALOGI("wait_for_remoter():");
while(retries--) {
if (property_get(prop_name, prop_value, NULL) <= 0) {
sleep(1);
continue;
} else {
ALOGI("wait_for_remoter(): Remoter ready");
break;
}
}
if (!retries) {
ALOGE("Timed out waiting for remoter");
return -1;
}
return 0;
}
/*****************************************************************************/
int mapUserspaceFrameBufferLocked(struct private_module_t* module)
{
if (module->framebuffer) {
return 0;
}
if (wait_for_remoter()) {
ALOGE("Remoter not available");
return -ENOENT;
}
int fd;
if ((fd = open(GceFrameBufferConfig::kFrameBufferPath, O_RDWR, 0)) < 0) {
ALOGE("Failed to open '%s' (%s)",
GceFrameBufferConfig::kFrameBufferPath, strerror(errno));
return -errno;
}
struct fb_fix_screeninfo finfo;
struct fb_var_screeninfo info;
memset(&info, 0, sizeof(info));
const GceFrameBufferConfig* config = GceFrameBufferConfig::getInstance();
info.xres = config->x_res();
info.yres = config->y_res();
info.bits_per_pixel = config->bits_per_pixel();
info.red.offset = GceFrameBufferConfig::kRedShift;
info.red.length = GceFrameBufferConfig::kRedBits;
info.green.offset = GceFrameBufferConfig::kGreenShift;
info.green.length = GceFrameBufferConfig::kGreenBits;
info.blue.offset = GceFrameBufferConfig::kBlueShift;
info.blue.length = GceFrameBufferConfig::kBlueBits;
info.xres_virtual = info.xres;
info.yres_virtual = config->y_res_virtual();
info.xoffset = 0;
info.yoffset = 0;
info.pixclock = 0;
info.vmode = FB_VMODE_NONINTERLACED;
info.width = ((info.xres * 25.4f) / config->dpi() + 0.5f);
info.height = ((info.yres * 25.4f) / config->dpi() + 0.5f);
memset(&finfo, 0, sizeof(finfo));
strcpy(finfo.id, "Userspace FB");
finfo.type = FB_TYPE_PACKED_PIXELS;
finfo.line_length = info.xres * (info.bits_per_pixel / 8);
finfo.accel = FB_ACCEL_NONE;
module->flags = PAGE_FLIP;
module->info = info;
module->finfo = finfo;
module->xdpi = (info.xres * 25.4f) / info.width;
module->ydpi = (info.yres * 25.4f) / info.height;
module->fps = (60 * 1000) / 1000.0f;
/*
* map the framebuffer
*/
size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres_virtual);
module->framebuffer = new private_handle_t(
dup(fd), fbSize,
config->hal_format(), config->x_res(), config->y_res(), 0);
module->numBuffers = info.yres_virtual / info.yres;
module->bufferMask = 0;
void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (vaddr == MAP_FAILED) {
ALOGE("Error mapping the framebuffer (%s)", strerror(errno));
return -errno;
}
module->framebuffer->base = vaddr;
memset(vaddr, 0, fbSize);
// Connect to the remoter so we can notify it of posted buffers and updated
// regions.
if ((module->remoter_socket = socket_local_client(
"remoter", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM)) < 0) {
ALOGE("Error connecting to remoter (%s)", strerror(errno));
return -errno;
}
return 0;
}
static int mapUserspaceFrameBuffer(struct private_module_t* module)
{
pthread_mutex_lock(&module->lock);
int err = mapUserspaceFrameBufferLocked(module);
pthread_mutex_unlock(&module->lock);
return err;
}
/*****************************************************************************/
static int fb_close(struct hw_device_t *dev)
{
fb_context_t* ctx = (fb_context_t*)dev;
if (ctx) {
free(ctx);
}
return 0;
}
int fb_device_open(hw_module_t const* module, const char* name,
hw_device_t** device)
{
int status = -EINVAL;
if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
char prop_value[PATH_MAX];
/* initialize our state here */
fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
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 = fb_close;
dev->device.setSwapInterval = fb_setSwapInterval;
dev->device.post = fb_post;
dev->device.setUpdateRect = fb_setUpdateRect;
private_module_t* m = (private_module_t*)module;
status = mapUserspaceFrameBuffer(m);
if (status >= 0) {
int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
int format =
GceFrameBufferConfig::getInstance()->hal_format();
const_cast<uint32_t&>(dev->device.flags) = 0;
const_cast<uint32_t&>(dev->device.width) = m->info.xres;
const_cast<uint32_t&>(dev->device.height) = m->info.yres;
const_cast<int&>(dev->device.stride) = stride;
const_cast<int&>(dev->device.format) = format;
const_cast<float&>(dev->device.xdpi) = m->xdpi;
const_cast<float&>(dev->device.ydpi) = m->ydpi;
const_cast<float&>(dev->device.fps) = m->fps;
const_cast<int&>(dev->device.minSwapInterval) = 1;
const_cast<int&>(dev->device.maxSwapInterval) = 1;
*device = &dev->device.common;
}
}
return status;
}
/*
* Copyright (C) 2008 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.
*/
#ifndef GR_H_
#define GR_H_
#include <stdint.h>
#include <limits.h>
#include <sys/cdefs.h>
#include <hardware/gralloc.h>
#include <pthread.h>
#include <errno.h>
#include <cutils/native_handle.h>
/*****************************************************************************/
struct private_module_t;
struct private_handle_t;
inline size_t roundUpToPageSize(size_t x) {
return (x + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
}
int mapUserspaceFrameBufferLocked(struct private_module_t* module);
int terminateBuffer(gralloc_module_t const* module, private_handle_t* hnd);
int mapBuffer(gralloc_module_t const* module, private_handle_t* hnd);
/*****************************************************************************/
class Locker {
pthread_mutex_t mutex;
public:
class Autolock {
Locker& locker;
public:
inline Autolock(Locker& locker) : locker(locker) { locker.lock(); }
inline ~Autolock() { locker.unlock(); }
};
inline Locker() { pthread_mutex_init(&mutex, 0); }
inline ~Locker() { pthread_mutex_destroy(&mutex); }
inline void lock() { pthread_mutex_lock(&mutex); }
inline void unlock() { pthread_mutex_unlock(&mutex); }
};
#endif /* GR_H_ */
/*
* Copyright (C) 2008 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 <api_level_fixes.h>
#include "GceFrameBufferConfig.h"
#include "gralloc_priv.h"
#include "gr.h"
/*****************************************************************************/
struct gralloc_context_t {
alloc_device_t device;
/* our private data here */
};
static int gralloc_alloc_buffer(
alloc_device_t* dev, int format, int w, int h,
buffer_handle_t* pHandle, int* pStrideInPixels);
/*****************************************************************************/
static int gralloc_device_open(
const hw_module_t* module, const char* name, hw_device_t** device);
/*****************************************************************************/
static struct hw_module_methods_t gralloc_module_methods = {
.open = gralloc_device_open
};
struct private_module_t HAL_MODULE_INFO_SYM = {
.base = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
#ifdef GCE_CONVERTING_GRALLOC
.id = "converting_gralloc",
#else
.id = GRALLOC_HARDWARE_MODULE_ID,
#endif
.name = "GCE X86 Graphics Memory Allocator Module",
.author = "The Android Open Source Project",
.methods = &gralloc_module_methods
},
.registerBuffer = gralloc_register_buffer,
.unregisterBuffer = gralloc_unregister_buffer,
#ifdef GCE_CONVERTING_GRALLOC
.lock = gralloc_converting_lock,
.unlock = gralloc_converting_unlock,
#else
.lock = gralloc_lock,
.unlock = gralloc_unlock,
#endif
},
.framebuffer = 0,
.remoter_socket = -1,
.flags = 0,
.numBuffers = 0,
.bufferMask = 0,
.lock = PTHREAD_MUTEX_INITIALIZER,
.currentBuffer = 0,
};
/*****************************************************************************/
static int gralloc_alloc_framebuffer_locked(
alloc_device_t* dev,
buffer_handle_t* pHandle, int* pStrideInPixels) {
static const GceFrameBufferConfig* config =
GceFrameBufferConfig::getInstance();
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
// allocate the framebuffer
if (m->framebuffer == NULL) {
// The framebuffer is mapped once and forever.
int err = mapUserspaceFrameBufferLocked(m);
if (err < 0) {
ALOGE("Failed to map framebuffer (%d)", errno);
return err;
}
}
const uint32_t bufferMask = m->bufferMask;
const uint32_t numBuffers = m->numBuffers;
const size_t bufferSize = m->finfo.line_length * m->info.yres;
if (numBuffers == 1) {
// If we have only one buffer, we never use page-flipping. Instead,
// we return a regular buffer which will be memcpy'ed to the main
// screen when post is called.
return gralloc_alloc_buffer(
dev, config->hal_format(), config->x_res(), config->y_res(),
pHandle, pStrideInPixels);
}
if (bufferMask >= ((1LU<<numBuffers)-1)) {
// We ran out of buffers.
return -ENOMEM;
}
// create a "fake" handles for it
intptr_t vaddr = intptr_t(m->framebuffer->base);
private_handle_t* hnd = new private_handle_t(
dup(m->framebuffer->fd), bufferSize,
config->hal_format(), config->x_res(), config->y_res(),
private_handle_t::PRIV_FLAGS_FRAMEBUFFER);
// find a free slot
for (uint32_t i=0 ; i<numBuffers ; i++) {
if ((bufferMask & (1LU << i)) == 0) {
m->bufferMask |= (1LU << i);
break;
}
vaddr += bufferSize;
}
hnd->base = reinterpret_cast<void*>(vaddr);
hnd->frame_offset = vaddr - intptr_t(m->framebuffer->base);
*pHandle = hnd;
*pStrideInPixels = config->line_length() / (config->bits_per_pixel() / 8);
return 0;
}
static int gralloc_alloc_framebuffer(
alloc_device_t* dev,
buffer_handle_t* pHandle, int* pStrideInPixels) {
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
pthread_mutex_lock(&m->lock);
int err = gralloc_alloc_framebuffer_locked(dev, pHandle, pStrideInPixels);
pthread_mutex_unlock(&m->lock);
return err;
}
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 = GceFrameBufferConfig::align(bytes_per_pixel * w);
int size = GceFrameBufferConfig::align(sizeof(gralloc_buffer_control_t));
int primary_offset = size;
size = roundUpToPageSize(size + bytes_per_line * h);
size += PAGE_SIZE;
int secondary_offset = 0;
if (bytes_per_pixel != 4) {
secondary_offset = size;
size += roundUpToPageSize(GceFrameBufferConfig::align(4 * 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) {
private_handle_t* hnd = new private_handle_t(fd, size, format, w, h, 0);
hnd->primary_offset = primary_offset;
hnd->secondary_offset = secondary_offset;
gralloc_module_t* module = reinterpret_cast<gralloc_module_t*>(
dev->common.module);
err = mapBuffer(module, hnd);
if (err == 0) {
reinterpret_cast<gralloc_buffer_control_t*>(hnd->base)->last_locked =
gralloc_buffer_control_t::PRIMARY;
*pHandle = hnd;
*pStrideInPixels = bytes_per_line / bytes_per_pixel;
}
}
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;
if (usage & GRALLOC_USAGE_HW_FB) {
err = gralloc_alloc_framebuffer(dev, pHandle, pStrideInPixels);
} else {
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);
if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
// free this buffer
private_module_t* m = reinterpret_cast<private_module_t*>(
dev->common.module);
const size_t bufferSize = m->finfo.line_length * m->info.yres;
int index = (uintptr_t(hnd->base) - uintptr_t(m->framebuffer->base)) / bufferSize;
m->bufferMask &= ~(1 << index);
} else {
gralloc_module_t* module = reinterpret_cast<gralloc_module_t*>(
dev->common.module);
terminateBuffer(module, const_cast<private_handle_t*>(hnd));
}
close(hnd->fd);
delete hnd;
return 0;
}
/*****************************************************************************/
static int gralloc_close(struct hw_device_t *dev) {
gralloc_context_t* ctx = reinterpret_cast<gralloc_context_t*>(dev);
if (ctx) {
/* TODO: keep a list of all buffer_handle_t created, and free them
* all here.
*/
free(ctx);
}
return 0;
}
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)) {
gralloc_context_t *dev;
dev = (gralloc_context_t*)malloc(sizeof(*dev));
/* 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;
}
/*
* Copyright (C) 2008 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 <errno.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <utils/ashmem.h>
#include <hardware/hardware.h>
#include <hardware/gralloc.h>
#include <system/graphics.h>
#include <libyuv/convert_argb.h>
#include <libyuv/convert_from.h>
#include "GceFrameBufferConfig.h"
#include "gralloc_priv.h"
/* desktop Linux needs a little help with gettid() */
#if defined(ARCH_X86) && !defined(HAVE_ANDROID_OS)
#define __KERNEL__
# include <linux/unistd.h>
pid_t gettid() { return syscall(__NR_gettid);}
#undef __KERNEL__
#endif
static const char* buffer_name(
private_handle_t* hnd, char output[ASHMEM_NAME_LEN]) {
output[0] = '\0';
if (!hnd) {
ALOGE("Attempted to log gralloc name hnd=NULL");
return output;
}
if (hnd->fd == -1) {
ALOGE("Attempted to log gralloc name hnd=%p with fd == -1", hnd);
return output;
}
int rval = ioctl(hnd->fd, ASHMEM_GET_NAME, output);
if (rval == -1) {
ALOGE("ASHMEM_GET_NAME failed, hnd=%p fd=%d (%s)", hnd, hnd->fd,
strerror(errno));
}
return output;
}
/*****************************************************************************/
static int gralloc_map(gralloc_module_t const* /*module*/,
buffer_handle_t handle,
void** vaddr) {
char name_buf[ASHMEM_NAME_LEN];
private_handle_t* hnd = (private_handle_t*)handle;
if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
size_t size = hnd->total_size;
void* mappedAddress = mmap(
0, size, PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0);
if (mappedAddress == MAP_FAILED) {
ALOGE("Could not mmap %s", strerror(errno));
return -errno;
}
// Set up the guard pages. The last page is always a guard
uintptr_t base = uintptr_t(mappedAddress);
uintptr_t addr = base + hnd->total_size - PAGE_SIZE;
if (mprotect((void*)addr, PAGE_SIZE, PROT_NONE) == -1) {
ALOGE("mprotect base=%p, pg=%p failed (%s)",
(void*)base, (void*)addr, strerror(errno));
}
// If we have a secondary buffer, then the page before it is also
// a guard page.
if (hnd->secondary_offset) {
addr = base + hnd->secondary_offset - PAGE_SIZE;
if (mprotect((void*)addr, PAGE_SIZE, PROT_NONE) == -1) {
ALOGE("mprotect base=%p, sec_pg=%p failed (%s)",
(void*)base, (void*)addr, strerror(errno));
}
}
hnd->base = reinterpret_cast<void*>(
uintptr_t(mappedAddress) + hnd->frame_offset);
ALOGI("Mapped %s hnd=%p fd=%d base=%p", buffer_name(hnd, name_buf), hnd,
hnd->fd, hnd->base);
ALOGI("... %s format=%d width=%d height=%d", name_buf, hnd->format,
hnd->x_res, hnd->y_res);
//ALOGD("gralloc_map() succeeded fd=%d, off=%d, size=%d, vaddr=%p",
// hnd->fd, hnd->offset, hnd->size, mappedAddress);
} else {
ALOGI("Mapped framebuffer hnd=%p base=%p", hnd, hnd->base);
}
*vaddr = (void*)hnd->base;
return 0;
}
static int gralloc_unmap(gralloc_module_t const* /*module*/,
buffer_handle_t handle) {
char name_buf[ASHMEM_NAME_LEN];
private_handle_t* hnd = (private_handle_t*)handle;
if (!(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
ALOGI("Unmapped %s hnd=%p fd=%d base=%p", buffer_name(hnd, name_buf), hnd,
hnd->fd, hnd->base);
if (munmap(hnd->base, hnd->total_size) < 0) {
ALOGE("Could not unmap %s", strerror(errno));
}
}
hnd->base = 0;
return 0;
}
/*****************************************************************************/
int gralloc_register_buffer(gralloc_module_t const* module,
buffer_handle_t handle) {
char name_buf[ASHMEM_NAME_LEN];
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
// *** WARNING WARNING WARNING ***
//
// If a buffer handle is passed from the process that allocated it to a
// different process, and then back to the allocator process, we will
// create a second mapping of the buffer. If the process reads and writes
// through both mappings, normal memory ordering guarantees may be
// violated, depending on the processor cache implementation*.
//
// If you are deriving a new gralloc implementation from this code, don't
// do this. A "real" gralloc should provide a single reference-counted
// mapping for each buffer in a process.
//
// In the current system, there is one case that needs a buffer to be
// registered in the same process that allocated it. The SurfaceFlinger
// process acts as the IGraphicBufferAlloc Binder provider, so all gralloc
// allocations happen in its process. After returning the buffer handle to
// the IGraphicBufferAlloc client, SurfaceFlinger free's its handle to the
// buffer (unmapping it from the SurfaceFlinger process). If
// SurfaceFlinger later acts as the producer end of the buffer queue the
// buffer belongs to, it will get a new handle to the buffer in response
// to IGraphicBufferProducer::requestBuffer(). Like any buffer handle
// received through Binder, the SurfaceFlinger process will register it.
// Since it already freed its original handle, it will only end up with
// one mapping to the buffer and there will be no problem.
//
// Currently SurfaceFlinger only acts as a buffer producer for a remote
// consumer when taking screenshots and when using virtual displays.
//
// Eventually, each application should be allowed to make its own gralloc
// allocations, solving the problem. Also, this ashmem-based gralloc
// should go away, replaced with a real ion-based gralloc.
//
// * Specifically, associative virtually-indexed caches are likely to have
// problems. Most modern L1 caches fit that description.
private_handle_t* hnd = (private_handle_t*)handle;
ALOGI("Registered %s hnd=%p fd=%d", buffer_name(hnd, name_buf), hnd,
hnd->fd);
ALOGD_IF(hnd->allocating_pid == getpid(),
"Registering a buffer in the process that created it. "
"This may cause memory ordering problems.");
void *vaddr;
return gralloc_map(module, handle, &vaddr);
}
int gralloc_unregister_buffer(gralloc_module_t const* module,
buffer_handle_t handle) {
char name_buf[ASHMEM_NAME_LEN];
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
private_handle_t* hnd = (private_handle_t*)handle;
ALOGI("Unregistered %s hnd=%p fd=%d", buffer_name(hnd, name_buf), hnd,
hnd->fd);
if (hnd->base)
gralloc_unmap(module, handle);
return 0;
}
int mapBuffer(gralloc_module_t const* module,
private_handle_t* hnd) {
void* vaddr;
return gralloc_map(module, hnd, &vaddr);
}
int terminateBuffer(gralloc_module_t const* module,
private_handle_t* hnd) {
if (hnd->base) {
// this buffer was mapped, unmap it now
gralloc_unmap(module, hnd);
}
return 0;
}
#ifdef GCE_CONVERTING_GRALLOC
int gralloc_converting_lock(
gralloc_module_t const* module, buffer_handle_t handle, int usage,
int l, int t, int w, int h, void** vaddr) {
char name_buf[ASHMEM_NAME_LEN];
if (private_handle_t::validate(handle) < 0) {
return -EINVAL;
}
private_handle_t* hnd = (private_handle_t*)handle;
buffer_name(hnd, name_buf);
gralloc_buffer_control_t* control = NULL;
if (hnd->primary_offset) {
control = reinterpret_cast<gralloc_buffer_control_t*>(hnd->base);
}
unsigned char* primary_buffer = reinterpret_cast<unsigned char*>(
uintptr_t(hnd->base) + hnd->primary_offset);
unsigned char* secondary_buffer = hnd->secondary_offset ?
reinterpret_cast<unsigned char*>(
uintptr_t(hnd->base) + hnd->secondary_offset) : primary_buffer;
if (hnd->format == HAL_PIXEL_FORMAT_RGB_565) {
if (control &&
(control->last_locked == gralloc_buffer_control_t::PRIMARY)) {
ALOGI("Converting RGB16 to RGB32 %s", name_buf);
libyuv::RGB565ToARGB(
primary_buffer, GceFrameBufferConfig::align(hnd->x_res * 2),
secondary_buffer, GceFrameBufferConfig::align(hnd->x_res * 4),
hnd->x_res, hnd->y_res);
control->last_locked = gralloc_buffer_control_t::SECONDARY;
} else {
ALOGE("Can't convert: RGB16, but no control structure %s", name_buf);
}
*vaddr = secondary_buffer;
} else {
*vaddr = primary_buffer;
}
ALOGI("Locking buffer %s hnd=%p secondary=%d at=%p",
name_buf, hnd, (control ? control->last_locked : 0), *vaddr);
return 0;
}
int gralloc_converting_unlock(gralloc_module_t const* module,
buffer_handle_t handle) {
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
return 0;
}
#else
int gralloc_lock(gralloc_module_t const* /*module*/,
buffer_handle_t handle, int /*usage*/,
int /*l*/, int /*t*/, int /*w*/, int /*h*/,
void** vaddr) {
char name_buf[ASHMEM_NAME_LEN];
// this is called when a buffer is being locked for software
// access. in thin implementation we have nothing to do since
// not synchronization with the h/w is needed.
// typically this is used to wait for the h/w to finish with
// this buffer if relevant. the data cache may need to be
// flushed or invalidated depending on the usage bits and the
// hardware.
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
private_handle_t* hnd = (private_handle_t*)handle;
buffer_name(hnd, name_buf);
gralloc_buffer_control_t* control = NULL;
if (hnd->primary_offset) {
control = reinterpret_cast<gralloc_buffer_control_t*>(hnd->base);
}
unsigned char* primary_buffer = reinterpret_cast<unsigned char*>(
uintptr_t(hnd->base) + hnd->primary_offset);
unsigned char* secondary_buffer = hnd->secondary_offset ?
reinterpret_cast<unsigned char*>(
uintptr_t(hnd->base) + hnd->secondary_offset) : primary_buffer;
if (control &&
(control->last_locked == gralloc_buffer_control_t::SECONDARY)) {
ALOGI("Converting RGB32 to RGB16 %s", name_buf);
libyuv::ARGBToRGB565(
secondary_buffer, GceFrameBufferConfig::align(hnd->x_res * 4),
primary_buffer, GceFrameBufferConfig::align(hnd->x_res * 2),
hnd->x_res, hnd->y_res);
control->last_locked = gralloc_buffer_control_t::PRIMARY;
}
*vaddr = primary_buffer;
return 0;
}
int gralloc_unlock(gralloc_module_t const* /*module*/,
buffer_handle_t handle) {
// we're done with a software buffer. nothing to do in this
// implementation. typically this is used to flush the data cache.
if (private_handle_t::validate(handle) < 0)
return -EINVAL;
return 0;
}
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment