if (viewAccessor == null || viewAccessor.Capacity < numberOfBytes || currentSize.Width != width)
ReleaseMemoryMappedView(ref mappedFile, ref viewAccessor);
mappedFile = MemoryMappedFile.CreateNew(null, numberOfBytes, MemoryMappedFileAccess.ReadWrite);
viewAccessor = mappedFile.CreateViewAccessor();
it resolves the issue.
before:
after:
I've spent a fair amount of time trying to figure out why reusing the larger memory mapped file for a smaller image is causing this tearing when the width of the image changes, but I'm at a loss.
InteropBitmap is strangely glitching on resize when reusing the same buffer as detailed in #3114 (comment)
Go back to the old method approach of creating a new buffer for every resize operation.
Revert part of commit b1bd749#diff-10ce38e86ac5782d06a15b191dc6216fd098f3e23fe1fa88b3711761d8944055
InteropBitmapRenderHandler will no longer be the default shortly.
Issue #3114
- No longer use InteropBitmapRenderHandler as the default (InteropBitmap doesn't support DPI scaling).
- Remove old IncreaseBufferInteropRenderHandler as reusing the buffer causing glitching as detailed in #3114 (comment)
Issue #3114
Looking at the history of InteropBitmapRenderHandler, I found that this resize issue was introduced in this commit - an optimization to only create a new memory mapped file if the current file is smaller than the space needed. I've found that if I change
Reverted in commit a8119cc a new buffer will be created for every resize (as was previously done)
Subsequently commit 59b8e7f removes the use of InteropBitmapRenderHandler
and defaults to WritableBitmapRenderHandler
for MultiThreadedMessageLoop = true (the default)
. At some point I'll add support for notifying an IRenderHandler
of a DPI
change, so this was something I had planned.
InteropBitmapRenderHandler
still exists and can be specified by the user if required.
I've spent a fair amount of time trying to figure out why reusing the larger memory mapped file for a smaller image is causing this tearing when the width of the image changes, but I'm at a loss.
Interestingly I did a quick check at 100% DPI
and saw only very very rare glitching with disable-gpu-compositing
set (default) nothing like the image you have provided, so there's likely some other environmental factors that exacerbate the problem.
When I remove disable-gpu-compositing
I still see glitching until I set WritableBitmapRenderHandler
to create a new buffer on each resize (effectively reverting b1bd749).
Doesn't make sense yet, at least it gives some further avenues of investigation. Thanks for your help @rstedman
Copying the data directly into the BackBuffer instead of calling WritePixels
still has the same glitching.
// Update whole bitmap
var sourceRect = new Int32Rect(0, 0, width, height);
bitmap.Lock();
NativeMethodWrapper.MemoryCopy(bitmap.BackBuffer, sourceBuffer.DangerousGetHandle(), noOfBytes);
bitmap.AddDirtyRect(sourceRect);
bitmap.Unlock();
A port of WritableBitmapRenderHandler to use Marshal.AllocHGlobal instead of MemoryMappedFile
Remove disable-gpu-compositing command line arg
Resovles #3114
InteropBitmap is strangely glitching on resize when reusing the same buffer as detailed in #3114 (comment)
Go back to the old method approach of creating a new buffer for every resize operation.
Revert part of commit b1bd749#diff-10ce38e86ac5782d06a15b191dc6216fd098f3e23fe1fa88b3711761d8944055
InteropBitmapRenderHandler will no longer be the default shortly.
Issue #3114
- No longer use InteropBitmapRenderHandler as the default (InteropBitmap doesn't support DPI scaling).
- Remove old IncreaseBufferInteropRenderHandler as reusing the buffer causing glitching as detailed in #3114 (comment)
Issue #3114
In version 86
we'll default to WritableBitmapRenderHandler and leave GPU Compositing
disabled. InteropBitmapRenderHandler will create a new buffer on resize relevant commits c04c20f and da918d6
Commit fb289d4 switches to using Marshal.AllocHGlobal
instead of MemoryMappedFile
which appears to resolve the issue. A sample size of one isn't very conclusive so I've enabled by default and will try to test on a few different machines before release. The user can switch to the original WritableBitmapRenderHandler
if there are any problems.
If I understand correctly it sounds like you'd be holding reference to memory unnecessarily, perhaps I'm not understanding correctly. You are welcome to submit a PR for review.
The current plan for DPI scaling is to reuse the same buffer regardless of scale. If you need a fine level of control over memory allocations then you can of course implement IRenderHandler
@amaitland Found reason of bug.
I assumed that second CreateOrUpdateBitmap can be raised before first Dispatcher operation is processed.
Now mmf contains new (2nd data), but dispatcher operation uses captured by lambda old parameters (in my case dirty rect).
After i programmatically found this reason (by ids) as i thought i saved image and it was i expected.
Second try
Also, my suggestion about scaled increasing does not apply in any way for "dpi", only reducing of allocates.
Now mmf contains new (2nd data), but dispatcher operation uses captured by lambda old parameters (in my case dirty rect).
Thanks for the feedback, makes sense. That should be easily fixable.
Also, my suggestion about scaled increasing does not apply in any way for "dpi", only reducing of allocates.
@timaiv I'll be honest I find your comments in general very cryptic and lacking in details. I mean no offence by this, I'd just really appreciate it if you'd add more detail. Input is welcomed, it would make my life easier if you'd submit a pull request with your proposed changes, then we have something concrete to discuss.
Now mmf contains new (2nd data), but dispatcher operation uses captured by lambda old parameters (in my case dirty rect).
This occurred to me as well. However, I tried making the dispatch synchronous (dispatcher.Invoke instead of dispatcher.BeginInvoke) as a quick test, but I still experienced the resize issue.
- Remove disable-gpu-compositing command line arg
- WritableBitmapRenderHandler/InteropBitmapRenderHandler ignore update if size doesn't match
It's possible that OnPaint is called multiple times before our BeginInvoke call is marshalled onto the UI Thread.
In those cases we check width/height and ignore the call if it doesn't match
Issue #3114
- WritableBitmapRenderHandler/InteropBitmapRenderHandler ignore update if size doesn't match
It's possible that OnPaint is called multiple times before our BeginInvoke call is marshalled onto the UI Thread.
In those cases we check width/height and ignore the call if it doesn't match
Issue #3114
- WritableBitmapRenderHandler/InteropBitmapRenderHandler ignore update if size doesn't match
- Revert back to using WritableBitmapRenderHandler as the default implementation
- CompositionTargetRenderHandler only update bitmap if buffer is dirty
- AllocHGlobalWritableBitmapRenderHandler only update bitmap if buffer is dirty
It's possible that OnPaint is called multiple times before our BeginInvoke call is marshalled onto the UI Thread.
In those cases we check width/height and ignore the call if it doesn't match
Issue #3114
This should now be resolved in commit b24efd2
Version 86 branch specific changes (commit a83dbc2)
The disable-gpu-compositing
command line arg has now been removed.
BeginInvoke
calls will now check the size and the call will be ignored if it doesn't match, this should result in slightly improved performance.
If anyone would like to test this out you can download a nightly build from https://www.myget.org/feed/cefsharp/package/nuget/CefSharp.Wpf
- WritableBitmapRenderHandler/InteropBitmapRenderHandler ignore update if size doesn't match
It's possible that OnPaint is called multiple times before our BeginInvoke call is marshalled onto the UI Thread.
In those cases we check width/height and ignore the call if it doesn't match
Issue cefsharp#3114