Imported Upstream version 0.1.0+git20131207+e452e83
[deb_libhybris.git] / hybris / egl / platforms / fbdev / fbdev_window.cpp
1 /*
2 * Copyright (C) 2013 libhybris
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "fbdev_window.h"
18 #include "logging.h"
19
20 #include <errno.h>
21 #include <assert.h>
22 #include <pthread.h>
23 #include <stdio.h>
24
25 #include <android/android-version.h>
26
27 #define FRAMEBUFFER_PARTITIONS 2
28
29 static pthread_cond_t _cond = PTHREAD_COND_INITIALIZER;
30 static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
31
32
33 FbDevNativeWindowBuffer::FbDevNativeWindowBuffer(alloc_device_t* alloc_device,
34 unsigned int width,
35 unsigned int height,
36 unsigned int format,
37 unsigned int usage)
38 {
39 ANativeWindowBuffer::width = width;
40 ANativeWindowBuffer::height = height;
41 ANativeWindowBuffer::format = format;
42 ANativeWindowBuffer::usage = usage;
43 busy = 0;
44 status = 0;
45 m_alloc = alloc_device;
46
47 if (m_alloc) {
48 status = m_alloc->alloc(m_alloc,
49 width, height, format, usage,
50 &handle, &stride);
51 }
52
53 TRACE("width=%d height=%d stride=%d format=x%x usage=x%x status=%s this=%p",
54 width, height, stride, format, usage, strerror(-status), this);
55 }
56
57
58
59 FbDevNativeWindowBuffer::~FbDevNativeWindowBuffer()
60 {
61 TRACE("%p", this);
62 if (m_alloc && handle)
63 m_alloc->free(m_alloc, handle);
64 }
65
66
67 ////////////////////////////////////////////////////////////////////////////////
68 FbDevNativeWindow::FbDevNativeWindow(gralloc_module_t* gralloc,
69 alloc_device_t* alloc,
70 framebuffer_device_t* fbDev)
71 {
72 m_alloc = alloc;
73 m_fbDev = fbDev;
74 m_bufFormat = m_fbDev->format;
75 m_usage = GRALLOC_USAGE_HW_FB;
76
77 #if ANDROID_VERSION_MAJOR>=4 && ANDROID_VERSION_MINOR>=2
78 if (m_fbDev->numFramebuffers>0)
79 setBufferCount(m_fbDev->numFramebuffers);
80 else
81 setBufferCount(FRAMEBUFFER_PARTITIONS);
82 #else
83 setBufferCount(FRAMEBUFFER_PARTITIONS);
84 #endif
85
86 }
87
88
89
90
91 FbDevNativeWindow::~FbDevNativeWindow()
92 {
93 destroyBuffers();
94 }
95
96
97
98 void FbDevNativeWindow::destroyBuffers()
99 {
100 TRACE("");
101
102 std::list<FbDevNativeWindowBuffer*>::iterator it = m_bufList.begin();
103 for (; it!=m_bufList.end(); ++it)
104 {
105 FbDevNativeWindowBuffer* fbnb = *it;
106 fbnb->common.decRef(&fbnb->common);
107 }
108 m_bufList.clear();
109 m_freeBufs = 0;
110 m_frontBuf = NULL;
111 }
112
113
114
115
116 /*
117 * Set the swap interval for this surface.
118 *
119 * Returns 0 on success or -errno on error.
120 */
121 int FbDevNativeWindow::setSwapInterval(int interval)
122 {
123 TRACE("interval=%i", interval);
124 return m_fbDev->setSwapInterval(m_fbDev, interval);
125 }
126
127
128 /*
129 * Hook called by EGL to acquire a buffer. This call may block if no
130 * buffers are available.
131 *
132 * The window holds a reference to the buffer between dequeueBuffer and
133 * either queueBuffer or cancelBuffer, so clients only need their own
134 * reference if they might use the buffer after queueing or canceling it.
135 * Holding a reference to a buffer after queueing or canceling it is only
136 * allowed if a specific buffer count has been set.
137 *
138 * The libsync fence file descriptor returned in the int pointed to by the
139 * fenceFd argument will refer to the fence that must signal before the
140 * dequeued buffer may be written to. A value of -1 indicates that the
141 * caller may access the buffer immediately without waiting on a fence. If
142 * a valid file descriptor is returned (i.e. any value except -1) then the
143 * caller is responsible for closing the file descriptor.
144 *
145 * Returns 0 on success or -errno on error.
146 */
147 int FbDevNativeWindow::dequeueBuffer(BaseNativeWindowBuffer** buffer, int *fenceFd)
148 {
149 HYBRIS_TRACE_BEGIN("fbdev-platform", "dequeueBuffer", "");
150 FbDevNativeWindowBuffer* fbnb=NULL;
151
152 pthread_mutex_lock(&_mutex);
153
154 HYBRIS_TRACE_BEGIN("fbdev-platform", "dequeueBuffer-wait", "");
155 #if defined(DEBUG)
156
157 if (m_frontBuf)
158 TRACE("Status: Has front buf %p", m_frontBuf);
159
160 std::list<FbDevNativeWindowBuffer*>::iterator cit = m_bufList.begin();
161 for (; cit != m_bufList.end(); ++cit)
162 {
163 TRACE("Status: Buffer %p with busy %i\n", (*cit), (*cit)->busy);
164 }
165 #endif
166
167 while (m_freeBufs==0)
168 {
169 pthread_cond_wait(&_cond, &_mutex);
170 }
171
172 while (1)
173 {
174 std::list<FbDevNativeWindowBuffer*>::iterator it = m_bufList.begin();
175 for (; it != m_bufList.end(); ++it)
176 {
177 if (*it==m_frontBuf)
178 continue;
179 if ((*it)->busy==0)
180 {
181 TRACE("Found a free non-front buffer");
182 break;
183 }
184 }
185
186 if (it == m_bufList.end())
187 {
188 #if ANDROID_VERSION_MAJOR<=4 && ANDROID_VERSION_MINOR<2
189 /*
190 * This is acceptable in case you are on a stack that calls lock() before starting to render into buffer
191 * When you are using fences (>= 2) you'll be waiting on the fence to signal instead.
192 *
193 * This optimization allows eglSwapBuffers to return and you can begin to utilize the GPU for rendering.
194 * The actual lock() probably first comes at glFlush/eglSwapBuffers
195 */
196 if (m_frontBuf && m_frontBuf->busy == 0)
197 {
198 TRACE("Used front buffer as buffer");
199 fbnb = m_frontBuf;
200 break;
201 }
202 #endif
203 // have to wait once again
204 pthread_cond_wait(&_cond, &_mutex);
205 continue;
206 }
207
208 fbnb = *it;
209 break;
210 }
211
212 HYBRIS_TRACE_END("fbdev-platform", "dequeueBuffer-wait", "");
213 assert(fbnb!=NULL);
214 fbnb->busy = 1;
215 m_freeBufs--;
216
217 *buffer = fbnb;
218 *fenceFd = -1;
219
220 TRACE("%lu DONE --> %p", pthread_self(), fbnb);
221 pthread_mutex_unlock(&_mutex);
222 HYBRIS_TRACE_END("fbdev-platform", "dequeueBuffer", "");
223 return 0;
224 }
225
226 /*
227 * Hook called by EGL when modifications to the render buffer are done.
228 * This unlocks and post the buffer.
229 *
230 * The window holds a reference to the buffer between dequeueBuffer and
231 * either queueBuffer or cancelBuffer, so clients only need their own
232 * reference if they might use the buffer after queueing or canceling it.
233 * Holding a reference to a buffer after queueing or canceling it is only
234 * allowed if a specific buffer count has been set.
235 *
236 * The fenceFd argument specifies a libsync fence file descriptor for a
237 * fence that must signal before the buffer can be accessed. If the buffer
238 * can be accessed immediately then a value of -1 should be used. The
239 * caller must not use the file descriptor after it is passed to
240 * queueBuffer, and the ANativeWindow implementation is responsible for
241 * closing it.
242 *
243 * Returns 0 on success or -errno on error.
244 */
245 int FbDevNativeWindow::queueBuffer(BaseNativeWindowBuffer* buffer, int fenceFd)
246 {
247
248 FbDevNativeWindowBuffer* fbnb = (FbDevNativeWindowBuffer*) buffer;
249
250 HYBRIS_TRACE_BEGIN("fbdev-platform", "queueBuffer", "-%p", fbnb);
251
252 pthread_mutex_lock(&_mutex);
253
254 assert(fbnb->busy==1);
255
256 fbnb->busy = 2;
257
258 pthread_mutex_unlock(&_mutex);
259
260 HYBRIS_TRACE_BEGIN("fbdev-platform", "queueBuffer-post", "-%p", fbnb);
261
262 int rv = m_fbDev->post(m_fbDev, fbnb->handle);
263 if (rv!=0)
264 {
265 fprintf(stderr,"ERROR: fb->post(%s)\n",strerror(-rv));
266 }
267 HYBRIS_TRACE_END("fbdev-platform", "queueBuffer-post", "-%p", fbnb);
268
269 pthread_mutex_lock(&_mutex);
270
271 fbnb->busy=0;
272 m_frontBuf = fbnb;
273
274 m_freeBufs++;
275
276 TRACE("%lu %p %p",pthread_self(), m_frontBuf, fbnb);
277
278 pthread_cond_signal(&_cond);
279 pthread_mutex_unlock(&_mutex);
280
281 HYBRIS_TRACE_END("fbdev-platform", "queueBuffer", "-%p", fbnb);
282 return rv;
283 }
284
285
286 /*
287 * Hook used to cancel a buffer that has been dequeued.
288 * No synchronization is performed between dequeue() and cancel(), so
289 * either external synchronization is needed, or these functions must be
290 * called from the same thread.
291 *
292 * The window holds a reference to the buffer between dequeueBuffer and
293 * either queueBuffer or cancelBuffer, so clients only need their own
294 * reference if they might use the buffer after queueing or canceling it.
295 * Holding a reference to a buffer after queueing or canceling it is only
296 * allowed if a specific buffer count has been set.
297 *
298 * The fenceFd argument specifies a libsync fence file decsriptor for a
299 * fence that must signal before the buffer can be accessed. If the buffer
300 * can be accessed immediately then a value of -1 should be used.
301 *
302 * Note that if the client has not waited on the fence that was returned
303 * from dequeueBuffer, that same fence should be passed to cancelBuffer to
304 * ensure that future uses of the buffer are preceded by a wait on that
305 * fence. The caller must not use the file descriptor after it is passed
306 * to cancelBuffer, and the ANativeWindow implementation is responsible for
307 * closing it.
308 *
309 * Returns 0 on success or -errno on error.
310 */
311 int FbDevNativeWindow::cancelBuffer(BaseNativeWindowBuffer* buffer, int fenceFd)
312 {
313 TRACE("");
314 FbDevNativeWindowBuffer* fbnb = (FbDevNativeWindowBuffer*)buffer;
315
316 pthread_mutex_lock(&_mutex);
317
318 fbnb->busy=0;
319
320 m_freeBufs++;
321
322 pthread_cond_signal(&_cond);
323 pthread_mutex_unlock(&_mutex);
324
325 return 0;
326 }
327
328
329
330 int FbDevNativeWindow::lockBuffer(BaseNativeWindowBuffer* buffer)
331 {
332
333 FbDevNativeWindowBuffer* fbnb = (FbDevNativeWindowBuffer*)buffer;
334
335 HYBRIS_TRACE_BEGIN("fbdev-platform", "lockBuffer", "-%p", fbnb);
336
337 pthread_mutex_lock(&_mutex);
338
339 // wait that the buffer we're locking is not front anymore
340 while (m_frontBuf==fbnb)
341 {
342 TRACE("waiting %p %p", m_frontBuf, fbnb);
343 pthread_cond_wait(&_cond, &_mutex);
344 }
345
346 pthread_mutex_unlock(&_mutex);
347 HYBRIS_TRACE_END("fbdev-platform", "lockBuffer", "-%p", fbnb);
348 return NO_ERROR;
349 }
350
351
352 /*
353 * see NATIVE_WINDOW_FORMAT
354 */
355 unsigned int FbDevNativeWindow::width() const
356 {
357 unsigned int rv = m_fbDev->width;
358 TRACE("width=%i", rv);
359 return rv;
360 }
361
362
363 /*
364 * see NATIVE_WINDOW_HEIGHT
365 */
366 unsigned int FbDevNativeWindow::height() const
367 {
368 unsigned int rv = m_fbDev->height;
369 TRACE("height=%i", rv);
370 return rv;
371 }
372
373
374 /*
375 * see NATIVE_WINDOW_FORMAT
376 */
377 unsigned int FbDevNativeWindow::format() const
378 {
379 unsigned int rv = m_fbDev->format;
380 TRACE("format=x%x", rv);
381 return rv;
382 }
383
384
385 /*
386 * Default width and height of ANativeWindow buffers, these are the
387 * dimensions of the window buffers irrespective of the
388 * NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS call and match the native window
389 * size unless overridden by NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS.
390 */
391 /*
392 * see NATIVE_WINDOW_DEFAULT_HEIGHT
393 */
394 unsigned int FbDevNativeWindow::defaultHeight() const
395 {
396 unsigned int rv = m_fbDev->height;
397 TRACE("height=%i", rv);
398 return rv;
399 }
400
401
402 /*
403 * see BaseNativeWindow::_query(NATIVE_WINDOW_DEFAULT_WIDTH)
404 */
405 unsigned int FbDevNativeWindow::defaultWidth() const
406 {
407 unsigned int rv = m_fbDev->width;
408 TRACE("width=%i", rv);
409 return rv;
410 }
411
412
413 /*
414 * see NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER
415 */
416 unsigned int FbDevNativeWindow::queueLength() const
417 {
418 TRACE("");
419 return 0;
420 }
421
422
423 /*
424 * see NATIVE_WINDOW_CONCRETE_TYPE
425 */
426 unsigned int FbDevNativeWindow::type() const
427 {
428 TRACE("");
429 return NATIVE_WINDOW_FRAMEBUFFER;
430 }
431
432
433 /*
434 * see NATIVE_WINDOW_TRANSFORM_HINT
435 */
436 unsigned int FbDevNativeWindow::transformHint() const
437 {
438 TRACE("");
439 return 0;
440 }
441
442
443
444 /*
445 * native_window_set_usage(..., usage)
446 * Sets the intended usage flags for the next buffers
447 * acquired with (*lockBuffer)() and on.
448 * By default (if this function is never called), a usage of
449 * GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE
450 * is assumed.
451 * Calling this function will usually cause following buffers to be
452 * reallocated.
453 */
454 int FbDevNativeWindow::setUsage(int usage)
455 {
456 int need_realloc = (m_usage != usage);
457 TRACE("usage=x%x realloc=%d", usage, need_realloc);
458 m_usage = usage;
459 if (need_realloc)
460 this->setBufferCount(m_bufList.size());
461
462 return NO_ERROR;
463 }
464
465
466 /*
467 * native_window_set_buffers_format(..., int format)
468 * All buffers dequeued after this call will have the format specified.
469 *
470 * If the specified format is 0, the default buffer format will be used.
471 */
472 int FbDevNativeWindow::setBuffersFormat(int format)
473 {
474 int need_realloc = (format != m_bufFormat);
475 TRACE("format=x%x realloc=%d", format, need_realloc);
476 m_bufFormat = format;
477 if (need_realloc)
478 this->setBufferCount(m_bufList.size());
479 return NO_ERROR;
480 }
481
482
483 /*
484 * native_window_set_buffer_count(..., count)
485 * Sets the number of buffers associated with this native window.
486 */
487 int FbDevNativeWindow::setBufferCount(int cnt)
488 {
489 TRACE("cnt=%d", cnt);
490 int err=NO_ERROR;
491 pthread_mutex_lock(&_mutex);
492
493 destroyBuffers();
494
495 for(unsigned int i = 0; i < cnt; i++)
496 {
497 FbDevNativeWindowBuffer *fbnb = new FbDevNativeWindowBuffer(m_alloc,
498 m_fbDev->width, m_fbDev->height, m_fbDev->format,
499 m_usage|GRALLOC_USAGE_HW_FB );
500
501 fbnb->common.incRef(&fbnb->common);
502
503 TRACE("buffer %i is at %p (native %p) err=%s handle=%p stride=%i",
504 i, fbnb, (ANativeWindowBuffer*)fbnb,
505 strerror(-fbnb->status), fbnb->handle, fbnb->stride);
506
507 if (fbnb->status)
508 {
509 fbnb->common.decRef(&fbnb->common);
510 fprintf(stderr,"WARNING: %s: allocated only %d buffers out of %d\n", __PRETTY_FUNCTION__, m_freeBufs, cnt);
511 break;
512 }
513
514 m_freeBufs++;
515 m_bufList.push_back(fbnb);
516 }
517 pthread_mutex_unlock(&_mutex);
518
519 return err;
520 }
521
522 /*
523 * native_window_set_buffers_dimensions(..., int w, int h)
524 * All buffers dequeued after this call will have the dimensions specified.
525 * In particular, all buffers will have a fixed-size, independent from the
526 * native-window size. They will be scaled according to the scaling mode
527 * (see native_window_set_scaling_mode) upon window composition.
528 *
529 * If w and h are 0, the normal behavior is restored. That is, dequeued buffers
530 * following this call will be sized to match the window's size.
531 *
532 * Calling this function will reset the window crop to a NULL value, which
533 * disables cropping of the buffers.
534 */
535 int FbDevNativeWindow::setBuffersDimensions(int width, int height)
536 {
537 TRACE("WARN: stub. size=%ix%i", width, height);
538 return NO_ERROR;
539 }
540 // vim: noai:ts=4:sw=4:ss=4:expandtab