blob: d06c98b9bb4db53c8419f040c55ec136a477414e [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001/*
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 "EGLDisplaySurface"
19
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <sys/ioctl.h>
26#include <sys/types.h>
27#include <sys/mman.h>
28
29#include <cutils/log.h>
30#include <cutils/atomic.h>
31#include <cutils/properties.h>
32
33#include <hardware/copybit.h>
34
35#include <ui/SurfaceComposerClient.h>
36#include <ui/DisplayInfo.h>
37#include <ui/Rect.h>
38#include <ui/Region.h>
39#include <ui/EGLDisplaySurface.h>
40
41#if HAVE_ANDROID_OS
42#include <linux/msm_mdp.h>
43#endif
44
45#include <EGL/egl.h>
46
47#include <pixelflinger/format.h>
48
49
50// ----------------------------------------------------------------------------
51
52egl_native_window_t* android_createDisplaySurface()
53{
54 egl_native_window_t* s = new android::EGLDisplaySurface();
55 s->memory_type = NATIVE_MEMORY_TYPE_GPU;
56 return s;
57}
58
59#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
60#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
61
62// ----------------------------------------------------------------------------
63namespace android {
64// ----------------------------------------------------------------------------
65
66EGLDisplaySurface::EGLDisplaySurface()
67 : EGLNativeSurface<EGLDisplaySurface>()
68{
69 egl_native_window_t::version = sizeof(egl_native_window_t);
70 egl_native_window_t::ident = 0;
71 egl_native_window_t::incRef = &EGLDisplaySurface::hook_incRef;
72 egl_native_window_t::decRef = &EGLDisplaySurface::hook_decRef;
73 egl_native_window_t::swapBuffers = &EGLDisplaySurface::hook_swapBuffers;
74 egl_native_window_t::connect = 0;
75 egl_native_window_t::disconnect = 0;
76
77 mFb[0].data = 0;
78 mFb[1].data = 0;
79 mBlitEngine = 0;
80 egl_native_window_t::fd = mapFrameBuffer();
81 if (egl_native_window_t::fd >= 0) {
82
83 hw_module_t const* module;
84 if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
85 copybit_open(module, &mBlitEngine);
86 }
87
88 const float in2mm = 25.4f;
89 float refreshRate = 1000000000000000LLU / (
90 float( mInfo.upper_margin + mInfo.lower_margin + mInfo.yres )
91 * ( mInfo.left_margin + mInfo.right_margin + mInfo.xres )
92 * mInfo.pixclock);
93
94 const GGLSurface& buffer = mFb[1 - mIndex];
95 egl_native_window_t::width = buffer.width;
96 egl_native_window_t::height = buffer.height;
97 egl_native_window_t::stride = buffer.stride;
98 egl_native_window_t::format = buffer.format;
99 egl_native_window_t::base = intptr_t(mFb[0].data);
100 egl_native_window_t::offset =
101 intptr_t(buffer.data) - egl_native_window_t::base;
102 egl_native_window_t::flags = 0;
103 egl_native_window_t::xdpi = (mInfo.xres * in2mm) / mInfo.width;
104 egl_native_window_t::ydpi = (mInfo.yres * in2mm) / mInfo.height;
105 egl_native_window_t::fps = refreshRate;
106 egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_FB;
107 // no error, set the magic word
108 egl_native_window_t::magic = 0x600913;
109 }
110 mSwapCount = -1;
111 mPageFlipCount = 0;
112}
113
114EGLDisplaySurface::~EGLDisplaySurface()
115{
116 magic = 0;
117 copybit_close(mBlitEngine);
118 mBlitEngine = 0;
119 close(egl_native_window_t::fd);
120 munmap(mFb[0].data, mSize);
121 if (!(mFlags & PAGE_FLIP))
122 free((void*)mFb[1].data);
123}
124
125void EGLDisplaySurface::hook_incRef(NativeWindowType window) {
126 EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
127 that->incStrong(that);
128}
129void EGLDisplaySurface::hook_decRef(NativeWindowType window) {
130 EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
131 that->decStrong(that);
132}
133uint32_t EGLDisplaySurface::hook_swapBuffers(NativeWindowType window) {
134 EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
135 return that->swapBuffers();
136}
137
138void EGLDisplaySurface::setSwapRectangle(int l, int t, int w, int h)
139{
140 mInfo.reserved[0] = 0x54445055; // "UPDT";
141 mInfo.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
142 mInfo.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
143}
144
145uint32_t EGLDisplaySurface::swapBuffers()
146{
147#define SHOW_FPS 0
148#if SHOW_FPS
149 nsecs_t now = systemTime();
150 if (mSwapCount == -1) {
151 mTime = now;
152 mSwapCount = 0;
153 mSleep = 0;
154 } else {
155 nsecs_t d = now-mTime;
156 if (d >= seconds(1)) {
157 double fps = (mSwapCount * double(seconds(1))) / double(d);
158 LOGD("%f fps, sleep=%d / frame",
159 fps, (int)ns2us(mSleep / mSwapCount));
160 mSwapCount = 0;
161 mTime = now;
162 mSleep = 0;
163 } else {
164 mSwapCount++;
165 }
166 }
167#endif
168 /* If we can't do the page_flip, just copy the back buffer to the front */
169 if (!(mFlags & PAGE_FLIP)) {
170 memcpy(mFb[0].data, mFb[1].data, mInfo.xres*mInfo.yres*2);
171 return 0;
172 }
173
174 // do the actual flip
175 mIndex = 1 - mIndex;
176 mInfo.activate = FB_ACTIVATE_VBL;
177 mInfo.yoffset = mIndex ? mInfo.yres : 0;
178 if (ioctl(egl_native_window_t::fd, FBIOPUT_VSCREENINFO, &mInfo) == -1) {
179 LOGE("FBIOPUT_VSCREENINFO failed");
180 return 0;
181 }
182
183 /*
184 * this is a monstrous hack: Because the h/w accelerator is not able
185 * to render directly into the framebuffer, we need to copy its
186 * internal framebuffer out to the fb.
187 * oem[0] is used to access the fd of internal fb.
188 * All this is needed only in standalone mode, in SurfaceFlinger mode
189 * we control where the GPU renders.
190 * We do this only if we have copybit, since this hack is needed only
191 * with msm7k.
192 */
193 if (egl_native_window_t::memory_type == NATIVE_MEMORY_TYPE_GPU && oem[0] && mBlitEngine) {
194 copybit_device_t *copybit = mBlitEngine;
195 copybit_rect_t sdrect = { 0, 0,
196 egl_native_window_t::width, egl_native_window_t::height };
197 copybit_image_t dst = {
198 egl_native_window_t::width,
199 egl_native_window_t::height,
200 egl_native_window_t::format,
201 egl_native_window_t::offset,
202 (void*)egl_native_window_t::base,
203 egl_native_window_t::fd
204 };
205 copybit_image_t src = {
206 egl_native_window_t::width,
207 egl_native_window_t::height,
208 egl_native_window_t::format, // XXX: use proper format
209 egl_native_window_t::offset,
210 (void*)egl_native_window_t::base, // XXX: use proper base
211 egl_native_window_t::oem[0]
212 };
213 region_iterator it(Region(Rect(
214 egl_native_window_t::width, egl_native_window_t::height)));
215 copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
216 copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
217 copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
218 copybit->stretch(copybit, &dst, &src, &sdrect, &sdrect, &it);
219 }
220
221 // update the address of the buffer to draw to next
222 const GGLSurface& buffer = mFb[1 - mIndex];
223 egl_native_window_t::offset =
224 intptr_t(buffer.data) - egl_native_window_t::base;
225
226#if SHOW_FPS
227 mSleep += systemTime()-now;
228#endif
229
230 mPageFlipCount++;
231
232 // We don't support screen-size changes for now
233 return 0;
234}
235
236int32_t EGLDisplaySurface::getPageFlipCount() const
237{
238 return mPageFlipCount;
239}
240
241void EGLDisplaySurface::copyFrontToBack(const Region& copyback)
242{
243#if HAVE_ANDROID_OS
244 if (mBlitEngine) {
245 copybit_image_t dst = {
246 w: egl_native_window_t::stride,
247 h: egl_native_window_t::height,
248 format: egl_native_window_t::format,
249 offset: mFb[1-mIndex].data - mFb[0].data,
250 base: (void*)egl_native_window_t::base,
251 fd: egl_native_window_t::fd
252 };
253 copybit_image_t src = {
254 w: egl_native_window_t::stride,
255 h: egl_native_window_t::height,
256 format: egl_native_window_t::format,
257 offset: mFb[mIndex].data - mFb[0].data,
258 base: (void*)egl_native_window_t::base,
259 fd: egl_native_window_t::fd
260 };
261 region_iterator it(copyback);
262 mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
263 } else
264#endif
265 {
266 /* no extra copy needed since we copied back to front instead of
267 * flipping */
268 if (!(mFlags & PAGE_FLIP)) {
269 return;
270 }
271
272 Region::iterator iterator(copyback);
273 if (iterator) {
274 Rect r;
275 uint8_t* const screen_src = mFb[ mIndex].data;
276 uint8_t* const screen_dst = mFb[1-mIndex].data;
277 const size_t bpp = bytesPerPixel(egl_native_window_t::format);
278 const size_t bpr = egl_native_window_t::stride * bpp;
279 while (iterator.iterate(&r)) {
280 ssize_t h = r.bottom - r.top;
281 if (h) {
282 size_t size = (r.right - r.left) * bpp;
283 size_t o = (r.left + egl_native_window_t::stride * r.top) * bpp;
284 uint8_t* s = screen_src + o;
285 uint8_t* d = screen_dst + o;
286 if (size == bpr) {
287 size *= h;
288 h = 1;
289 }
290 do {
291 memcpy(d, s, size);
292 d += bpr;
293 s += bpr;
294 } while (--h > 0);
295 }
296 }
297 }
298 }
299}
300
301void EGLDisplaySurface::copyFrontToImage(const copybit_image_t& dst)
302{
303#if HAVE_ANDROID_OS
304 if (mBlitEngine) {
305 copybit_image_t src = {
306 w: egl_native_window_t::stride,
307 h: egl_native_window_t::height,
308 format: egl_native_window_t::format,
309 offset: mFb[mIndex].data - mFb[0].data,
310 base: (void*)egl_native_window_t::base,
311 fd: egl_native_window_t::fd
312 };
313 region_iterator it(Region(Rect(
314 egl_native_window_t::width, egl_native_window_t::height)));
315 mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
316 } else
317#endif
318 {
319 uint8_t* const screen_src = mFb[ mIndex].data;
320 const size_t bpp = bytesPerPixel(egl_native_window_t::format);
321 const size_t bpr = egl_native_window_t::stride * bpp;
322 memcpy((char*)dst.base + dst.offset, screen_src,
323 bpr*egl_native_window_t::height);
324 }
325}
326
327void EGLDisplaySurface::copyBackToImage(const copybit_image_t& dst)
328{
329#if HAVE_ANDROID_OS
330 if (mBlitEngine) {
331 copybit_image_t src = {
332 w: egl_native_window_t::stride,
333 h: egl_native_window_t::height,
334 format: egl_native_window_t::format,
335 offset: mFb[1-mIndex].data - mFb[0].data,
336 base: (void*)egl_native_window_t::base,
337 fd: egl_native_window_t::fd
338 };
339 region_iterator it(Region(Rect(
340 egl_native_window_t::width, egl_native_window_t::height)));
341 mBlitEngine->blit(mBlitEngine, &dst, &src, &it);
342 } else
343#endif
344 {
345 uint8_t* const screen_src = mFb[1-mIndex].data;
346 const size_t bpp = bytesPerPixel(egl_native_window_t::format);
347 const size_t bpr = egl_native_window_t::stride * bpp;
348 memcpy((char*)dst.base + dst.offset, screen_src,
349 bpr*egl_native_window_t::height);
350 }
351}
352
353
354status_t EGLDisplaySurface::mapFrameBuffer()
355{
356 char const * const device_template[] = {
357 "/dev/graphics/fb%u",
358 "/dev/fb%u",
359 0 };
360 int fd = -1;
361 int i=0;
362 char name[64];
363 while ((fd==-1) && device_template[i]) {
364 snprintf(name, 64, device_template[i], 0);
365 fd = open(name, O_RDWR, 0);
366 i++;
367 }
368 if (fd < 0)
369 return -errno;
370
371 struct fb_fix_screeninfo finfo;
372 if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
373 return -errno;
374
375 struct fb_var_screeninfo info;
376 if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
377 return -errno;
378
379 info.reserved[0] = 0;
380 info.reserved[1] = 0;
381 info.reserved[2] = 0;
382 info.xoffset = 0;
383 info.yoffset = 0;
384 info.yres_virtual = info.yres * 2;
385 info.bits_per_pixel = 16;
386 /* Explicitly request 5/6/5 */
387 info.red.offset = 11;
388 info.red.length = 5;
389 info.green.offset = 5;
390 info.green.length = 6;
391 info.blue.offset = 0;
392 info.blue.length = 5;
393 info.transp.offset = 0;
394 info.transp.length = 0;
395 info.activate = FB_ACTIVATE_NOW;
396
397 uint32_t flags = PAGE_FLIP;
398 if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
399 info.yres_virtual = info.yres;
400 flags &= ~PAGE_FLIP;
401 LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
402 }
403
404 if (info.yres_virtual < info.yres * 2) {
405 info.yres_virtual = info.yres;
406 flags &= ~PAGE_FLIP;
407 LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
408 info.yres_virtual, info.yres*2);
409 }
410
411 if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
412 return -errno;
413
414 int refreshRate = 1000000000000000LLU /
415 (
416 uint64_t( info.upper_margin + info.lower_margin + info.yres )
417 * ( info.left_margin + info.right_margin + info.xres )
418 * info.pixclock
419 );
420
421 if (refreshRate == 0) {
422 // bleagh, bad info from the driver
423 refreshRate = 60*1000; // 60 Hz
424 }
425 if (int(info.width) <= 0 || int(info.height) <= 0) {
426 // the driver doesn't return that information
427 // default to 160 dpi
428 info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
429 info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
430 }
431
432 float xdpi = (info.xres * 25.4f) / info.width;
433 float ydpi = (info.yres * 25.4f) / info.height;
434 float fps = refreshRate / 1000.0f;
435
436 LOGI( "using (fd=%d)\n"
437 "id = %s\n"
438 "xres = %d px\n"
439 "yres = %d px\n"
440 "xres_virtual = %d px\n"
441 "yres_virtual = %d px\n"
442 "bpp = %d\n"
443 "r = %2u:%u\n"
444 "g = %2u:%u\n"
445 "b = %2u:%u\n",
446 fd,
447 finfo.id,
448 info.xres,
449 info.yres,
450 info.xres_virtual,
451 info.yres_virtual,
452 info.bits_per_pixel,
453 info.red.offset, info.red.length,
454 info.green.offset, info.green.length,
455 info.blue.offset, info.blue.length
456 );
457
458 LOGI( "width = %d mm (%f dpi)\n"
459 "height = %d mm (%f dpi)\n"
460 "refresh rate = %.2f Hz\n",
461 info.width, xdpi,
462 info.height, ydpi,
463 fps
464 );
465
466
467 if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
468 return -errno;
469
470 if (finfo.smem_len <= 0)
471 return -errno;
472
473 /*
474 * Open and map the display.
475 */
476
477 void* buffer = (uint16_t*) mmap(
478 0, finfo.smem_len,
479 PROT_READ | PROT_WRITE,
480 MAP_SHARED,
481 fd, 0);
482
483 if (buffer == MAP_FAILED)
484 return -errno;
485
486 // at least for now, always clear the fb
487 memset(buffer, 0, finfo.smem_len);
488
489 uint8_t* offscreen[2];
490 offscreen[0] = (uint8_t*)buffer;
491 if (flags & PAGE_FLIP) {
492 offscreen[1] = (uint8_t*)buffer + finfo.line_length*info.yres;
493 } else {
494 offscreen[1] = (uint8_t*)malloc(finfo.smem_len);
495 if (offscreen[1] == 0) {
496 munmap(buffer, finfo.smem_len);
497 return NO_MEMORY;
498 }
499 }
500
501 mFlags = flags;
502 mInfo = info;
503 mFinfo = finfo;
504 mSize = finfo.smem_len;
505 mIndex = 0;
506 for (int i=0 ; i<2 ; i++) {
507 mFb[i].version = sizeof(GGLSurface);
508 mFb[i].width = info.xres;
509 mFb[i].height = info.yres;
510 mFb[i].stride = finfo.line_length / (info.bits_per_pixel >> 3);
511 mFb[i].data = (GGLubyte*)(offscreen[i]);
512 mFb[i].format = GGL_PIXEL_FORMAT_RGB_565;
513 }
514 return fd;
515}
516
517// ----------------------------------------------------------------------------
518}; // namespace android
519// ----------------------------------------------------------------------------