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 // ---------------------------------------------------------------------------- 40 namespace android { 41 // ---------------------------------------------------------------------------- 42 43 class NativeBuffer 44 : public ANativeObjectBase< 45 ANativeWindowBuffer, 46 NativeBuffer, 47 LightRefBase<NativeBuffer> > 48 { 49 public: 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 } 56 private: 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 74 FramebufferNativeWindow::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 154 FramebufferNativeWindow::~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 169 status_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 177 status_t FramebufferNativeWindow::compositionComplete() 178 { 179 if (fbDev->compositionComplete) { 180 return fbDev->compositionComplete(fbDev); 181 } 182 return INVALID_OPERATION; 183 } 184 185 int FramebufferNativeWindow::setSwapInterval( 186 ANativeWindow* window, int interval) 187 { 188 framebuffer_device_t* fb = getSelf(window)->fbDev; 189 return fb->setSwapInterval(fb, interval); 190 } 191 192 void 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 203 int FramebufferNativeWindow::getCurrentBufferIndex() const 204 { 205 Mutex::Autolock _l(mutex); 206 const int index = mCurrentBufferIndex; 207 return index; 208 } 209 210 int 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 234 int 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 250 int 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 266 int 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 302 int 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 333 using namespace android; 334 335 EGLNativeWindowType 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