From patchwork Fri Dec 28 22:26:59 2007 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Reinhard Nissl X-Patchwork-Id: 12560 Received: from mail.gmx.net ([213.165.64.20]) by www.linuxtv.org with smtp (Exim 4.63) (envelope-from ) id 1J8Nfw-0002bu-22 for vdr@linuxtv.org; Fri, 28 Dec 2007 23:27:32 +0100 Received: (qmail invoked by alias); 28 Dec 2007 22:27:00 -0000 Received: from p54933202.dip0.t-ipconnect.de (EHLO [192.168.101.15]) [84.147.50.2] by mail.gmx.net (mp047) with SMTP; 28 Dec 2007 23:27:00 +0100 X-Authenticated: #527675 X-Provags-ID: V01U2FsdGVkX1+8Bsk9o1S8ImWZ1tDPO2CNfbYXjR3LjX36ljwpDy 9uviGM082igbX6 Message-ID: <47757833.6020701@gmx.de> Date: Fri, 28 Dec 2007 23:26:59 +0100 From: Reinhard Nissl User-Agent: Mozilla/5.0 (X11; U; Linux i686; de; rv:1.8.1.9) Gecko/20070801 SUSE/2.0.0.9-0.1 Thunderbird/2.0.0.9 Mnenhy/0.7.5.666 MIME-Version: 1.0 To: VDR Mailing List References: <476ED734.4010802@gmx.de> <4772E6E6.7040909@gmx.de> <477417C7.2080707@gmx.de> In-Reply-To: <477417C7.2080707@gmx.de> X-Y-GMX-Trusted: 0 Subject: Re: [vdr] [ANNOUNCE] VDR-1.5.12: some "micro" speed improvements X-BeenThere: vdr@linuxtv.org X-Mailman-Version: 2.1.9 Precedence: list Reply-To: VDR Mailing List List-Id: VDR Mailing List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 28 Dec 2007 22:27:32 -0000 Status: O X-Status: X-Keywords: X-UID: 14913 Hi, the first patch optimizes cNitFilter::Process() by looping only over the relevant channels. It introduces a further hash in cChannels and implements an iterator for hiding this implementation detail. The channel_display patch avoids to call DrawText() when the "date" text has not changed in the channel display. As DrawText() calls DrawRectangle() when a non transparent background color was specified, drawing the same text will always yield a dirty area although there is no difference when looking at the bitmap before and after the call to DrawText(). And finally, the formerly released osd_draw patch has been updated a little bit. DrawBitmap() and DrawRectangle() use now memcpy() when possible. Bye. --- ../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-28 10:21:35.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,147 @@ 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, CanUseMemCpy) \ + 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]; \ + int n = sizeof(tIndex) * (x2 - x1 + 1); \ + for (int yy = y1; yy <= y2; yy++) { \ + tIndex *pSrc = pRowSrc; \ + tIndex *pDst = pRowDst; \ + if (CanUseMemCpy) \ + memcpy(pDst, pSrc, n); \ + else { \ + 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, false); + else + DRAW_BITMAP(true, *pSrc, true); } 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], false); + else + DRAW_BITMAP(true, Indexes[(int)*pSrc], false); } } + +#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 +617,91 @@ 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++) - for (int x = x1; x <= x2; x++) - SetIndex(x, y, c); + +#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]; + tIndex *pDst = pRowDst; + for (int x = x1; x <= x2; x++) + *pDst++ = c; + // copy the single line above to all other lines + tIndex *pRowSrc = pRowDst; + int n = sizeof(tIndex) * (x2 - x1 + 1); + for (int y = y1 + 1; y <= y2; y++) { + pRowDst += width; + memcpy(pRowDst, pRowSrc, n); + } } + +#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)