update copyright date
[gnash.git] / libdevice / rawfb / RawFBDevice.cpp
blob59cbf02cfe1c58a007842722f481cf61b3ff2c76
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #ifdef HAVE_CONFIG_H
20 #include "gnashconfig.h"
21 #endif
23 #include <iostream>
24 #include <cerrno>
25 #include <exception>
26 #include <sstream>
27 #include <csignal>
29 #include "log.h"
30 #include "GnashException.h"
32 #include "RawFBDevice.h"
33 #include "GnashDevice.h"
35 namespace gnash {
37 namespace renderer {
39 namespace rawfb {
41 // The debug log used by all the gnash libraries.
42 static LogFile& dbglogfile = LogFile::getDefaultInstance();
45 RawFBDevice::RawFBDevice()
46 : _fd(0),
47 _fbmem(0)
49 // GNASH_REPORT_FUNCTION;
51 // dbglogfile.setVerbosity();
54 RawFBDevice::RawFBDevice(int /* vid */)
55 : _fd(0),
56 _fbmem(0)
58 // GNASH_REPORT_FUNCTION;
60 memset(&_cmap, 0, sizeof(struct fb_cmap));
62 if (!initDevice(0, 0)) {
63 log_error(_("Couldn't initialize RAWFB device!"));
67 RawFBDevice::RawFBDevice(int /* argc */ , char ** /* argv */)
68 : _fd(0),
69 _fbmem(0)
71 // GNASH_REPORT_FUNCTION;
73 memset(&_cmap, 0, sizeof(struct fb_cmap));
76 void
77 RawFBDevice::clear()
79 GNASH_REPORT_FUNCTION;
80 if (_fbmem) {
81 memset(_fbmem, 0, _fixinfo.smem_len);
83 if (_offscreen_buffer) {
84 memset(_offscreen_buffer.get(), 0, _fixinfo.smem_len);
88 RawFBDevice::~RawFBDevice()
90 // GNASH_REPORT_FUNCTION;
92 if (_fbmem) {
93 munmap(_fbmem, 0);
94 log_debug(_("Freeing framebuffer memory"));
95 _fbmem = 0;
98 if (_offscreen_buffer) {
99 log_debug(_("Freeing offscreen buffer"));
100 _offscreen_buffer.reset();
103 if (_fd) {
104 close (_fd);
105 _fd = -1;
109 bool
110 RawFBDevice::initDevice(int /* argc */, char **/* argv[] */)
112 GNASH_REPORT_FUNCTION;
114 const char *devname = 0;
115 // Open the framebuffer device
116 #ifdef ENABLE_FAKE_FRAMEBUFFER
117 _fd = open(FAKEFB, O_RDWR);
118 log_debug(_("WARNING: Using %s as a fake framebuffer!"), FAKEFB);
119 #else
120 devname = getenv("FRAMEBUFFER");
121 if (!devname) {
122 // We can't use the fake framebuffer with the FRAMEBUFFER
123 // environment variable, as it coinfuses X11. So this
124 // lets us redefine this at runtime.
125 devname = getenv("FAKE_FRAMEBUFFER");
126 if (!devname) {
127 devname = "/dev/fb0";
130 _fd = open(devname, O_RDWR);
131 #endif
132 if (_fd < 0) {
133 log_error(_("Could not open framebuffer device: %s"), strerror(errno));
134 return false;
135 } else {
136 log_debug(_("Opened framebuffer device: %s"), devname);
139 // Load framebuffer properties
140 #ifdef ENABLE_FAKE_FRAMEBUFFER
141 fakefb_ioctl(_fd, FBIOGET_VSCREENINFO, &_varinfo);
142 fakefb_ioctl(_fd, FBIOGET_FSCREENINFO, &_fixinfo);
143 #else
144 ioctl(_fd, FBIOGET_VSCREENINFO, &_varinfo);
145 ioctl(_fd, FBIOGET_FSCREENINFO, &_fixinfo);
146 #endif
147 log_debug(_("Framebuffer device uses %d bytes of memory."),
148 _fixinfo.smem_len);
149 log_debug(_("Video mode: %dx%d with %d bits per pixel."),
150 _varinfo.xres, _varinfo.yres,
151 _varinfo.bits_per_pixel);
153 log_debug(_("Framebuffer stride is: %d."), _fixinfo.line_length);
155 return true;
158 bool
159 RawFBDevice::setGrayscaleLUT8()
161 #define TO_16BIT(x) (x | (x<<8))
163 GNASH_REPORT_FUNCTION;
165 int i;
167 log_debug(_("LUT8: Setting up colormap"));
169 _cmap.start=0;
170 _cmap.len=256;
171 _cmap.red = (__u16*)malloc(CMAP_SIZE);
172 _cmap.green = (__u16*)malloc(CMAP_SIZE);
173 _cmap.blue = (__u16*)malloc(CMAP_SIZE);
174 _cmap.transp = NULL;
176 for (i=0; i<256; i++) {
177 int r = i;
178 int g = i;
179 int b = i;
181 _cmap.red[i] = TO_16BIT(r);
182 _cmap.green[i] = TO_16BIT(g);
183 _cmap.blue[i] = TO_16BIT(b);
186 #ifdef ENABLE_FAKE_FRAMEBUFFER
187 if (fakefb_ioctl(_fd, FBIOPUTCMAP, &_cmap))
188 #else
189 if (ioctl(_fd, FBIOPUTCMAP, &_cmap))
190 #endif
192 log_error(_("LUT8: Error setting colormap: %s"), strerror(errno));
193 return false;
196 return true;
198 #undef TO_16BIT
201 // Initialize RAWFB Window layer
202 bool
203 RawFBDevice::attachWindow(GnashDevice::native_window_t window)
205 GNASH_REPORT_FUNCTION;
207 // map framebuffer into memory. There isn't really a native
208 // window when using a frambuffer, it's actualy the file descriptor
209 // of the opened device. EGL wants the descriptor here too, so
210 // this way we work in a similar manner.
211 if (window) {
212 _fbmem = reinterpret_cast<boost::uint8_t *>(mmap(0, _fixinfo.smem_len,
213 PROT_READ|PROT_WRITE, MAP_SHARED,
214 window, 0));
217 if (!_fbmem) {
218 log_error(("Couldn't mmap() %d bytes of memory!"),
219 _fixinfo.smem_len);
220 return false;
223 if (!isSingleBuffered()) {
224 // Create an offscreen buffer the same size as the Framebuffer
225 _offscreen_buffer.reset(new boost::uint8_t[_fixinfo.smem_len]);
226 memset(_offscreen_buffer.get(), 0, _fixinfo.smem_len);
229 return true;
232 bool
233 RawFBDevice::swapBuffers()
235 // When using AGG, the pointer to the offscreen buffer has been
236 // passed to AGG, so it renders in the offscreen buffer by default,
237 // leaving it up to us to manually copy the data from the offscreeen
238 // buffer into the real framebuffer memory.
239 if (_fbmem && _offscreen_buffer) {
240 std::copy(_offscreen_buffer.get(),
241 _offscreen_buffer.get() + _fixinfo.smem_len,
242 _fbmem);
243 return true;
244 } else {
245 // When single buffered, there is no data to copy, so always true
246 return true;
248 return false;
251 // Return a string with the error code as text, instead of a numeric value
252 const char *
253 RawFBDevice::getErrorString(int /* error */)
255 return 0;
258 // Create an RAWFB window to render in. This is only used by testing
259 void
260 RawFBDevice::createWindow(const char * /* name */, int /* x */,
261 int /* y */, int /* width */, int /* height */)
263 GNASH_REPORT_FUNCTION;
266 void
267 RawFBDevice::eventLoop(size_t /* passes */)
269 GNASH_REPORT_FUNCTION;
272 #ifdef ENABLE_FAKE_FRAMEBUFFER
273 // Simulate the ioctls used to get information from the framebuffer
274 // driver. Since this is an emulator, we have to set these fields
275 // to a reasonable default.
277 fakefb_ioctl(int /* fd */, int request, void *data)
279 // GNASH_REPORT_FUNCTION;
281 switch (request) {
282 case FBIOGET_VSCREENINFO:
284 struct fb_var_screeninfo *ptr =
285 reinterpret_cast<struct fb_var_screeninfo *>(data);
286 // Note that the fake framebuffer is only used for
287 // debugging and development.
288 // Framebuffer device uses 1536000 bytes of memory at this size
289 #if 0
290 ptr->xres = 1024; // visible resolution
291 ptr->xres_virtual = 1024; // virtual resolution
292 ptr->yres = 768; // visible resolution
293 ptr->yres_virtual = 768; // virtual resolution
295 // standard PC framebuffer use a 32 bit 8/8/8 framebuffer
296 ptr->bits_per_pixel = 24;
297 ptr->red.offset = 0;
298 ptr->red.length = 8;
299 ptr->green.offset = 16;
300 ptr->green.length = 8;
301 ptr->blue.offset = 0;
302 ptr->blue.length = 6;
303 ptr->transp.offset = 0;
304 ptr->transp.length = 0;
305 #else
306 ptr->xres = 800; // visible resolution
307 ptr->xres_virtual = 1600; // virtual resolution
308 ptr->yres = 480; // visible resolution
309 ptr->yres_virtual = 480; // virtual resolution
311 // Most modile devices use a 16bit 5/6/5 framebuffer
312 ptr->bits_per_pixel = 16;
313 ptr->red.length = 5;
314 ptr->red.offset = 11;
315 ptr->green.length = 6;
316 ptr->green.offset = 5;
317 ptr->blue.length = 5;
318 ptr->blue.offset = 0;
319 ptr->transp.offset = 0;
320 ptr->transp.length = 0;
321 #endif
322 // 8bit framebuffer
323 // ptr->bits_per_pixel = 8;
324 // ptr->red.length = 8;
325 // ptr->red.offset = 0;
326 // ptr->green.length = 8;
327 // ptr->green.offset = 0;
328 // ptr->blue.length = 8;
329 // ptr->blue.offset = 0;
330 // ptr->transp.offset = 0;
331 // ptr->transp.length = 0;
332 ptr->grayscale = 1; // != 0 Graylevels instead of color
334 break;
336 case FBIOGET_FSCREENINFO:
338 struct fb_fix_screeninfo *ptr =
339 reinterpret_cast<struct fb_fix_screeninfo *>(data);
340 #if 1
341 // Most mobile devices use a 16bit 5/6/5 framebuffer
342 ptr->smem_len = 33554432; // size of frame buffer memory
343 ptr->type = 0; // see FB_TYPE_*
344 ptr->visual = 2; // see FB_VISUAL_*
345 ptr->xpanstep = 1; // zero if no hardware panning
346 ptr->ypanstep = 1; // zero if no hardware panning
347 ptr->ywrapstep = 0; // zero if no hardware panning
348 ptr->line_length = 1600; // line length
349 ptr->accel = FB_ACCEL_NONE; // Indicate to driver which specific
350 // chip/card we have
351 #else
352 // Android and fbe use a 16bit 5/6/5 framebuffer
353 ptr->smem_len = 307200; // Length of frame buffer mem
354 ptr->type = FB_TYPE_PACKED_PIXELS; // see FB_TYPE_*
355 ptr->visual = FB_VISUAL_PSEUDOCOLOR; // see FB_VISUAL_*
356 ptr->xpanstep = 0; // zero if no hardware panning
357 ptr->ypanstep = 0; // zero if no hardware panning
358 ptr->ywrapstep = 0; // zero if no hardware panning
359 ptr->accel = FB_ACCEL_NONE; // Indicate to driver which specific
360 // chip/card we have
361 #endif
362 break;
364 case FBIOPUTCMAP:
366 // Fbe uses this name for the fake framebuffer, so in this
367 // case assume we're using fbe, so write to the known fbe
368 // cmap file.
369 std::string str = FAKEFB;
370 if (str == "/tmp/fbe_buffer") {
371 int fd = open("/tmp/fbe_cmap", O_WRONLY);
372 if (fd) {
373 write(fd, data, sizeof(struct fb_cmap));
374 close(fd);
375 } else {
376 log_error(_("Couldn't write to the fake cmap!"));
377 return -1;
379 } else {
380 log_error(_("Couldn't write to the fake cmap, unknown type!"));
381 return -1;
383 // If we send a SIGUSR1 signal to fbe, it'll reload the
384 // color map.
385 int fd = open("/tmp/fbe.pid", O_RDONLY);
386 char buf[10];
387 if (fd) {
388 if (read(fd, buf, 10) == 0) {
389 close(fd);
390 return -1;
391 } else {
392 pid_t pid = strtol(buf, 0, NULL);
393 kill(pid, SIGUSR1);
394 log_debug(_("Signaled fbe to reload it's colormap."));
396 close(fd);
398 break;
400 default:
401 log_unimpl(_("fakefb_ioctl(%d)"), request);
402 break;
405 return 0;
407 #endif // ENABLE_FAKE_FRAMEBUFFER
409 } // namespace rawfb
410 } // namespace renderer
411 } // namespace gnash
413 // local Variables:
414 // mode: C++
415 // indent-tabs-mode: nil
416 // End: