1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "GraphicBufferMapper"
18
19#include <stdint.h>
20#ifdef HAVE_ANDROID_OS      // just want PAGE_SIZE define
21# include <asm/page.h>
22#else
23# include <sys/user.h>
24#endif
25#include <errno.h>
26#include <sys/mman.h>
27
28#include <cutils/ashmem.h>
29
30#include <utils/Errors.h>
31#include <utils/Log.h>
32
33#include <ui/GraphicBufferMapper.h>
34#include <ui/Rect.h>
35
36#include <hardware/gralloc.h>
37
38#include <private/ui/sw_gralloc_handle.h>
39
40
41namespace android {
42// ---------------------------------------------------------------------------
43
44ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferMapper )
45
46GraphicBufferMapper::GraphicBufferMapper()
47    : mAllocMod(0)
48{
49    hw_module_t const* module;
50    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
51    LOGE_IF(err, "FATAL: can't find the %s module", GRALLOC_HARDWARE_MODULE_ID);
52    if (err == 0) {
53        mAllocMod = (gralloc_module_t const *)module;
54    }
55}
56
57status_t GraphicBufferMapper::registerBuffer(buffer_handle_t handle)
58{
59    status_t err;
60    if (sw_gralloc_handle_t::validate(handle) < 0) {
61        err = mAllocMod->registerBuffer(mAllocMod, handle);
62    } else {
63        err = sw_gralloc_handle_t::registerBuffer((sw_gralloc_handle_t*)handle);
64    }
65    LOGW_IF(err, "registerBuffer(%p) failed %d (%s)",
66            handle, err, strerror(-err));
67    return err;
68}
69
70status_t GraphicBufferMapper::unregisterBuffer(buffer_handle_t handle)
71{
72    status_t err;
73    if (sw_gralloc_handle_t::validate(handle) < 0) {
74        err = mAllocMod->unregisterBuffer(mAllocMod, handle);
75    } else {
76        err = sw_gralloc_handle_t::unregisterBuffer((sw_gralloc_handle_t*)handle);
77    }
78    LOGW_IF(err, "unregisterBuffer(%p) failed %d (%s)",
79            handle, err, strerror(-err));
80    return err;
81}
82
83status_t GraphicBufferMapper::lock(buffer_handle_t handle,
84        int usage, const Rect& bounds, void** vaddr)
85{
86    status_t err;
87    if (sw_gralloc_handle_t::validate(handle) < 0) {
88        err = mAllocMod->lock(mAllocMod, handle, usage,
89                bounds.left, bounds.top, bounds.width(), bounds.height(),
90                vaddr);
91    } else {
92        err = sw_gralloc_handle_t::lock((sw_gralloc_handle_t*)handle, usage,
93                bounds.left, bounds.top, bounds.width(), bounds.height(),
94                vaddr);
95    }
96    LOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
97    return err;
98}
99
100status_t GraphicBufferMapper::unlock(buffer_handle_t handle)
101{
102    status_t err;
103    if (sw_gralloc_handle_t::validate(handle) < 0) {
104        err = mAllocMod->unlock(mAllocMod, handle);
105    } else {
106        err = sw_gralloc_handle_t::unlock((sw_gralloc_handle_t*)handle);
107    }
108    LOGW_IF(err, "unlock(...) failed %d (%s)", err, strerror(-err));
109    return err;
110}
111
112// ---------------------------------------------------------------------------
113
114status_t sw_gralloc_handle_t::alloc(uint32_t w, uint32_t h, int format,
115        int usage, buffer_handle_t* pHandle, int32_t* pStride)
116{
117    int align = 4;
118    int bpp = 0;
119    switch (format) {
120        case HAL_PIXEL_FORMAT_RGBA_8888:
121        case HAL_PIXEL_FORMAT_RGBX_8888:
122        case HAL_PIXEL_FORMAT_BGRA_8888:
123            bpp = 4;
124            break;
125        case HAL_PIXEL_FORMAT_RGB_888:
126            bpp = 3;
127            break;
128        case HAL_PIXEL_FORMAT_RGB_565:
129        case HAL_PIXEL_FORMAT_RGBA_5551:
130        case HAL_PIXEL_FORMAT_RGBA_4444:
131            bpp = 2;
132            break;
133        default:
134            return -EINVAL;
135    }
136    size_t bpr = (w*bpp + (align-1)) & ~(align-1);
137    size_t size = bpr * h;
138    size_t stride = bpr / bpp;
139    size = (size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);
140
141    int fd = ashmem_create_region("sw-gralloc-buffer", size);
142    if (fd < 0) {
143        LOGE("ashmem_create_region(size=%d) failed (%s)",
144                size, strerror(-errno));
145        return -errno;
146    }
147
148    int prot = PROT_READ;
149    if (usage & GRALLOC_USAGE_SW_WRITE_MASK)
150        prot |= PROT_WRITE;
151
152    if (ashmem_set_prot_region(fd, prot) < 0) {
153        LOGE("ashmem_set_prot_region(fd=%d, prot=%x) failed (%s)",
154                fd, prot, strerror(-errno));
155        close(fd);
156        return -errno;
157    }
158
159    void* base = mmap(0, size, prot, MAP_SHARED, fd, 0);
160    if (base == MAP_FAILED) {
161        LOGE("alloc mmap(fd=%d, size=%d, prot=%x) failed (%s)",
162                fd, size, prot, strerror(-errno));
163        close(fd);
164        return -errno;
165    }
166
167    sw_gralloc_handle_t* hnd = new sw_gralloc_handle_t();
168    hnd->fd = fd;
169    hnd->size = size;
170    hnd->base = intptr_t(base);
171    hnd->prot = prot;
172    *pStride = stride;
173    *pHandle = hnd;
174
175    return NO_ERROR;
176}
177
178status_t sw_gralloc_handle_t::free(sw_gralloc_handle_t* hnd)
179{
180    if (hnd->base) {
181        munmap((void*)hnd->base, hnd->size);
182    }
183    if (hnd->fd >= 0) {
184        close(hnd->fd);
185    }
186    delete hnd;
187    return NO_ERROR;
188}
189
190status_t sw_gralloc_handle_t::registerBuffer(sw_gralloc_handle_t* hnd)
191{
192    if (hnd->pid != getpid()) {
193        void* base = mmap(0, hnd->size, hnd->prot, MAP_SHARED, hnd->fd, 0);
194        if (base == MAP_FAILED) {
195            LOGE("registerBuffer mmap(fd=%d, size=%d, prot=%x) failed (%s)",
196                    hnd->fd, hnd->size, hnd->prot, strerror(-errno));
197            return -errno;
198        }
199        hnd->base = intptr_t(base);
200    }
201    return NO_ERROR;
202}
203
204status_t sw_gralloc_handle_t::unregisterBuffer(sw_gralloc_handle_t* hnd)
205{
206    if (hnd->pid != getpid()) {
207        if (hnd->base) {
208            munmap((void*)hnd->base, hnd->size);
209        }
210        hnd->base = 0;
211    }
212    return NO_ERROR;
213}
214
215status_t sw_gralloc_handle_t::lock(sw_gralloc_handle_t* hnd, int usage,
216        int l, int t, int w, int h, void** vaddr)
217{
218    *vaddr = (void*)hnd->base;
219    return NO_ERROR;
220}
221
222status_t sw_gralloc_handle_t::unlock(sw_gralloc_handle_t* hnd)
223{
224    return NO_ERROR;
225}
226
227// ---------------------------------------------------------------------------
228}; // namespace android
229