Skip to content

Precompute and cache RGB/XYZ matrices in RgbWorkingSpace - #3181

Open
stefannikolei wants to merge 2 commits into
SixLabors:mainfrom
stefannikolei:sn/optimize_colorconversion
Open

stefannikolei wants to merge 2 commits into
SixLabors:mainfrom
stefannikolei:sn/optimize_colorconversion

Conversation

@stefannikolei

Copy link
Copy Markdown
Contributor

Prerequisites

  • I have written a descriptive pull-request title
  • I have verified that there are no overlapping pull-requests open
  • I have verified that I am following the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules 👮.
  • I have provided test coverage for my change (where applicable)

Description

Move RgbToCieXyz and CieXyzToRgb matrix construction from Rgb into RgbWorkingSpace, computing both matrices once at construction. Pass the precomputed inverse adaptation matrix through all chromatic adaptation calls to eliminate repeated Matrix4x4.Invert invocations during color conversions.

Benchmark Method Before After Speedup
ColorspaceCieXyzToRgbConvert ImageSharp Convert 79.70 ns 19.06 ns 4.18x
RgbWorkingSpaceAdapt ImageSharp Adapt 110.70 ns 58.93 ns 1.88x

@JimBobSquarePants What do you think about this?

Move RgbToCieXyz and CieXyzToRgb matrix construction from Rgb into
RgbWorkingSpace, computing both matrices once at construction. Pass
the precomputed inverse adaptation matrix through all chromatic
adaptation calls to eliminate repeated Matrix4x4.Invert invocations
during color conversions.
/// <param name="matrix">The chromatic adaptation matrix.</param>
public static void Transform(
/// <param name="inverseMatrix">The inverse of <paramref name="matrix"/>.</param>
internal static void Transform(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why was this made internal?

/// <param name="matrix">The chromatic adaptation matrix.</param>
/// <param name="inverseMatrix">The inverse of <paramref name="matrix"/>.</param>
/// <returns>The <see cref="CieXyz"/></returns>
internal static CieXyz Transform(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused now. We have a public and internal version overloads of this method.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the public ones are the ones without the inverse matrix. I made the methods with the invers matrix internal, to not change the public api. so at the public level we create the inverse matrix by our selfs to not open space for errors.

We can also go the way to only offer the methods with the inverse matrix as a parameter.

@JimBobSquarePants

Copy link
Copy Markdown
Member

@stefannikolei A good idea on paper. I'm just confused by the API now.

@stefannikolei

Copy link
Copy Markdown
Contributor Author

@stefannikolei A good idea on paper. I'm just confused by the API now.

I will have a look.

@stefannikolei

Copy link
Copy Markdown
Contributor Author

@stefannikolei A good idea on paper. I'm just confused by the API now.

Should I make all new overloads public? Or only keep the overloads around which accept matrix and inverse?

@stefannikolei

Copy link
Copy Markdown
Contributor Author

@JimBobSquarePants how do you want the api. Can it change? Should it be backwards compatible? Now it supports both ways which makes it a bit akward.

@JimBobSquarePants

Copy link
Copy Markdown
Member

@stefannikolei let me have a wee think. I might be able to figure out something.

Copilot AI balanced review requested due to automatic review settings October 10, 2026 09:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new private matrix-construction helper lacks documentation required by the repository guidelines.

1 open finding
What changed in this PR

Precomputes RGB/XYZ matrices and reuses inverse chromatic-adaptation matrices to improve color-conversion performance.

Changes:

  • Cache RGB↔XYZ matrices in RgbWorkingSpace.
  • Add internal adaptation overloads accepting precomputed inverses.
  • Update conversion paths and ICC validation to use cached matrices.

Verification: Static review of implementation and existing tests; tests were not executed.

File Description
IccProfile.SRGB.cs Reuses Bradford inverse during colorant adaptation.
RgbWorkingSpace.cs Computes and stores RGB/XYZ matrices.
VonKriesChromaticAdaptation.cs Adds precomputed-inverse overloads.
Rgb.cs Uses cached working-space matrices.
ColorProfileConverterExtensionsRgbRgb.cs Reuses cached adaptation inverse.
ColorProfileConverterExtensionsRgbCieXyz.cs Reuses cached adaptation inverse.
ColorProfileConverterExtensionsRgbCieLab.cs Reuses cached adaptation inverse.
ColorProfileConverterExtensionsCieXyzRgb.cs Reuses cached adaptation inverse.
ColorProfileConverterExtensionsCieXyzCieXyz.cs Reuses cached adaptation inverse.
ColorProfileConverterExtensionsCieXyzCieLab.cs Reuses cached adaptation inverse.
ColorProfileConverterExtensionsCieLabRgb.cs Reuses cached adaptation inverse.
ColorProfileConverterExtensionsCieLabCieXyz.cs Reuses cached adaptation inverse.
ColorProfileConverterExtensionsCieLabCieLab.cs Reuses cached adaptation inverse.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

public override int GetHashCode()
=> HashCode.Combine(this.GetType(), this.WhitePoint, this.ChromaticityCoordinates);

private static Matrix4x4 CreateRgbToCieXyzMatrix(CieXyz referenceWhite, RgbPrimariesChromaticityCoordinates chromaticityCoordinates)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants