Open Zintom opened 6 months ago
The API surface is up for debate, I have just used that as an example.
Below is a benchmark which draws an image to a Bitmap
, comparing my C# impl and the GDI+ impl, as you can see, performance scales throughout image size and iterations, the C# impl being around 16 times faster; the Graphics
object is initialized in the class constructor so all overhead was avoided, this is pure Draw Call vs Draw Call.
Doesn't this say more about implementation of GDI+ needing improvement? Or are you recommending the WinForms replace its drawing function or something else.
@JeremyKuhne has been doing a lot of changes to System.Drawing
and should be able to let you know if this is likely to get accepted.
Doesn't this say more about implementation of GDI+ needing improvement? Or are you recommending the WinForms replace its drawing function or something else.
Where GDI+ is shipped with windows and is a "legacy" product, I imagine it does indicate a poor implementation, but also indicates we wouldn't get a fix from the Windows team.
It would be nice though, for the Windows team to refactor and optimize the GDI+ library as there still lots of parts of Windows that use it to display menus.
Doesn't this say more about implementation of GDI+ needing improvement? Or are you recommending the WinForms replace its drawing function or something else.
Also, I think this demonstrates that .NET Core is capable of holding its own when it comes to CPU bound drawing tasks, the need for GDI+ diminishes. I imagine a time when all controls use Runtime level rendering and are drawn to a single Direct2D "canvas".
Certainly, something to take a look, although it is much more likely that we're ending up utilizing something we have started to look into for A11Y reasons: Direct2D/DirectWrite. @JeremyKuhne needs to chime in here but expect a couple of weeks delay.
It'll be nice to see WinForms move to Direct2D in the future, I built my own lib a while ago which mimicked WinForms and was based on OpenGL, performance was very good.
In terms of my proposal, I'm still going to tinker with using my approach for fun, I might even put it into a public lib.
Related: #10740
I am a bit worrying about Direct2D/DirectWrite and other similar gdi optimization in terms of using winforms apps over rdp 🤔 Rdp have it's own optimisation with gdi. And this is the main reason that we're stick to winforms still. Performance over rdp is much much critical/sensitive then local.
I am a bit worrying about Direct2D/DirectWrite and other similar gdi optimization in terms of using winforms apps over rdp 🤔 Rdp have it's own optimisation with gdi. And this is the main reason that we're stick to winforms still. Performance over rdp is much much critical/sensitive then local.
My proposal here does not deviate from GDI+, it just works directly on the Bitmap instead calling out to GDI+ to do the work.
I am a bit worrying about Direct2D/DirectWrite and other similar gdi optimization in terms of using winforms apps over rdp 🤔 Rdp have it's own optimisation with gdi. And this is the main reason that we're stick to winforms still. Performance over rdp is much much critical/sensitive then local.
@kirsan31 interesting feedback. I'm not sure how we can track performance here. We'll definitely keep it in mind and keep a sharp eye on feedback on performance regressing in this scenario.
@JeremyKuhne
I'm not sure how we can track performance here.
Measure the amount of data transmitted over the network during a RDP session with a test application before and after optimization... 👀 I think I can participate in testing if needed...
@Zintom I'm happy to take vectorization changes for performance here. As called out already, there is almost no chance of GDI+ changes happening so we can entertain and take these sorts of functionality improvements on our end.
Note that locking the bitmap appears to always makes a full copy of the data (I'm reasonably confident, but I could be misreading the code). Keep that in mind when measuring perf.
Things that make it easier to take changes:
When changing existing APIs if we can't be confident of getting identical results we need to and can address this in a number of ways. Possibilities are overloads with option flags, AppContext switches, docs, etc.
As far as Direct2D related functionality I'm currently inclined to make a new set of APIs in System.Drawing for that with conversion methods. Functionality is just too different. For example, something like System.Drawing.WindowsImaging
for WIC.
Please tag me directly with anything in this space to draw my attention. :)
@Zintom
it just works directly on the Bitmap instead calling out to GDI+ to do the work.
Yes and I am afraid that this will be performance decrease over rdp. RDP can transfer some GDI instructions/primitives instead of pictures. And in your case we will defiantly transfer a picture itself.
@kirsan31 are you aware of any GDI+ calls that are remoted via RDP? I'll try to keep an eye out for that sort of functionality when I'm looking at the code.
Could we just gate the functionality around SystemInformation.TerminalServerSession
if it does cause a perf regression for RDP?
Could we just gate the functionality around
SystemInformation.TerminalServerSession
if it does cause a perf regression for RDP?
Yep. Another option to consider.
Background and motivation
All calls to draw any kind of graphics, even just clearing a Bitmap to a certain colour, will result in a GDI/GDI+ invocation.
Anecdotal testing shows that using vectorised API's like AVX/SSE to directly modify the underlying Bitmap data displayed significantly improved performance. I imagine this is due to the GDI libraries being old and not being vectorised themselves.
For example; to clear a Bitmap, instead of calling
Graphics.Clear(color)
, you can locate the Bitmap in memory usingLockBits
, create a stack allocated integer containingcolor
, and useSpan.Fill(color)
, this won't call out to GDI+, and Span uses vectorised instructions to accelerate the clearing of the pixels.Code example:
This is just one example of the basic
Clear
functionality, I have also experimented with drawing another bitmap directly into the memory of the source bitmap using AVX/SSE, this drastically improves draw performance (increasing as the number of draw calls increases), you can also choose to draw with transparency on each draw call, rather than dictating transparency support in the PixelFormat.If this kind of proposal has support I am more than willing to provide PRs to add this to Bitmap.cs
API Proposal
API Usage
Alternative Designs
No response
Risks
No response
Will this feature affect UI controls?
No