blob: b0777f8c1c02e3bb5ad59d2e0a29642a72dd2781 [file] [log] [blame]
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001/*
2 **
3 ** Copyright 2008 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#include <stdlib.h>
19#include <stdio.h>
20#include <string.h>
21#include <unistd.h>
22#include <fcntl.h>
23#include <errno.h>
24#include <sys/ioctl.h>
25#include <sys/types.h>
26#include <sys/mman.h>
27
28#include <GLES/egl.h>
29
30#include "egl_surface.h"
31
32#define LOGI(x...) do { printf("INFO: " x); } while (0)
33#define LOGW(x...) do { printf("WARN: " x); } while (0)
34#define LOGE(x...) do { printf("ERR: " x); } while (0)
35
36// ----------------------------------------------------------------------------
37
38egl_native_window_t* android_createDisplaySurface()
39{
40 egl_native_window_t* s = new android::EGLDisplaySurface();
41 s->memory_type = NATIVE_MEMORY_TYPE_GPU;
42 return s;
43}
44
45#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
46#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
47
48// ----------------------------------------------------------------------------
49namespace android {
50// ----------------------------------------------------------------------------
51
52EGLDisplaySurface::EGLDisplaySurface()
53 : EGLNativeSurface<EGLDisplaySurface>()
54{
55 egl_native_window_t::version = sizeof(egl_native_window_t);
56 egl_native_window_t::ident = 0;
57 egl_native_window_t::incRef = &EGLDisplaySurface::hook_incRef;
58 egl_native_window_t::decRef = &EGLDisplaySurface::hook_decRef;
59 egl_native_window_t::swapBuffers = &EGLDisplaySurface::hook_swapBuffers;
60 egl_native_window_t::setSwapRectangle = &EGLDisplaySurface::hook_setSwapRectangle;
61 egl_native_window_t::nextBuffer = &EGLDisplaySurface::hook_nextBuffer;
62 egl_native_window_t::connect = 0;
63 egl_native_window_t::disconnect = 0;
64
65 mFb[0].data = 0;
66 mFb[1].data = 0;
67 egl_native_window_t::fd = mapFrameBuffer();
68 if (egl_native_window_t::fd >= 0) {
69 const float in2mm = 25.4f;
70 float refreshRate = 1000000000000000LLU / (
71 float( mInfo.upper_margin + mInfo.lower_margin + mInfo.yres )
72 * ( mInfo.left_margin + mInfo.right_margin + mInfo.xres )
73 * mInfo.pixclock);
74
75 const GGLSurface& buffer = mFb[1 - mIndex];
76 egl_native_window_t::width = buffer.width;
77 egl_native_window_t::height = buffer.height;
78 egl_native_window_t::stride = buffer.stride;
79 egl_native_window_t::format = buffer.format;
80 egl_native_window_t::base = intptr_t(mFb[0].data);
81 egl_native_window_t::offset =
82 intptr_t(buffer.data) - egl_native_window_t::base;
83 egl_native_window_t::flags = 0;
84 egl_native_window_t::xdpi = (mInfo.xres * in2mm) / mInfo.width;
85 egl_native_window_t::ydpi = (mInfo.yres * in2mm) / mInfo.height;
86 egl_native_window_t::fps = refreshRate;
87 egl_native_window_t::memory_type = NATIVE_MEMORY_TYPE_FB;
88 // no error, set the magic word
89 egl_native_window_t::magic = 0x600913;
90 }
91 mSwapCount = -1;
92 mPageFlipCount = 0;
93}
94
95EGLDisplaySurface::~EGLDisplaySurface()
96{
97 magic = 0;
98 close(egl_native_window_t::fd);
99 munmap(mFb[0].data, mSize);
100 if (!(mFlags & PAGE_FLIP))
101 free((void*)mFb[1].data);
102}
103
104void EGLDisplaySurface::hook_incRef(NativeWindowType window) {
105 EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
106 that->incStrong(that);
107}
108void EGLDisplaySurface::hook_decRef(NativeWindowType window) {
109 EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
110 that->decStrong(that);
111}
112uint32_t EGLDisplaySurface::hook_swapBuffers(NativeWindowType window) {
113 EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
114 return that->swapBuffers();
115}
116uint32_t EGLDisplaySurface::hook_nextBuffer(NativeWindowType window) {
117 EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
118 return that->nextBuffer();
119}
120void EGLDisplaySurface::hook_setSwapRectangle(NativeWindowType window,
121 int l, int t, int w, int h) {
122 EGLDisplaySurface* that = static_cast<EGLDisplaySurface*>(window);
123 that->setSwapRectangle(l, t, w, h);
124}
125
126void EGLDisplaySurface::setSwapRectangle(int l, int t, int w, int h)
127{
128 mInfo.reserved[0] = 0x54445055; // "UPDT";
129 mInfo.reserved[1] = (uint16_t)l | ((uint32_t)t << 16);
130 mInfo.reserved[2] = (uint16_t)(l+w) | ((uint32_t)(t+h) << 16);
131}
132
133uint32_t EGLDisplaySurface::swapBuffers()
134{
135 if (!(mFlags & PAGE_FLIP))
136 return 0;
137
138 // do the actual flip
139 mIndex = 1 - mIndex;
140 mInfo.activate = FB_ACTIVATE_VBL;
141 mInfo.yoffset = mIndex ? mInfo.yres : 0;
142 if (ioctl(egl_native_window_t::fd, FBIOPUT_VSCREENINFO, &mInfo) == -1) {
143 LOGE("FBIOPUT_VSCREENINFO failed");
144 return 0;
145 }
146
147 /*
148 * this is a monstruous hack: Because the h/w accelerator is not able
149 * to render directly into the framebuffer, we need to copy its
150 * internal framebuffer out to the fb. the base address of the internal fb
151 * is given in oem[0].
152 * All this is needed only in standalone mode, in SurfaceFlinger mode
153 * we control where the GPU renders.
154 */
155 if (egl_native_window_t::memory_type == NATIVE_MEMORY_TYPE_GPU && oem[0]) {
156 // could use MDP here, but that's tricky because we need
157 // /dev/pmem_gpu* filedescriptor
158 const GGLSurface& buffer = mFb[mIndex];
159 memcpy( buffer.data,
160 (void*)(oem[0] + egl_native_window_t::offset),
161 buffer.stride*buffer.height*2);
162 }
163
164 // update the address of the buffer to draw to next
165 const GGLSurface& buffer = mFb[1 - mIndex];
166 egl_native_window_t::offset =
167 intptr_t(buffer.data) - egl_native_window_t::base;
168
169 mPageFlipCount++;
170
171 // We don't support screen-size changes for now
172 return 0;
173}
174
175int32_t EGLDisplaySurface::getPageFlipCount() const
176{
177 return mPageFlipCount;
178}
179
180uint32_t EGLDisplaySurface::nextBuffer()
181{
182 // update the address of the buffer to draw to next
183 const GGLSurface& buffer = mFb[mIndex];
184 egl_native_window_t::offset =
185 intptr_t(buffer.data) - egl_native_window_t::base;
186 return 0;
187}
188
189int EGLDisplaySurface::mapFrameBuffer()
190{
191 char const * const device_template[] = {
192 "/dev/graphics/fb%u",
193 "/dev/fb%u",
194 0 };
195 int fd = -1;
196 int i=0;
197 char name[64];
198 while ((fd==-1) && device_template[i]) {
199 snprintf(name, 64, device_template[i], 0);
200 fd = open(name, O_RDWR, 0);
201 i++;
202 }
203 if (fd < 0)
204 return -errno;
205
206 struct fb_fix_screeninfo finfo;
207 if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
208 return -errno;
209
210 struct fb_var_screeninfo info;
211 if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
212 return -errno;
213
214 info.reserved[0] = 0;
215 info.reserved[1] = 0;
216 info.reserved[2] = 0;
217 info.xoffset = 0;
218 info.yoffset = 0;
219 info.yres_virtual = info.yres * 2;
220 info.bits_per_pixel = 16;
221 info.activate = FB_ACTIVATE_NOW;
222
223 uint32_t flags = PAGE_FLIP;
224 if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
225 info.yres_virtual = info.yres;
226 flags &= ~PAGE_FLIP;
227 LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
228 }
229
230 if (info.yres_virtual < info.yres * 2) {
231 info.yres_virtual = info.yres;
232 flags &= ~PAGE_FLIP;
233 LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
234 info.yres_virtual, info.yres*2);
235 }
236
237 if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
238 return -errno;
239
240 int refreshRate = 1000000000000000LLU /
241 (
242 uint64_t( info.upper_margin + info.lower_margin + info.yres )
243 * ( info.left_margin + info.right_margin + info.xres )
244 * info.pixclock
245 );
246
247 if (refreshRate == 0) {
248 // bleagh, bad info from the driver
249 refreshRate = 60*1000; // 60 Hz
250 }
251
252 if (int(info.width) <= 0 || int(info.height) <= 0) {
253 // stupid driver, doesn't return that information
254 // default to Sooner's screen size (160 dpi)
255 info.width = 51;
256 info.height = 38;
257 }
258
259 float xdpi = (info.xres * 25.4f) / info.width;
260 float ydpi = (info.yres * 25.4f) / info.height;
261 float fps = refreshRate / 1000.0f;
262
263 LOGI( "using (fd=%d)\n"
264 "id = %s\n"
265 "xres = %d px\n"
266 "yres = %d px\n"
267 "xres_virtual = %d px\n"
268 "yres_virtual = %d px\n"
269 "bpp = %d\n"
270 "r = %2u:%u\n"
271 "g = %2u:%u\n"
272 "b = %2u:%u\n",
273 fd,
274 finfo.id,
275 info.xres,
276 info.yres,
277 info.xres_virtual,
278 info.yres_virtual,
279 info.bits_per_pixel,
280 info.red.offset, info.red.length,
281 info.green.offset, info.green.length,
282 info.blue.offset, info.blue.length
283 );
284
285 LOGI( "width = %d mm (%f dpi)\n"
286 "height = %d mm (%f dpi)\n"
287 "refresh rate = %.2f Hz\n",
288 info.width, xdpi,
289 info.height, ydpi,
290 fps
291 );
292
293
294 if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
295 return -errno;
296
297 if (finfo.smem_len <= 0)
298 return -errno;
299
300 /*
301 * Open and map the display.
302 */
303
304 void* buffer = (uint16_t*) mmap(
305 0, finfo.smem_len,
306 PROT_READ | PROT_WRITE,
307 MAP_SHARED,
308 fd, 0);
309
310 if (buffer == MAP_FAILED)
311 return -errno;
312
313 // at least for now, always clear the fb
314 memset(buffer, 0, finfo.smem_len);
315
316 uint8_t* offscreen[2];
317 offscreen[0] = (uint8_t*)buffer;
318 if (flags & PAGE_FLIP) {
319 offscreen[1] = (uint8_t*)buffer + finfo.line_length*info.yres;
320 } else {
321 offscreen[1] = (uint8_t*)malloc(finfo.smem_len);
322 if (offscreen[1] == 0) {
323 munmap(buffer, finfo.smem_len);
324 return -ENOMEM;
325 }
326 }
327
328 mFlags = flags;
329 mInfo = info;
330 mFinfo = finfo;
331 mSize = finfo.smem_len;
332 mIndex = 0;
333 for (int i=0 ; i<2 ; i++) {
334 mFb[i].version = sizeof(GGLSurface);
335 mFb[i].width = info.xres;
336 mFb[i].height = info.yres;
337 mFb[i].stride = finfo.line_length / (info.bits_per_pixel >> 3);
338 mFb[i].data = (uint8_t*)(offscreen[i]);
339 mFb[i].format = NATIVE_PIXEL_FORMAT_RGB_565;
340 }
341 return fd;
342}
343
344// ----------------------------------------------------------------------------
345}; // namespace android
346// ----------------------------------------------------------------------------