1 //
2 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
3 //   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
18 
19 #ifdef HAVE_CONFIG_H
20 #include "gnashconfig.h"
21 #endif
22 
23 #include <sys/ioctl.h>
24 #include <sys/mman.h>
25 #include <cstring>
26 #include <cstdint>
27 #include <fcntl.h>
28 
29 #include "log.h"
30 #include "Renderer.h"
31 #include "Renderer_agg.h"
32 #include "fbsup.h"
33 #include "RunResources.h"
34 #include "fb_glue_agg.h"
35 
36 #ifdef BUILD_RAWFB_DEVICE
37 #include "rawfb/RawFBDevice.h"
38 #endif
39 
40 namespace gnash {
41 
42 namespace gui {
43 
44 //---------------------------------------------
FBAggGlue()45 FBAggGlue::FBAggGlue()
46     : _fd(-1),
47       _fixinfo(),
48       _varinfo()
49 {
50 //    GNASH_REPORT_FUNCTION;
51 }
52 
FBAggGlue(int fd)53 FBAggGlue::FBAggGlue(int fd)
54     : _fd(fd),
55       _fixinfo(),
56       _varinfo()
57 {
58 //    GNASH_REPORT_FUNCTION;
59 }
60 
~FBAggGlue()61 FBAggGlue::~FBAggGlue()
62 {
63 //    GNASH_REPORT_FUNCTION;
64 
65     // Close the memory
66     if (_fd) {
67         ::close(_fd);
68     }
69 }
70 
71 void
setInvalidatedRegion(const SWFRect &)72 FBAggGlue::setInvalidatedRegion(const SWFRect &/*bounds */)
73 {
74     // GNASH_REPORT_FUNCTION;
75 
76     if (!_renderer) {
77         log_error(_("No renderer set!"));
78         return;
79     }
80 }
81 
82 void
setInvalidatedRegions(const InvalidatedRanges & ranges)83 FBAggGlue::setInvalidatedRegions(const InvalidatedRanges &ranges)
84 {
85 //    GNASH_REPORT_FUNCTION;
86 
87     if (!_renderer) {
88         log_error(_("No renderer set in %s!"), __FUNCTION__);
89         return;
90     }
91 
92     _renderer->set_invalidated_regions(ranges);
93 
94     _drawbounds.clear();
95 
96     for (size_t rno = 0; rno<ranges.size(); rno++) {
97         geometry::Range2d<int> bounds = Intersection(
98             _renderer->world_to_pixel(ranges.getRange(rno)),
99             _validbounds);
100         // it may happen that a particular range is out of the screen, which
101         // will lead to bounds==null.
102         if (bounds.isNull()) continue;
103 
104         _drawbounds.push_back(bounds);
105     }
106 }
107 
108 bool
init(int argc,char *** argv)109 FBAggGlue::init (int argc, char ***argv)
110 {
111 //    GNASH_REPORT_FUNCTION;
112 
113     // The device must be initialized before the renderer. AGG only supports
114     // The Raw framebuffer, so we use that.
115     _device.reset(new renderer::rawfb::RawFBDevice);
116     _device->initDevice(argc, *argv);
117 
118     renderer::rawfb::RawFBDevice *rawfb = reinterpret_cast
119         <renderer::rawfb::RawFBDevice *>(_device.get());
120 
121     // You must pass in the file descriptor to the opened
122     // framebuffer when creating a window.
123     return _device->attachWindow(rawfb->getHandle());
124 
125     // Set the renderer for the AGG glue layer
126     gnash::Renderer *rend = reinterpret_cast<gnash::Renderer *>
127                                                 (createRenderHandler());
128     if (rend) {
129         _renderer.reset(rend);
130     } else {
131         log_error(_("failed to create a render handler for AGG!"));
132         return false;
133     }
134 
135     // Set grayscale for 8 bit modes
136     if (_varinfo.bits_per_pixel == 8) {
137 	if (!rawfb->setGrayscaleLUT8())
138 	    return false;
139     }
140 
141     return true;
142 }
143 
144 #define TO_16BIT(x) (x | (x<<8))
145 
146 Renderer *
createRenderHandler()147 FBAggGlue::createRenderHandler()
148 {
149 //    GNASH_REPORT_FUNCTION;
150 
151     if (!_device) {
152         log_error(_("No Device layer initialized yet!"));
153         return nullptr;
154     }
155 
156     const int width     = _device->getWidth();
157     const int height    = _device->getHeight();
158 
159     _validbounds.setTo(0, 0, width - 1, height - 1);
160 
161     // choose apropriate pixel format
162 
163     renderer::rawfb::RawFBDevice *rawfb = reinterpret_cast
164         <renderer::rawfb::RawFBDevice *>(_device.get());
165     log_debug("red channel: %d / %d", rawfb->getRedOffset(),
166 	      rawfb->getRedSize());
167     log_debug("green channel: %d / %d", rawfb->getGreenOffset(),
168 	      rawfb->getGreenSize());
169     log_debug("blue channel: %d / %d", rawfb->getBlueOffset(),
170               rawfb->getBlueSize());
171     log_debug("Total bits per pixel: %d",  rawfb->getDepth());
172 
173     const char* pixelformat = agg_detect_pixel_format(
174         rawfb->getRedOffset(),   rawfb->getRedSize(),
175         rawfb->getGreenOffset(), rawfb->getGreenSize(),
176         rawfb->getBlueOffset(),  rawfb->getBlueSize(),
177         rawfb->getDepth());
178 
179     Renderer_agg_base *agg_handler = nullptr;
180     if (pixelformat) {
181 	agg_handler = create_Renderer_agg(pixelformat);
182     } else {
183 	log_error(_("The pixel format of your framebuffer could not be detected."));
184 	return nullptr;
185     }
186 
187     assert(agg_handler != nullptr);
188 
189     // Get the memory buffer to have AGG render into.
190     std::uint8_t *mem = nullptr;
191     if (rawfb->isSingleBuffered()) {
192         log_debug(_("Double buffering disabled"));
193         mem = rawfb->getFBMemory();
194     } else {
195         log_debug(_("Double buffering enabled"));
196         mem = rawfb->getOffscreenBuffer();
197     }
198 
199     // This attaches the memory from the device to the AGG renderer
200     agg_handler->init_buffer(mem, rawfb->getFBMemSize(),
201                              width, height, rawfb->getStride());
202 
203     _renderer.reset(agg_handler);
204 
205     return agg_handler;
206 }
207 
208 void
prepDrawingArea(FbWidget *)209 FBAggGlue::prepDrawingArea(FbWidget */* drawing_area */)
210 {
211 //    GNASH_REPORT_FUNCTION;
212     // nothing to do here, the memory was attached when
213     // creating the renderer.
214 }
215 
216 void
render()217 FBAggGlue::render()
218 {
219 //    GNASH_REPORT_FUNCTION;
220 
221     if (_drawbounds.size() == 0 ) {
222         log_error(_("No Drawbounds set in %s!"), __FUNCTION__);
223         return; // nothing to do..
224     }
225 
226     _device->swapBuffers();
227 
228 #ifdef DEBUG_SHOW_FPS
229     profile();
230 #endif
231 }
232 
233 int
width()234 FBAggGlue::width()
235 {
236 //    GNASH_REPORT_FUNCTION;
237 
238     if (_device) {
239         return _device->getWidth();
240     }
241     return 0;
242 }
243 
244 int
height()245 FBAggGlue::height()
246 {
247 //    GNASH_REPORT_FUNCTION;
248 
249     if (_device) {
250         return _device->getHeight();
251     }
252     return 0;
253 }
254 
255 } // end of namespace gui
256 } // end of namespace gnash
257 
258 // Local Variables:
259 // mode: C++
260 // indent-tabs-mode: nil
261 // End:
262