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