Odd artifacts writing to FMX bitmap with TBitmapData on Windows 10

  

I have an odd bug in FMX that has all the hallmarks of a pointer overrun or a hardware-specific bug, which I haven’t been able to track down. Small apps to reproduce it, don’t (yet.) I have code snippets below, but since I haven’t managed to reproduce this in a small application they are only snippets.

The app loads some PNG files, and then creates in-memory bitmaps based on colour-coding in the PNG files – that is, it will create an in-memory bitmap which is big enough to bound all red areas of the original, and is initially blank. There is a byte array the same size as the in-memory bitmap which is a mask (zero, non-zero) indicating if that pixel corresponds to a red (say) area in the original or not. The user can paint in the app, painting on a temporary display bitmap, and then when they let go the mouse button that bitmap is scanned against the byte array to write on the in-memory bitmap.

With me so far? Basically, colour-coded subsets of an original, masks created for the colour areas, painting on the subset is masked. Here’s a diagram:

This works fine on XP (GDI+ canvas) and Win7 (D2D canvas) and Win8.1 and most Win10 machines. However, on two Win10 machines, one with an Intel HD 4600 and another with an Intel Iris 5000, a client gets odd artifacts on the bitmap after doing the step of masking and setting pixels.

The artifacts are rectangles scattered apparently randomly over the bitmap, either large (100x20px, say) or small (10×8, say). I’ve also seen screenshots where parts of the rest of the UI, like button glyphs, are also present on the bitmap. Here are some example screenshots:

Here the user has already painted the dark red area, and painted the lighter colour somewhere else. These small flecked rectangles appear.

Here the user has painted the broad stripe down the middle. The dark red and lighter red rectangles are examples of the artifacts after masking and drawing to the bitmap.

To me that sounds like I’m writing pixels at the wrong stride or something. I’ve rigorously code-inspected for off-by-one errors in array or bitmap data access, and I’m using the following code to get or set pixels in bitmap data:

function GetBitmapColor(const M : PBitmapData; const X, Y : Integer) : TAlphaColor;
begin
Result := PixelToAlphaColor(
@PAlphaColorArray(M.Data)[Y * (M.Pitch div PixelFormatBytes[M.PixelFormat]) + X],
M.PixelFormat);
end;

procedure SetBitmapColor(const M : PBitmapData; const X, Y : Integer; const C : TAlphaColor);
begin
AlphaColorToPixel(C,
@PAlphaColorArray(M.Data)[Y * (M.Pitch div PixelFormatBytes[M.PixelFormat]) + X],
M.PixelFormat);
end;

These are based on the example code for accessing bitmap data in the Seattle documentation. Assertions that X and Y are in a valid range (in the bitmap size) are all ok. While this happens on the OS & hardware given above, it does not happen for the same OS (Win10) with other cards – another Intel HD, a Nvidia, etc; on a Win10 tablet; on a Win10 VM I tried; on my Win7 development machine; etc. As far as buffer overruns etc are concerned, compiling with range checks on does not give any errors, nor have any asserts of my own checking valid X/Y coordinates against bitmap size.

The error occurs with both XE6 and Seattle on the same machines.

I can’t reproduce this. They’re in the process of setting up remote access to this machine but it’s still going to be tricky to figure out what’s going on, so I wonder if anyone has seen something like this before, or has concrete suggestions of specific ways to check for bitmap pointer overruns or similar?

Comments are closed.