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/Rect.h> 31#include <ui/FramebufferNativeWindow.h> 32#include <ui/GraphicLog.h> 33 34#include <EGL/egl.h> 35 36#include <pixelflinger/format.h> 37#include <pixelflinger/pixelflinger.h> 38 39#include <hardware/hardware.h> 40#include <hardware/gralloc.h> 41 42#include <private/ui/android_natives_priv.h> 43 44// ---------------------------------------------------------------------------- 45namespace android { 46// ---------------------------------------------------------------------------- 47 48class NativeBuffer 49 : public EGLNativeBase< 50 android_native_buffer_t, 51 NativeBuffer, 52 LightRefBase<NativeBuffer> > 53{ 54public: 55 NativeBuffer(int w, int h, int f, int u) : BASE() { 56 android_native_buffer_t::width = w; 57 android_native_buffer_t::height = h; 58 android_native_buffer_t::format = f; 59 android_native_buffer_t::usage = u; 60 } 61private: 62 friend class LightRefBase<NativeBuffer>; 63 ~NativeBuffer() { }; // this class cannot be overloaded 64}; 65 66 67/* 68 * This implements the (main) framebuffer management. This class is used 69 * mostly by SurfaceFlinger, but also by command line GL application. 70 * 71 * In fact this is an implementation of ANativeWindow on top of 72 * the framebuffer. 73 * 74 * Currently it is pretty simple, it manages only two buffers (the front and 75 * back buffer). 76 * 77 */ 78 79FramebufferNativeWindow::FramebufferNativeWindow() 80 : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false) 81{ 82 hw_module_t const* module; 83 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { 84 int stride; 85 int err; 86 err = framebuffer_open(module, &fbDev); 87 LOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err)); 88 89 err = gralloc_open(module, &grDev); 90 LOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err)); 91 92 // bail out if we can't initialize the modules 93 if (!fbDev || !grDev) 94 return; 95 96 mUpdateOnDemand = (fbDev->setUpdateRect != 0); 97 98 // initialize the buffer FIFO 99 mNumBuffers = 2; 100 mNumFreeBuffers = 2; 101 mBufferHead = mNumBuffers-1; 102 buffers[0] = new NativeBuffer( 103 fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB); 104 buffers[1] = new NativeBuffer( 105 fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB); 106 107 err = grDev->alloc(grDev, 108 fbDev->width, fbDev->height, fbDev->format, 109 GRALLOC_USAGE_HW_FB, &buffers[0]->handle, &buffers[0]->stride); 110 111 LOGE_IF(err, "fb buffer 0 allocation failed w=%d, h=%d, err=%s", 112 fbDev->width, fbDev->height, strerror(-err)); 113 114 err = grDev->alloc(grDev, 115 fbDev->width, fbDev->height, fbDev->format, 116 GRALLOC_USAGE_HW_FB, &buffers[1]->handle, &buffers[1]->stride); 117 118 LOGE_IF(err, "fb buffer 1 allocation failed w=%d, h=%d, err=%s", 119 fbDev->width, fbDev->height, strerror(-err)); 120 121 const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags; 122 const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi; 123 const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi; 124 const_cast<int&>(ANativeWindow::minSwapInterval) = 125 fbDev->minSwapInterval; 126 const_cast<int&>(ANativeWindow::maxSwapInterval) = 127 fbDev->maxSwapInterval; 128 } else { 129 LOGE("Couldn't get gralloc module"); 130 } 131 132 ANativeWindow::setSwapInterval = setSwapInterval; 133 ANativeWindow::dequeueBuffer = dequeueBuffer; 134 ANativeWindow::lockBuffer = lockBuffer; 135 ANativeWindow::queueBuffer = queueBuffer; 136 ANativeWindow::query = query; 137 ANativeWindow::perform = perform; 138} 139 140FramebufferNativeWindow::~FramebufferNativeWindow() 141{ 142 if (grDev) { 143 if (buffers[0] != NULL) 144 grDev->free(grDev, buffers[0]->handle); 145 if (buffers[1] != NULL) 146 grDev->free(grDev, buffers[1]->handle); 147 gralloc_close(grDev); 148 } 149 150 if (fbDev) { 151 framebuffer_close(fbDev); 152 } 153} 154 155status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r) 156{ 157 if (!mUpdateOnDemand) { 158 return INVALID_OPERATION; 159 } 160 return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height()); 161} 162 163status_t FramebufferNativeWindow::compositionComplete() 164{ 165 if (fbDev->compositionComplete) { 166 return fbDev->compositionComplete(fbDev); 167 } 168 return INVALID_OPERATION; 169} 170 171int FramebufferNativeWindow::setSwapInterval( 172 ANativeWindow* window, int interval) 173{ 174 framebuffer_device_t* fb = getSelf(window)->fbDev; 175 return fb->setSwapInterval(fb, interval); 176} 177 178// only for debugging / logging 179int FramebufferNativeWindow::getCurrentBufferIndex() const 180{ 181 Mutex::Autolock _l(mutex); 182 const int index = mCurrentBufferIndex; 183 return index; 184} 185 186int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, 187 android_native_buffer_t** buffer) 188{ 189 FramebufferNativeWindow* self = getSelf(window); 190 Mutex::Autolock _l(self->mutex); 191 framebuffer_device_t* fb = self->fbDev; 192 193 int index = self->mBufferHead++; 194 if (self->mBufferHead >= self->mNumBuffers) 195 self->mBufferHead = 0; 196 197 GraphicLog& logger(GraphicLog::getInstance()); 198 logger.log(GraphicLog::SF_FB_DEQUEUE_BEFORE, index); 199 200 // wait for a free buffer 201 while (!self->mNumFreeBuffers) { 202 self->mCondition.wait(self->mutex); 203 } 204 // get this buffer 205 self->mNumFreeBuffers--; 206 self->mCurrentBufferIndex = index; 207 208 *buffer = self->buffers[index].get(); 209 210 logger.log(GraphicLog::SF_FB_DEQUEUE_AFTER, index); 211 return 0; 212} 213 214int FramebufferNativeWindow::lockBuffer(ANativeWindow* window, 215 android_native_buffer_t* buffer) 216{ 217 FramebufferNativeWindow* self = getSelf(window); 218 Mutex::Autolock _l(self->mutex); 219 220 const int index = self->mCurrentBufferIndex; 221 GraphicLog& logger(GraphicLog::getInstance()); 222 logger.log(GraphicLog::SF_FB_LOCK_BEFORE, index); 223 224 // wait that the buffer we're locking is not front anymore 225 while (self->front == buffer) { 226 self->mCondition.wait(self->mutex); 227 } 228 229 logger.log(GraphicLog::SF_FB_LOCK_AFTER, index); 230 231 return NO_ERROR; 232} 233 234int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, 235 android_native_buffer_t* buffer) 236{ 237 FramebufferNativeWindow* self = getSelf(window); 238 Mutex::Autolock _l(self->mutex); 239 framebuffer_device_t* fb = self->fbDev; 240 buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle; 241 242 const int index = self->mCurrentBufferIndex; 243 GraphicLog& logger(GraphicLog::getInstance()); 244 logger.log(GraphicLog::SF_FB_POST_BEFORE, index); 245 246 int res = fb->post(fb, handle); 247 248 logger.log(GraphicLog::SF_FB_POST_AFTER, index); 249 250 self->front = static_cast<NativeBuffer*>(buffer); 251 self->mNumFreeBuffers++; 252 self->mCondition.broadcast(); 253 return res; 254} 255 256int FramebufferNativeWindow::query(ANativeWindow* window, 257 int what, int* value) 258{ 259 FramebufferNativeWindow* self = getSelf(window); 260 Mutex::Autolock _l(self->mutex); 261 framebuffer_device_t* fb = self->fbDev; 262 switch (what) { 263 case NATIVE_WINDOW_WIDTH: 264 *value = fb->width; 265 return NO_ERROR; 266 case NATIVE_WINDOW_HEIGHT: 267 *value = fb->height; 268 return NO_ERROR; 269 case NATIVE_WINDOW_FORMAT: 270 *value = fb->format; 271 return NO_ERROR; 272 } 273 *value = 0; 274 return BAD_VALUE; 275} 276 277int FramebufferNativeWindow::perform(ANativeWindow* window, 278 int operation, ...) 279{ 280 switch (operation) { 281 case NATIVE_WINDOW_SET_USAGE: 282 case NATIVE_WINDOW_CONNECT: 283 case NATIVE_WINDOW_DISCONNECT: 284 break; 285 default: 286 return NAME_NOT_FOUND; 287 } 288 return NO_ERROR; 289} 290 291// ---------------------------------------------------------------------------- 292}; // namespace android 293// ---------------------------------------------------------------------------- 294 295using namespace android; 296 297EGLNativeWindowType android_createDisplaySurface(void) 298{ 299 FramebufferNativeWindow* w; 300 w = new FramebufferNativeWindow(); 301 if (w->getDevice() == NULL) { 302 // get a ref so it can be destroyed when we exit this block 303 sp<FramebufferNativeWindow> ref(w); 304 return NULL; 305 } 306 return (EGLNativeWindowType)w; 307} 308