Add Matrix4x4 transform overloads and corresponding tests#3077
Merged
JimBobSquarePants merged 4 commits intomainfrom Mar 10, 2026
Merged
Add Matrix4x4 transform overloads and corresponding tests#3077JimBobSquarePants merged 4 commits intomainfrom
JimBobSquarePants merged 4 commits intomainfrom
Conversation
antonfirsov
reviewed
Mar 9, 2026
Comment on lines
+258
to
+259
| public static PointF Transform(PointF point, Matrix4x4 matrix) | ||
| => TransformUtilities.ProjectiveTransform2D(point.X, point.Y, matrix); |
Member
There was a problem hiding this comment.
This is an established pattern so nothing we can do probably, but I keep wondering if these methods are expected to be used on hot path anywhere since this translates to 2 copies of Matrix4x4 which is relatively large.
Member
Author
There was a problem hiding this comment.
It's getting inlined as far as I can see
; Assembly listing for method SixLabors.ImageSharp.PointF:Transform(SixLabors.ImageSharp.PointF,System.Numerics.Matrix3x2):SixLabors.ImageSharp.PointF (FullOpts)
; Emitting BLENDED_CODE for X64 with AVX512 - Windows
; FullOpts code
; optimized code
; rsp based frame
; partially interruptible
; No PGO data
; 0 inlinees with PGO data; 10 single block inlinees; 0 inlinees without PGO data
G_M000_IG01: ;; offset=0x0000
push rax
vzeroupper
mov qword ptr [rsp+0x10], rcx
G_M000_IG02: ;; offset=0x0009
vmovss xmm0, dword ptr [rsp+0x10]
vmovss xmm1, dword ptr [rsp+0x14]
vinsertps xmm0, xmm0, xmm1, 28
vmovsd xmm1, qword ptr [rdx]
vmovsd xmm2, qword ptr [rdx+0x08]
vmovsd xmm3, qword ptr [rdx+0x10]
vmovaps xmm4, xmm0
vbroadcastss xmm4, xmm4
vmulps xmm1, xmm1, xmm4
vmovshdup xmm0, xmm0
vbroadcastss xmm0, xmm0
vmulps xmm0, xmm2, xmm0
vaddps xmm0, xmm1, xmm0
vaddps xmm0, xmm0, xmm3
xor eax, eax
mov qword ptr [rsp], rax
vmovsd qword ptr [rsp], xmm0
mov rax, qword ptr [rsp]
G_M000_IG03: ;; offset=0x005A
add rsp, 8
ret
; Total bytes of code 95
; Assembly listing for method SixLabors.ImageSharp.PointF:Transform(SixLabors.ImageSharp.PointF,System.Numerics.Matrix4x4):SixLabors.ImageSharp.PointF (FullOpts)
; Emitting BLENDED_CODE for X64 with AVX512 - Windows
; FullOpts code
; optimized code
; rsp based frame
; partially interruptible
; No PGO data
; 0 inlinees with PGO data; 10 single block inlinees; 0 inlinees without PGO data
G_M000_IG01: ;; offset=0x0000
sub rsp, 40
vzeroupper
mov qword ptr [rsp+0x30], rcx
G_M000_IG02: ;; offset=0x000C
vmovss xmm0, dword ptr [rsp+0x30]
vinsertps xmm0, xmm0, dword ptr [rsp+0x34], 20
vinsertps xmm0, xmm0, dword ptr [reloc @RWD00], 48
vmovups xmm1, xmmword ptr [rdx]
vmovups xmm2, xmmword ptr [rdx+0x10]
vmovups xmm3, xmmword ptr [rdx+0x20]
vmovups xmm4, xmmword ptr [rdx+0x30]
vmovaps xmm5, xmm0
vbroadcastss xmm5, xmm5
vmulps xmm1, xmm1, xmm5
vmovshdup xmm5, xmm0
vbroadcastss xmm5, xmm5
vmulps xmm2, xmm2, xmm5
vaddps xmm1, xmm1, xmm2
vunpckhps xmm2, xmm0, xmm0
vbroadcastss xmm2, xmm2
vmulps xmm2, xmm3, xmm2
vaddps xmm1, xmm1, xmm2
vshufps xmm0, xmm0, xmm0, -1
vbroadcastss xmm0, xmm0
vmulps xmm0, xmm4, xmm0
vaddps xmm0, xmm1, xmm0
vmovaps xmmword ptr [rsp+0x10], xmm0
vmovsd xmm0, qword ptr [rsp+0x10]
vmovups xmm1, xmmword ptr [reloc @RWD16]
vmaxss xmm1, xmm1, dword ptr [rsp+0x1C]
vbroadcastss xmm1, xmm1
vdivps xmm0, xmm0, xmm1
xor eax, eax
mov qword ptr [rsp+0x08], rax
vmovsd qword ptr [rsp+0x08], xmm0
mov rax, qword ptr [rsp+0x08]
G_M000_IG03: ;; offset=0x00AD
add rsp, 40
ret
RWD00 dq 3F8000003F800000h, 3F8000003F800000h
RWD16 dq 0000000033D6BF95h, 0000000000000000h
; Total bytes of code 178
Member
Author
There was a problem hiding this comment.
It's even inlined here. I think we're good.
/// <summary>
/// Transforms a rectangle by the given 4x4 matrix, applying a projective transform
/// flattened into 2D space.
/// </summary>
/// <param name="rectangle">The source rectangle.</param>
/// <param name="matrix">The transformation matrix.</param>
/// <returns>A transformed rectangle.</returns>
public static RectangleF Transform(Rectangle rectangle, Matrix4x4 matrix)
{
PointF bottomRight = PointF.Transform(new PointF(rectangle.Right, rectangle.Bottom), matrix);
PointF topLeft = PointF.Transform(new PointF(rectangle.Location.X, rectangle.Location.Y), matrix);
return new RectangleF(topLeft, new SizeF(bottomRight - topLeft));
}; Assembly listing for method SixLabors.ImageSharp.Rectangle:Transform(SixLabors.ImageSharp.Rectangle,System.Numerics.Matrix3x2):SixLabors.ImageSharp.RectangleF (FullOpts)
; Emitting BLENDED_CODE for X64 with AVX512 - Windows
; FullOpts code
; optimized code
; rsp based frame
; partially interruptible
; No PGO data
; 0 inlinees with PGO data; 70 single block inlinees; 0 inlinees without PGO data
G_M000_IG01: ;; offset=0x0000
vzeroupper
G_M000_IG02: ;; offset=0x0003
mov eax, dword ptr [rdx]
mov r10d, dword ptr [rdx+0x04]
mov r9d, dword ptr [rdx+0x08]
mov edx, dword ptr [rdx+0x0C]
vmovsd xmm0, qword ptr [r8]
vmovsd xmm1, qword ptr [r8+0x08]
vmovsd xmm2, qword ptr [r8+0x10]
add r9d, eax
add edx, r10d
vxorps xmm3, xmm3, xmm3
vcvtsi2ss xmm3, xmm3, r9d
vxorps xmm4, xmm4, xmm4
vcvtsi2ss xmm4, xmm4, edx
vinsertps xmm3, xmm3, xmm4, 28
vmovaps xmm4, xmm3
vbroadcastss xmm4, xmm4
vmulps xmm4, xmm0, xmm4
vmovshdup xmm3, xmm3
vbroadcastss xmm3, xmm3
vmulps xmm3, xmm1, xmm3
vaddps xmm3, xmm4, xmm3
vaddps xmm3, xmm3, xmm2
vmovaps xmm4, xmm3
vroundss xmm4, xmm4, xmm4, 4
vcvttss2si edx, xmm4
vmovshdup xmm3, xmm3
vroundss xmm3, xmm3, xmm3, 4
vcvttss2si r8d, xmm3
vxorps xmm3, xmm3, xmm3
vcvtsi2ss xmm3, xmm3, edx
vxorps xmm4, xmm4, xmm4
vcvtsi2ss xmm4, xmm4, r8d
vxorps xmm5, xmm5, xmm5
vcvtsi2ss xmm5, xmm5, eax
vxorps xmm16, xmm16, xmm16
vcvtsi2ss xmm16, xmm16, r10d
vinsertps xmm5, xmm5, xmm16, 28
vmovaps xmm16, xmm5
vbroadcastss xmm16, xmm16
vmulps xmm0, xmm0, xmm16
vmovshdup xmm5, xmm5
vbroadcastss xmm5, xmm5
vmulps xmm1, xmm1, xmm5
vaddps xmm0, xmm0, xmm1
vaddps xmm0, xmm0, xmm2
vmovaps xmm1, xmm0
vroundss xmm1, xmm1, xmm1, 4
vcvttss2si eax, xmm1
vmovshdup xmm0, xmm0
vroundss xmm0, xmm0, xmm0, 4
vcvttss2si edx, xmm0
vxorps xmm0, xmm0, xmm0
vcvtsi2ss xmm0, xmm0, eax
vxorps xmm1, xmm1, xmm1
vcvtsi2ss xmm1, xmm1, edx
vsubss xmm2, xmm3, xmm0
vsubss xmm3, xmm4, xmm1
vmovss dword ptr [rcx], xmm0
vmovss dword ptr [rcx+0x04], xmm1
vmovss dword ptr [rcx+0x08], xmm2
vmovss dword ptr [rcx+0x0C], xmm3
mov rax, rcx
G_M000_IG03: ;; offset=0x0119
ret
; Total bytes of code 282
; Assembly listing for method SixLabors.ImageSharp.Rectangle:Transform(SixLabors.ImageSharp.Rectangle,System.Numerics.Matrix4x4):SixLabors.ImageSharp.RectangleF (FullOpts)
; Emitting BLENDED_CODE for X64 with AVX512 - Windows
; FullOpts code
; optimized code
; rsp based frame
; partially interruptible
; No PGO data
; 0 inlinees with PGO data; 71 single block inlinees; 0 inlinees without PGO data
G_M000_IG01: ;; offset=0x0000
sub rsp, 72
vzeroupper
G_M000_IG02: ;; offset=0x0007
mov eax, dword ptr [rdx]
mov r10d, dword ptr [rdx+0x04]
mov r9d, dword ptr [rdx+0x08]
mov edx, dword ptr [rdx+0x0C]
vmovups xmm0, xmmword ptr [r8]
vmovups xmm1, xmmword ptr [r8+0x10]
vmovups xmm2, xmmword ptr [r8+0x20]
vmovups xmm3, xmmword ptr [r8+0x30]
add r9d, eax
vxorps xmm4, xmm4, xmm4
vcvtsi2ss xmm4, xmm4, r9d
add edx, r10d
vxorps xmm5, xmm5, xmm5
vcvtsi2ss xmm5, xmm5, edx
vinsertps xmm4, xmm4, xmm5, 20
vmovss xmm5, dword ptr [reloc @RWD00]
vinsertps xmm4, xmm4, xmm5, 48
vmovaps xmm16, xmm4
vbroadcastss xmm16, xmm16
vmulps xmm16, xmm0, xmm16
vmovshdup xmm17, xmm4
vbroadcastss xmm17, xmm17
vmulps xmm17, xmm1, xmm17
vaddps xmm16, xmm16, xmm17
vunpckhps xmm17, xmm4, xmm4
vbroadcastss xmm17, xmm17
vmulps xmm17, xmm2, xmm17
vaddps xmm16, xmm16, xmm17
vshufps xmm4, xmm4, xmm4, -1
vbroadcastss xmm4, xmm4
vmulps xmm4, xmm3, xmm4
vaddps xmm4, xmm16, xmm4
vmovaps xmmword ptr [rsp+0x30], xmm4
vmovups xmm4, xmmword ptr [reloc @RWD16]
vmaxss xmm16, xmm4, dword ptr [rsp+0x3C]
vbroadcastss xmm16, xmm16
vmovsd xmm17, qword ptr [rsp+0x30]
vdivps xmm16, xmm17, xmm16
xor edx, edx
mov qword ptr [rsp+0x28], rdx
vmovsd qword ptr [rsp+0x28], xmm16
vmovss xmm16, dword ptr [rsp+0x28]
vmovss xmm17, dword ptr [rsp+0x2C]
vxorps xmm18, xmm18, xmm18
vcvtsi2ss xmm18, xmm18, eax
vxorps xmm19, xmm19, xmm19
vcvtsi2ss xmm19, xmm19, r10d
vinsertps xmm18, xmm18, xmm19, 20
vinsertps xmm5, xmm18, xmm5, 48
vmovaps xmm18, xmm5
vbroadcastss xmm18, xmm18
vmulps xmm0, xmm0, xmm18
vmovshdup xmm18, xmm5
vbroadcastss xmm18, xmm18
vmulps xmm1, xmm1, xmm18
vaddps xmm0, xmm0, xmm1
vunpckhps xmm1, xmm5, xmm5
vbroadcastss xmm1, xmm1
vmulps xmm1, xmm2, xmm1
vaddps xmm0, xmm0, xmm1
vshufps xmm1, xmm5, xmm5, -1
vbroadcastss xmm1, xmm1
vmulps xmm1, xmm3, xmm1
vaddps xmm0, xmm0, xmm1
G_M000_IG03: ;; offset=0x0166
vmovaps xmmword ptr [rsp+0x10], xmm0
vmaxss xmm0, xmm4, dword ptr [rsp+0x1C]
vbroadcastss xmm0, xmm0
vmovsd xmm1, qword ptr [rsp+0x10]
vdivps xmm0, xmm1, xmm0
G_M000_IG04: ;; offset=0x0181
mov qword ptr [rsp+0x08], rdx
vmovsd qword ptr [rsp+0x08], xmm0
vmovss xmm0, dword ptr [rsp+0x08]
vmovss xmm1, dword ptr [rsp+0x0C]
vsubss xmm2, xmm16, xmm0
vsubss xmm3, xmm17, xmm1
vmovss dword ptr [rcx], xmm0
vmovss dword ptr [rcx+0x04], xmm1
vmovss dword ptr [rcx+0x08], xmm2
vmovss dword ptr [rcx+0x0C], xmm3
mov rax, rcx
G_M000_IG05: ;; offset=0x01BA
add rsp, 72
ret
RWD00 dd 3F800000h ; 1
RWD04 dd 00000000h, 00000000h, 00000000h
RWD16 dq 0000000033D6BF95h, 0000000000000000h
; Total bytes of code 447
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Prerequisites
Description
This pull request introduces support for projective (4x4 matrix) transformations across the
Point,PointF,Rectangle, andRectangleFprimitives, enabling advanced 2D transformations such as perspective mapping. The changes include new transformation methods, updates to transformation utilities, and comprehensive unit tests to validate both affine and projective scenarios.4x4 Matrix Transformation Support
Transform(Point, Matrix4x4)andTransform(PointF, Matrix4x4)methods toPointandPointFrespectively, allowing points to be transformed with a projective matrix. [1] [2]Transform(Rectangle, Matrix4x4)andTransform(RectangleF, Matrix4x4)methods toRectangleandRectangleF, enabling rectangle transformations using 4x4 matrices. [1] [2]Transformation Utility Enhancements
TransformUtilities.ProjectiveTransform2D, explaining how the perspective divide is handled and why negative or zero W values are clamped.Unit Testing for 4x4 Transformations
PointTests,PointFTests,RectangleTests, andRectangleFTests, covering affine, identity, translation, scale, and projective cases to ensure correctness and compatibility with existing 3x2 matrix transformations. [1] [2] [3] [4]