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