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