Speedup for Slow NETFX_CORE BitmapContext.Dispose implementation

Sep 19, 2012 at 4:32 PM

Hi, this code is very slow because it performs too many writes;

public unsafe void Dispose()
      {
         // Decrement the update count. If it hits zero
         if (DecrementRefCount(writeableBitmap) == 0)
         {
            // Remove this bitmap from the update map 
            UpdateCountByBmp.Remove(writeableBitmap);
            PixelCacheByBmp.Remove(writeableBitmap);

            // Copy data back
            using (var stream = writeableBitmap.PixelBuffer.AsStream())
            {
               var buffer = new byte[4];
               fixed (int* srcPtr = pixels)
               {                   
                  for (var i = 0; i < length; i++)
                  {
                     buffer[3] = (byte)((srcPtr[i] >> 24) & 0xff);
                     buffer[2] = (byte)((srcPtr[i] >> 16) & 0xff);
                     buffer[1] = (byte)((srcPtr[i] >> 8) & 0xff);
                     buffer[0] = (byte)((srcPtr[i]) & 0xff);
                     stream.Write(buffer, 0, 4);
                  }
               }
            }
            writeableBitmap.Invalidate();
         }
      }

This code is significantly faster;

public unsafe void Dispose()
        {
            // Decrement the update count. If it hits zero
            if (DecrementRefCount(writeableBitmap) == 0)
            {
                // Remove this bitmap from the update map 
                UpdateCountByBmp.Remove(writeableBitmap);
                PixelCacheByBmp.Remove(writeableBitmap);

                // Copy data back
                using (var stream = writeableBitmap.PixelBuffer.AsStream())
                {
                    var buffer = new byte[length * 4];

                    fixed (int* srcPtr = pixels)
                    {
                        for (var i = 0; i < length; i++)
                        {
                            int p = i * 4;
                            buffer[3 + p] = (byte)((srcPtr[i] >> 24) & 0xff);
                            buffer[2 + p] = (byte)((srcPtr[i] >> 16) & 0xff);
                            buffer[1 + p] = (byte)((srcPtr[i] >> 8) & 0xff);
                            buffer[0 + p] = (byte)((srcPtr[i]) & 0xff);
                        }
                        stream.Write(buffer, 0, length * 4);
                    }

                }
                writeableBitmap.Invalidate();
            }
        }

Oct 26, 2012 at 12:58 AM

The copy-back is also unnecessary if the context is opened in ReadOnly mode (e.g., the source for a Blit operation should do this).

Coordinator
Oct 28, 2012 at 12:13 PM

o_O 

How did I miss that?! Ouch! Of course you're right. I just checked in the changes and a new binary release will go out in a few days too.

Thanks for pointing this mega-flaw out.

- Rene 

Nov 7, 2012 at 4:31 PM

This is probably even faster.

                        for (var i = 0; i < length; i++)
                        {
                            int p = i * 4;
                            int sp = srcPtr[i];
                            buffer[3 + p] = (byte)(sp >> 24);
                            buffer[2 + p] = (byte)(sp >> 16);
                            buffer[1 + p] = (byte)(sp >> 8);
                            buffer[0 + p] = (byte)sp;
                        }
Nov 7, 2012 at 5:33 PM

It probably is - I've looked at the code and last time I checked this speedup wasn't included. It's a HUGE speedup for larg(e|ish) images. My game went from unplayable to quite snappy! http://apps.microsoft.com/webpdp/en-in/app/flow8/c46988b1-6b41-4fca-9f6a-65a1efaaa799

Coordinator
Nov 7, 2012 at 7:06 PM

It's actually checked in since Oct 28. The initial code was more like of a bug with the copying of each single pixel. Like I wrote above it was a huge flaw.

Thanks for pointing it out.

 

- Rene

Nov 8, 2012 at 6:49 AM

Sorry man, your're right, it's there allright.

Thanks for creating this library, it's saved me sooo much time over the years!