| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |  | 
| Mathias Agopian | 0926f50 | 2009-05-04 14:17:04 -0700 | [diff] [blame] | 18 | #define LOG_TAG "FramebufferNativeWindow" | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 19 |  | 
|  | 20 | #include <stdlib.h> | 
|  | 21 | #include <stdio.h> | 
|  | 22 | #include <string.h> | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 23 | #include <errno.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 24 |  | 
|  | 25 | #include <cutils/log.h> | 
|  | 26 | #include <cutils/atomic.h> | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 27 | #include <utils/threads.h> | 
| Mathias Agopian | 42db9dc | 2009-08-06 20:46:44 -0700 | [diff] [blame] | 28 | #include <utils/RefBase.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 29 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 30 | #include <ui/Rect.h> | 
| Mathias Agopian | 0926f50 | 2009-05-04 14:17:04 -0700 | [diff] [blame] | 31 | #include <ui/FramebufferNativeWindow.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 32 |  | 
|  | 33 | #include <EGL/egl.h> | 
|  | 34 |  | 
|  | 35 | #include <pixelflinger/format.h> | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 36 | #include <pixelflinger/pixelflinger.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 37 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 38 | #include <hardware/hardware.h> | 
|  | 39 | #include <hardware/gralloc.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 40 |  | 
| Mathias Agopian | 58a79f4 | 2009-05-05 18:21:32 -0700 | [diff] [blame] | 41 | #include <private/ui/android_natives_priv.h> | 
|  | 42 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 43 | // ---------------------------------------------------------------------------- | 
|  | 44 | namespace android { | 
|  | 45 | // ---------------------------------------------------------------------------- | 
|  | 46 |  | 
| Mathias Agopian | 7189c00 | 2009-05-05 18:11:11 -0700 | [diff] [blame] | 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 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 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 | */ | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 77 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 78 | FramebufferNativeWindow::FramebufferNativeWindow() | 
| Mathias Agopian | 1e16b13 | 2009-05-07 17:40:23 -0700 | [diff] [blame] | 79 | : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 80 | { | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 81 | hw_module_t const* module; | 
|  | 82 | if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { | 
|  | 83 | int stride; | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 84 | int err; | 
| Mathias Agopian | 42db9dc | 2009-08-06 20:46:44 -0700 | [diff] [blame] | 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)); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 90 |  | 
| Mathias Agopian | 42db9dc | 2009-08-06 20:46:44 -0700 | [diff] [blame] | 91 | // bail out if we can't initialize the modules | 
|  | 92 | if (!fbDev || !grDev) | 
|  | 93 | return; | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 94 |  | 
| Mathias Agopian | 1e16b13 | 2009-05-07 17:40:23 -0700 | [diff] [blame] | 95 | mUpdateOnDemand = (fbDev->setUpdateRect != 0); | 
|  | 96 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 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); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 109 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 110 | LOGE_IF(err, "fb buffer 0 allocation failed w=%d, h=%d, err=%s", | 
|  | 111 | fbDev->width, fbDev->height, strerror(-err)); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 112 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 113 | err = grDev->alloc(grDev, | 
|  | 114 | fbDev->width, fbDev->height, fbDev->format, | 
|  | 115 | GRALLOC_USAGE_HW_FB, &buffers[1]->handle, &buffers[1]->stride); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 116 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 117 | LOGE_IF(err, "fb buffer 1 allocation failed w=%d, h=%d, err=%s", | 
|  | 118 | fbDev->width, fbDev->height, strerror(-err)); | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 119 |  | 
| Marco Nelissen | a455793 | 2009-09-23 10:54:36 -0700 | [diff] [blame] | 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 | } | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 130 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 131 | android_native_window_t::setSwapInterval = setSwapInterval; | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 132 | android_native_window_t::dequeueBuffer = dequeueBuffer; | 
|  | 133 | android_native_window_t::lockBuffer = lockBuffer; | 
|  | 134 | android_native_window_t::queueBuffer = queueBuffer; | 
| Mathias Agopian | cb6b904 | 2009-07-30 18:14:56 -0700 | [diff] [blame] | 135 | android_native_window_t::query = query; | 
| Mathias Agopian | 5221271 | 2009-08-11 22:34:02 -0700 | [diff] [blame] | 136 | android_native_window_t::perform = perform; | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 137 | } | 
|  | 138 |  | 
| Mathias Agopian | 42db9dc | 2009-08-06 20:46:44 -0700 | [diff] [blame] | 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 | } | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 152 | } | 
|  | 153 |  | 
| Mathias Agopian | 1e16b13 | 2009-05-07 17:40:23 -0700 | [diff] [blame] | 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 |  | 
| Mathias Agopian | 74faca2 | 2009-09-17 16:18:16 -0700 | [diff] [blame] | 162 | status_t FramebufferNativeWindow::compositionComplete() | 
|  | 163 | { | 
|  | 164 | if (fbDev->compositionComplete) { | 
|  | 165 | return fbDev->compositionComplete(fbDev); | 
|  | 166 | } | 
|  | 167 | return INVALID_OPERATION; | 
|  | 168 | } | 
|  | 169 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 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 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 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; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 183 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 184 | // wait for a free buffer | 
|  | 185 | while (!self->mNumFreeBuffers) { | 
|  | 186 | self->mCondition.wait(self->mutex); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 187 | } | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 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; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 197 | } | 
|  | 198 |  | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 199 | int FramebufferNativeWindow::lockBuffer(android_native_window_t* window, | 
|  | 200 | android_native_buffer_t* buffer) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 201 | { | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 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); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 208 | } | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 209 |  | 
| Mathias Agopian | 0926f50 | 2009-05-04 14:17:04 -0700 | [diff] [blame] | 210 | return NO_ERROR; | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 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; | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 219 | buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle; | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 220 | int res = fb->post(fb, handle); | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 221 | self->front = static_cast<NativeBuffer*>(buffer); | 
|  | 222 | self->mNumFreeBuffers++; | 
|  | 223 | self->mCondition.broadcast(); | 
|  | 224 | return res; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 225 | } | 
|  | 226 |  | 
| Mathias Agopian | cb6b904 | 2009-07-30 18:14:56 -0700 | [diff] [blame] | 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; | 
| Mathias Agopian | 6b1f410 | 2009-08-06 16:04:29 -0700 | [diff] [blame] | 240 | case NATIVE_WINDOW_FORMAT: | 
|  | 241 | *value = fb->format; | 
|  | 242 | return NO_ERROR; | 
| Mathias Agopian | cb6b904 | 2009-07-30 18:14:56 -0700 | [diff] [blame] | 243 | } | 
| Mathias Agopian | 42db9dc | 2009-08-06 20:46:44 -0700 | [diff] [blame] | 244 | *value = 0; | 
| Mathias Agopian | cb6b904 | 2009-07-30 18:14:56 -0700 | [diff] [blame] | 245 | return BAD_VALUE; | 
|  | 246 | } | 
|  | 247 |  | 
| Mathias Agopian | 5221271 | 2009-08-11 22:34:02 -0700 | [diff] [blame] | 248 | int FramebufferNativeWindow::perform(android_native_window_t* window, | 
|  | 249 | int operation, ...) | 
|  | 250 | { | 
|  | 251 | switch (operation) { | 
|  | 252 | case NATIVE_WINDOW_SET_USAGE: | 
| Mathias Agopian | 55fa251 | 2010-03-11 15:06:54 -0800 | [diff] [blame] | 253 | case NATIVE_WINDOW_CONNECT: | 
|  | 254 | case NATIVE_WINDOW_DISCONNECT: | 
| Mathias Agopian | 5221271 | 2009-08-11 22:34:02 -0700 | [diff] [blame] | 255 | break; | 
|  | 256 | default: | 
|  | 257 | return NAME_NOT_FOUND; | 
|  | 258 | } | 
|  | 259 | return NO_ERROR; | 
|  | 260 | } | 
|  | 261 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 262 | // ---------------------------------------------------------------------------- | 
|  | 263 | }; // namespace android | 
|  | 264 | // ---------------------------------------------------------------------------- | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 265 |  | 
| Mathias Agopian | 42db9dc | 2009-08-06 20:46:44 -0700 | [diff] [blame] | 266 | using namespace android; | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 267 |  | 
|  | 268 | EGLNativeWindowType android_createDisplaySurface(void) | 
|  | 269 | { | 
| Mathias Agopian | 42db9dc | 2009-08-06 20:46:44 -0700 | [diff] [blame] | 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; | 
| Mathias Agopian | 076b1cc | 2009-04-10 14:24:30 -0700 | [diff] [blame] | 278 | } |