FramebufferNativeWindow.cpp revision e6f43ddce78d6846af12550ff9193c5c6fe5844b
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 ANativeWindowBuffer, 51 NativeBuffer, 52 LightRefBase<NativeBuffer> > 53{ 54public: 55 NativeBuffer(int w, int h, int f, int u) : BASE() { 56 ANativeWindowBuffer::width = w; 57 ANativeWindowBuffer::height = h; 58 ANativeWindowBuffer::format = f; 59 ANativeWindowBuffer::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 int i; 87 err = framebuffer_open(module, &fbDev); 88 ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err)); 89 90 err = gralloc_open(module, &grDev); 91 ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err)); 92 93 // bail out if we can't initialize the modules 94 if (!fbDev || !grDev) 95 return; 96 97 mUpdateOnDemand = (fbDev->setUpdateRect != 0); 98 99 // initialize the buffer FIFO 100 mNumBuffers = NUM_FRAME_BUFFERS; 101 mNumFreeBuffers = NUM_FRAME_BUFFERS; 102 mBufferHead = mNumBuffers-1; 103 104 for (i = 0; i < mNumBuffers; i++) 105 { 106 buffers[i] = new NativeBuffer( 107 fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB); 108 } 109 110 for (i = 0; i < mNumBuffers; i++) 111 { 112 err = grDev->alloc(grDev, 113 fbDev->width, fbDev->height, fbDev->format, 114 GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride); 115 116 ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s", 117 i, fbDev->width, fbDev->height, strerror(-err)); 118 119 if (err) 120 { 121 mNumBuffers = i; 122 mNumFreeBuffers = i; 123 mBufferHead = mNumBuffers-1; 124 break; 125 } 126 } 127 128 const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags; 129 const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi; 130 const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi; 131 const_cast<int&>(ANativeWindow::minSwapInterval) = 132 fbDev->minSwapInterval; 133 const_cast<int&>(ANativeWindow::maxSwapInterval) = 134 fbDev->maxSwapInterval; 135 } else { 136 ALOGE("Couldn't get gralloc module"); 137 } 138 139 ANativeWindow::setSwapInterval = setSwapInterval; 140 ANativeWindow::dequeueBuffer = dequeueBuffer; 141 ANativeWindow::lockBuffer = lockBuffer; 142 ANativeWindow::queueBuffer = queueBuffer; 143 ANativeWindow::query = query; 144 ANativeWindow::perform = perform; 145} 146 147FramebufferNativeWindow::~FramebufferNativeWindow() 148{ 149 if (grDev) { 150 if (buffers[0] != NULL) 151 grDev->free(grDev, buffers[0]->handle); 152 if (buffers[1] != NULL) 153 grDev->free(grDev, buffers[1]->handle); 154 gralloc_close(grDev); 155 } 156 157 if (fbDev) { 158 framebuffer_close(fbDev); 159 } 160} 161 162status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r) 163{ 164 if (!mUpdateOnDemand) { 165 return INVALID_OPERATION; 166 } 167 return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height()); 168} 169 170status_t FramebufferNativeWindow::compositionComplete() 171{ 172 if (fbDev->compositionComplete) { 173 return fbDev->compositionComplete(fbDev); 174 } 175 return INVALID_OPERATION; 176} 177 178int FramebufferNativeWindow::setSwapInterval( 179 ANativeWindow* window, int interval) 180{ 181 framebuffer_device_t* fb = getSelf(window)->fbDev; 182 return fb->setSwapInterval(fb, interval); 183} 184 185void FramebufferNativeWindow::dump(String8& result) { 186 if (fbDev->common.version >= 1 && fbDev->dump) { 187 const size_t SIZE = 4096; 188 char buffer[SIZE]; 189 190 fbDev->dump(fbDev, buffer, SIZE); 191 result.append(buffer); 192 } 193} 194 195// only for debugging / logging 196int FramebufferNativeWindow::getCurrentBufferIndex() const 197{ 198 Mutex::Autolock _l(mutex); 199 const int index = mCurrentBufferIndex; 200 return index; 201} 202 203int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, 204 ANativeWindowBuffer** buffer) 205{ 206 FramebufferNativeWindow* self = getSelf(window); 207 Mutex::Autolock _l(self->mutex); 208 framebuffer_device_t* fb = self->fbDev; 209 210 int index = self->mBufferHead++; 211 if (self->mBufferHead >= self->mNumBuffers) 212 self->mBufferHead = 0; 213 214 GraphicLog& logger(GraphicLog::getInstance()); 215 logger.log(GraphicLog::SF_FB_DEQUEUE_BEFORE, index); 216 217 // wait for a free buffer 218 while (!self->mNumFreeBuffers) { 219 self->mCondition.wait(self->mutex); 220 } 221 // get this buffer 222 self->mNumFreeBuffers--; 223 self->mCurrentBufferIndex = index; 224 225 *buffer = self->buffers[index].get(); 226 227 logger.log(GraphicLog::SF_FB_DEQUEUE_AFTER, index); 228 return 0; 229} 230 231int FramebufferNativeWindow::lockBuffer(ANativeWindow* window, 232 ANativeWindowBuffer* buffer) 233{ 234 FramebufferNativeWindow* self = getSelf(window); 235 Mutex::Autolock _l(self->mutex); 236 237 const int index = self->mCurrentBufferIndex; 238 GraphicLog& logger(GraphicLog::getInstance()); 239 logger.log(GraphicLog::SF_FB_LOCK_BEFORE, index); 240 241 // wait that the buffer we're locking is not front anymore 242 while (self->front == buffer) { 243 self->mCondition.wait(self->mutex); 244 } 245 246 logger.log(GraphicLog::SF_FB_LOCK_AFTER, index); 247 248 return NO_ERROR; 249} 250 251int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, 252 ANativeWindowBuffer* buffer) 253{ 254 FramebufferNativeWindow* self = getSelf(window); 255 Mutex::Autolock _l(self->mutex); 256 framebuffer_device_t* fb = self->fbDev; 257 buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle; 258 259 const int index = self->mCurrentBufferIndex; 260 GraphicLog& logger(GraphicLog::getInstance()); 261 logger.log(GraphicLog::SF_FB_POST_BEFORE, index); 262 263 int res = fb->post(fb, handle); 264 265 logger.log(GraphicLog::SF_FB_POST_AFTER, index); 266 267 self->front = static_cast<NativeBuffer*>(buffer); 268 self->mNumFreeBuffers++; 269 self->mCondition.broadcast(); 270 return res; 271} 272 273int FramebufferNativeWindow::query(const ANativeWindow* window, 274 int what, int* value) 275{ 276 const FramebufferNativeWindow* self = getSelf(window); 277 Mutex::Autolock _l(self->mutex); 278 framebuffer_device_t* fb = self->fbDev; 279 switch (what) { 280 case NATIVE_WINDOW_WIDTH: 281 *value = fb->width; 282 return NO_ERROR; 283 case NATIVE_WINDOW_HEIGHT: 284 *value = fb->height; 285 return NO_ERROR; 286 case NATIVE_WINDOW_FORMAT: 287 *value = fb->format; 288 return NO_ERROR; 289 case NATIVE_WINDOW_CONCRETE_TYPE: 290 *value = NATIVE_WINDOW_FRAMEBUFFER; 291 return NO_ERROR; 292 case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: 293 *value = 0; 294 return NO_ERROR; 295 case NATIVE_WINDOW_DEFAULT_WIDTH: 296 *value = fb->width; 297 return NO_ERROR; 298 case NATIVE_WINDOW_DEFAULT_HEIGHT: 299 *value = fb->height; 300 return NO_ERROR; 301 case NATIVE_WINDOW_TRANSFORM_HINT: 302 *value = 0; 303 return NO_ERROR; 304 } 305 *value = 0; 306 return BAD_VALUE; 307} 308 309int FramebufferNativeWindow::perform(ANativeWindow* window, 310 int operation, ...) 311{ 312 switch (operation) { 313 case NATIVE_WINDOW_CONNECT: 314 case NATIVE_WINDOW_DISCONNECT: 315 case NATIVE_WINDOW_SET_USAGE: 316 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: 317 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: 318 case NATIVE_WINDOW_SET_BUFFERS_FORMAT: 319 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: 320 case NATIVE_WINDOW_API_CONNECT: 321 case NATIVE_WINDOW_API_DISCONNECT: 322 // TODO: we should implement these 323 return NO_ERROR; 324 325 case NATIVE_WINDOW_LOCK: 326 case NATIVE_WINDOW_UNLOCK_AND_POST: 327 case NATIVE_WINDOW_SET_CROP: 328 case NATIVE_WINDOW_SET_BUFFER_COUNT: 329 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: 330 case NATIVE_WINDOW_SET_SCALING_MODE: 331 return INVALID_OPERATION; 332 } 333 return NAME_NOT_FOUND; 334} 335 336// ---------------------------------------------------------------------------- 337}; // namespace android 338// ---------------------------------------------------------------------------- 339 340using namespace android; 341 342EGLNativeWindowType android_createDisplaySurface(void) 343{ 344 FramebufferNativeWindow* w; 345 w = new FramebufferNativeWindow(); 346 if (w->getDevice() == NULL) { 347 // get a ref so it can be destroyed when we exit this block 348 sp<FramebufferNativeWindow> ref(w); 349 return NULL; 350 } 351 return (EGLNativeWindowType)w; 352} 353