FramebufferNativeWindow.cpp revision 5f2165f9455d4893b581b73a67c5431f4344b47e
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/FramebufferNativeWindow.h> 32#include <ui/Rect.h> 33 34#include <EGL/egl.h> 35 36#include <hardware/hardware.h> 37#include <hardware/gralloc.h> 38 39// ---------------------------------------------------------------------------- 40namespace android { 41// ---------------------------------------------------------------------------- 42 43class NativeBuffer 44 : public ANativeObjectBase< 45 ANativeWindowBuffer, 46 NativeBuffer, 47 LightRefBase<NativeBuffer> > 48{ 49public: 50 NativeBuffer(int w, int h, int f, int u) : BASE() { 51 ANativeWindowBuffer::width = w; 52 ANativeWindowBuffer::height = h; 53 ANativeWindowBuffer::format = f; 54 ANativeWindowBuffer::usage = u; 55 } 56private: 57 friend class LightRefBase<NativeBuffer>; 58 ~NativeBuffer() { }; // this class cannot be overloaded 59}; 60 61 62/* 63 * This implements the (main) framebuffer management. This class is used 64 * mostly by SurfaceFlinger, but also by command line GL application. 65 * 66 * In fact this is an implementation of ANativeWindow on top of 67 * the framebuffer. 68 * 69 * Currently it is pretty simple, it manages only two buffers (the front and 70 * back buffer). 71 * 72 */ 73 74FramebufferNativeWindow::FramebufferNativeWindow() 75 : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false) 76{ 77 hw_module_t const* module; 78 if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { 79 int stride; 80 int err; 81 int i; 82 err = framebuffer_open(module, &fbDev); 83 ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err)); 84 85 err = gralloc_open(module, &grDev); 86 ALOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err)); 87 88 // bail out if we can't initialize the modules 89 if (!fbDev || !grDev) 90 return; 91 92 mUpdateOnDemand = (fbDev->setUpdateRect != 0); 93 94 // initialize the buffer FIFO 95 mNumBuffers = NUM_FRAME_BUFFERS; 96 mNumFreeBuffers = NUM_FRAME_BUFFERS; 97 mBufferHead = mNumBuffers-1; 98 99 /* 100 * This does not actually change the framebuffer format. It merely 101 * fakes this format to surfaceflinger so that when it creates 102 * framebuffer surfaces it will use this format. It's really a giant 103 * HACK to allow interworking with buggy gralloc+GPU driver 104 * implementations. You should *NEVER* need to set this for shipping 105 * devices. 106 */ 107#ifdef FRAMEBUFFER_FORCE_FORMAT 108 *((uint32_t *)&fbDev->format) = FRAMEBUFFER_FORCE_FORMAT; 109#endif 110 111 for (i = 0; i < mNumBuffers; i++) 112 { 113 buffers[i] = new NativeBuffer( 114 fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB); 115 } 116 117 for (i = 0; i < mNumBuffers; i++) 118 { 119 err = grDev->alloc(grDev, 120 fbDev->width, fbDev->height, fbDev->format, 121 GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride); 122 123 ALOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s", 124 i, fbDev->width, fbDev->height, strerror(-err)); 125 126 if (err) 127 { 128 mNumBuffers = i; 129 mNumFreeBuffers = i; 130 mBufferHead = mNumBuffers-1; 131 break; 132 } 133 } 134 135 const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags; 136 const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi; 137 const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi; 138 const_cast<int&>(ANativeWindow::minSwapInterval) = 139 fbDev->minSwapInterval; 140 const_cast<int&>(ANativeWindow::maxSwapInterval) = 141 fbDev->maxSwapInterval; 142 } else { 143 ALOGE("Couldn't get gralloc module"); 144 } 145 146 ANativeWindow::setSwapInterval = setSwapInterval; 147 ANativeWindow::dequeueBuffer = dequeueBuffer; 148 ANativeWindow::lockBuffer = lockBuffer; 149 ANativeWindow::queueBuffer = queueBuffer; 150 ANativeWindow::query = query; 151 ANativeWindow::perform = perform; 152} 153 154FramebufferNativeWindow::~FramebufferNativeWindow() 155{ 156 if (grDev) { 157 if (buffers[0] != NULL) 158 grDev->free(grDev, buffers[0]->handle); 159 if (buffers[1] != NULL) 160 grDev->free(grDev, buffers[1]->handle); 161 gralloc_close(grDev); 162 } 163 164 if (fbDev) { 165 framebuffer_close(fbDev); 166 } 167} 168 169status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r) 170{ 171 if (!mUpdateOnDemand) { 172 return INVALID_OPERATION; 173 } 174 return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height()); 175} 176 177status_t FramebufferNativeWindow::compositionComplete() 178{ 179 if (fbDev->compositionComplete) { 180 return fbDev->compositionComplete(fbDev); 181 } 182 return INVALID_OPERATION; 183} 184 185int FramebufferNativeWindow::setSwapInterval( 186 ANativeWindow* window, int interval) 187{ 188 framebuffer_device_t* fb = getSelf(window)->fbDev; 189 return fb->setSwapInterval(fb, interval); 190} 191 192void FramebufferNativeWindow::dump(String8& result) { 193 if (fbDev->common.version >= 1 && fbDev->dump) { 194 const size_t SIZE = 4096; 195 char buffer[SIZE]; 196 197 fbDev->dump(fbDev, buffer, SIZE); 198 result.append(buffer); 199 } 200} 201 202// only for debugging / logging 203int FramebufferNativeWindow::getCurrentBufferIndex() const 204{ 205 Mutex::Autolock _l(mutex); 206 const int index = mCurrentBufferIndex; 207 return index; 208} 209 210int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window, 211 ANativeWindowBuffer** buffer) 212{ 213 FramebufferNativeWindow* self = getSelf(window); 214 Mutex::Autolock _l(self->mutex); 215 framebuffer_device_t* fb = self->fbDev; 216 217 int index = self->mBufferHead++; 218 if (self->mBufferHead >= self->mNumBuffers) 219 self->mBufferHead = 0; 220 221 // wait for a free buffer 222 while (!self->mNumFreeBuffers) { 223 self->mCondition.wait(self->mutex); 224 } 225 // get this buffer 226 self->mNumFreeBuffers--; 227 self->mCurrentBufferIndex = index; 228 229 *buffer = self->buffers[index].get(); 230 231 return 0; 232} 233 234int FramebufferNativeWindow::lockBuffer(ANativeWindow* window, 235 ANativeWindowBuffer* buffer) 236{ 237 FramebufferNativeWindow* self = getSelf(window); 238 Mutex::Autolock _l(self->mutex); 239 240 const int index = self->mCurrentBufferIndex; 241 242 // wait that the buffer we're locking is not front anymore 243 while (self->front == buffer) { 244 self->mCondition.wait(self->mutex); 245 } 246 247 return NO_ERROR; 248} 249 250int FramebufferNativeWindow::queueBuffer(ANativeWindow* window, 251 ANativeWindowBuffer* buffer) 252{ 253 FramebufferNativeWindow* self = getSelf(window); 254 Mutex::Autolock _l(self->mutex); 255 framebuffer_device_t* fb = self->fbDev; 256 buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle; 257 258 const int index = self->mCurrentBufferIndex; 259 int res = fb->post(fb, handle); 260 self->front = static_cast<NativeBuffer*>(buffer); 261 self->mNumFreeBuffers++; 262 self->mCondition.broadcast(); 263 return res; 264} 265 266int FramebufferNativeWindow::query(const ANativeWindow* window, 267 int what, int* value) 268{ 269 const FramebufferNativeWindow* self = getSelf(window); 270 Mutex::Autolock _l(self->mutex); 271 framebuffer_device_t* fb = self->fbDev; 272 switch (what) { 273 case NATIVE_WINDOW_WIDTH: 274 *value = fb->width; 275 return NO_ERROR; 276 case NATIVE_WINDOW_HEIGHT: 277 *value = fb->height; 278 return NO_ERROR; 279 case NATIVE_WINDOW_FORMAT: 280 *value = fb->format; 281 return NO_ERROR; 282 case NATIVE_WINDOW_CONCRETE_TYPE: 283 *value = NATIVE_WINDOW_FRAMEBUFFER; 284 return NO_ERROR; 285 case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: 286 *value = 0; 287 return NO_ERROR; 288 case NATIVE_WINDOW_DEFAULT_WIDTH: 289 *value = fb->width; 290 return NO_ERROR; 291 case NATIVE_WINDOW_DEFAULT_HEIGHT: 292 *value = fb->height; 293 return NO_ERROR; 294 case NATIVE_WINDOW_TRANSFORM_HINT: 295 *value = 0; 296 return NO_ERROR; 297 } 298 *value = 0; 299 return BAD_VALUE; 300} 301 302int FramebufferNativeWindow::perform(ANativeWindow* window, 303 int operation, ...) 304{ 305 switch (operation) { 306 case NATIVE_WINDOW_CONNECT: 307 case NATIVE_WINDOW_DISCONNECT: 308 case NATIVE_WINDOW_SET_USAGE: 309 case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: 310 case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: 311 case NATIVE_WINDOW_SET_BUFFERS_FORMAT: 312 case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: 313 case NATIVE_WINDOW_API_CONNECT: 314 case NATIVE_WINDOW_API_DISCONNECT: 315 // TODO: we should implement these 316 return NO_ERROR; 317 318 case NATIVE_WINDOW_LOCK: 319 case NATIVE_WINDOW_UNLOCK_AND_POST: 320 case NATIVE_WINDOW_SET_CROP: 321 case NATIVE_WINDOW_SET_BUFFER_COUNT: 322 case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: 323 case NATIVE_WINDOW_SET_SCALING_MODE: 324 return INVALID_OPERATION; 325 } 326 return NAME_NOT_FOUND; 327} 328 329// ---------------------------------------------------------------------------- 330}; // namespace android 331// ---------------------------------------------------------------------------- 332 333using namespace android; 334 335EGLNativeWindowType android_createDisplaySurface(void) 336{ 337 FramebufferNativeWindow* w; 338 w = new FramebufferNativeWindow(); 339 if (w->getDevice() == NULL) { 340 // get a ref so it can be destroyed when we exit this block 341 sp<FramebufferNativeWindow> ref(w); 342 return NULL; 343 } 344 return (EGLNativeWindowType)w; 345} 346