• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <ui/GraphicLog.h>
33 
34 #include <EGL/egl.h>
35 
36 #include <pixelflinger/format.h>
37 #include <pixelflinger/pixelflinger.h>
38 
39 #include <hardware/hardware.h>
40 #include <hardware/gralloc.h>
41 
42 #include <private/ui/android_natives_priv.h>
43 
44 // ----------------------------------------------------------------------------
45 namespace android {
46 // ----------------------------------------------------------------------------
47 
48 class NativeBuffer
49     : public EGLNativeBase<
50         ANativeWindowBuffer,
51         NativeBuffer,
52         LightRefBase<NativeBuffer> >
53 {
54 public:
NativeBuffer(int w,int h,int f,int u)55     NativeBuffer(int w, int h, int f, int u) : BASE() {
56         ANativeWindowBuffer::width  = w;
57         ANativeWindowBuffer::height = h;
58         ANativeWindowBuffer::format = f;
59         ANativeWindowBuffer::usage  = u;
60     }
61 private:
62     friend class LightRefBase<NativeBuffer>;
~NativeBuffer()63     ~NativeBuffer() { }; // this class cannot be overloaded
64 };
65 
66 
67 /*
68  * This implements the (main) framebuffer management. This class is used
69  * mostly by SurfaceFlinger, but also by command line GL application.
70  *
71  * In fact this is an implementation of ANativeWindow on top of
72  * the framebuffer.
73  *
74  * Currently it is pretty simple, it manages only two buffers (the front and
75  * back buffer).
76  *
77  */
78 
FramebufferNativeWindow()79 FramebufferNativeWindow::FramebufferNativeWindow()
80     : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
81 {
82     hw_module_t const* module;
83     if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
84         int stride;
85         int err;
86         int i;
87         err = framebuffer_open(module, &fbDev);
88         LOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
89 
90         err = gralloc_open(module, &grDev);
91         LOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
92 
93         // bail out if we can't initialize the modules
94         if (!fbDev || !grDev)
95             return;
96 
97         mUpdateOnDemand = (fbDev->setUpdateRect != 0);
98 
99         // initialize the buffer FIFO
100         mNumBuffers = NUM_FRAME_BUFFERS;
101         mNumFreeBuffers = NUM_FRAME_BUFFERS;
102         mBufferHead = mNumBuffers-1;
103 
104         for (i = 0; i < mNumBuffers; i++)
105         {
106                 buffers[i] = new NativeBuffer(
107                         fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
108         }
109 
110         for (i = 0; i < mNumBuffers; i++)
111         {
112                 err = grDev->alloc(grDev,
113                         fbDev->width, fbDev->height, fbDev->format,
114                         GRALLOC_USAGE_HW_FB, &buffers[i]->handle, &buffers[i]->stride);
115 
116                 LOGE_IF(err, "fb buffer %d allocation failed w=%d, h=%d, err=%s",
117                         i, fbDev->width, fbDev->height, strerror(-err));
118 
119                 if (err)
120                 {
121                         mNumBuffers = i;
122                         mNumFreeBuffers = i;
123                         mBufferHead = mNumBuffers-1;
124                         break;
125                 }
126         }
127 
128         const_cast<uint32_t&>(ANativeWindow::flags) = fbDev->flags;
129         const_cast<float&>(ANativeWindow::xdpi) = fbDev->xdpi;
130         const_cast<float&>(ANativeWindow::ydpi) = fbDev->ydpi;
131         const_cast<int&>(ANativeWindow::minSwapInterval) =
132             fbDev->minSwapInterval;
133         const_cast<int&>(ANativeWindow::maxSwapInterval) =
134             fbDev->maxSwapInterval;
135     } else {
136         LOGE("Couldn't get gralloc module");
137     }
138 
139     ANativeWindow::setSwapInterval = setSwapInterval;
140     ANativeWindow::dequeueBuffer = dequeueBuffer;
141     ANativeWindow::lockBuffer = lockBuffer;
142     ANativeWindow::queueBuffer = queueBuffer;
143     ANativeWindow::query = query;
144     ANativeWindow::perform = perform;
145 }
146 
~FramebufferNativeWindow()147 FramebufferNativeWindow::~FramebufferNativeWindow()
148 {
149     if (grDev) {
150         if (buffers[0] != NULL)
151             grDev->free(grDev, buffers[0]->handle);
152         if (buffers[1] != NULL)
153             grDev->free(grDev, buffers[1]->handle);
154         gralloc_close(grDev);
155     }
156 
157     if (fbDev) {
158         framebuffer_close(fbDev);
159     }
160 }
161 
setUpdateRectangle(const Rect & r)162 status_t FramebufferNativeWindow::setUpdateRectangle(const Rect& r)
163 {
164     if (!mUpdateOnDemand) {
165         return INVALID_OPERATION;
166     }
167     return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height());
168 }
169 
compositionComplete()170 status_t FramebufferNativeWindow::compositionComplete()
171 {
172     if (fbDev->compositionComplete) {
173         return fbDev->compositionComplete(fbDev);
174     }
175     return INVALID_OPERATION;
176 }
177 
setSwapInterval(ANativeWindow * window,int interval)178 int FramebufferNativeWindow::setSwapInterval(
179         ANativeWindow* window, int interval)
180 {
181     framebuffer_device_t* fb = getSelf(window)->fbDev;
182     return fb->setSwapInterval(fb, interval);
183 }
184 
dump(String8 & result)185 void FramebufferNativeWindow::dump(String8& result) {
186     if (fbDev->common.version >= 1 && fbDev->dump) {
187         const size_t SIZE = 4096;
188         char buffer[SIZE];
189 
190         fbDev->dump(fbDev, buffer, SIZE);
191         result.append(buffer);
192     }
193 }
194 
195 // only for debugging / logging
getCurrentBufferIndex() const196 int FramebufferNativeWindow::getCurrentBufferIndex() const
197 {
198     Mutex::Autolock _l(mutex);
199     const int index = mCurrentBufferIndex;
200     return index;
201 }
202 
dequeueBuffer(ANativeWindow * window,ANativeWindowBuffer ** buffer)203 int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window,
204         ANativeWindowBuffer** buffer)
205 {
206     FramebufferNativeWindow* self = getSelf(window);
207     Mutex::Autolock _l(self->mutex);
208     framebuffer_device_t* fb = self->fbDev;
209 
210     int index = self->mBufferHead++;
211     if (self->mBufferHead >= self->mNumBuffers)
212         self->mBufferHead = 0;
213 
214     GraphicLog& logger(GraphicLog::getInstance());
215     logger.log(GraphicLog::SF_FB_DEQUEUE_BEFORE, index);
216 
217     // wait for a free buffer
218     while (!self->mNumFreeBuffers) {
219         self->mCondition.wait(self->mutex);
220     }
221     // get this buffer
222     self->mNumFreeBuffers--;
223     self->mCurrentBufferIndex = index;
224 
225     *buffer = self->buffers[index].get();
226 
227     logger.log(GraphicLog::SF_FB_DEQUEUE_AFTER, index);
228     return 0;
229 }
230 
lockBuffer(ANativeWindow * window,ANativeWindowBuffer * buffer)231 int FramebufferNativeWindow::lockBuffer(ANativeWindow* window,
232         ANativeWindowBuffer* buffer)
233 {
234     FramebufferNativeWindow* self = getSelf(window);
235     Mutex::Autolock _l(self->mutex);
236 
237     const int index = self->mCurrentBufferIndex;
238     GraphicLog& logger(GraphicLog::getInstance());
239     logger.log(GraphicLog::SF_FB_LOCK_BEFORE, index);
240 
241     // wait that the buffer we're locking is not front anymore
242     while (self->front == buffer) {
243         self->mCondition.wait(self->mutex);
244     }
245 
246     logger.log(GraphicLog::SF_FB_LOCK_AFTER, index);
247 
248     return NO_ERROR;
249 }
250 
queueBuffer(ANativeWindow * window,ANativeWindowBuffer * buffer)251 int FramebufferNativeWindow::queueBuffer(ANativeWindow* window,
252         ANativeWindowBuffer* buffer)
253 {
254     FramebufferNativeWindow* self = getSelf(window);
255     Mutex::Autolock _l(self->mutex);
256     framebuffer_device_t* fb = self->fbDev;
257     buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle;
258 
259     const int index = self->mCurrentBufferIndex;
260     GraphicLog& logger(GraphicLog::getInstance());
261     logger.log(GraphicLog::SF_FB_POST_BEFORE, index);
262 
263     int res = fb->post(fb, handle);
264 
265     logger.log(GraphicLog::SF_FB_POST_AFTER, index);
266 
267     self->front = static_cast<NativeBuffer*>(buffer);
268     self->mNumFreeBuffers++;
269     self->mCondition.broadcast();
270     return res;
271 }
272 
query(const ANativeWindow * window,int what,int * value)273 int FramebufferNativeWindow::query(const ANativeWindow* window,
274         int what, int* value)
275 {
276     const FramebufferNativeWindow* self = getSelf(window);
277     Mutex::Autolock _l(self->mutex);
278     framebuffer_device_t* fb = self->fbDev;
279     switch (what) {
280         case NATIVE_WINDOW_WIDTH:
281             *value = fb->width;
282             return NO_ERROR;
283         case NATIVE_WINDOW_HEIGHT:
284             *value = fb->height;
285             return NO_ERROR;
286         case NATIVE_WINDOW_FORMAT:
287             *value = fb->format;
288             return NO_ERROR;
289         case NATIVE_WINDOW_CONCRETE_TYPE:
290             *value = NATIVE_WINDOW_FRAMEBUFFER;
291             return NO_ERROR;
292         case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
293             *value = 0;
294             return NO_ERROR;
295         case NATIVE_WINDOW_DEFAULT_WIDTH:
296             *value = fb->width;
297             return NO_ERROR;
298         case NATIVE_WINDOW_DEFAULT_HEIGHT:
299             *value = fb->height;
300             return NO_ERROR;
301         case NATIVE_WINDOW_TRANSFORM_HINT:
302             *value = 0;
303             return NO_ERROR;
304     }
305     *value = 0;
306     return BAD_VALUE;
307 }
308 
perform(ANativeWindow * window,int operation,...)309 int FramebufferNativeWindow::perform(ANativeWindow* window,
310         int operation, ...)
311 {
312     switch (operation) {
313         case NATIVE_WINDOW_CONNECT:
314         case NATIVE_WINDOW_DISCONNECT:
315         case NATIVE_WINDOW_SET_USAGE:
316         case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
317         case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
318         case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
319         case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
320         case NATIVE_WINDOW_API_CONNECT:
321         case NATIVE_WINDOW_API_DISCONNECT:
322             // TODO: we should implement these
323             return NO_ERROR;
324 
325         case NATIVE_WINDOW_LOCK:
326         case NATIVE_WINDOW_UNLOCK_AND_POST:
327         case NATIVE_WINDOW_SET_CROP:
328         case NATIVE_WINDOW_SET_BUFFER_COUNT:
329         case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
330         case NATIVE_WINDOW_SET_SCALING_MODE:
331             return INVALID_OPERATION;
332     }
333     return NAME_NOT_FOUND;
334 }
335 
336 // ----------------------------------------------------------------------------
337 }; // namespace android
338 // ----------------------------------------------------------------------------
339 
340 using namespace android;
341 
android_createDisplaySurface(void)342 EGLNativeWindowType android_createDisplaySurface(void)
343 {
344     FramebufferNativeWindow* w;
345     w = new FramebufferNativeWindow();
346     if (w->getDevice() == NULL) {
347         // get a ref so it can be destroyed when we exit this block
348         sp<FramebufferNativeWindow> ref(w);
349         return NULL;
350     }
351     return (EGLNativeWindowType)w;
352 }
353