Skip to content

Commit 1f2797d

Browse files
author
Wayfarer
committed
fix some small fry.
1 parent 6b1f0e0 commit 1f2797d

2 files changed

Lines changed: 66 additions & 33 deletions

File tree

CommonLibraryTests/DirectBitmapImageTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public void SetPixelsSimdTwoInputsShouldSetCorrectPixels()
107107
};
108108

109109
// Act
110-
_bitmapImage.SetPixelsSimd(pixels);
110+
_bitmapImage.SetPixelsBulk(pixels);
111111

112112
// Assert using Pixel32 channels
113113
var p0 = _bitmapImage.Bits[0];
@@ -319,7 +319,7 @@ public void SetPixelsSimdValidPixelsUpdatesBits()
319319
(2, 2, Color.FromArgb(255, 0, 0, 255)) // Blue
320320
};
321321

322-
_bitmapImage.SetPixelsSimd(pixels);
322+
_bitmapImage.SetPixelsBulk(pixels);
323323

324324
// Check Red at (0,0)
325325
var p0 = _bitmapImage.Bits[0];

Imaging/DirectBitmapImage.cs

Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -250,59 +250,92 @@ public void SetPixels(IEnumerable<PixelData> pixels)
250250
/// </summary>
251251
/// <param name="src">Source pixels to blend (same size as current bitmap)</param>
252252
/// <exception cref="System.ArgumentException">Source must match image size</exception>
253-
public void BlendSimd(uint[] src)
253+
public unsafe void BlendInt(uint[] src)
254254
{
255255
if (src == null || src.Length != Bits.Length)
256256
throw new ArgumentException("Source must match image size");
257257

258-
var dst = MemoryMarshal.Cast<Pixel32, uint>(Bits);
258+
// Get spans for safe bounds check elimination (optional but good practice)
259+
// Casting Pixel32[] to uint[] for easier bitwise ops
260+
var dstSpan = System.Runtime.InteropServices.MemoryMarshal.Cast<Pixel32, uint>(Bits.AsSpan());
261+
var srcSpan = src.AsSpan();
259262

260-
var len = dst.Length;
263+
int len = dstSpan.Length;
261264

262-
for (var i = 0; i < len; i++)
265+
// Use unsafe pointers for maximum speed in the loop
266+
fixed (uint* pDst = dstSpan)
267+
fixed (uint* pSrc = srcSpan)
263268
{
264-
var s = src[i];
265-
if ((s >> 24) == 0)
266-
continue;
269+
uint* dPtr = pDst;
270+
uint* sPtr = pSrc;
271+
272+
for (int i = 0; i < len; i++)
273+
{
274+
uint s = *sPtr;
275+
276+
// Fast check: if source is fully transparent, skip
277+
uint sa = s >> 24;
278+
if (sa == 0)
279+
{
280+
dPtr++;
281+
sPtr++;
282+
continue;
283+
}
284+
285+
// Fast check: if source is fully opaque, just overwrite
286+
if (sa == 255)
287+
{
288+
*dPtr = s;
289+
dPtr++;
290+
sPtr++;
291+
continue;
292+
}
267293

268-
var d = dst[i];
294+
uint d = *dPtr;
269295

270-
var sf = new Vector4(
271-
(s >> 16) & 255,
272-
(s >> 8) & 255,
273-
(s) & 255,
274-
(s >> 24) & 255
275-
);
296+
// Extract components (0xAARRGGBB format)
297+
// Destination
298+
uint da = d >> 24;
299+
uint dr = (d >> 16) & 0xFF;
300+
uint dg = (d >> 8) & 0xFF;
301+
uint db = d & 0xFF;
276302

277-
var df = new Vector4(
278-
(d >> 16) & 255,
279-
(d >> 8) & 255,
280-
(d) & 255,
281-
(d >> 24) & 255
282-
);
303+
// Source
304+
uint sr = (s >> 16) & 0xFF;
305+
uint sg = (s >> 8) & 0xFF;
306+
uint sb = s & 0xFF;
283307

284-
var a = sf.W * (1f / 255f);
285-
if (a <= 0.0001f)
286-
continue;
308+
// Standard Alpha Blending Formula: Out = (Src * Alpha + Dst * (255 - Alpha)) / 255
309+
// We approximate division by 255 using: (x + 128) / 255 ~= (x * 257 + 128) >> 16
310+
// Or simpler fast approximation: (v + (v >> 8)) >> 8
287311

288-
var r = sf * a + df * (1f - a);
312+
uint invA = 255 - sa;
289313

290-
dst[i] =
291-
((uint)Math.Clamp(r.W, 0, 255) << 24) |
292-
((uint)Math.Clamp(r.X, 0, 255) << 16) |
293-
((uint)Math.Clamp(r.Y, 0, 255) << 8) |
294-
(uint)Math.Clamp(r.Z, 0, 255);
314+
// Blend Color Channels
315+
uint r = (sr * sa + dr * invA) / 255;
316+
uint g = (sg * sa + dg * invA) / 255;
317+
uint b = (sb * sa + db * invA) / 255;
318+
319+
// Blend Alpha Channel (Standard "Over" operator)
320+
// ResultAlpha = SrcAlpha + DstAlpha * (1 - SrcAlpha)
321+
uint a = sa + ((da * invA) / 255);
322+
323+
// Re-pack and write
324+
*dPtr = (a << 24) | (r << 16) | (g << 8) | b;
325+
326+
dPtr++;
327+
sPtr++;
328+
}
295329
}
296330

297331
UpdateBitmapFromBits();
298332
}
299333

300-
301334
/// <summary>
302335
/// SIMD-based batch pixel update from (x,y,color) triplets.
303336
/// </summary>
304337
/// <param name="pixels">The pixels.</param>
305-
public void SetPixelsSimd(IEnumerable<(int x, int y, Color color)> pixels)
338+
public void SetPixelsBulk(IEnumerable<(int x, int y, Color color)> pixels)
306339
{
307340
foreach (var (x, y, c) in pixels)
308341
{

0 commit comments

Comments
 (0)