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