add comment
[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_cond_signal(&cond);  // wakeup gdi thread
67                         pthread_mutex_unlock(&mutex);
68 #else
69                         thread();
70 #endif
71                         //printf("render buffer full...\n");
72                         //fflush(stdout);
73                         usleep(1000);  // wait 1 msec
74                         continue;
75                 }
76                 int free=rp-wp;
77                 if ( free <= 0 )
78                         free+=MAXSIZE;
79                 queue[wp++]=o;
80                 if ( wp == MAXSIZE )
81                         wp = 0;
82                 if (o.opcode==gOpcode::flush||o.opcode==gOpcode::shutdown||o.opcode==gOpcode::notify)
83 #ifndef SYNC_PAINT
84                         pthread_cond_signal(&cond);  // wakeup gdi thread
85                 pthread_mutex_unlock(&mutex);
86 #else
87                         thread(); // paint
88 #endif
89                 break;
90         }
91 }
92
93 void *gRC::thread()
94 {
95         int need_notify = 0;
96 #ifndef SYNC_PAINT
97         while (1)
98         {
99 #else
100         while (rp != wp)
101         {
102 #endif
103 #ifndef SYNC_PAINT
104                 pthread_mutex_lock(&mutex);
105 #endif
106                 if ( rp != wp )
107                 {
108                         gOpcode o(queue[rp++]);
109                         if ( rp == MAXSIZE )
110                                 rp=0;
111 #ifndef SYNC_PAINT
112                         pthread_mutex_unlock(&mutex);
113 #endif
114                         if (o.opcode==gOpcode::shutdown)
115                                 break;
116                         else if (o.opcode==gOpcode::notify)
117                                 need_notify = 1;
118                         else
119                         {
120                                 o.dc->exec(&o);
121                                 // o.dc is a gDC* filled with grabref... so we must release it here
122                                 o.dc->Release();
123                         }
124                 }
125                 else
126                 {
127                         if (need_notify)
128                         {
129                                 need_notify = 0;
130                                 m_notify_pump.send(1);
131                         }
132 #ifndef SYNC_PAINT
133                         while(rp == wp)
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.empty()?0:strdup(string.c_str());
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                 m_background_color_rgb = getRGB(m_background_color);
516                 delete o->parm.setColor;
517                 break;
518         case gOpcode::setForegroundColor:
519                 m_foreground_color = o->parm.setColor->color;
520                 m_background_color_rgb = getRGB(m_foreground_color);
521                 delete o->parm.setColor;
522                 break;
523         case gOpcode::setBackgroundColorRGB:
524                 if (m_pixmap->needClut())
525                         m_background_color = m_pixmap->surface->clut.findColor(o->parm.setColorRGB->color);
526                 m_background_color_rgb = o->parm.setColorRGB->color;
527                 delete o->parm.setColorRGB;
528                 break;
529         case gOpcode::setForegroundColorRGB:
530                 if (m_pixmap->needClut())
531                         m_foreground_color = m_pixmap->surface->clut.findColor(o->parm.setColorRGB->color);
532                 m_foreground_color_rgb = o->parm.setColorRGB->color;
533                 delete o->parm.setColorRGB;
534                 break;
535         case gOpcode::setFont:
536                 m_current_font = o->parm.setFont->font;
537                 o->parm.setFont->font->Release();
538                 delete o->parm.setFont;
539                 break;
540         case gOpcode::renderText:
541         {
542                 ePtr<eTextPara> para = new eTextPara(o->parm.renderText->area);
543                 int flags = o->parm.renderText->flags;
544                 assert(m_current_font);
545                 para->setFont(m_current_font);
546                 para->renderString(o->parm.renderText->text, (flags & gPainter::RT_WRAP) ? RS_WRAP : 0);
547                 if (o->parm.renderText->text)
548                         free(o->parm.renderText->text);
549                 if (flags & gPainter::RT_HALIGN_RIGHT)
550                         para->realign(eTextPara::dirRight);
551                 else if (flags & gPainter::RT_HALIGN_CENTER)
552                         para->realign(eTextPara::dirCenter);
553                 else if (flags & gPainter::RT_HALIGN_BLOCK)
554                         para->realign(eTextPara::dirBlock);
555                 
556                 ePoint offset = m_current_offset;
557                 
558                 if (o->parm.renderText->flags & gPainter::RT_VALIGN_CENTER)
559                 {
560                         eRect bbox = para->getBoundBox();
561                         int vcentered_top = o->parm.renderText->area.top() + ((o->parm.renderText->area.height() - bbox.height()) / 2);
562                         int correction = vcentered_top - bbox.top();
563                         offset += ePoint(0, correction);
564                 }
565                 
566                 para->blit(*this, offset, m_background_color_rgb, m_foreground_color_rgb);
567                 delete o->parm.renderText;
568                 break;
569         }
570         case gOpcode::renderPara:
571         {
572                 o->parm.renderPara->textpara->blit(*this, o->parm.renderPara->offset + m_current_offset, m_background_color_rgb, m_foreground_color_rgb);
573                 o->parm.renderPara->textpara->Release();
574                 delete o->parm.renderPara;
575                 break;
576         }
577         case gOpcode::fill:
578         {
579                 eRect area = o->parm.fill->area;
580                 area.moveBy(m_current_offset);
581                 gRegion clip = m_current_clip & area;
582                 if (m_pixmap->needClut())
583                         m_pixmap->fill(clip, m_foreground_color);
584                 else
585                         m_pixmap->fill(clip, m_foreground_color_rgb);
586                 delete o->parm.fill;
587                 break;
588         }
589         case gOpcode::fillRegion:
590         {
591                 o->parm.fillRegion->region.moveBy(m_current_offset);
592                 gRegion clip = m_current_clip & o->parm.fillRegion->region;
593                 if (m_pixmap->needClut())
594                         m_pixmap->fill(clip, m_foreground_color);
595                 else
596                         m_pixmap->fill(clip, m_foreground_color_rgb);
597                 delete o->parm.fillRegion;
598                 break;
599         }
600         case gOpcode::clear:
601                 if (m_pixmap->needClut())
602                         m_pixmap->fill(m_current_clip, m_background_color);
603                 else
604                         m_pixmap->fill(m_current_clip, m_background_color_rgb);
605                 delete o->parm.fill;
606                 break;
607         case gOpcode::blit:
608         {
609                 gRegion clip;
610                                 // this code should be checked again but i'm too tired now
611                 
612                 o->parm.blit->position += m_current_offset;
613                 
614                 if (o->parm.blit->clip.valid())
615                 {
616                         o->parm.blit->clip.moveBy(m_current_offset);
617                         clip.intersect(gRegion(o->parm.blit->clip), m_current_clip);
618                 } else
619                         clip = m_current_clip;
620                 
621                 m_pixmap->blit(*o->parm.blit->pixmap, o->parm.blit->position, clip, o->parm.blit->flags);
622                 o->parm.blit->pixmap->Release();
623                 delete o->parm.blit;
624                 break;
625         }
626         case gOpcode::setPalette:
627                 if (o->parm.setPalette->palette->start > m_pixmap->surface->clut.colors)
628                         o->parm.setPalette->palette->start = m_pixmap->surface->clut.colors;
629                 if (o->parm.setPalette->palette->colors > (m_pixmap->surface->clut.colors-o->parm.setPalette->palette->start))
630                         o->parm.setPalette->palette->colors = m_pixmap->surface->clut.colors-o->parm.setPalette->palette->start;
631                 if (o->parm.setPalette->palette->colors)
632                         memcpy(m_pixmap->surface->clut.data+o->parm.setPalette->palette->start, o->parm.setPalette->palette->data, o->parm.setPalette->palette->colors*sizeof(gRGB));
633                 
634                 delete[] o->parm.setPalette->palette->data;
635                 delete o->parm.setPalette->palette;
636                 delete o->parm.setPalette;
637                 break;
638         case gOpcode::mergePalette:
639                 m_pixmap->mergePalette(*o->parm.mergePalette->target);
640                 o->parm.mergePalette->target->Release();
641                 delete o->parm.mergePalette;
642                 break; 
643         case gOpcode::line:
644         {
645                 ePoint start = o->parm.line->start + m_current_offset, end = o->parm.line->end + m_current_offset;
646                 m_pixmap->line(m_current_clip, start, end, m_foreground_color);
647                 delete o->parm.line;
648                 break;
649         }
650         case gOpcode::addClip:
651                 m_clip_stack.push(m_current_clip);
652                 o->parm.clip->region.moveBy(m_current_offset);
653                 m_current_clip &= o->parm.clip->region;
654                 delete o->parm.clip;
655                 break;
656         case gOpcode::setClip:
657                 o->parm.clip->region.moveBy(m_current_offset);
658                 m_current_clip = o->parm.clip->region & eRect(ePoint(0, 0), m_pixmap->size());
659                 delete o->parm.clip;
660                 break;
661         case gOpcode::popClip:
662                 if (!m_clip_stack.empty())
663                 {
664                         m_current_clip = m_clip_stack.top();
665                         m_clip_stack.pop();
666                 }
667                 break;
668         case gOpcode::setOffset:
669                 if (o->parm.setOffset->rel)
670                         m_current_offset += o->parm.setOffset->value;
671                 else
672                         m_current_offset  = o->parm.setOffset->value;
673                 delete o->parm.setOffset;
674                 break;
675         case gOpcode::waitVSync:
676                 break;
677         case gOpcode::flip:
678                 break;
679         case gOpcode::flush:
680                 break;
681         default:
682                 eFatal("illegal opcode %d. expect memory leak!", o->opcode);
683         }
684 }
685
686 gRGB gDC::getRGB(gColor col)
687 {
688         if ((!m_pixmap) || (!m_pixmap->surface->clut.data))
689                 return gRGB(col, col, col);
690         if (col<0)
691         {
692                 eFatal("bla transp");
693                 return gRGB(0, 0, 0, 0xFF);
694         }
695         return m_pixmap->surface->clut.data[col];
696 }
697
698 DEFINE_REF(gDC);
699
700 eAutoInitPtr<gRC> init_grc(eAutoInitNumbers::graphic, "gRC");