Hi, some more patches: HASHSIZE should be a prime: 512 looks like a typo of 521. oprofile and gprof showed the possibilty to speed up some OSD drawing operations. Please find attached a patch for DrawRectangle and DrawBitmap. BTW: text2skin will not benefit from the DrawBitmap changes as it uses it's own copy of DrawBitmap. oprofile also showed strreplace among the top 10 when profiling a 120 second VDR session. Please find attached a "faster" solution. Bye. -- Dipl.-Inform. (FH) Reinhard Nissl mailto:rnissl@xxxxxx
--- ../vdr-1.5.12-orig/tools.h 2007-08-25 16:16:39.000000000 +0200 +++ tools.h 2007-12-06 22:58:05.000000000 +0100 @@ -523,7 +525,7 @@ public: cList<cHashObject> *GetList(unsigned int Id) const; }; -#define HASHSIZE 512 +#define HASHSIZE 521 template<class T> class cHash : public cHashBase { public:
--- ../vdr-1.5.12-orig/osd.h 2007-10-12 16:28:44.000000000 +0200 +++ osd.h 2007-12-26 22:49:13.000000000 +0100 @@ -135,6 +135,7 @@ private: int x0, y0; int width, height; int dirtyX1, dirtyY1, dirtyX2, dirtyY2; + void SetIndexInternal(int x, int y, tIndex Index); public: cBitmap(int Width, int Height, int Bpp, int X0 = 0, int Y0 = 0); ///< Creates a bitmap with the given Width, Height and color depth (Bpp). --- ../vdr-1.5.12-orig/osd.c 2007-10-12 14:38:36.000000000 +0200 +++ osd.c 2007-12-26 23:44:23.000000000 +0100 @@ -394,15 +394,20 @@ bool cBitmap::SetXpm(const char *const X void cBitmap::SetIndex(int x, int y, tIndex Index) { if (bitmap) { - if (0 <= x && x < width && 0 <= y && y < height) { - if (bitmap[width * y + x] != Index) { - bitmap[width * y + x] = Index; - if (dirtyX1 > x) dirtyX1 = x; - if (dirtyY1 > y) dirtyY1 = y; - if (dirtyX2 < x) dirtyX2 = x; - if (dirtyY2 < y) dirtyY2 = y; - } - } + if (0 <= x && x < width && 0 <= y && y < height) + SetIndexInternal(x, y, Index); + } +} + +void cBitmap::SetIndexInternal(int x, int y, tIndex Index) +{ + // this function relies on existing bitmap and valid coordinates + if (bitmap[width * y + x] != Index) { + bitmap[width * y + x] = Index; + if (dirtyX1 > x) dirtyX1 = x; + if (dirtyY1 > y) dirtyY1 = y; + if (dirtyX2 < x) dirtyX2 = x; + if (dirtyY2 < y) dirtyY2 = y; } } @@ -410,37 +415,142 @@ void cBitmap::DrawPixel(int x, int y, tC { x -= x0; y -= y0; - if (0 <= x && x < width && 0 <= y && y < height) - SetIndex(x, y, Index(Color)); + if (bitmap && 0 <= x && x < width && 0 <= y && y < height) + SetIndexInternal(x, y, Index(Color)); } void cBitmap::DrawBitmap(int x, int y, const cBitmap &Bitmap, tColor ColorFg, tColor ColorBg, bool ReplacePalette, bool Overlay) { if (bitmap && Bitmap.bitmap && Intersects(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1)) { - if (Covers(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1)) + bool Covered = Covers(x, y, x + Bitmap.Width() - 1, y + Bitmap.Height() - 1); + if (Covered) Reset(); x -= x0; y -= y0; - if (ReplacePalette && Covers(x + x0, y + y0, x + x0 + Bitmap.Width() - 1, y + y0 + Bitmap.Height() - 1)) { + // determine valid destination area [x1,x2]x[y1,y2] to avoid range checks inside the loops + int x1 = max(0, x), x2 = min(0 + width , x + Bitmap.width) - 1; + int y1 = max(0, y), y2 = min(0 + height, y + Bitmap.height) - 1; + +#define FOR_Y_LOOP0 \ + tIndex *pRowSrc = &Bitmap.bitmap[Bitmap.width * (y1 - y) + (x1 - x)]; \ + tIndex *pRowDst = &bitmap[width * y1 + x1]; \ + for (int &yy = y1, ye = min(y2, dirtyY1 - 1); yy <= ye; yy++, pRowDst += width, pRowSrc += Bitmap.width) + +#define FOR_Y_LOOP1 \ + tIndex *pRowSrc = &Bitmap.bitmap[Bitmap.width * (y2 - y) + (x1 - x)]; \ + tIndex *pRowDst = &bitmap[width * y2 + x1]; \ + for (int &yy = y2, ye = max(y1, dirtyY2 + 1); yy >= ye; yy--, pRowDst -= width, pRowSrc -= Bitmap.width) + +#define DETECT_DIRTY_AREA_Y(Reverse, TransferCondition, TransferOperation) \ + do { \ + FOR_Y_LOOP##Reverse { \ + tIndex *pSrc = pRowSrc; \ + tIndex *pDst = pRowDst; \ + bool GotDirty = false; \ + for (int xx = x1; xx <= x2; xx++) { \ + if (TransferCondition) { \ + if (*pDst != TransferOperation) { \ + GotDirty = true; \ + if (dirtyX1 > xx) dirtyX1 = xx; \ + if (dirtyX2 < xx) dirtyX2 = xx; \ + } \ + } \ + pSrc++; \ + pDst++; \ + } \ + if (GotDirty) { \ + if (dirtyY1 > yy) dirtyY1 = yy; \ + if (dirtyY2 < yy) dirtyY2 = yy; \ + break; \ + } \ + } \ + } \ + while (false) + +#define FOR_X_LOOP0 \ + tIndex *pColSrc = &Bitmap.bitmap[Bitmap.width * (y1 - y) + (x1 - x)]; \ + tIndex *pColDst = &bitmap[width * y1 + x1]; \ + for (int &xx = x1, xe = min(x2, dirtyX1 - 1); xx <= xe; xx++, pColDst++, pColSrc++) + +#define FOR_X_LOOP1 \ + tIndex *pColSrc = &Bitmap.bitmap[Bitmap.width * (y1 - y) + (x2 - x)]; \ + tIndex *pColDst = &bitmap[width * y1 + x2]; \ + for (int &xx = x2, xe = max(x1, dirtyX2 + 1); xx >= xe; xx--, pColDst--, pColSrc--) + +#define DETECT_DIRTY_AREA_X(Reverse, TransferCondition, TransferOperation) \ + do { \ + FOR_X_LOOP##Reverse { \ + tIndex *pSrc = pColSrc; \ + tIndex *pDst = pColDst; \ + bool GotDirty = false; \ + for (int yy = y1; yy <= y2; yy++) { \ + if (TransferCondition) { \ + if (*pDst != TransferOperation) { \ + GotDirty = true; \ + if (dirtyX1 > xx) dirtyX1 = xx; \ + if (dirtyX2 < xx) dirtyX2 = xx; \ + break; \ + } \ + } \ + pSrc += Bitmap.width; \ + pDst += width; \ + } \ + if (GotDirty) \ + break; \ + } \ + } \ + while (false) + +#define DRAW_BITMAP(TransferCondition, TransferOperation) \ + do { \ + DETECT_DIRTY_AREA_Y(0, TransferCondition, TransferOperation); /* above */ \ + DETECT_DIRTY_AREA_Y(1, TransferCondition, TransferOperation); /* below */ \ + if (y2 < y1) /* nothing dirty */ \ + return; \ + DETECT_DIRTY_AREA_X(0, TransferCondition, TransferOperation); /* left */ \ + DETECT_DIRTY_AREA_X(1, TransferCondition, TransferOperation); /* right */ \ + /* process dirty area now */ \ + tIndex *pRowSrc = &Bitmap.bitmap[Bitmap.width * (y1 - y) + (x1 - x)]; \ + tIndex *pRowDst = &bitmap[width * y1 + x1]; \ + for (int yy = y1; yy <= y2; yy++) { \ + tIndex *pSrc = pRowSrc; \ + tIndex *pDst = pRowDst; \ + for (int xx = x1; xx <= x2; xx++) { \ + if (TransferCondition) \ + *pDst = TransferOperation; \ + pSrc++; \ + pDst++; \ + } \ + pRowSrc += Bitmap.width; \ + pRowDst += width; \ + } \ + } \ + while (false) + + if (ReplacePalette && Covered) { Replace(Bitmap); - for (int ix = 0; ix < Bitmap.width; ix++) { - for (int iy = 0; iy < Bitmap.height; iy++) { - if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0) - SetIndex(x + ix, y + iy, Bitmap.bitmap[Bitmap.width * iy + ix]); - } - } + if (Overlay) + DRAW_BITMAP(*pSrc != 0, *pSrc); + else + DRAW_BITMAP(true, *pSrc); } else { tIndexes Indexes; Take(Bitmap, &Indexes, ColorFg, ColorBg); - for (int ix = 0; ix < Bitmap.width; ix++) { - for (int iy = 0; iy < Bitmap.height; iy++) { - if (!Overlay || Bitmap.bitmap[Bitmap.width * iy + ix] != 0) - SetIndex(x + ix, y + iy, Indexes[int(Bitmap.bitmap[Bitmap.width * iy + ix])]); - } - } + if (Overlay) + DRAW_BITMAP(*pSrc != 0, Indexes[(int)*pSrc]); + else + DRAW_BITMAP(true, Indexes[(int)*pSrc]); } } + +#undef DRAW_BITMAP +#undef DETECT_DIRTY_AREA_Y +#undef FOR_Y_LOOP0 +#undef FOR_Y_LOOP1 +#undef DETECT_DIRTY_AREA_X +#undef FOR_X_LOOP0 +#undef FOR_X_LOOP1 } void cBitmap::DrawText(int x, int y, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font, int Width, int Height, int Alignment) @@ -502,10 +612,87 @@ void cBitmap::DrawRectangle(int x1, int x2 = min(x2, width - 1); y2 = min(y2, height - 1); tIndex c = Index(Color); - for (int y = y1; y <= y2; y++) + +#define FOR_Y_LOOP0 \ + tIndex *pRowDst = &bitmap[width * y1 + x1]; \ + for (int &yy = y1, ye = min(y2, dirtyY1 - 1); yy <= ye; yy++, pRowDst += width) + +#define FOR_Y_LOOP1 \ + tIndex *pRowDst = &bitmap[width * y2 + x1]; \ + for (int &yy = y2, ye = max(y1, dirtyY2 + 1); yy >= ye; yy--, pRowDst -= width) + +#define DETECT_DIRTY_AREA_Y(Reverse) \ + do { \ + FOR_Y_LOOP##Reverse { \ + tIndex *pDst = pRowDst; \ + bool GotDirty = false; \ + for (int xx = x1; xx <= x2; xx++) { \ + if (*pDst != c) { \ + GotDirty = true; \ + if (dirtyX1 > xx) dirtyX1 = xx; \ + if (dirtyX2 < xx) dirtyX2 = xx; \ + } \ + pDst++; \ + } \ + if (GotDirty) { \ + if (dirtyY1 > yy) dirtyY1 = yy; \ + if (dirtyY2 < yy) dirtyY2 = yy; \ + break; \ + } \ + } \ + } \ + while (false) + +#define FOR_X_LOOP0 \ + tIndex *pColDst = &bitmap[width * y1 + x1]; \ + for (int &xx = x1, xe = min(x2, dirtyX1 - 1); xx <= xe; xx++, pColDst++) + +#define FOR_X_LOOP1 \ + tIndex *pColDst = &bitmap[width * y1 + x2]; \ + for (int &xx = x2, xe = max(x1, dirtyX2 + 1); xx >= xe; xx--, pColDst--) + +#define DETECT_DIRTY_AREA_X(Reverse) \ + do { \ + FOR_X_LOOP##Reverse { \ + tIndex *pDst = pColDst; \ + bool GotDirty = false; \ + for (int yy = y1; yy <= y2; yy++) { \ + if (*pDst != c) { \ + GotDirty = true; \ + if (dirtyX1 > xx) dirtyX1 = xx; \ + if (dirtyX2 < xx) dirtyX2 = xx; \ + break; \ + } \ + pDst += width; \ + } \ + if (GotDirty) \ + break; \ + } \ + } \ + while (false) + + DETECT_DIRTY_AREA_Y(0); /* above */ + DETECT_DIRTY_AREA_Y(1); /* below */ + if (y2 < y1) /* nothing dirty */ + return; + DETECT_DIRTY_AREA_X(0); /* left */ + DETECT_DIRTY_AREA_X(1); /* right */ + // now fill only dirty area of rectangle + tIndex *pRowDst = &bitmap[width * y1 + x1]; + for (int y = y1; y <= y2; y++) { + tIndex *pDst = pRowDst; for (int x = x1; x <= x2; x++) - SetIndex(x, y, c); + *pDst++ = c; + pRowDst += width; + } } + +#undef DETECT_DIRTY_AREA_Y +#undef FOR_Y_LOOP0 +#undef FOR_Y_LOOP1 +#undef DETECT_DIRTY_AREA_X +#undef FOR_X_LOOP0 +#undef FOR_X_LOOP1 } void cBitmap::DrawEllipse(int x1, int y1, int x2, int y2, tColor Color, int Quadrants)
--- ../vdr-1.5.12-orig/tools.c 2007-11-03 16:34:07.000000000 +0100 +++ tools.c 2007-12-27 00:31:31.000000000 +0100 @@ -140,11 +142,8 @@ char *strreplace(char *s, char c1, char { if (s) { char *p = s; - while (*p) { - if (*p == c1) - *p = c2; - p++; - } + while ((p = strchr(p, c1))) + *p++ = c2; } return s; }
_______________________________________________ vdr mailing list vdr@xxxxxxxxxxx http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr