diff options
Diffstat (limited to 'modules/gralloc/mapper.cpp')
-rw-r--r-- | modules/gralloc/mapper.cpp | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/modules/gralloc/mapper.cpp b/modules/gralloc/mapper.cpp new file mode 100644 index 0000000..a5f52ed --- /dev/null +++ b/modules/gralloc/mapper.cpp @@ -0,0 +1,231 @@ +/* + * 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 <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <cutils/log.h> +#include <cutils/atomic.h> + +#include <hardware/hardware.h> +#include <hardware/gralloc.h> + +#include "gralloc_priv.h" + +/*****************************************************************************/ + +struct mapped_buffer_t { + intptr_t key; + int size; + int base; + int refCount; + + int init(private_handle_t* hnd) { + size = hnd->size; + base = 0; + refCount = 0; + struct stat buf; + int result = 0; + key = intptr_t(hnd); + return result; + } +}; + +static int compare(const mapped_buffer_t& a, const mapped_buffer_t& b) { + if (a.key < b.key) { + return -1; + } + if (a.key > b.key) { + return 1; + } + return 0; +} + +struct mapped_buffers_t { + pthread_mutex_t mutex; + growable_sorted_array_t<mapped_buffer_t> records; + + int map(gralloc_module_t const* module, + buffer_handle_t handle, + void** vaddr) + { + private_handle_t* hnd = (private_handle_t*)(handle); + mapped_buffer_t key; + int result = key.init(hnd); + //printRecord(ANDROID_LOG_DEBUG, "map", &key); + if (result) { + return result; + } + mapped_buffer_t* record = 0; + pthread_mutex_lock(&mutex); + // From here to the end of the function we return by jumping to "exit" + // so that we always unlock the mutex. + + int index = -1; + if (!records.find(key, index)) { + //LOGD("New item at %d", index); + void* mappedAddress = mmap(0, hnd->size, + PROT_READ|PROT_WRITE, MAP_SHARED, hnd->fd, 0); + if (mappedAddress == MAP_FAILED) { + result = -errno; + //LOGE("map failed %d", result); + goto exit; + } + key.base = intptr_t(mappedAddress); + records.insert(index, key); + record = records.at(index); + } else { + //LOGD("Found existing mapping at index %d", index); + record = records.at(index); + if (record->size != key.size) { + LOGE("Requested a new mapping at the same offset" + "but with a different size"); + printRecord(ANDROID_LOG_ERROR, "old", record); + printRecord(ANDROID_LOG_ERROR, "new", &key); + result = -EINVAL; + goto exit; + } + } + record->refCount += 1; + hnd->base = record->base; + *vaddr = (void*) record->base; + exit: + //print(); + pthread_mutex_unlock(&mutex); + return result; + } + + int unmap(gralloc_module_t const* module, + buffer_handle_t handle) + { + mapped_buffer_t key; + key.init((private_handle_t*) handle); + //printRecord(ANDROID_LOG_DEBUG, "unmap", &key); + int index = -1; + + int result = 0; + mapped_buffer_t* record = 0; + pthread_mutex_lock(&mutex); + // From here to the end of the function we return by jumping to "exit" + // so that we always unlock the mutex. + + if (!records.find(key, index)) { + // This handle is not currently locked. + //LOGE("Could not find existing mapping near %d", index); + result = -ENOENT; + goto exit; + } + record = records.at(index); + //printRecord(ANDROID_LOG_DEBUG, "record", record); + record->refCount -= 1; + if (record->refCount == 0) { + //LOGD("Unmapping..."); + if (munmap((void*)record->base, record->size) < 0) { + result = -errno; + //LOGE("Could not unmap %d", result); + } + records.remove(index); + ((private_handle_t*)handle)->base = 0; + } + + exit: + //print(); + pthread_mutex_unlock(&mutex); + return result; + } + + void print() { + char prefix[16]; + LOGD("Dumping records: count=%d size=%d", records.count, records.size); + for(int i=0; i<records.count ; i++) { + sprintf(prefix, "%3d", i); + printRecord(ANDROID_LOG_DEBUG, prefix, records.at(i)); + } + } + + void printRecord(int level, const char* what, mapped_buffer_t* record) { + LOG_PRI(level, LOG_TAG, + "%s: key=0x%08x, size=0x%08x, base=0x%08x refCount=%d", + what, int(record->key), record->size, + record->base, record->refCount); + } +}; + +static mapped_buffers_t sMappedBuffers = { + mutex: PTHREAD_MUTEX_INITIALIZER +}; + +/*****************************************************************************/ + +int gralloc_map(gralloc_module_t const* module, + buffer_handle_t handle, + void** vaddr) +{ + if (private_handle_t::validate(handle) < 0) + return -EINVAL; + + private_handle_t* hnd = (private_handle_t*)(handle); + if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { + const private_module_t* m = + reinterpret_cast<const private_module_t*>(module); + handle = m->framebuffer; + } + + int err = sMappedBuffers.map(module, handle, vaddr); + + if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { + *vaddr = (void*)hnd->base; + } + + return err; +} + +int gralloc_unmap(gralloc_module_t const* module, + buffer_handle_t handle) +{ + if (private_handle_t::validate(handle) < 0) + return -EINVAL; + + private_handle_t* hnd = (private_handle_t*)(handle); + if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { + const private_module_t* m = + reinterpret_cast<const private_module_t*>(module); + handle = m->framebuffer; + } + + return sMappedBuffers.unmap(module, handle); +} + + +int gralloc_lock(gralloc_module_t const* module, + buffer_handle_t handle, int usage, + int l, int t, int w, int h) +{ + // FIXME: gralloc_lock() needs implementation + return 0; +} + +int gralloc_unlock(gralloc_module_t const* module, + buffer_handle_t handle) +{ + // FIXME: gralloc_unlock() needs implementation + return 0; +} |