35626a9357b44be96e86063ab6d0a9c3077717e7
[enigma2.git] / lib / gdi / grc.cpp
1 // for debugging use:
2 // #define SYNC_PAINT
3 #include <unistd.h>
4 #ifndef SYNC_PAINT
5 #include <pthread.h>
6 #endif
7
8 #include <lib/gdi/grc.h>
9 #include <lib/gdi/font.h>
10 #include <lib/base/init.h>
11 #include <lib/base/init_num.h>
12
13 #ifndef SYNC_PAINT
14 void *gRC::thread_wrapper(void *ptr)
15 {
16         return ((gRC*)ptr)->thread();
17 }
18 #endif
19
20 gRC *gRC::instance=0;
21
22 gRC::gRC(): rp(0), wp(0)
23 #ifdef SYNC_PAINT
24 ,m_notify_pump(eApp, 0)
25 #else
26 ,m_notify_pump(eApp, 1)
27 #endif
28 {
29         ASSERT(!instance);
30         instance=this;
31         CONNECT(m_notify_pump.recv_msg, gRC::recv_notify);
32 #ifndef SYNC_PAINT
33         pthread_mutex_init(&mutex, 0);
34         pthread_cond_init(&cond, 0);
35         int res = pthread_create(&the_thread, 0, thread_wrapper, this);
36         if (res)
37                 eFatal("RC thread couldn't be created");
38         else
39                 eDebug("RC thread created successfully");
40 #endif
41 }
42
43 DEFINE_REF(gRC);
44
45 gRC::~gRC()
46 {
47         instance=0;
48
49         gOpcode o;
50         o.opcode=gOpcode::shutdown;
51         submit(o);
52 #ifndef SYNC_PAINT
53         eDebug("waiting for gRC thread shutdown");
54         pthread_join(the_thread, 0);
55         eDebug("gRC thread has finished");
56 #endif
57 }
58
59 void gRC::submit(const gOpcode &o)
60 {
61         while(1)
62         {
63 #ifndef SYNC_PAINT
64                 pthread_mutex_lock(&mutex);
65 #endif
66                 int tmp=wp+1;
67                 if ( tmp == MAXSIZE )
68                         tmp=0;
69                 if ( tmp == rp )
70                 {
71 #ifndef SYNC_PAINT
72                         pthread_mutex_unlock(&mutex);
73 #else
74                         thread();
75 #endif
76                         //printf("render buffer full...\n");
77                         //fflush(stdout);
78                         usleep(1000);  // wait 1 msec
79                         continue;
80                 }
81                 int free=rp-wp;
82                 if ( free <= 0 )
83                         free+=MAXSIZE;
84                 queue[wp++]=o;
85                 if ( wp == MAXSIZE )
86                         wp = 0;
87                 if (o.opcode==gOpcode::flush||o.opcode==gOpcode::shutdown||o.opcode==gOpcode::notify)
88 #ifndef SYNC_PAINT
89                         pthread_cond_signal(&cond);  // wakeup gdi thread
90                 pthread_mutex_unlock(&mutex);
91 #else
92                         thread(); // paint
93 #endif
94                 break;
95         }
96 }
97
98 void *gRC::thread()
99 {
100         int need_notify = 0;
101 #ifndef SYNC_PAINT
102         while (1)
103         {
104 #else
105         while (rp != wp)
106         {
107 #endif
108 #ifndef SYNC_PAINT
109                 pthread_mutex_lock(&mutex);
110 #endif
111                 if ( rp != wp )
112                 {
113                         gOpcode o(queue[rp++]);
114                         if ( rp == MAXSIZE )
115                                 rp=0;
116 #ifndef SYNC_PAINT
117                         pthread_mutex_unlock(&mutex);
118 #endif
119                         if (o.opcode==gOpcode::shutdown)
120                                 break;
121                         else if (o.opcode==gOpcode::notify)
122                                 need_notify = 1;
123                         else
124                                 o.dc->exec(&o);
125                 }
126                 else
127                 {
128                         if (need_notify)
129                         {
130                                 need_notify = 0;
131                                 m_notify_pump.send(1);
132                         }
133 #ifndef SYNC_PAINT
134                         pthread_cond_wait(&cond, &mutex);
135                         pthread_mutex_unlock(&mutex);
136 #endif
137                 }
138         }
139 #ifndef SYNC_PAINT
140         pthread_exit(0);
141 #endif
142         return 0;
143 }
144
145 void gRC::recv_notify(const int &i)
146 {
147         notify();
148 }
149
150 gRC *gRC::getInstance()
151 {
152         return instance;
153 }
154
155 static int gPainter_instances;
156
157 gPainter::gPainter(gDC *dc, eRect rect): m_dc(dc), m_rc(gRC::getInstance())
158 {
159 //      ASSERT(!gPainter_instances);
160         gPainter_instances++;
161 //      begin(rect);
162 }
163
164 gPainter::~gPainter()
165 {
166         end();
167         gPainter_instances--;
168 }
169
170 void gPainter::setBackgroundColor(const gColor &color)
171 {
172         if ( m_dc->islocked() )
173                 return;
174         gOpcode o;
175         o.opcode = gOpcode::setBackgroundColor;
176         o.dc = m_dc.grabRef();
177         o.parm.setColor = new gOpcode::para::psetColor;
178         o.parm.setColor->color = color;
179
180         m_rc->submit(o);
181 }
182
183 void gPainter::setForegroundColor(const gColor &color)
184 {
185         if ( m_dc->islocked() )
186                 return;
187         gOpcode o;
188         o.opcode = gOpcode::setForegroundColor;
189         o.dc = m_dc.grabRef();
190         o.parm.setColor = new gOpcode::para::psetColor;
191         o.parm.setColor->color = color;
192
193         m_rc->submit(o);
194 }
195
196 void gPainter::setBackgroundColor(const gRGB &color)
197 {
198         if ( m_dc->islocked() )
199                 return;
200         gOpcode o;
201         o.opcode = gOpcode::setBackgroundColorRGB;
202         o.dc = m_dc.grabRef();
203         o.parm.setColorRGB = new gOpcode::para::psetColorRGB;
204         o.parm.setColorRGB->color = color;
205
206         m_rc->submit(o);
207 }
208
209 void gPainter::setForegroundColor(const gRGB &color)
210 {
211         if ( m_dc->islocked() )
212                 return;
213         gOpcode o;
214         o.opcode = gOpcode::setForegroundColorRGB;
215         o.dc = m_dc.grabRef();
216         o.parm.setColorRGB = new gOpcode::para::psetColorRGB;
217         o.parm.setColorRGB->color = color;
218
219         m_rc->submit(o);
220 }
221
222 void gPainter::setFont(gFont *font)
223 {
224         if ( m_dc->islocked() )
225                 return;
226         gOpcode o;
227         o.opcode = gOpcode::setFont;
228         o.dc = m_dc.grabRef();
229         font->AddRef();
230         o.parm.setFont = new gOpcode::para::psetFont;
231         o.parm.setFont->font = font;
232
233         m_rc->submit(o);
234 }
235
236 void gPainter::renderText(const eRect &pos, const std::string &string, int flags)
237 {
238         if ( m_dc->islocked() )
239                 return;
240         gOpcode o;
241         o.opcode=gOpcode::renderText;
242         o.dc = m_dc.grabRef();
243         o.parm.renderText = new gOpcode::para::prenderText;
244         o.parm.renderText->area = pos;
245         o.parm.renderText->text = string;
246         o.parm.renderText->flags = flags;
247         m_rc->submit(o);
248 }
249
250 void gPainter::renderPara(eTextPara *para, ePoint offset)
251 {
252         if ( m_dc->islocked() )
253                 return;
254         gOpcode o;
255         o.opcode=gOpcode::renderPara;
256         o.dc = m_dc.grabRef();
257         o.parm.renderPara = new gOpcode::para::prenderPara;
258         o.parm.renderPara->offset = offset;
259
260         para->AddRef();
261         o.parm.renderPara->textpara = para;
262         m_rc->submit(o);
263 }
264
265 void gPainter::fill(const eRect &area)
266 {
267         if ( m_dc->islocked() )
268                 return;
269         gOpcode o;
270         o.opcode=gOpcode::fill;
271
272         o.dc = m_dc.grabRef();
273         o.parm.fill = new gOpcode::para::pfillRect;
274         o.parm.fill->area = area;
275         m_rc->submit(o);
276 }
277
278 void gPainter::fill(const gRegion &region)
279 {
280         if ( m_dc->islocked() )
281                 return;
282         gOpcode o;
283         o.opcode=gOpcode::fillRegion;
284
285         o.dc = m_dc.grabRef();
286         o.parm.fillRegion = new gOpcode::para::pfillRegion;
287         o.parm.fillRegion->region = region;
288         m_rc->submit(o);
289 }
290
291 void gPainter::clear()
292 {
293         if ( m_dc->islocked() )
294                 return;
295         gOpcode o;
296         o.opcode=gOpcode::clear;
297         o.dc = m_dc.grabRef();
298         o.parm.fill = new gOpcode::para::pfillRect;
299         o.parm.fill->area = eRect();
300         m_rc->submit(o);
301 }
302
303 void gPainter::blit(gPixmap *pixmap, ePoint pos, const eRect &clip, int flags)
304 {
305         if ( m_dc->islocked() )
306                 return;
307         gOpcode o;
308
309         ASSERT(pixmap);
310
311         o.opcode=gOpcode::blit;
312         o.dc = m_dc.grabRef();
313         pixmap->AddRef();
314         o.parm.blit  = new gOpcode::para::pblit;
315         o.parm.blit->pixmap = pixmap;
316         o.parm.blit->position = pos;
317         o.parm.blit->clip = clip;
318         o.parm.blit->flags=flags;
319         m_rc->submit(o);
320 }
321
322
323 void gPainter::setPalette(gRGB *colors, int start, int len)
324 {
325         if ( m_dc->islocked() )
326                 return;
327         gOpcode o;
328         o.opcode=gOpcode::setPalette;
329         o.dc = m_dc.grabRef();
330         gPalette *p=new gPalette;
331
332         o.parm.setPalette = new gOpcode::para::psetPalette;
333         p->data=new gRGB[len];
334
335         memcpy(p->data, colors, len*sizeof(gRGB));
336         p->start=start;
337         p->colors=len;
338         o.parm.setPalette->palette = p;
339         m_rc->submit(o);
340 }
341
342 void gPainter::setPalette(gPixmap *source)
343 {
344         ASSERT(source);
345         setPalette(source->surface->clut.data, source->surface->clut.start, source->surface->clut.colors);
346 }
347
348 void gPainter::mergePalette(gPixmap *target)
349 {
350         if ( m_dc->islocked() )
351                 return;
352         gOpcode o;
353         o.opcode = gOpcode::mergePalette;
354         o.dc = m_dc.grabRef();
355         target->AddRef();
356         o.parm.mergePalette = new gOpcode::para::pmergePalette;
357         o.parm.mergePalette->target = target;
358         m_rc->submit(o);
359 }
360
361 void gPainter::line(ePoint start, ePoint end)
362 {
363         if ( m_dc->islocked() )
364                 return;
365         gOpcode o;
366         o.opcode=gOpcode::line;
367         o.dc = m_dc.grabRef();
368         o.parm.line = new gOpcode::para::pline;
369         o.parm.line->start = start;
370         o.parm.line->end = end;
371         m_rc->submit(o);
372 }
373
374 void gPainter::setOffset(ePoint val)
375 {
376         if ( m_dc->islocked() )
377                 return;
378         gOpcode o;
379         o.opcode=gOpcode::setOffset;
380         o.dc = m_dc.grabRef();
381         o.parm.setOffset = new gOpcode::para::psetOffset;
382         o.parm.setOffset->rel = 0;
383         o.parm.setOffset->value = val;
384         m_rc->submit(o);
385 }
386
387 void gPainter::moveOffset(ePoint rel)
388 {
389         if ( m_dc->islocked() )
390                 return;
391         gOpcode o;
392         o.opcode=gOpcode::setOffset;
393         o.dc = m_dc.grabRef();
394         o.parm.setOffset = new gOpcode::para::psetOffset;
395         o.parm.setOffset->rel = 1;
396         o.parm.setOffset->value = rel;
397         m_rc->submit(o);
398 }
399
400 void gPainter::resetOffset()
401 {
402         if ( m_dc->islocked() )
403                 return;
404         gOpcode o;
405         o.opcode=gOpcode::setOffset;
406         o.dc = m_dc.grabRef();
407         o.parm.setOffset = new gOpcode::para::psetOffset;
408         o.parm.setOffset->rel = 0;
409         o.parm.setOffset->value = ePoint(0, 0);
410         m_rc->submit(o);
411 }
412
413 void gPainter::resetClip(const gRegion &region)
414 {
415         if ( m_dc->islocked() )
416                 return;
417         gOpcode o;
418         o.opcode = gOpcode::setClip;
419         o.dc = m_dc.grabRef();
420         o.parm.clip = new gOpcode::para::psetClip;
421         o.parm.clip->region = region;
422         m_rc->submit(o);
423 }
424
425 void gPainter::clip(const gRegion &region)
426 {
427         if ( m_dc->islocked() )
428                 return;
429         gOpcode o;
430         o.opcode = gOpcode::addClip;
431         o.dc = m_dc.grabRef();
432         o.parm.clip = new gOpcode::para::psetClip;
433         o.parm.clip->region = region;
434         m_rc->submit(o);
435 }
436
437 void gPainter::clippop()
438 {
439         if ( m_dc->islocked() )
440                 return;
441         gOpcode o;
442         o.opcode = gOpcode::popClip;
443         o.dc = m_dc.grabRef();
444         m_rc->submit(o);
445 }
446
447 void gPainter::flush()
448 {
449         if ( m_dc->islocked() )
450                 return;
451         gOpcode o;
452         o.opcode = gOpcode::flush;
453         o.dc = m_dc.grabRef();
454         m_rc->submit(o);
455 }
456
457 void gPainter::waitVSync()
458 {
459         if ( m_dc->islocked() )
460                 return;
461         gOpcode o;
462         o.opcode = gOpcode::waitVSync;
463         o.dc = m_dc.grabRef();
464         m_rc->submit(o);
465 }
466
467 void gPainter::flip()
468 {
469         if ( m_dc->islocked() )
470                 return;
471         gOpcode o;
472         o.opcode = gOpcode::flip;
473         o.dc = m_dc.grabRef();
474         m_rc->submit(o);
475 }
476
477 void gPainter::notify()
478 {
479         if ( m_dc->islocked() )
480                 return;
481         gOpcode o;
482         o.opcode = gOpcode::notify;
483         o.dc = m_dc.grabRef();
484         m_rc->submit(o);
485 }
486
487 void gPainter::end()
488 {
489         if ( m_dc->islocked() )
490                 return;
491         gOpcode o;
492         o.opcode = gOpcode::flush;
493         o.dc = m_dc.grabRef();
494         m_rc->submit(o);
495 }
496
497 gDC::gDC()
498 {
499 }
500
501 gDC::gDC(gPixmap *pixmap): m_pixmap(pixmap)
502 {
503 }
504
505 gDC::~gDC()
506 {
507 }
508
509 void gDC::exec(gOpcode *o)
510 {
511         switch (o->opcode)
512         {
513         case gOpcode::setBackgroundColor:
514                 m_background_color = o->parm.setColor->color;
515                 delete o->parm.setColor;
516                 break;
517         case gOpcode::setForegroundColor:
518                 m_foreground_color = o->parm.setColor->color;
519                 delete o->parm.setColor;
520                 break;
521         case gOpcode::setBackgroundColorRGB:
522                 m_background_color = m_pixmap->surface->clut.findColor(o->parm.setColorRGB->color);
523                 delete o->parm.setColorRGB;
524                 break;
525         case gOpcode::setForegroundColorRGB:
526                 m_foreground_color = m_pixmap->surface->clut.findColor(o->parm.setColorRGB->color);
527                 delete o->parm.setColorRGB;
528                 break;
529         case gOpcode::setFont:
530                 m_current_font = o->parm.setFont->font;
531                 o->parm.setFont->font->Release();
532                 delete o->parm.setFont;
533                 break;
534         case gOpcode::renderText:
535         {
536                 ePtr<eTextPara> para = new eTextPara(o->parm.renderText->area);
537                 int flags = o->parm.renderText->flags;
538                 assert(m_current_font);
539                 para->setFont(m_current_font);
540                 para->renderString(o->parm.renderText->text, (flags & gPainter::RT_WRAP) ? RS_WRAP : 0);
541                 
542                 if (flags & gPainter::RT_HALIGN_RIGHT)
543                         para->realign(eTextPara::dirRight);
544                 else if (flags & gPainter::RT_HALIGN_CENTER)
545                         para->realign(eTextPara::dirCenter);
546                 else if (flags & gPainter::RT_HALIGN_BLOCK)
547                         para->realign(eTextPara::dirBlock);
548                 
549                 ePoint offset = m_current_offset;
550                 
551                 if (o->parm.renderText->flags & gPainter::RT_VALIGN_CENTER)
552                 {
553                         eRect bbox = para->getBoundBox();
554                         int vcentered_top = o->parm.renderText->area.top() + ((o->parm.renderText->area.height() - bbox.height()) / 2);
555                         int correction = vcentered_top - bbox.top();
556                         offset += ePoint(0, correction);
557                 }
558                 para->blit(*this, offset, getRGB(m_background_color), getRGB(m_foreground_color));
559                 delete o->parm.renderText;
560                 break;
561         }
562         case gOpcode::renderPara:
563         {
564                 o->parm.renderPara->textpara->blit(*this, o->parm.renderPara->offset + m_current_offset, getRGB(m_background_color), getRGB(m_foreground_color));
565                 o->parm.renderPara->textpara->Release();
566                 delete o->parm.renderPara;
567                 break;
568         }
569         case gOpcode::fill:
570         {
571                 eRect area = o->parm.fill->area;
572                 area.moveBy(m_current_offset);
573                 gRegion clip = m_current_clip & area;
574                 m_pixmap->fill(clip, m_foreground_color);
575                 delete o->parm.fill;
576                 break;
577         }
578         case gOpcode::fillRegion:
579         {
580                 o->parm.fillRegion->region.moveBy(m_current_offset);
581                 gRegion clip = m_current_clip & o->parm.fillRegion->region;
582                 m_pixmap->fill(clip, m_foreground_color);
583                 delete o->parm.fillRegion;
584                 break;
585         }
586         case gOpcode::clear:
587                 m_pixmap->fill(m_current_clip, m_background_color);
588                 delete o->parm.fill;
589                 break;
590         case gOpcode::blit:
591         {
592                 gRegion clip;
593                                 // this code should be checked again but i'm too tired now
594                 
595                 o->parm.blit->position += m_current_offset;
596                 
597                 if (o->parm.blit->clip.valid())
598                 {
599                         o->parm.blit->clip.moveBy(m_current_offset);
600                         clip.intersect(gRegion(o->parm.blit->clip), m_current_clip);
601                 } else
602                         clip = m_current_clip;
603                 
604                 m_pixmap->blit(*o->parm.blit->pixmap, o->parm.blit->position, clip, o->parm.blit->flags);
605                 o->parm.blit->pixmap->Release();
606                 delete o->parm.blit;
607                 break;
608         }
609         case gOpcode::setPalette:
610                 if (o->parm.setPalette->palette->start > m_pixmap->surface->clut.colors)
611                         o->parm.setPalette->palette->start = m_pixmap->surface->clut.colors;
612                 if (o->parm.setPalette->palette->colors > (m_pixmap->surface->clut.colors-o->parm.setPalette->palette->start))
613                         o->parm.setPalette->palette->colors = m_pixmap->surface->clut.colors-o->parm.setPalette->palette->start;
614                 if (o->parm.setPalette->palette->colors)
615                         memcpy(m_pixmap->surface->clut.data+o->parm.setPalette->palette->start, o->parm.setPalette->palette->data, o->parm.setPalette->palette->colors*sizeof(gRGB));
616                 
617                 delete[] o->parm.setPalette->palette->data;
618                 delete o->parm.setPalette->palette;
619                 delete o->parm.setPalette;
620                 break;
621         case gOpcode::mergePalette:
622                 m_pixmap->mergePalette(*o->parm.mergePalette->target);
623                 o->parm.mergePalette->target->Release();
624                 delete o->parm.mergePalette;
625                 break; 
626         case gOpcode::line:
627         {
628                 ePoint start = o->parm.line->start + m_current_offset, end = o->parm.line->end + m_current_offset;
629                 m_pixmap->line(m_current_clip, start, end, m_foreground_color);
630                 delete o->parm.line;
631                 break;
632         }
633         case gOpcode::addClip:
634                 m_clip_stack.push(m_current_clip);
635                 o->parm.clip->region.moveBy(m_current_offset);
636                 m_current_clip &= o->parm.clip->region;
637                 delete o->parm.clip;
638                 break;
639         case gOpcode::setClip:
640                 o->parm.clip->region.moveBy(m_current_offset);
641                 m_current_clip = o->parm.clip->region & eRect(ePoint(0, 0), m_pixmap->size());
642                 delete o->parm.clip;
643                 break;
644         case gOpcode::popClip:
645                 if (!m_clip_stack.empty())
646                 {
647                         m_current_clip = m_clip_stack.top();
648                         m_clip_stack.pop();
649                 }
650                 break;
651         case gOpcode::setOffset:
652                 if (o->parm.setOffset->rel)
653                         m_current_offset += o->parm.setOffset->value;
654                 else
655                         m_current_offset  = o->parm.setOffset->value;
656                 delete o->parm.setOffset;
657                 break;
658         case gOpcode::waitVSync:
659                 break;
660         case gOpcode::flip:
661                 break;
662         case gOpcode::flush:
663                 break;
664         default:
665                 eFatal("illegal opcode %d. expect memory leak!", o->opcode);
666         }
667 }
668
669 gRGB gDC::getRGB(gColor col)
670 {
671         if ((!m_pixmap) || (!m_pixmap->surface->clut.data))
672                 return gRGB(col, col, col);
673         if (col<0)
674         {
675                 eFatal("bla transp");
676                 return gRGB(0, 0, 0, 0xFF);
677         }
678         return m_pixmap->surface->clut.data[col];
679 }
680
681 DEFINE_REF(gDC);
682
683 eAutoInitPtr<gRC> init_grc(eAutoInitNumbers::graphic, "gRC");