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