blob: b6b4a8f417df6b7e9dab1b391a8a1e7d8af0086b [file] [log] [blame]
Iliyan Malchev202a77d2012-06-11 14:41:12 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3* Copyright (c) 2010-2012 Code Aurora Forum. All rights reserved.
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#include <sys/mman.h>
19
20#include <dlfcn.h>
21
22#include <cutils/ashmem.h>
23#include <cutils/log.h>
24#include <cutils/properties.h>
25#include <utils/Timers.h>
26
27#include <hardware/hardware.h>
28#include <hardware/gralloc.h>
29
30#include <fcntl.h>
31#include <errno.h>
32#include <sys/ioctl.h>
33#include <string.h>
34#include <stdlib.h>
35#include <pthread.h>
36#include <utils/Timers.h>
37
38#include <cutils/log.h>
39#include <cutils/atomic.h>
40
41#include <linux/fb.h>
42#include <linux/msm_mdp.h>
43
44#include <GLES/gl.h>
45
46#include "gralloc_priv.h"
47#include "gr.h"
48#ifdef NO_SURFACEFLINGER_SWAPINTERVAL
49#include <cutils/properties.h>
50#endif
51
52#include <qcom_ui.h>
53
54#define FB_DEBUG 0
55
56#if defined(HDMI_DUAL_DISPLAY)
57#define EVEN_OUT(x) if (x & 0x0001) {x--;}
58using overlay::Overlay;
59/** min of int a, b */
60static inline int min(int a, int b) {
61 return (a<b) ? a : b;
62}
63/** max of int a, b */
64static inline int max(int a, int b) {
65 return (a>b) ? a : b;
66}
67#endif
68
69char framebufferStateName[] = {'S', 'R', 'A'};
70
71/*****************************************************************************/
72
73enum {
74 MDDI_PANEL = '1',
75 EBI2_PANEL = '2',
76 LCDC_PANEL = '3',
77 EXT_MDDI_PANEL = '4',
78 TV_PANEL = '5'
79};
80
81enum {
82 PAGE_FLIP = 0x00000001,
83 LOCKED = 0x00000002
84};
85
86struct fb_context_t {
87 framebuffer_device_t device;
88};
89
90static int neworientation;
91
92/*****************************************************************************/
93
94static void
95msm_copy_buffer(buffer_handle_t handle, int fd,
96 int width, int height, int format,
97 int x, int y, int w, int h);
98
99static int fb_setSwapInterval(struct framebuffer_device_t* dev,
100 int interval)
101{
102 char pval[PROPERTY_VALUE_MAX];
103 property_get("debug.gr.swapinterval", pval, "-1");
104 int property_interval = atoi(pval);
105 if (property_interval >= 0)
106 interval = property_interval;
107
108 fb_context_t* ctx = (fb_context_t*)dev;
109 private_module_t* m = reinterpret_cast<private_module_t*>(
110 dev->common.module);
111 if (interval < dev->minSwapInterval || interval > dev->maxSwapInterval)
112 return -EINVAL;
113
114 m->swapInterval = interval;
115 return 0;
116}
117
118static int fb_setUpdateRect(struct framebuffer_device_t* dev,
119 int l, int t, int w, int h)
120{
121 if (((w|h) <= 0) || ((l|t)<0))
122 return -EINVAL;
123 fb_context_t* ctx = (fb_context_t*)dev;
124 private_module_t* m = reinterpret_cast<private_module_t*>(
125 dev->common.module);
126 m->info.reserved[0] = 0x54445055; // "UPDT";
127 m->info.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
128 m->info.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
129 return 0;
130}
131
132static void *disp_loop(void *ptr)
133{
134 struct qbuf_t nxtBuf;
135 static int cur_buf=-1;
136 private_module_t *m = reinterpret_cast<private_module_t*>(ptr);
137
138 while (1) {
139 pthread_mutex_lock(&(m->qlock));
140
141 // wait (sleep) while display queue is empty;
142 if (m->disp.isEmpty()) {
143 pthread_cond_wait(&(m->qpost),&(m->qlock));
144 }
145
146 // dequeue next buff to display and lock it
147 nxtBuf = m->disp.getHeadValue();
148 m->disp.pop();
149 pthread_mutex_unlock(&(m->qlock));
150
151 // post buf out to display synchronously
152 private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>
153 (nxtBuf.buf);
154 const size_t offset = hnd->base - m->framebuffer->base;
155 m->info.activate = FB_ACTIVATE_VBL;
156 m->info.yoffset = offset / m->finfo.line_length;
157
158#if defined(HDMI_DUAL_DISPLAY)
159 pthread_mutex_lock(&m->overlayLock);
160 m->orientation = neworientation;
161 m->currentOffset = offset;
162 m->hdmiStateChanged = true;
163 pthread_cond_signal(&(m->overlayPost));
164 pthread_mutex_unlock(&m->overlayLock);
165#endif
166 if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) {
167 ALOGE("ERROR FBIOPUT_VSCREENINFO failed; frame not displayed");
168 }
169
170 CALC_FPS();
171
172 if (cur_buf == -1) {
173 int nxtAvail = ((nxtBuf.idx + 1) % m->numBuffers);
174 pthread_mutex_lock(&(m->avail[nxtBuf.idx].lock));
175 m->avail[nxtBuf.idx].is_avail = true;
176 m->avail[nxtBuf.idx].state = REF;
177 pthread_cond_broadcast(&(m->avail[nxtBuf.idx].cond));
178 pthread_mutex_unlock(&(m->avail[nxtBuf.idx].lock));
179 } else {
180 pthread_mutex_lock(&(m->avail[nxtBuf.idx].lock));
181 if (m->avail[nxtBuf.idx].state != SUB) {
182 ALOGE_IF(m->swapInterval != 0, "[%d] state %c, expected %c", nxtBuf.idx,
183 framebufferStateName[m->avail[nxtBuf.idx].state],
184 framebufferStateName[SUB]);
185 }
186 m->avail[nxtBuf.idx].state = REF;
187 pthread_mutex_unlock(&(m->avail[nxtBuf.idx].lock));
188
189 pthread_mutex_lock(&(m->avail[cur_buf].lock));
190 m->avail[cur_buf].is_avail = true;
191 if (m->avail[cur_buf].state != REF) {
192 ALOGE_IF(m->swapInterval != 0, "[%d] state %c, expected %c", cur_buf,
193 framebufferStateName[m->avail[cur_buf].state],
194 framebufferStateName[REF]);
195 }
196 m->avail[cur_buf].state = AVL;
197 pthread_cond_broadcast(&(m->avail[cur_buf].cond));
198 pthread_mutex_unlock(&(m->avail[cur_buf].lock));
199 }
200 cur_buf = nxtBuf.idx;
201 }
202 return NULL;
203}
204
205#if defined(HDMI_DUAL_DISPLAY)
206static int closeHDMIChannel(private_module_t* m)
207{
208 Overlay* pTemp = m->pobjOverlay;
209 if(pTemp != NULL)
210 pTemp->closeChannel();
211 return 0;
212}
213
214static void getSecondaryDisplayDestinationInfo(private_module_t* m, overlay_rect&
215 rect, int& orientation)
216{
217 Overlay* pTemp = m->pobjOverlay;
218 int width = pTemp->getFBWidth();
219 int height = pTemp->getFBHeight();
220 int fbwidth = m->info.xres, fbheight = m->info.yres;
221 rect.x = 0; rect.y = 0;
222 rect.w = width; rect.h = height;
223 int rot = m->orientation;
224 switch(rot) {
225 // ROT_0
226 case 0:
227 // ROT_180
228 case HAL_TRANSFORM_ROT_180:
229 pTemp->getAspectRatioPosition(fbwidth, fbheight,
230 &rect);
231 if(rot == HAL_TRANSFORM_ROT_180)
232 orientation = HAL_TRANSFORM_ROT_180;
233 else
234 orientation = 0;
235 break;
236 // ROT_90
237 case HAL_TRANSFORM_ROT_90:
238 // ROT_270
239 case HAL_TRANSFORM_ROT_270:
240 //Calculate the Aspectratio for the UI
241 //in the landscape mode
242 //Width and height will be swapped as there
243 //is rotation
244 pTemp->getAspectRatioPosition(fbheight, fbwidth,
245 &rect);
246
247 if(rot == HAL_TRANSFORM_ROT_90)
248 orientation = HAL_TRANSFORM_ROT_270;
249 else if(rot == HAL_TRANSFORM_ROT_270)
250 orientation = HAL_TRANSFORM_ROT_90;
251 break;
252 }
253 return;
254}
255
256static void *hdmi_ui_loop(void *ptr)
257{
258 private_module_t* m = reinterpret_cast<private_module_t*>(
259 ptr);
260 while (1) {
261 pthread_mutex_lock(&m->overlayLock);
262 while(!(m->hdmiStateChanged))
263 pthread_cond_wait(&(m->overlayPost), &(m->overlayLock));
264 m->hdmiStateChanged = false;
265 if (m->exitHDMIUILoop) {
266 pthread_mutex_unlock(&m->overlayLock);
267 return NULL;
268 }
269 bool waitForVsync = true;
270 int flags = WAIT_FOR_VSYNC;
271 if (m->pobjOverlay) {
272 Overlay* pTemp = m->pobjOverlay;
273 if (m->hdmiMirroringState == HDMI_NO_MIRRORING)
274 closeHDMIChannel(m);
275 else if(m->hdmiMirroringState == HDMI_UI_MIRRORING) {
276 if (!pTemp->isChannelUP()) {
277 int alignedW = ALIGN(m->info.xres, 32);
278
279 private_handle_t const* hnd =
280 reinterpret_cast<private_handle_t const*>(m->framebuffer);
281 overlay_buffer_info info;
282 info.width = alignedW;
283 info.height = hnd->height;
284 info.format = hnd->format;
285 info.size = hnd->size;
286
287 if (m->trueMirrorSupport)
288 flags &= ~WAIT_FOR_VSYNC;
289 // start the overlay Channel for mirroring
290 // m->enableHDMIOutput corresponds to the fbnum
291 if (pTemp->startChannel(info, m->enableHDMIOutput,
292 false, true, 0, VG0_PIPE, flags)) {
293 pTemp->setFd(m->framebuffer->fd);
294 pTemp->setCrop(0, 0, m->info.xres, m->info.yres);
295 } else
296 closeHDMIChannel(m);
297 }
298
299 if (pTemp->isChannelUP()) {
300 overlay_rect destRect;
301 int rot = 0;
302 int currOrientation = 0;
303 getSecondaryDisplayDestinationInfo(m, destRect, rot);
304 pTemp->getOrientation(currOrientation);
305 if(rot != currOrientation) {
306 pTemp->setTransform(rot);
307 }
308 EVEN_OUT(destRect.x);
309 EVEN_OUT(destRect.y);
310 EVEN_OUT(destRect.w);
311 EVEN_OUT(destRect.h);
312 int currentX = 0, currentY = 0;
313 uint32_t currentW = 0, currentH = 0;
314 if (pTemp->getPosition(currentX, currentY, currentW, currentH)) {
315 if ((currentX != destRect.x) || (currentY != destRect.y) ||
316 (currentW != destRect.w) || (currentH != destRect.h)) {
317 pTemp->setPosition(destRect.x, destRect.y, destRect.w,
318 destRect.h);
319 }
320 }
321 if (m->trueMirrorSupport) {
322 // if video is started the UI channel should be NO_WAIT.
323 flags = !m->videoOverlay ? WAIT_FOR_VSYNC : 0;
324 pTemp->updateOverlayFlags(flags);
325 }
326 pTemp->queueBuffer(m->currentOffset);
327 }
328 }
329 else
330 closeHDMIChannel(m);
331 }
332 pthread_mutex_unlock(&m->overlayLock);
333 }
334 return NULL;
335}
336
337static int fb_videoOverlayStarted(struct framebuffer_device_t* dev, int started)
338{
339 private_module_t* m = reinterpret_cast<private_module_t*>(
340 dev->common.module);
341 pthread_mutex_lock(&m->overlayLock);
342 Overlay* pTemp = m->pobjOverlay;
343 if(started != m->videoOverlay) {
344 m->videoOverlay = started;
345 if (!m->trueMirrorSupport) {
346 m->hdmiStateChanged = true;
347 if (started && pTemp) {
348 m->hdmiMirroringState = HDMI_NO_MIRRORING;
349 closeHDMIChannel(m);
350 } else if (m->enableHDMIOutput)
351 m->hdmiMirroringState = HDMI_UI_MIRRORING;
352 pthread_cond_signal(&(m->overlayPost));
353 }
354 }
355 pthread_mutex_unlock(&m->overlayLock);
356 return 0;
357}
358
359static int fb_enableHDMIOutput(struct framebuffer_device_t* dev, int externaltype)
360{
361 private_module_t* m = reinterpret_cast<private_module_t*>(
362 dev->common.module);
363 pthread_mutex_lock(&m->overlayLock);
364 Overlay* pTemp = m->pobjOverlay;
365 //Check if true mirroring can be supported
366 m->trueMirrorSupport = FrameBufferInfo::getInstance()->canSupportTrueMirroring();
367 m->enableHDMIOutput = externaltype;
368 ALOGE("In fb_enableHDMIOutput: externaltype = %d", m->enableHDMIOutput);
369 if(externaltype) {
370 if (m->trueMirrorSupport) {
371 m->hdmiMirroringState = HDMI_UI_MIRRORING;
372 } else {
373 if(!m->videoOverlay)
374 m->hdmiMirroringState = HDMI_UI_MIRRORING;
375 }
376 } else if (!externaltype && pTemp) {
377 m->hdmiMirroringState = HDMI_NO_MIRRORING;
378 closeHDMIChannel(m);
379 }
380 m->hdmiStateChanged = true;
381 pthread_cond_signal(&(m->overlayPost));
382 pthread_mutex_unlock(&m->overlayLock);
383 return 0;
384}
385
386
387static int fb_setActionSafeWidthRatio(struct framebuffer_device_t* dev, float asWidthRatio)
388{
389 private_module_t* m = reinterpret_cast<private_module_t*>(
390 dev->common.module);
391 pthread_mutex_lock(&m->overlayLock);
392 m->actionsafeWidthRatio = asWidthRatio;
393 pthread_mutex_unlock(&m->overlayLock);
394 return 0;
395}
396
397static int fb_setActionSafeHeightRatio(struct framebuffer_device_t* dev, float asHeightRatio)
398{
399 private_module_t* m = reinterpret_cast<private_module_t*>(
400 dev->common.module);
401 pthread_mutex_lock(&m->overlayLock);
402 m->actionsafeHeightRatio = asHeightRatio;
403 pthread_mutex_unlock(&m->overlayLock);
404 return 0;
405}
406
407static int fb_orientationChanged(struct framebuffer_device_t* dev, int orientation)
408{
409 private_module_t* m = reinterpret_cast<private_module_t*>(
410 dev->common.module);
411 pthread_mutex_lock(&m->overlayLock);
412 neworientation = orientation;
413 pthread_mutex_unlock(&m->overlayLock);
414 return 0;
415}
416#endif
417
418static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
419{
420 if (private_handle_t::validate(buffer) < 0)
421 return -EINVAL;
422
423 int nxtIdx, futureIdx = -1;
424 bool reuse;
425 struct qbuf_t qb;
426 fb_context_t* ctx = (fb_context_t*)dev;
427
428 private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer);
429 private_module_t* m = reinterpret_cast<private_module_t*>(
430 dev->common.module);
431
432 if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
433
434 reuse = false;
435 nxtIdx = (m->currentIdx + 1) % m->numBuffers;
436 futureIdx = (nxtIdx + 1) % m->numBuffers;
437
438 if (m->swapInterval == 0) {
439 // if SwapInterval = 0 and no buffers available then reuse
440 // current buf for next rendering so don't post new buffer
441 if (pthread_mutex_trylock(&(m->avail[nxtIdx].lock))) {
442 reuse = true;
443 } else {
444 if (! m->avail[nxtIdx].is_avail)
445 reuse = true;
446 pthread_mutex_unlock(&(m->avail[nxtIdx].lock));
447 }
448 }
449
450 if(!reuse){
451 // unlock previous ("current") Buffer and lock the new buffer
452 m->base.lock(&m->base, buffer,
453 private_module_t::PRIV_USAGE_LOCKED_FOR_POST,
454 0,0, m->info.xres, m->info.yres, NULL);
455
456 // post/queue the new buffer
457 pthread_mutex_lock(&(m->avail[nxtIdx].lock));
458 if (m->avail[nxtIdx].is_avail != true) {
459 ALOGE_IF(m->swapInterval != 0, "Found %d buf to be not avail", nxtIdx);
460 }
461
462 m->avail[nxtIdx].is_avail = false;
463
464 if (m->avail[nxtIdx].state != AVL) {
465 ALOGD("[%d] state %c, expected %c", nxtIdx,
466 framebufferStateName[m->avail[nxtIdx].state],
467 framebufferStateName[AVL]);
468 }
469
470 m->avail[nxtIdx].state = SUB;
471 pthread_mutex_unlock(&(m->avail[nxtIdx].lock));
472
473 qb.idx = nxtIdx;
474 qb.buf = buffer;
475 pthread_mutex_lock(&(m->qlock));
476 m->disp.push(qb);
477 pthread_cond_signal(&(m->qpost));
478 pthread_mutex_unlock(&(m->qlock));
479
480 if (m->currentBuffer)
481 m->base.unlock(&m->base, m->currentBuffer);
482
483 m->currentBuffer = buffer;
484 m->currentIdx = nxtIdx;
485 } else {
486 if (m->currentBuffer)
487 m->base.unlock(&m->base, m->currentBuffer);
488 m->base.lock(&m->base, buffer,
489 private_module_t::PRIV_USAGE_LOCKED_FOR_POST,
490 0,0, m->info.xres, m->info.yres, NULL);
491 m->currentBuffer = buffer;
492 }
493
494 } else {
495 void* fb_vaddr;
496 void* buffer_vaddr;
497 m->base.lock(&m->base, m->framebuffer,
498 GRALLOC_USAGE_SW_WRITE_RARELY,
499 0, 0, m->info.xres, m->info.yres,
500 &fb_vaddr);
501
502 m->base.lock(&m->base, buffer,
503 GRALLOC_USAGE_SW_READ_RARELY,
504 0, 0, m->info.xres, m->info.yres,
505 &buffer_vaddr);
506
507 //memcpy(fb_vaddr, buffer_vaddr, m->finfo.line_length * m->info.yres);
508
509 msm_copy_buffer(
510 m->framebuffer, m->framebuffer->fd,
511 m->info.xres, m->info.yres, m->fbFormat,
512 m->info.xoffset, m->info.yoffset,
513 m->info.width, m->info.height);
514
515 m->base.unlock(&m->base, buffer);
516 m->base.unlock(&m->base, m->framebuffer);
517 }
518
519 ALOGD_IF(FB_DEBUG, "Framebuffer state: [0] = %c [1] = %c [2] = %c",
520 framebufferStateName[m->avail[0].state],
521 framebufferStateName[m->avail[1].state],
522 framebufferStateName[m->avail[2].state]);
523 return 0;
524}
525
526static int fb_compositionComplete(struct framebuffer_device_t* dev)
527{
528 // TODO: Properly implement composition complete callback
529 glFinish();
530
531 return 0;
532}
533
534static int fb_lockBuffer(struct framebuffer_device_t* dev, int index)
535{
536 private_module_t* m = reinterpret_cast<private_module_t*>(
537 dev->common.module);
538
539 // Return immediately if the buffer is available
540 if ((m->avail[index].state == AVL) || (m->swapInterval == 0))
541 return 0;
542
543 pthread_mutex_lock(&(m->avail[index].lock));
544 while (m->avail[index].state != AVL) {
545 pthread_cond_wait(&(m->avail[index].cond),
546 &(m->avail[index].lock));
547 }
548 pthread_mutex_unlock(&(m->avail[index].lock));
549
550 return 0;
551}
552
553/*****************************************************************************/
554
555int mapFrameBufferLocked(struct private_module_t* module)
556{
557 // already initialized...
558 if (module->framebuffer) {
559 return 0;
560 }
561 char const * const device_template[] = {
562 "/dev/graphics/fb%u",
563 "/dev/fb%u",
564 0 };
565
566 int fd = -1;
567 int i=0;
568 char name[64];
569 char property[PROPERTY_VALUE_MAX];
570
571 while ((fd==-1) && device_template[i]) {
572 snprintf(name, 64, device_template[i], 0);
573 fd = open(name, O_RDWR, 0);
574 i++;
575 }
576 if (fd < 0)
577 return -errno;
578
579 struct fb_fix_screeninfo finfo;
580 if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
581 return -errno;
582
583 struct fb_var_screeninfo info;
584 if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
585 return -errno;
586
587 info.reserved[0] = 0;
588 info.reserved[1] = 0;
589 info.reserved[2] = 0;
590 info.xoffset = 0;
591 info.yoffset = 0;
592 info.activate = FB_ACTIVATE_NOW;
593
594 /* Interpretation of offset for color fields: All offsets are from the right,
595 * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you
596 * can use the offset as right argument to <<). A pixel afterwards is a bit
597 * stream and is written to video memory as that unmodified. This implies
598 * big-endian byte order if bits_per_pixel is greater than 8.
599 */
600
601 if(info.bits_per_pixel == 32) {
602 /*
603 * Explicitly request RGBA_8888
604 */
605 info.bits_per_pixel = 32;
606 info.red.offset = 24;
607 info.red.length = 8;
608 info.green.offset = 16;
609 info.green.length = 8;
610 info.blue.offset = 8;
611 info.blue.length = 8;
612 info.transp.offset = 0;
613 info.transp.length = 8;
614
615 /* Note: the GL driver does not have a r=8 g=8 b=8 a=0 config, so if we do
616 * not use the MDP for composition (i.e. hw composition == 0), ask for
617 * RGBA instead of RGBX. */
618 if (property_get("debug.sf.hw", property, NULL) > 0 && atoi(property) == 0)
619 module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888;
620 else if(property_get("debug.composition.type", property, NULL) > 0 && (strncmp(property, "mdp", 3) == 0))
621 module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888;
622 else
623 module->fbFormat = HAL_PIXEL_FORMAT_RGBA_8888;
624 } else {
625 /*
626 * Explicitly request 5/6/5
627 */
628 info.bits_per_pixel = 16;
629 info.red.offset = 11;
630 info.red.length = 5;
631 info.green.offset = 5;
632 info.green.length = 6;
633 info.blue.offset = 0;
634 info.blue.length = 5;
635 info.transp.offset = 0;
636 info.transp.length = 0;
637 module->fbFormat = HAL_PIXEL_FORMAT_RGB_565;
638 }
639
640 //adreno needs 4k aligned offsets. Max hole size is 4096-1
641 int size = roundUpToPageSize(info.yres * info.xres * (info.bits_per_pixel/8));
642
643 /*
644 * Request NUM_BUFFERS screens (at lest 2 for page flipping)
645 */
646 int numberOfBuffers = (int)(finfo.smem_len/size);
647 ALOGV("num supported framebuffers in kernel = %d", numberOfBuffers);
648
649 if (property_get("debug.gr.numframebuffers", property, NULL) > 0) {
650 int num = atoi(property);
651 if ((num >= NUM_FRAMEBUFFERS_MIN) && (num <= NUM_FRAMEBUFFERS_MAX)) {
652 numberOfBuffers = num;
653 }
654 }
655 if (numberOfBuffers > NUM_FRAMEBUFFERS_MAX)
656 numberOfBuffers = NUM_FRAMEBUFFERS_MAX;
657
658 ALOGV("We support %d buffers", numberOfBuffers);
659
660 //consider the included hole by 4k alignment
661 uint32_t line_length = (info.xres * info.bits_per_pixel / 8);
662 info.yres_virtual = (size * numberOfBuffers) / line_length;
663
664 uint32_t flags = PAGE_FLIP;
665 if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
666 info.yres_virtual = size / line_length;
667 flags &= ~PAGE_FLIP;
668 ALOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
669 }
670
671 if (info.yres_virtual < ((size * 2) / line_length) ) {
672 // we need at least 2 for page-flipping
673 info.yres_virtual = size / line_length;
674 flags &= ~PAGE_FLIP;
675 ALOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
676 info.yres_virtual, info.yres*2);
677 }
678
679 if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
680 return -errno;
681
682 if (int(info.width) <= 0 || int(info.height) <= 0) {
683 // the driver doesn't return that information
684 // default to 160 dpi
685 info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
686 info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
687 }
688
689 float xdpi = (info.xres * 25.4f) / info.width;
690 float ydpi = (info.yres * 25.4f) / info.height;
691 //The reserved[4] field is used to store FPS by the driver.
692 float fps = info.reserved[4];
693
694 ALOGI( "using (fd=%d)\n"
695 "id = %s\n"
696 "xres = %d px\n"
697 "yres = %d px\n"
698 "xres_virtual = %d px\n"
699 "yres_virtual = %d px\n"
700 "bpp = %d\n"
701 "r = %2u:%u\n"
702 "g = %2u:%u\n"
703 "b = %2u:%u\n",
704 fd,
705 finfo.id,
706 info.xres,
707 info.yres,
708 info.xres_virtual,
709 info.yres_virtual,
710 info.bits_per_pixel,
711 info.red.offset, info.red.length,
712 info.green.offset, info.green.length,
713 info.blue.offset, info.blue.length
714 );
715
716 ALOGI( "width = %d mm (%f dpi)\n"
717 "height = %d mm (%f dpi)\n"
718 "refresh rate = %.2f Hz\n",
719 info.width, xdpi,
720 info.height, ydpi,
721 fps
722 );
723
724
725 if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
726 return -errno;
727
728 if (finfo.smem_len <= 0)
729 return -errno;
730
731 module->flags = flags;
732 module->info = info;
733 module->finfo = finfo;
734 module->xdpi = xdpi;
735 module->ydpi = ydpi;
736 module->fps = fps;
737
738#ifdef NO_SURFACEFLINGER_SWAPINTERVAL
739 char pval[PROPERTY_VALUE_MAX];
740 property_get("debug.gr.swapinterval", pval, "1");
741 module->swapInterval = atoi(pval);
742 if (module->swapInterval < private_module_t::PRIV_MIN_SWAP_INTERVAL ||
743 module->swapInterval > private_module_t::PRIV_MAX_SWAP_INTERVAL) {
744 module->swapInterval = 1;
745 ALOGW("Out of range (%d to %d) value for debug.gr.swapinterval, using 1",
746 private_module_t::PRIV_MIN_SWAP_INTERVAL,
747 private_module_t::PRIV_MAX_SWAP_INTERVAL);
748 }
749
750#else
751 /* when surfaceflinger supports swapInterval then can just do this */
752 module->swapInterval = 1;
753#endif
754
755 CALC_INIT();
756
757 module->currentIdx = -1;
758 pthread_cond_init(&(module->qpost), NULL);
759 pthread_mutex_init(&(module->qlock), NULL);
760 for (i = 0; i < NUM_FRAMEBUFFERS_MAX; i++) {
761 pthread_mutex_init(&(module->avail[i].lock), NULL);
762 pthread_cond_init(&(module->avail[i].cond), NULL);
763 module->avail[i].is_avail = true;
764 module->avail[i].state = AVL;
765 }
766
767 /* create display update thread */
768 pthread_t thread1;
769 if (pthread_create(&thread1, NULL, &disp_loop, (void *) module)) {
770 return -errno;
771 }
772
773 /*
774 * map the framebuffer
775 */
776
777 int err;
778 module->numBuffers = info.yres_virtual / info.yres;
779 module->bufferMask = 0;
780 //adreno needs page aligned offsets. Align the fbsize to pagesize.
781 size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres) * module->numBuffers;
782 module->framebuffer = new private_handle_t(fd, fbSize,
783 private_handle_t::PRIV_FLAGS_USES_PMEM, BUFFER_TYPE_UI,
784 module->fbFormat, info.xres, info.yres);
785 void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
786 if (vaddr == MAP_FAILED) {
787 ALOGE("Error mapping the framebuffer (%s)", strerror(errno));
788 return -errno;
789 }
790 module->framebuffer->base = intptr_t(vaddr);
791 memset(vaddr, 0, fbSize);
792
793#if defined(HDMI_DUAL_DISPLAY)
794 /* Overlay for HDMI*/
795 pthread_mutex_init(&(module->overlayLock), NULL);
796 pthread_cond_init(&(module->overlayPost), NULL);
797 module->pobjOverlay = new Overlay();
798 module->currentOffset = 0;
799 module->exitHDMIUILoop = false;
800 module->hdmiStateChanged = false;
801 pthread_t hdmiUIThread;
802 pthread_create(&hdmiUIThread, NULL, &hdmi_ui_loop, (void *) module);
803 module->hdmiMirroringState = HDMI_NO_MIRRORING;
804 module->trueMirrorSupport = false;
805#endif
806
807 return 0;
808}
809
810static int mapFrameBuffer(struct private_module_t* module)
811{
812 pthread_mutex_lock(&module->lock);
813 int err = mapFrameBufferLocked(module);
814 pthread_mutex_unlock(&module->lock);
815 return err;
816}
817
818/*****************************************************************************/
819
820static int fb_close(struct hw_device_t *dev)
821{
822 fb_context_t* ctx = (fb_context_t*)dev;
823#if defined(HDMI_DUAL_DISPLAY)
824 private_module_t* m = reinterpret_cast<private_module_t*>(
825 ctx->device.common.module);
826 pthread_mutex_lock(&m->overlayLock);
827 m->exitHDMIUILoop = true;
828 pthread_cond_signal(&(m->overlayPost));
829 pthread_mutex_unlock(&m->overlayLock);
830#endif
831 if (ctx) {
832 free(ctx);
833 }
834 return 0;
835}
836
837int fb_device_open(hw_module_t const* module, const char* name,
838 hw_device_t** device)
839{
840 int status = -EINVAL;
841 if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
842 alloc_device_t* gralloc_device;
843 status = gralloc_open(module, &gralloc_device);
844 if (status < 0)
845 return status;
846
847 /* initialize our state here */
848 fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
849 memset(dev, 0, sizeof(*dev));
850
851 /* initialize the procs */
852 dev->device.common.tag = HARDWARE_DEVICE_TAG;
853 dev->device.common.version = 0;
854 dev->device.common.module = const_cast<hw_module_t*>(module);
855 dev->device.common.close = fb_close;
856 dev->device.setSwapInterval = fb_setSwapInterval;
857 dev->device.post = fb_post;
858 dev->device.setUpdateRect = 0;
859 dev->device.compositionComplete = fb_compositionComplete;
860 //dev->device.lockBuffer = fb_lockBuffer;
861#if defined(HDMI_DUAL_DISPLAY)
862 dev->device.orientationChanged = fb_orientationChanged;
863 dev->device.videoOverlayStarted = fb_videoOverlayStarted;
864 dev->device.enableHDMIOutput = fb_enableHDMIOutput;
865 dev->device.setActionSafeWidthRatio = fb_setActionSafeWidthRatio;
866 dev->device.setActionSafeHeightRatio = fb_setActionSafeHeightRatio;
867#endif
868
869 private_module_t* m = (private_module_t*)module;
870 status = mapFrameBuffer(m);
871 if (status >= 0) {
872 int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
873 const_cast<uint32_t&>(dev->device.flags) = 0;
874 const_cast<uint32_t&>(dev->device.width) = m->info.xres;
875 const_cast<uint32_t&>(dev->device.height) = m->info.yres;
876 const_cast<int&>(dev->device.stride) = stride;
877 const_cast<int&>(dev->device.format) = m->fbFormat;
878 const_cast<float&>(dev->device.xdpi) = m->xdpi;
879 const_cast<float&>(dev->device.ydpi) = m->ydpi;
880 const_cast<float&>(dev->device.fps) = m->fps;
881 const_cast<int&>(dev->device.minSwapInterval) = private_module_t::PRIV_MIN_SWAP_INTERVAL;
882 const_cast<int&>(dev->device.maxSwapInterval) = private_module_t::PRIV_MAX_SWAP_INTERVAL;
883 //const_cast<int&>(dev->device.numFramebuffers) = m->numBuffers;
884 if (m->finfo.reserved[0] == 0x5444 &&
885 m->finfo.reserved[1] == 0x5055) {
886 dev->device.setUpdateRect = fb_setUpdateRect;
887 ALOGD("UPDATE_ON_DEMAND supported");
888 }
889
890 *device = &dev->device.common;
891 }
892
893 // Close the gralloc module
894 gralloc_close(gralloc_device);
895 }
896 return status;
897}
898
899/* Copy a pmem buffer to the framebuffer */
900
901static void
902msm_copy_buffer(buffer_handle_t handle, int fd,
903 int width, int height, int format,
904 int x, int y, int w, int h)
905{
906 struct {
907 unsigned int count;
908 mdp_blit_req req;
909 } blit;
910 private_handle_t *priv = (private_handle_t*) handle;
911
912 memset(&blit, 0, sizeof(blit));
913 blit.count = 1;
914
915 blit.req.flags = 0;
916 blit.req.alpha = 0xff;
917 blit.req.transp_mask = 0xffffffff;
918
919 blit.req.src.width = width;
920 blit.req.src.height = height;
921 blit.req.src.offset = 0;
922 blit.req.src.memory_id = priv->fd;
923
924 blit.req.dst.width = width;
925 blit.req.dst.height = height;
926 blit.req.dst.offset = 0;
927 blit.req.dst.memory_id = fd;
928 blit.req.dst.format = format;
929
930 blit.req.src_rect.x = blit.req.dst_rect.x = x;
931 blit.req.src_rect.y = blit.req.dst_rect.y = y;
932 blit.req.src_rect.w = blit.req.dst_rect.w = w;
933 blit.req.src_rect.h = blit.req.dst_rect.h = h;
934
935 if (ioctl(fd, MSMFB_BLIT, &blit))
936 ALOGE("MSMFB_BLIT failed = %d", -errno);
937}