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