Re: [ANNOUNCE] VDR-1.5.12: some "micro" speed improvements

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.
-- 
Dipl.-Inform. (FH) Reinhard Nissl
mailto:rnissl@xxxxxx
--- ../vdr-1.5.12-orig/channels.h	2007-09-02 12:23:11.000000000 +0200
+++ channels.h	2007-12-28 22:56:02.000000000 +0100
@@ -219,13 +219,49 @@ public:
   void SetRefChannel(cChannel *RefChannel);
   };
 
+class cIteratorImpl {
+private:
+  int refCount;
+  cIteratorImpl(const cIteratorImpl &);
+  const cIteratorImpl &operator =(const cIteratorImpl &);
+public:
+  cIteratorImpl(void) { refCount = 0; }
+  virtual ~cIteratorImpl() {}
+  virtual int AddRef(void) { return ++refCount; }
+  virtual int DelRef(void) { int RefCount = --refCount; if (RefCount <= 0) delete this; return RefCount; }
+  virtual void *First(void) = 0;
+  virtual void *Last(void)  = 0;
+  virtual void *Prev(void)  = 0;
+  virtual void *Next(void)  = 0;
+  virtual void *Current(void) const = 0;
+  };
+
+template <class T> class cIterator
+{
+private:
+  cIteratorImpl *impl;
+public:
+  cIterator(cIteratorImpl *Impl) { impl = Impl; impl->AddRef(); }
+  cIterator(const cIterator &rhs) { impl = rhs.impl; impl->AddRef(); }
+  ~cIterator() { impl->DelRef(); }
+  const cIterator &operator =(const cIterator &rhs) { rhs.impl->AddRef(); impl->DelRef(); impl = rhs.impl; return *this; }
+  T *First(void) const   { return (T *)impl->First(); }
+  T *Last(void) const    { return (T *)impl->Last(); }
+  T *Prev(void) const    { return (T *)impl->Prev(); }
+  T *Next(void) const    { return (T *)impl->Next(); }
+  T *Current(void) const { return (T *)impl->Current(); }
+  };
+
 class cChannels : public cRwLock, public cConfig<cChannel> {
 private:
   int maxNumber;
   int modified;
   int beingEdited;
   cHash<cChannel> channelsHashSid;
+  cHash<cChannel> channelsHashNidTid;
   void DeleteDuplicateChannels(void);
+  void ClearChannelHashes(void);
+  static unsigned int HashKeyNidTid(unsigned short Nid, unsigned short Tid);
 public:
   cChannels(void);
   bool Load(const char *FileName, bool AllowComments = false, bool MustExist = false);
@@ -240,6 +276,7 @@ public:
   cChannel *GetByServiceID(int Source, int Transponder, unsigned short ServiceID);
   cChannel *GetByChannelID(tChannelID ChannelID, bool TryWithoutRid = false, bool TryWithoutPolarization = false);
   cChannel *GetByTransponderID(tChannelID ChannelID);
+  cIterator<cChannel> GetChannelsBySourceNidTid(int Source, unsigned short Nid, unsigned short Tid);
   int BeingEdited(void) { return beingEdited; }
   void IncBeingEdited(void) { beingEdited++; }
   void DecBeingEdited(void) { beingEdited--; }
--- ../vdr-1.5.12-orig/channels.c	2007-10-12 16:40:53.000000000 +0200
+++ channels.c	2007-12-28 22:56:02.000000000 +0100
@@ -905,14 +905,72 @@ bool cChannels::Load(const char *FileNam
   return false;
 }
 
+void cChannels::ClearChannelHashes(void)
+{
+  channelsHashSid.Clear();
+  channelsHashNidTid.Clear();
+}
+
 void cChannels::HashChannel(cChannel *Channel)
 {
   channelsHashSid.Add(Channel, Channel->Sid());
+  channelsHashNidTid.Add(Channel, HashKeyNidTid(Channel->Nid(), Channel->Tid()));
 }
 
 void cChannels::UnhashChannel(cChannel *Channel)
 {
   channelsHashSid.Del(Channel, Channel->Sid());
+  channelsHashNidTid.Del(Channel, HashKeyNidTid(Channel->Nid(), Channel->Tid()));
+}
+
+unsigned int cChannels::HashKeyNidTid(unsigned short Nid, unsigned short Tid)
+{
+  return Nid << 16 | Tid;
+}
+
+cIterator<cChannel> cChannels::GetChannelsBySourceNidTid(int Source, unsigned short Nid, unsigned short Tid)
+{
+  class cIteratorImplSourceNidTid : public cIteratorImpl {
+  private:
+    cList<cHashObject> *hashList;
+    cHashObject *current;
+    int source;
+    unsigned short nid;
+    unsigned short tid;
+    cChannel *FindMatchingChannel(bool reverse, bool reset = false) {
+      if (!hashList || (!current && !reset))
+         return NULL;
+      while (true) {
+            if (reset) {
+               reset = false;
+               current = reverse ? hashList->Last() : hashList->First();
+               }
+            else
+               current = reverse ? hashList->Prev(current) : hashList->Next(current);
+            if (!current)
+               break;
+            cChannel *Channel = (cChannel *)current->Object();
+            if (Channel->Source() == source && Channel->Nid() == nid && Channel->Tid() == tid)
+               return Channel;
+            }
+      return NULL;
+      }
+  public:
+    cIteratorImplSourceNidTid(cList<cHashObject> *HashList, int Source, unsigned short Nid, unsigned short Tid) {
+       hashList = HashList;
+       source = Source;
+       nid = Nid;
+       tid = Tid;
+       current = NULL;
+       }
+    virtual void *First(void) { return FindMatchingChannel(false, true); }
+    virtual void *Last(void)  { return FindMatchingChannel(true,  true); }
+    virtual void *Prev(void)  { return FindMatchingChannel(false); }
+    virtual void *Next(void)  { return FindMatchingChannel(true);  }
+    virtual void *Current(void) const  { return current ? (cChannel *)current->Object() : NULL; }
+    };
+
+  return cIterator<cChannel>(new cIteratorImplSourceNidTid(channelsHashNidTid.GetList(HashKeyNidTid(Nid, Tid)), Source, Nid, Tid));
 }
 
 int cChannels::GetNextGroup(int Idx)
@@ -949,7 +1007,7 @@ int cChannels::GetPrevNormal(int Idx)
 
 void cChannels::ReNumber( void )
 {
-  channelsHashSid.Clear();
+  ClearChannelHashes();
   int Number = 1;
   for (cChannel *channel = First(); channel; channel = Next(channel)) {
       if (channel->GroupSep()) {
--- ../vdr-1.5.12-orig/nit.c	2007-08-17 16:02:45.000000000 +0200
+++ nit.c	2007-12-28 22:58:21.000000000 +0100
@@ -142,20 +142,19 @@ void cNitFilter::Process(u_short Pid, u_
                     }
                  if (Setup.UpdateChannels >= 5) {
                     bool found = false;
-                    for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
-                        if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
-                           int transponder = Channel->Transponder();
-                           if (!ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), transponder)) {
-                              for (int n = 0; n < NumFrequencies; n++) {
-                                  if (ISTRANSPONDER(cChannel::Transponder(Frequencies[n], Polarization), transponder)) {
-                                     Frequency = Frequencies[n];
-                                     break;
-                                     }
+                    cIterator<cChannel> ChannelIterator = Channels.GetChannelsBySourceNidTid(Source, ts.getOriginalNetworkId(), ts.getTransportStreamId());
+                    for (cChannel *Channel = ChannelIterator.First(); Channel; Channel = ChannelIterator.Next()) {
+                        int transponder = Channel->Transponder();
+                        if (!ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), transponder)) {
+                           for (int n = 0; n < NumFrequencies; n++) {
+                               if (ISTRANSPONDER(cChannel::Transponder(Frequencies[n], Polarization), transponder)) {
+                                  Frequency = Frequencies[n];
+                                  break;
                                   }
-                              }
-                           if (ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), Transponder())) // only modify channels if we're actually receiving this transponder
-                              Channel->SetSatTransponderData(Source, Frequency, Polarization, SymbolRate, CodeRate);
+                               }
                            }
+                        if (ISTRANSPONDER(cChannel::Transponder(Frequency, Polarization), Transponder())) // only modify channels if we're actually receiving this transponder
+                           Channel->SetSatTransponderData(Source, Frequency, Polarization, SymbolRate, CodeRate);
                         found = true;
                         }
                     if (!found) {
@@ -193,20 +192,19 @@ void cNitFilter::Process(u_short Pid, u_
                     }
                  if (Setup.UpdateChannels >= 5) {
                     bool found = false;
-                    for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
-                        if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
-                           int transponder = Channel->Transponder();
-                           if (!ISTRANSPONDER(Frequency / 1000, transponder)) {
-                              for (int n = 0; n < NumFrequencies; n++) {
-                                  if (ISTRANSPONDER(Frequencies[n] / 1000, transponder)) {
-                                     Frequency = Frequencies[n];
-                                     break;
-                                     }
+                    cIterator<cChannel> ChannelIterator = Channels.GetChannelsBySourceNidTid(Source, ts.getOriginalNetworkId(), ts.getTransportStreamId());
+                    for (cChannel *Channel = ChannelIterator.First(); Channel; Channel = ChannelIterator.Next()) {
+                        int transponder = Channel->Transponder();
+                        if (!ISTRANSPONDER(Frequency / 1000, transponder)) {
+                           for (int n = 0; n < NumFrequencies; n++) {
+                               if (ISTRANSPONDER(Frequencies[n] / 1000, transponder)) {
+                                  Frequency = Frequencies[n];
+                                  break;
                                   }
-                              }
-                           if (ISTRANSPONDER(Frequency / 1000, Transponder())) // only modify channels if we're actually receiving this transponder
-                              Channel->SetCableTransponderData(Source, Frequency, Modulation, SymbolRate, CodeRate);
+                               }
                            }
+                        if (ISTRANSPONDER(Frequency / 1000, Transponder())) // only modify channels if we're actually receiving this transponder
+                           Channel->SetCableTransponderData(Source, Frequency, Modulation, SymbolRate, CodeRate);
                         found = true;
                         }
                     if (!found) {
@@ -251,32 +249,31 @@ void cNitFilter::Process(u_short Pid, u_
                     }
                  if (Setup.UpdateChannels >= 5) {
                     bool found = false;
-                    for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
-                        if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
-                           int transponder = Channel->Transponder();
-                           if (!ISTRANSPONDER(Frequency / 1000000, transponder)) {
-                              for (int n = 0; n < NumFrequencies; n++) {
-                                  if (ISTRANSPONDER(Frequencies[n] / 1000000, transponder)) {
-                                     Frequency = Frequencies[n];
-                                     break;
-                                     }
+                    cIterator<cChannel> ChannelIterator = Channels.GetChannelsBySourceNidTid(Source, ts.getOriginalNetworkId(), ts.getTransportStreamId());
+                    for (cChannel *Channel = ChannelIterator.First(); Channel; Channel = ChannelIterator.Next()) {
+                        int transponder = Channel->Transponder();
+                        if (!ISTRANSPONDER(Frequency / 1000000, transponder)) {
+                           for (int n = 0; n < NumFrequencies; n++) {
+                               if (ISTRANSPONDER(Frequencies[n] / 1000000, transponder)) {
+                                  Frequency = Frequencies[n];
+                                  break;
                                   }
-                              }
-                           if (ISTRANSPONDER(Frequency / 1000000, Transponder())) // only modify channels if we're actually receiving this transponder
-                              Channel->SetTerrTransponderData(Source, Frequency, Bandwidth, Constellation, Hierarchy, CodeRateHP, CodeRateLP, GuardInterval, TransmissionMode);
+                               }
                            }
+                        if (ISTRANSPONDER(Frequency / 1000000, Transponder())) // only modify channels if we're actually receiving this transponder
+                           Channel->SetTerrTransponderData(Source, Frequency, Bandwidth, Constellation, Hierarchy, CodeRateHP, CodeRateLP, GuardInterval, TransmissionMode);
                         found = true;
                         }
                     if (!found) {
                        for (int n = 0; n < NumFrequencies; n++) {
                            cChannel *Channel = new cChannel;
                            Channel->SetId(ts.getOriginalNetworkId(), ts.getTransportStreamId(), 0, 0);
-                           if (Channel->SetTerrTransponderData(Source, Frequencies[n], Bandwidth, Constellation, Hierarchy, CodeRateHP, CodeRateLP, GuardInterval, TransmissionMode))
+                           if (Channel->SetTerrTransponderData(Source, Frequencies[n], Bandwidth, Constellation, Hierarchy, CodeRateHP, CodeRateLP, GuardInterval, TransmissionMode, Alpha, Priority))
                               EITScanner.AddTransponder(Channel);
                            else
                               delete Channel;
                            }
-                        }
+                       }
                     }
                  }
                  break;
--- ../vdr-1.5.12-orig/skinclassic.c	2007-07-29 14:35:03.000000000 +0200
+++ skinclassic.c	2007-12-28 22:33:42.000000000 +0100
@@ -77,6 +77,7 @@ private:
   int lineHeight;
   int timeWidth;
   bool message;
+  cString lastDate;
 public:
   cSkinClassicDisplayChannel(bool WithInfo);
   virtual ~cSkinClassicDisplayChannel();
@@ -149,7 +150,10 @@ void cSkinClassicDisplayChannel::Flush(v
      cString date = DayDateTime();
      const cFont *font = cFont::GetFont(fontSml);
      int w = font->Width(date);
-     osd->DrawText(osd->Width() - w - 2, 0, date, Theme.Color(clrChannelDate), Theme.Color(clrBackground), cFont::GetFont(fontSml), w);
+     if (!lastDate || strcmp(lastDate, date)) {
+        osd->DrawText(osd->Width() - w - 2, 0, date, Theme.Color(clrChannelDate), Theme.Color(clrBackground), cFont::GetFont(fontSml), w);
+        lastDate = date;
+        }
      }
   osd->Flush();
 }
--- ../vdr-1.5.12-orig/skinsttng.c	2007-06-17 15:51:56.000000000 +0200
+++ skinsttng.c	2007-12-28 22:38:59.000000000 +0100
@@ -131,6 +131,7 @@ private:
   const cEvent *present;
   int lastSeen;
   tTrackId lastTrackId;
+  cString lastDate;
   static cBitmap bmTeletext, bmRadio, bmAudio, bmDolbyDigital, bmEncrypted, bmRecording;
 public:
   cSkinSTTNGDisplayChannel(bool WithInfo);
@@ -307,7 +308,11 @@ void cSkinSTTNGDisplayChannel::Flush(voi
         const cFont *font = cFont::GetFont(fontSml);
         cString date = DayDateTime();
         int w = font->Width(date);
-        osd->DrawText(x4 - w - 2, y7 - font->Height(), date, Theme.Color(clrChannelDate), frameColor, font, w);
+        if (!lastDate || strcmp(lastDate, date)) {
+           osd->DrawText(x4 - w - 2, y7 - font->Height(), date, Theme.Color(clrChannelDate), frameColor, font, w);
+           lastDate = date;
+           }
+
         cDevice *Device = cDevice::PrimaryDevice();
         const tTrackId *Track = Device->GetTrack(Device->GetCurrentAudioTrack());
         if (!Track && *lastTrackId.description || Track && strcmp(lastTrackId.description, Track->description)) {
--- ../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)
_______________________________________________
vdr mailing list
vdr@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr

[Index of Archives]     [Linux Media]     [Asterisk]     [DCCP]     [Netdev]     [Xorg]     [Util Linux NG]     [Xfree86]     [Big List of Linux Books]     [Fedora Users]     [Fedora Women]     [ALSA Devel]     [Linux USB]

  Powered by Linux