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