FramebufferNativeWindow.cpp revision 55fa25161a7626ae6a15bc2cc46e22771455ed80
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 android_native_buffer_t, 50 NativeBuffer, 51 LightRefBase<NativeBuffer> > 52{ 53public: 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 } 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 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 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 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 139FramebufferNativeWindow::~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 154status_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 162status_t FramebufferNativeWindow::compositionComplete() 163{ 164 if (fbDev->compositionComplete) { 165 return fbDev->compositionComplete(fbDev); 166 } 167 return INVALID_OPERATION; 168} 169 170int 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 177int 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 199int 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 213int 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 227int 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 248int 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 266using namespace android; 267 268EGLNativeWindowType 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