]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/scout/lib/src/platform_fb.cc
Update
[l4.git] / l4 / pkg / scout / lib / src / platform_fb.cc
1 #include <l4/re/env>
2 #include <cstdio>
3 #include <pthread.h>
4
5 #include <l4/re/util/debug>
6 #include <l4/re/event>
7 #include <l4/re/console>
8 #include <l4/re/rm>
9 #include <l4/re/env>
10 #include <l4/re/error_helper>
11 #include <l4/re/util/cap_alloc>
12 #include <l4/re/video/goos>
13 #include <unistd.h>
14 #include <l4/scout-gfx/redraw_manager>
15
16
17 #include "platform.h"
18 #include "config.h"
19 #include <semaphore.h>
20 #include <pthread.h>
21 #include <cstring>
22 #include <l4/re/event_enums.h>
23 #include <l4/re/event>
24 #include <l4/sys/factory>
25 #include <l4/scout-gfx/redraw_manager>
26 #include <l4/scout-gfx/user_state>
27 #include "factory.h"
28
29 namespace {
30 using L4Re::Util::Auto_cap;
31
32 class Semaphore
33 {
34 private:
35   sem_t _s;
36
37 public:
38   Semaphore()
39   { sem_init(&_s, 0, 0); }
40
41   void up() { sem_post(&_s); }
42   void down() { sem_wait(&_s); }
43
44   ~Semaphore() { sem_destroy(&_s); }
45
46 };
47
48 class Lock
49 {
50 private:
51   pthread_mutex_t _m;
52
53 public:
54   Lock()
55   { pthread_mutex_init(&_m, NULL); }
56
57   ~Lock()
58   { pthread_mutex_destroy(&_m); }
59
60   void lock()
61   { pthread_mutex_lock(&_m); }
62
63   void unlock()
64   { pthread_mutex_unlock(&_m); }
65
66 };
67
68 template< typename L >
69 class Lock_guard
70 {
71 private:
72   L &_l;
73
74 public:
75   explicit Lock_guard(L &l) : _l(l) { _l.lock(); }
76   ~Lock_guard() { _l.unlock(); }
77 };
78
79 /*****************
80  ** Event queue **
81  *****************/
82 class Eventqueue
83 {
84 private:
85
86   enum { queue_size = 1024 };
87
88   int           _head;
89   int           _tail;
90   Semaphore     _sem;
91   Lock  _head_lock;  /* synchronize add */
92
93   Scout_gfx::Event _queue[queue_size];
94
95 public:
96
97   /**
98    * Constructor
99    */
100   Eventqueue(): _head(0), _tail(0)
101   {
102     memset(_queue, 0, sizeof(_queue));
103   }
104
105   void add(Scout_gfx::Event const &ev)
106   {
107     Lock_guard<Lock> lock_guard(_head_lock);
108
109     if ((_head + 1)%queue_size != _tail)
110       {
111
112         _queue[_head] = ev;
113         _head = (_head + 1)%queue_size;
114         _sem.up();
115       }
116   }
117
118   void get(Scout_gfx::Event *dst_ev)
119   {
120     _sem.down();
121     *dst_ev = _queue[_tail];
122     _tail = (_tail + 1)%queue_size;
123   }
124
125   int pending() { return _head != _tail; }
126
127 } _evqueue;
128
129 /******************
130  ** Timer thread **
131  ******************/
132
133 using Mag_gfx::Point;
134
135 class Timer_thread
136 {
137 private:
138
139   pthread_t _th;
140   Auto_cap<L4Re::Dataspace>::Cap _ev_ds;
141   Auto_cap<L4::Irq>::Cap _ev_irq;
142   L4Re::Rm::Auto_region<void *> _ev_ds_addr;
143   L4Re::Event_buffer _evb;
144
145   Point _m;
146   int _key_cnt;
147
148   l4_uint64_t _timer_tick;
149
150   void _set_ev(Scout_gfx::Event &ev)
151   {
152     ev.key_cnt = _key_cnt;
153     ev.m = _m;
154   }
155
156   void _import_events()
157   {
158     using Scout_gfx::Event;
159     typedef L4Re::Event_buffer::Event Re_ev;
160
161     for (Re_ev *re = _evb.next(); re; re->free(), re = _evb.next())
162       {
163         Event ev;
164         Point om = _m;
165         switch (re->payload.type)
166           {
167           case L4RE_EV_KEY:
168             switch (re->payload.value)
169               {
170               case 1:  ++_key_cnt; ev.type = Event::PRESS; break;
171               case 0:  --_key_cnt; ev.type = Event::RELEASE; break;
172               default: continue;
173               }
174             if (_key_cnt < 0)
175               _key_cnt = 0;
176
177             _set_ev(ev);
178             ev.code = re->payload.code;
179             ev.wx = 0;
180             ev.wy = 0;
181             break;
182
183           case L4RE_EV_ABS:
184             switch (re->payload.code)
185               {
186               case L4RE_ABS_X:
187                 _m = Point(re->payload.value, _m.y());
188                 break;
189               case L4RE_ABS_Y:
190                 _m = Point(_m.x(), re->payload.value);
191                 break;
192               default: continue;
193               }
194             if (_m != om)
195               {
196                 _set_ev(ev);
197                 ev.wx = 0;
198                 ev.wy = 0;
199                 ev.type = Event::MOTION;
200                 ev.code = 0;
201                 break;
202               }
203             continue;
204
205           case L4RE_EV_REL:
206             _set_ev(ev);
207             ev.type = Event::WHEEL;
208             ev.code = 0;
209             switch (re->payload.code)
210               {
211               case L4RE_REL_WHEEL:
212                 ev.wx = 0;
213                 ev.wy = re->payload.value;
214                 break;
215               case L4RE_REL_HWHEEL:
216                 ev.wy = 0;
217                 ev.wx = re->payload.value;
218                 break;
219               default:
220                 continue;
221               }
222             break;
223
224           default:
225             continue;
226           }
227
228         _evqueue.add(ev);
229       }
230   }
231
232   static void *_tstart(void *t)
233   {
234     reinterpret_cast<Timer_thread*>(t)->entry();
235     return NULL;
236   }
237
238 public:
239
240   l4_uint64_t ticks() const { return _timer_tick; }
241
242   /**
243    * Constructor
244    *
245    * Start thread immediately on construction.
246    */
247   Timer_thread()
248     : _key_cnt(0), _timer_tick(0)
249   {}
250
251   void start(L4::Cap<L4Re::Event> const &e)
252   {
253
254     using L4Re::Util::cap_alloc;
255     using L4Re::chksys;
256
257     _ev_ds = cap_alloc.alloc<L4Re::Dataspace>();
258     _ev_irq = cap_alloc.alloc<L4::Irq>();
259     chksys(L4Re::Env::env()->factory()->create(_ev_irq.get()));
260     chksys(e->get_buffer(_ev_ds.get()));
261     chksys(L4Re::Env::env()->rm()->attach(&_ev_ds_addr, _ev_ds->size(),
262            L4Re::Rm::Search_addr, _ev_ds.get(), 0, L4_PAGESHIFT));
263
264     _evb = L4Re::Event_buffer(_ev_ds_addr.get(), _ev_ds->size());
265
266     pthread_create(&_th, NULL, &_tstart, this);
267   }
268
269   void entry()
270   {
271     while (1)
272       {
273         Scout_gfx::Event ev;
274         ev.assign(Scout_gfx::Event::TIMER, _m, 0);
275         _evqueue.add(ev);
276
277         _import_events();
278
279         usleep(10 * 1000);
280         _timer_tick += 10;
281       }
282   }
283 };
284
285
286
287 class Re_view : public Scout_gfx::View
288 {
289 private:
290   Rect _v;
291   Scout_gfx::Redraw_manager *_rdm;
292   Mag_gfx::Canvas *_canvas;
293   L4Re::Video::View _view;
294   L4Re::Video::View::Info _view_info;
295
296   unsigned long _buffer_offset;
297
298 public:
299
300   Re_view(Rect const &r, Rect const &ol, Scout_gfx::Redraw_manager *rdm,
301           Mag_gfx::Canvas *canvas, L4Re::Video::View const &v,
302           unsigned long buffer_offset);
303   /**
304    * View geometry accessor functions
305    */
306   virtual Rect geometry() const { return _v; }
307
308   virtual void redraw(Rect const &r)
309   { _rdm->request(r-_v.p1()); }
310
311   void scr_refresh(Rect const &r)
312   { _view.refresh(r.x1(), r.y1(), r.w(), r.h()); }
313
314   void set_buf_pos(unsigned long offset)
315   {
316     _buffer_offset = offset;
317     _view.set_viewport(_v.x1(), _v.y1(), _v.w(), _v.h(), offset);
318   }
319   /**
320    * Define geometry of viewport on screen
321    *
322    * The specified area is relative to the screen
323    * of the platform.
324    */
325   virtual Rect set_geometry(Rect const &pos, bool do_redraw)
326   {
327     // printf("view geometry: %d,%d-%d,%d %d\n", pos.x1(), pos.y1(), pos.x2(), pos.y2(), do_redraw);
328     if (!_view_info.has_set_position())
329       return _v;
330
331     Rect old_pos = _v;
332     _v = pos; //Rect(Point(0,0), scr_size());
333     if (pos != old_pos)
334       {
335         //_rdm->request(old_pos);
336         _view.set_viewport(_v.x1(), _v.y1(), _v.w(), _v.h(), _buffer_offset);
337         if (do_redraw)
338           _rdm->request(pos);
339       }
340
341     return _v;
342   }
343
344   /**
345    * Bring Scouts view ontop
346    */
347   virtual void top() { _view.push_top(); }
348
349   void set_view_info(L4Re::Video::View::Info const &vi)
350   { _view_info = vi; }
351
352   L4Re::Video::View::Info const *view_info() const
353   { return &_view_info; }
354
355   Mag_gfx::Pixel_info const *pixel_info() const
356   { return _canvas->type(); }
357 };
358
359 Re_view::Re_view(Rect const &r, Rect const &ol, Scout_gfx::Redraw_manager *rdm,
360                  Mag_gfx::Canvas *canvas, L4Re::Video::View const &v, unsigned long buffer_offset)
361 : _v(r & ol), _rdm(rdm), _canvas(canvas), _view(v), _buffer_offset(buffer_offset)
362 {
363 }
364
365 class Re_ust : public Scout_gfx::User_state
366 {
367 public:
368   void draw(Mag_gfx::Canvas *c, Mag_gfx::Point const &p)
369   {
370     for (Scout_gfx::Widget *e = _first; e; e = e->next)
371       e->try_draw(c, p);
372   }
373 };
374
375 class Re_pf : public Platform, public Scout_gfx::Screen_update
376 {
377 private:
378
379   L4Re::Video::Goos::Info _scr_info;
380   L4::Cap<L4Re::Console> _screen;
381   Auto_cap<L4Re::Dataspace>::Cap _fb_ds;
382   L4Re::Rm::Auto_region<char *> _fb_addr;
383   Area _size;
384
385   bool _ready;
386
387   Re_view *_view;
388   Timer_thread _timer;
389   Scout_gfx::Redraw_manager _rdm;
390   Re_ust _ust;
391   Mag_gfx::Canvas *_canvas;
392
393   void *_front_buffer;
394   void *_back_buffer;
395   bool _dbl_buffer_2;
396
397 public:
398   static bool probe();
399   Re_pf(Rect const &sz);
400   Mag_gfx::Pixel_info const *pixel_info() const
401   { return _canvas->type(); }
402
403   int max_num_views() { return 1; }
404   Scout_gfx::View *create_view(Rect const &/*r*/)
405   {
406     return _view;
407   }
408
409   virtual int initialized()
410   { return _ready; }
411
412   /**
413    * Request screen width and height
414    */
415   virtual Area scr_size() { return _size; }
416
417
418
419   /**
420    * Get timer ticks in miilliseconds
421    */
422   virtual unsigned long timer_ticks() { return _timer.ticks(); } 
423
424   /**
425    * Request if an event is pending
426    *
427    * \retval 1  event is pending
428    * \retval 0  no event pending
429    */
430   virtual int event_pending() { return _evqueue.pending(); }
431
432   /**
433    * Request event
434    *
435    * \param e  destination where to store event information.
436    *
437    * If there is no event pending, this function blocks
438    * until there is an event to deliver.
439    */
440   virtual int get_event(Scout_gfx::Event *out_e)
441   {
442     _evqueue.get(out_e);
443     return 1;
444   }
445
446   /**
447    * Screen update interface
448    */
449   virtual void *scr_adr()
450   { return _front_buffer; }
451 #if 0
452     long ofs = _size.h() * _dbl_buffer_2 * _view_info.bytes_per_line;
453     return _fb_addr.get() + _view_info.buffer_offset + ofs;
454   }
455 #endif
456   virtual void  scr_update(Rect const &r)
457   {
458     _view->scr_refresh(r);
459   }
460
461   /**
462    * Exchange foreground and back buffers
463    */
464   void flip_buf_scr()
465   {
466     if (_view->view_info()->has_static_buffer_offset())
467       {
468         copy_buf_to_scr(Rect(_size));
469         return;
470       }
471     _dbl_buffer_2 = !_dbl_buffer_2;
472     void *tmp = _front_buffer;
473     _front_buffer = _back_buffer;
474     _back_buffer = tmp;
475     _view->set_buf_pos(_size.h() * (_dbl_buffer_2) * _view->view_info()->bytes_per_line);
476     _canvas->buffer(_back_buffer);
477   }
478
479   void copy_buf_to_scr(Rect const &r);
480
481   void process_redraws()
482   { _rdm.process(_view->geometry()); }
483
484   Scout_gfx::Parent_widget *root() { return &_ust; }
485 };
486
487 bool
488 Re_pf::probe()
489 {
490   using L4Re::Util::cap_alloc;
491   L4Re::Env const *e = L4Re::Env::env();
492   L4::Cap<void> _mag = e->get_cap<void>("fb");
493   return _mag.is_valid();
494 }
495
496 Re_pf::Re_pf(Rect const &sz)
497 : Platform(), _size(sz.area()), _ready(false), _view(0),
498   _canvas(0), _dbl_buffer_2(false)
499 {
500   using L4Re::chksys;
501   using L4Re::Util::cap_alloc;
502   (void)sz;
503
504   L4Re::Video::View::Info _view_info;
505
506   L4Re::Env const *e = L4Re::Env::env();
507   _screen = chkcap(e->get_cap<L4Re::Console>("fb"));
508   chksys(_screen->L4Re::Video::Goos::info(&_scr_info), "requesting screen info");
509
510   L4Re::Video::View view;
511
512   if (_scr_info.has_dynamic_views())
513     chksys(_screen->create_view(&view), "creating new view");
514   else
515     view = _screen->view(0);
516
517   chksys(view.info(&_view_info), "requesting view infos");
518 #if 0
519   printf("SCREEN: size = %ld, %ld, bypp=%d\n",
520          _scr_info.width, _scr_info.height,
521          _scr_info.pixel_info.bytes_per_pixel());
522 #endif
523
524   _fb_ds = cap_alloc.alloc<L4Re::Dataspace>();
525
526   if (!_view_info.has_static_buffer())
527     {
528       _size = sz.area();
529       unsigned long bsize = _size.pixels() * _scr_info.pixel_info.bytes_per_pixel() * 2;
530       _view_info.buffer_index = chksys(_screen->create_buffer(bsize, _fb_ds.get()));
531       _view_info.xpos = 0;
532       _view_info.ypos = 0;
533       _view_info.width = sz.w();
534       _view_info.height = sz.h();
535       _view_info.buffer_offset = 0;
536       _view_info.bytes_per_line = _size.w() * _scr_info.pixel_info.bytes_per_pixel();
537       chksys(view.set_info(_view_info), "setting view infos");
538 //      view.push_top();
539       _back_buffer = 0;
540
541       Config::browser_attr      = 7;
542     }
543   else
544     {
545       chksys(_screen->get_static_buffer(_view_info.buffer_index, _fb_ds.get()), "requesting static bvuffer");
546       _size = Area(_view_info.width, _view_info.height);
547       _back_buffer = new char[_fb_ds->size()];
548     }
549
550
551
552   chksys(e->rm()->attach(&_fb_addr, _fb_ds->size(), L4Re::Rm::Search_addr,
553                          _fb_ds.get(), 0, L4_SUPERPAGESHIFT));
554
555   L4Re::Util::Dbg dbg;
556   _view_info.dump(dbg);
557   dbg.printf("  memory %p-%p\n", (void*)_fb_addr.get(),
558              (void*)(_fb_addr.get() + _fb_ds->size()));
559
560   _timer.start(_screen);
561
562   _max = scr_size();
563
564   _ust.set_geometry(Rect(Point(0,0), Area(_scr_info.width, _scr_info.height)));
565   ::Factory *f = dynamic_cast< ::Factory* >(::Factory::set.find(_view_info.pixel_info));
566
567   if (!f)
568     {
569       printf("No factory for this framebuffer config\n");
570       return;
571     }
572
573   _front_buffer = _fb_addr.get() + _view_info.buffer_offset;
574   if (!_back_buffer)
575     _back_buffer = _fb_addr.get() + _view_info.buffer_offset + _size.h() * _view_info.bytes_per_line;
576
577   _canvas = f->create_canvas(_back_buffer, scr_size(), _view_info.bytes_per_line);
578   if (!_canvas)
579     {
580       printf("Could not create canvas\n");
581       return;
582     }
583
584   _view = new Re_view(Rect(sz.p1(), _size), Rect(Point(0,0), scr_size()), &_rdm, _canvas, view,
585                       _view_info.buffer_offset);
586
587   _view->set_view_info(_view_info);
588
589   _rdm.setup(_canvas, this, scr_size());
590   _rdm.root(&_ust);
591
592   _ready = true;
593 }
594
595 void
596 Re_pf::copy_buf_to_scr(Rect const &_r)
597 {
598   unsigned bpp = _view->view_info()->pixel_info.bytes_per_pixel();
599   Rect r = _r & Rect(scr_size());// - o;
600   /* copy background buffer to foreground buffer */
601   int len     = r.w() * bpp;
602   int linelen = _view->view_info()->bytes_per_line;
603
604   char *src = (char*)_back_buffer + r.y1() * linelen + r.x1() * bpp;
605   char *dst = (char*)_front_buffer + r.y1() * linelen + r.x1() * bpp;
606
607   //    blit(src, linelen, dst, linelen, len, h);
608   for (int j = 0; j < r.h(); j++, dst += linelen, src += linelen)
609     memcpy(dst, src, len);
610 }
611
612 static Platform::Pf_factory_t<Re_pf> pff;
613
614 }
615