Home | History | Annotate | Download | only in ui
      1 /*
      2 **
      3 ** Copyright 2007 The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License Version 2.0(the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing software
     12 ** distributed under the License is distributed on an "AS IS" BASIS
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #define LOG_TAG "FramebufferNativeWindow"
     19 
     20 #include <stdlib.h>
     21 #include <stdio.h>
     22 #include <string.h>
     23 #include <errno.h>
     24 
     25 #include <cutils/log.h>
     26 #include <cutils/atomic.h>
     27 #include <utils/threads.h>
     28 #include <utils/RefBase.h>
     29 
     30 #include <ui/ANativeObjectBase.h>
     31 #include <ui/Fence.h>
     32 #include <ui/FramebufferNativeWindow.h>
     33 #include <ui/Rect.h>
     34 
     35 #include <EGL/egl.h>
     36 
     37 #include <hardware/hardware.h>
     38 #include <hardware/gralloc.h>
     39 
     40 // ----------------------------------------------------------------------------
     41 namespace android {
     42 // ----------------------------------------------------------------------------
     43 
     44 class NativeBuffer
     45     : public ANativeObjectBase<
     46         ANativeWindowBuffer,
     47         NativeBuffer,
     48         LightRefBase<NativeBuffer> >
     49 {
     50 public:
     51     NativeBuffer(int w, int h, int f, int u) : BASE() {
     52         ANativeWindowBuffer::width  = w;
     53         ANativeWindowBuffer::height = h;
     54         ANativeWindowBuffer::format = f;
     55         ANativeWindowBuffer::usage  = u;
     56     }
     57 private:
     58     friend class LightRefBase<NativeBuffer>;
     59     ~NativeBuffer() { }; // this class cannot be overloaded
     60 };
     61 
     62 
     63 /*
     64  * This implements the (main) framebuffer management. This class is used
     65  * mostly by SurfaceFlinger, but also by command line GL application.
     66  *
     67  * In fact this is an implementation of ANativeWindow on top of
     68  * the framebuffer.
     69  *
     70  * Currently it is pretty simple, it manages only two buffers (the front and
     71  * back buffer).
     72  *
     73  */
     74 
     75 FramebufferNativeWindow::FramebufferNativeWindow()
     76     : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
     77 {
     78     hw_module_t const* module;
     79     if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
     80         int stride;
     81         int err;
     82         int i;
     83         err = framebuffer_open(module, &fbDev);
     84         ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
     85 
     86         err = gralloc_open(module, &grDev);
     87         ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
     88 
     89         // bail out if we can't initialize the modules
     90         if (!fbDev || !grDev)
     91             return;
     92 
     93         mUpdateOnDemand = (fbDev->setUpdateRect != 0);
     94 
     95         // initialize the buffer FIFO
     96         if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&
     97            fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){
     98             mNumBuffers = fbDev->numFramebuffers;
     99         } else {
    100             mNumBuffers = MIN_NUM_FRAME_BUFFERS;
    101         }
    102         mNumFreeBuffers = mNumBuffers;
    103         mBufferHead = mNumBuffers-1;
    104 
    105         /*
    106          * This does not actually change the framebuffer format. It merely
    107          * fakes this format to surfaceflinger so that when it creates
    108          * framebuffer surfaces it will use this format. It's really a giant
    109          * HACK to allow interworking with buggy gralloc+GPU driver
    110          * implementations. You should *NEVER* need to set this for shipping
    111          * devices.
    112          */
    113 #ifdef FRAMEBUFFER_FORCE_FORMAT
    114         *((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT;
    115 #endif
    116 
    117         for (i = 0; i < mNumBuffers; i++)
    118         {
    119                 buffers[i] = new NativeBuffer(
    120                         fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
    121         }
    122 
    123         for (i = 0; i < mNumBuffers; i++)
    124         {
    125                 err = grDev->alloc(grDev,
    126                         fbDev->width, fbDev->height, fbDev->format,
    127                         GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);
    128 
    129                 ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
    130                         i, fbDev->width, fbDev->height, strerror(-err));
    131 
    132                 if (err)
    133                 {
    134                         mNumBuffers = i;
    135                         mNumFreeBuffers = i;
    136                         mBufferHead = mNumBuffers-1;
    137                         break;
    138                 }
    139         }
    140 
    141         const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
    142         const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
    143         const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
    144         const_cast<int&>(ANativeWindow::minSwapInterval) =
    145             fbDev->minSwapInterval;
    146         const_cast<int&>(ANativeWindow::maxSwapInterval) =
    147             fbDev->maxSwapInterval;
    148     } else {
    149         ALOGE("Couldn't get gralloc module");
    150     }
    151 
    152     ANativeWindow::setSwapInterval = setSwapInterval;
    153     ANativeWindow::dequeueBuffer = dequeueBuffer;
    154     ANativeWindow::queueBuffer = queueBuffer;
    155     ANativeWindow::query = query;
    156     ANativeWindow::perform = perform;
    157 
    158     ANativeWindow::dequeueBuffer_DEPRECATED = dequeueBuffer_DEPRECATED;
    159     ANativeWindow::lockBuffer_DEPRECATED = lockBuffer_DEPRECATED;
    160     ANativeWindow::queueBuffer_DEPRECATED = queueBuffer_DEPRECATED;
    161 }
    162 
    163 FramebufferNativeWindow::~FramebufferNativeWindow()
    164 {
    165     if (grDev) {
    166         for(int i = 0; i < mNumBuffers; i++) {
    167             if (buffers[i] != NULL) {
    168                 grDev->free(grDev, buffers[i]->handle);
    169             }
    170         }
    171         gralloc_close(grDev);
    172     }
    173 
    174     if (fbDev) {
    175         framebuffer_close(fbDev);
    176     }
    177 }
    178 
    179 status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r)
    180 {
    181     if (!mUpdateOnDemand) {
    182         return INVALID_OPERATION;
    183     }
    184     return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height());
    185 }
    186 
    187 status_t FramebufferNativeWindow::compositionComplete()
    188 {
    189     if (fbDev->compositionComplete) {
    190         return fbDev->compositionComplete(fbDev);
    191     }
    192     return INVALID_OPERATION;
    193 }
    194 
    195 int FramebufferNativeWindow::setSwapInterval(
    196         ANativeWindow* window, int interval)
    197 {
    198     framebuffer_device_t* fb = getSelf(window)->fbDev;
    199     return fb->setSwapInterval(fb, interval);
    200 }
    201 
    202 void FramebufferNativeWindow::dump(String8& result) {
    203     if (fbDev->common.version >= 1 && fbDev->dump) {
    204         const size_t SIZE = 4096;
    205         char buffer[SIZE];
    206 
    207         fbDev->dump(fbDev, buffer, SIZE);
    208         result.append(buffer);
    209     }
    210 }
    211 
    212 // only for debugging / logging
    213 int FramebufferNativeWindow::getCurrentBufferIndex() const
    214 {
    215     Mutex::Autolock _l(mutex);
    216     const int index = mCurrentBufferIndex;
    217     return index;
    218 }
    219 
    220 int FramebufferNativeWindow::dequeueBuffer_DEPRECATED(ANativeWindow* window,
    221         ANativeWindowBuffer** buffer)
    222 {
    223     int fenceFd = -1;
    224     int result = dequeueBuffer(window, buffer, &fenceFd);
    225     sp<Fence> fence(new Fence(fenceFd));
    226     int waitResult = fence->wait(Fence::TIMEOUT_NEVER);
    227     if (waitResult != OK) {
    228         ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an "
    229                 "error: %d", waitResult);
    230         return waitResult;
    231     }
    232     return result;
    233 }
    234 
    235 int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window,
    236         ANativeWindowBuffer** buffer, int* fenceFd)
    237 {
    238     FramebufferNativeWindow* self = getSelf(window);
    239     Mutex::Autolock _l(self->mutex);
    240     framebuffer_device_t* fb = self->fbDev;
    241 
    242     int index = self->mBufferHead++;
    243     if (self->mBufferHead >= self->mNumBuffers)
    244         self->mBufferHead = 0;
    245 
    246     // wait for a free non-front buffer
    247     while (self->mNumFreeBuffers < 2) {
    248         self->mCondition.wait(self->mutex);
    249     }
    250     ALOG_ASSERT(self->buffers[index] != self->front);
    251 
    252     // get this buffer
    253     self->mNumFreeBuffers--;
    254     self->mCurrentBufferIndex = index;
    255 
    256     *buffer = self->buffers[index].get();
    257     *fenceFd = -1;
    258 
    259     return 0;
    260 }
    261 
    262 int FramebufferNativeWindow::lockBuffer_DEPRECATED(ANativeWindow* window,
    263         ANativeWindowBuffer* buffer)
    264 {
    265     return NO_ERROR;
    266 }
    267 
    268 int FramebufferNativeWindow::queueBuffer_DEPRECATED(ANativeWindow* window,
    269         ANativeWindowBuffer* buffer)
    270 {
    271     return queueBuffer(window, buffer, -1);
    272 }
    273 
    274 int FramebufferNativeWindow::queueBuffer(ANativeWindow* window,
    275         ANativeWindowBuffer* buffer, int fenceFd)
    276 {
    277     FramebufferNativeWindow* self = getSelf(window);
    278     Mutex::Autolock _l(self->mutex);
    279     framebuffer_device_t* fb = self->fbDev;
    280     buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle;
    281 
    282     sp<Fence> fence(new Fence(fenceFd));
    283     fence->wait(Fence::TIMEOUT_NEVER);
    284 
    285     const int index = self->mCurrentBufferIndex;
    286     int res = fb->post(fb, handle);
    287     self->front = static_cast<NativeBuffer*>(buffer);
    288     self->mNumFreeBuffers++;
    289     self->mCondition.broadcast();
    290     return res;
    291 }
    292 
    293 int FramebufferNativeWindow::query(const ANativeWindow* window,
    294         int what, int* value)
    295 {
    296     const FramebufferNativeWindow* self = getSelf(window);
    297     Mutex::Autolock _l(self->mutex);
    298     framebuffer_device_t* fb = self->fbDev;
    299     switch (what) {
    300         case NATIVE_WINDOW_WIDTH:
    301             *value = fb->width;
    302             return NO_ERROR;
    303         case NATIVE_WINDOW_HEIGHT:
    304             *value = fb->height;
    305             return NO_ERROR;
    306         case NATIVE_WINDOW_FORMAT:
    307             *value = fb->format;
    308             return NO_ERROR;
    309         case NATIVE_WINDOW_CONCRETE_TYPE:
    310             *value = NATIVE_WINDOW_FRAMEBUFFER;
    311             return NO_ERROR;
    312         case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
    313             *value = 0;
    314             return NO_ERROR;
    315         case NATIVE_WINDOW_DEFAULT_WIDTH:
    316             *value = fb->width;
    317             return NO_ERROR;
    318         case NATIVE_WINDOW_DEFAULT_HEIGHT:
    319             *value = fb->height;
    320             return NO_ERROR;
    321         case NATIVE_WINDOW_TRANSFORM_HINT:
    322             *value = 0;
    323             return NO_ERROR;
    324     }
    325     *value = 0;
    326     return BAD_VALUE;
    327 }
    328 
    329 int FramebufferNativeWindow::perform(ANativeWindow* window,
    330         int operation, ...)
    331 {
    332     switch (operation) {
    333         case NATIVE_WINDOW_CONNECT:
    334         case NATIVE_WINDOW_DISCONNECT:
    335         case NATIVE_WINDOW_SET_USAGE:
    336         case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
    337         case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
    338         case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
    339         case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
    340         case NATIVE_WINDOW_API_CONNECT:
    341         case NATIVE_WINDOW_API_DISCONNECT:
    342             // TODO: we should implement these
    343             return NO_ERROR;
    344 
    345         case NATIVE_WINDOW_LOCK:
    346         case NATIVE_WINDOW_UNLOCK_AND_POST:
    347         case NATIVE_WINDOW_SET_CROP:
    348         case NATIVE_WINDOW_SET_BUFFER_COUNT:
    349         case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
    350         case NATIVE_WINDOW_SET_SCALING_MODE:
    351             return INVALID_OPERATION;
    352     }
    353     return NAME_NOT_FOUND;
    354 }
    355 
    356 // ----------------------------------------------------------------------------
    357 }; // namespace android
    358 // ----------------------------------------------------------------------------
    359 
    360 using namespace android;
    361 
    362 EGLNativeWindowType android_createDisplaySurface(void)
    363 {
    364     FramebufferNativeWindow* w;
    365     w = new FramebufferNativeWindow();
    366     if (w->getDevice() == NULL) {
    367         // get a ref so it can be destroyed when we exit this block
    368         sp<FramebufferNativeWindow> ref(w);
    369         return NULL;
    370     }
    371     return (EGLNativeWindowType)w;
    372 }
    373