Commit | Line | Data |
---|---|---|
d42e7319 JB |
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 |