[Windows] Layered windows with per-pixel alpha + Max2D

BlitzMax Forums/BlitzMax Programming/[Windows] Layered windows with per-pixel alpha + Max2D

grable(Posted 2017) [#1]
Building on the previous sample Layered windows with per-pixel alpha, this uses Max2D for rendering.

This sample uses UpdateLayeredWindow and the result from Max2D+D3D9/GL rendering to only show what is drawn on screen.
For D3D9, it copies from the render target into a surface, then copies that into a bitmap and then it draws the image to the screen with proper transparency.
For GL it copies it directly to a buffer and then to a bitmap, and finally to the screen.

The bitmap is needed by UpdateLayeredWindow for per-pixel transparency.

This sample uses a Desktop sized window, which isnt really needed unless you need to draw all over the screen.
If all you need is some movable region to draw to, a smaller window will be faster.

I use MaxGUI for this, but it should work with Graphics windows too.

D3D9:

GL:



Henri(Posted 2017) [#2]
Hi,

I'm getting some really bad fps on Windows 7. I'll test again when I'm home.

-Henri


grable(Posted February) [#3]
Thats weird, i get 60+ with Windows 10. This was the fastest method i found of grabbing the rendered output.
But i do grab the entire screen though, so depending on screen resolution and cpu power it probably eats a lot.
The grabbing uses practically the same technique as GrabPixmap() so shouldt be THAT slow.

Maybe Windows 7 just sucks with UpdateLayeredWindow, or the window is too big for it...

EDIT: I added some error checking, it should print an error if any of the APIs complain.


grable(Posted February) [#4]
Heres a version with performance monitoring of various parts of the source.
If anyone wants to check why its so slow on Windows 7, run it and see what it spits out on exit.



EDIT: Heres the numbers i get, Windows 10 64-bit, Skylake 6700K 4Ghz, AMD R390 8GB.
EVENT_GADGETPAINT: time=15  avg=15  count=1499
Flip;Cls: time=7  avg=7  count=1499
UpdateBitmapFromDeviceSurface: time=8  avg=7  count=1499
GetRenderTarget: time=0  avg=0  count=1499
BitBlt: time=6  avg=5  count=1499
LockRect: time=0  avg=0  count=1499
Transform Alpha: time=1  avg=0  count=1499
SetDIBits: time=1  avg=1  count=1499
UpdateLayeredWindow: time=2  avg=1  count=1501

EDIT2: Lowering the timer frequency to 30 should help too btw. Seeing as i get roughly 16ms per frame i can keep it at 60fps.


Dan(Posted February) [#5]
Cool, thanks grable.


Henri(Posted February) [#6]
Some dedicated debugging there :-)

Here are the results:
EVENT_GADGETPAINT: time=905  avg=684  count=14
Flip;Cls: time=0  avg=0  count=14
UpdateBitmapFromDeviceSurface: time=905  avg=684  count=14
GetRenderTarget: time=0  avg=0  count=14
BitBlt: time=902  avg=681  count=14
LockRect: time=0  avg=0  count=14
Transform Alpha: time=2  avg=1  count=14
SetDIBits: time=1  avg=1  count=14
UpdateLayeredWindow: time=1  avg=1  count=15


Frequency isn't the issue, it almost seems like it's not hardware excelerated.

-Henri


grable(Posted February) [#7]
@Dan
Hope you find a use for it, most of what i see are crap bloatware and mmo launchers using this lol

Hmmm.. BitBlt is not supposed to be that slow, its one of the fastest blitting functions in windows!

Thanks for checking it out for me :)


grable(Posted February) [#8]
.


grable(Posted February) [#9]
After lots of testing the fix was embarrassingly simple :(
It would seem that BitBlt does not have an optimized path involving D3D9 Surfaces on Windows 7.

The fix was using another primitive, GetRenderTargetData which copies between surfaces instead.
This was the same speed on Windows 10, and fast enough on Windows 7 that im using that one instead now.

All posts updated, im leaving the performance monitored version up if anyone encounters similar trouble in the future (XP maybe? :p)

This makes me want to see if changing GrabPixmap() is possible as well, since it also uses BitBlt.


grable(Posted February) [#10]
Added OpenGL version to top post, even using glReadPixels is fast enough it seems :)


Henri(Posted February) [#11]
Nicely catched. I have a feeling that I've heard people say GrapPixmap is slow so maybe you got something there.

One final thing. Not sure if it's a bug, but the image stops following after you press left mouse button.

Anyway, cool stuff :-)

-Henri


grable(Posted February) [#12]
One final thing. Not sure if it's a bug, but the image stops following after you press left mouse button.
Thats because it loses focus. Since the mouse is not over the window, whatever is behind gets focus instead. So not a bug ;)

I have a feeling that I've heard people say GrapPixmap is slow so maybe you got something there
I looked at GrabPixmap some more. But it cant use GetRenderTargetData, since it requires the surfaces have specific types and only copies the whole surface :/
But there are optimization opportunities though, i think it would help to not allocate a new surface and pixmap every time for one.

Thanks. I have no idea what im gonna use it for, but it is cool :)