Question

I have a layered window which is normally drawn this way:

    private void SelectBitmap(Bitmap bitmap)
    {
        IntPtr screenDc = GetDC(IntPtr.Zero);
        IntPtr memDc = CreateCompatibleDC(screenDc);
        IntPtr hBitmap = IntPtr.Zero;
        IntPtr hOldBitmap = IntPtr.Zero;

        try
        {
            hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));
            hOldBitmap = SelectObject(memDc, hBitmap);

            POINT sourceLocation = new POINT(0, 0);
            BLENDFUNCTION blend = new BLENDFUNCTION();

            blend.BlendOp = AC_SRC_OVER;
            blend.BlendFlags = 0;
            blend.SourceConstantAlpha = 255;
            blend.AlphaFormat = AC_SRC_ALPHA;

            SIZE newSize = new SIZE(bitmap.Width, bitmap.Height);
            POINT newLocation = new POINT(Location.X, Location.Y);

            UpdateLayeredWindow(Handle, screenDc,
                ref newLocation, ref newSize,
                memDc,
                ref sourceLocation, 0,
                ref blend,
                ULW_ALPHA);
        }
        finally
        {
            ReleaseDC(IntPtr.Zero, screenDc);

            if (hBitmap != IntPtr.Zero)
            {
                SelectObject(memDc, hOldBitmap);
                DeleteObject(hBitmap);
            }

            DeleteDC(memDc);
        }
    }

However, this obviously redraw the whole window every time it's called. It's quite a performance drain on large window. (even on my top of the line PC, which make me wonder how people could handle that in Win2K)

If I read the Microsoft paper on the layered window, it says: UpdateLayeredWindow always updates the entire window. To update part of a window, use the traditional WM_PAINT and set the blend value using SetLayeredWindowAttributes.

I just can't understand the above. How is WM_PAINT supposed to access the layered window bitmap and redraw only part of it on the window? From what I understood, layered windows simply disable the WM_PAINT message and expect the user to draw the window by himself. There's obviously no way to bind the WM_PAINT to the custom drawing done.

Am I missing something very obvious?

Was it helpful?

Solution

After long profiling, I found out it wasn't really the layered window update that was bottleneck. Refreshing the whole screen, the SelectBitmap method above, on a 1920*1200 was taking about 6-8ms. Sure, not very amazing, but plenty enough to refresh at 30 FPS+.

In my case, the performance drains was coming from some thread asking for refresh almost a hundred time per redraw, making everything sluggish. The solution was to break down the refresh/redraw and separate them. One would update (union) a region and the other, when not drawing, would take that region, draw it and then empty it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top