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 // ---------------------------------------------------------------------------- 44 namespace android { 45 // ---------------------------------------------------------------------------- 46 47 class NativeBuffer 48 : public EGLNativeBase< 49 android_native_buffer_t, 50 NativeBuffer, 51 LightRefBase<NativeBuffer> > 52 { 53 public: 54 NativeBuffer(int w, int h, int f, int u) : BASE() { 55 android_native_buffer_t::width = w; 56 android_native_buffer_t::height = h; 57 android_native_buffer_t::format = f; 58 android_native_buffer_t::usage = u; 59 } 60 private: 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 android_native_window_t 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 78 FramebufferNativeWindow::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 err = framebuffer_open(module, &fbDev); 86 LOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err)); 87 88 err = gralloc_open(module, &grDev); 89 LOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err)); 90 91 // bail out if we can't initialize the modules 92 if (!fbDev || !grDev) 93 return; 94 95 mUpdateOnDemand = (fbDev->setUpdateRect != 0); 96 97 // initialize the buffer FIFO 98 mNumBuffers = 2; 99 mNumFreeBuffers = 2; 100 mBufferHead = mNumBuffers-1; 101 buffers[0] = new NativeBuffer( 102 fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB); 103 buffers[1] = new NativeBuffer( 104 fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB); 105 106 err = grDev->alloc(grDev, 107 fbDev->width, fbDev->height, fbDev->format, 108 GRALLOC_USAGE_HW_FB, &buffers[0]->handle, &buffers[0]->stride); 109 110 LOGE_IF(err, "fb buffer 0 allocation failed w=%d, h=%d, err=%s", 111 fbDev->width, fbDev->height, strerror(-err)); 112 113 err = grDev->alloc(grDev, 114 fbDev->width, fbDev->height, fbDev->format, 115 GRALLOC_USAGE_HW_FB, &buffers[1]->handle, &buffers[1]->stride); 116 117 LOGE_IF(err, "fb buffer 1 allocation failed w=%d, h=%d, err=%s", 118 fbDev->width, fbDev->height, strerror(-err)); 119 120 const_cast<uint32_t&>(android_native_window_t::flags) = fbDev->flags; 121 const_cast<float&>(android_native_window_t::xdpi) = fbDev->xdpi; 122 const_cast<float&>(android_native_window_t::ydpi) = fbDev->ydpi; 123 const_cast<int&>(android_native_window_t::minSwapInterval) = 124 fbDev->minSwapInterval; 125 const_cast<int&>(android_native_window_t::maxSwapInterval) = 126 fbDev->maxSwapInterval; 127 } else { 128 LOGE("Couldn't get gralloc module"); 129 } 130 131 android_native_window_t::setSwapInterval = setSwapInterval; 132 android_native_window_t::dequeueBuffer = dequeueBuffer; 133 android_native_window_t::lockBuffer = lockBuffer; 134 android_native_window_t::queueBuffer = queueBuffer; 135 android_native_window_t::query = query; 136 android_native_window_t::perform = perform; 137 } 138 139 FramebufferNativeWindow::~FramebufferNativeWindow() 140 { 141 if (grDev) { 142 if (buffers[0] != NULL) 143 grDev->free(grDev, buffers[0]->handle); 144 if (buffers[1] != NULL) 145 grDev->free(grDev, buffers[1]->handle); 146 gralloc_close(grDev); 147 } 148 149 if (fbDev) { 150 framebuffer_close(fbDev); 151 } 152 } 153 154 status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r) 155 { 156 if (!mUpdateOnDemand) { 157 return INVALID_OPERATION; 158 } 159 return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height()); 160 } 161 162 status_t FramebufferNativeWindow::compositionComplete() 163 { 164 if (fbDev->compositionComplete) { 165 return fbDev->compositionComplete(fbDev); 166 } 167 return INVALID_OPERATION; 168 } 169 170 int FramebufferNativeWindow::setSwapInterval( 171 android_native_window_t* window, int interval) 172 { 173 framebuffer_device_t* fb = getSelf(window)->fbDev; 174 return fb->setSwapInterval(fb, interval); 175 } 176 177 int FramebufferNativeWindow::dequeueBuffer(android_native_window_t* window, 178 android_native_buffer_t** buffer) 179 { 180 FramebufferNativeWindow* self = getSelf(window); 181 Mutex::Autolock _l(self->mutex); 182 framebuffer_device_t* fb = self->fbDev; 183 184 // wait for a free buffer 185 while (!self->mNumFreeBuffers) { 186 self->mCondition.wait(self->mutex); 187 } 188 // get this buffer 189 self->mNumFreeBuffers--; 190 int index = self->mBufferHead++; 191 if (self->mBufferHead >= self->mNumBuffers) 192 self->mBufferHead = 0; 193 194 *buffer = self->buffers[index].get(); 195 196 return 0; 197 } 198 199 int FramebufferNativeWindow::lockBuffer(android_native_window_t* window, 200 android_native_buffer_t* buffer) 201 { 202 FramebufferNativeWindow* self = getSelf(window); 203 Mutex::Autolock _l(self->mutex); 204 205 // wait that the buffer we're locking is not front anymore 206 while (self->front == buffer) { 207 self->mCondition.wait(self->mutex); 208 } 209 210 return NO_ERROR; 211 } 212 213 int FramebufferNativeWindow::queueBuffer(android_native_window_t* window, 214 android_native_buffer_t* buffer) 215 { 216 FramebufferNativeWindow* self = getSelf(window); 217 Mutex::Autolock _l(self->mutex); 218 framebuffer_device_t* fb = self->fbDev; 219 buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle; 220 int res = fb->post(fb, handle); 221 self->front = static_cast<NativeBuffer*>(buffer); 222 self->mNumFreeBuffers++; 223 self->mCondition.broadcast(); 224 return res; 225 } 226 227 int FramebufferNativeWindow::query(android_native_window_t* window, 228 int what, int* value) 229 { 230 FramebufferNativeWindow* self = getSelf(window); 231 Mutex::Autolock _l(self->mutex); 232 framebuffer_device_t* fb = self->fbDev; 233 switch (what) { 234 case NATIVE_WINDOW_WIDTH: 235 *value = fb->width; 236 return NO_ERROR; 237 case NATIVE_WINDOW_HEIGHT: 238 *value = fb->height; 239 return NO_ERROR; 240 case NATIVE_WINDOW_FORMAT: 241 *value = fb->format; 242 return NO_ERROR; 243 } 244 *value = 0; 245 return BAD_VALUE; 246 } 247 248 int FramebufferNativeWindow::perform(android_native_window_t* window, 249 int operation, ...) 250 { 251 switch (operation) { 252 case NATIVE_WINDOW_SET_USAGE: 253 case NATIVE_WINDOW_CONNECT: 254 case NATIVE_WINDOW_DISCONNECT: 255 break; 256 default: 257 return NAME_NOT_FOUND; 258 } 259 return NO_ERROR; 260 } 261 262 // ---------------------------------------------------------------------------- 263 }; // namespace android 264 // ---------------------------------------------------------------------------- 265 266 using namespace android; 267 268 EGLNativeWindowType android_createDisplaySurface(void) 269 { 270 FramebufferNativeWindow* w; 271 w = new FramebufferNativeWindow(); 272 if (w->getDevice() == NULL) { 273 // get a ref so it can be destroyed when we exit this block 274 sp<FramebufferNativeWindow> ref(w); 275 return NULL; 276 } 277 return (EGLNativeWindowType)w; 278 } 279