Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Colorspace Transforms #664

Merged
merged 78 commits into from
Oct 10, 2018
Merged

WIP Colorspace Transforms #664

merged 78 commits into from
Oct 10, 2018

Conversation

JimBobSquarePants
Copy link
Member

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 matches 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

I've been slowly but surely refactoring the colorspace transformation code to make it usable and performant. This PR reintroduces the transform code into the codebase.

  • Streamlined struct layout to better fit memory and removed boxing.
  • Made structs readonly
  • Added Span<T> based bulk transforms.
  • General style cleanup.
  • Added better tests.

@JimBobSquarePants
Copy link
Member Author

@antonfirsov I've been revisiting this PR and the method you suggested and I cannot see how adding it will give use any advantage.

As it stands we loop through the span and perform conversion + adaptation in a single loop. If we introduce that method and attempt to integrate it into a bulk conversion we have to loop through and create the unadapted destination span, then loop through again to create the adapted version.

Copy link
Member

@antonfirsov antonfirsov left a comment

Choose a reason for hiding this comment

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

@JimBobSquarePants it will enable bulk variants for converter API-s which could be SIMD-optimized and conditions like this or this are evaluated only once per bulk loop.

whitePoint is invariant (could be readonly) in a ColorSpaceConverter instance.

If we introduce that method and attempt to integrate it into a bulk conversion we have to loop through and create the unadapted destination span, then loop through again to create the adapted version.

I think I fail to understand this. But if you mean that it's an issue to create a temporary buffer to call the bulk variant of IChromaticAdaptation.Adapt(...) before calling bulk conversion on the adapted data -it shouldn't be. A MemoryAllocator could quickly allocate it, and with the bulk optimization, the execution will be faster.

Nevertheless, it looks like my main findigs are addressed now. The bulk adaptation API could be added later, we just need to make sure it's possible to do it without breaking changes.

private CieXyzAndLmsConverter cachedCieXyzAndLmsConverter;
// Options.
private Matrix4x4 lmsAdaptationMatrix;
private CieXyz whitePoint;
Copy link
Member

Choose a reason for hiding this comment

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

All white point members could be readonly!

Copy link
Member Author

Choose a reason for hiding this comment

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

Thought I'd got these... Will update.

@JimBobSquarePants
Copy link
Member Author

I think I fail to understand this. But if you mean that it's an issue to create a temporary buffer to call the bulk variant of IChromaticAdaptation.Adapt(...) before calling bulk conversion on the adapted data -it shouldn't be. A MemoryAllocator could quickly allocate it, and with the bulk optimization, the execution will be faster.

@antonfirsov What I mean it that for many, if not most conversions, the Adapt method comes after the initial conversion which takes place inside the loop.

In pseudo code.

(for var i = 0 etc){
 var d = ToDWithAdapt(source[i]);
}

In order to do the actual optimization we'd have to stop calling the single methods and inline their code. That dramatically decreases our code reuse and increases the tests we need to write. (I already have to write so, so many conversion tests). Possible of course but so much work...

Once inlined I don't think we'll need an allocater so I'll add the method to the interface now and we can add a chore optimization task to the tracker.

@antonfirsov
Copy link
Member

I guess we mean the same: Initial conversion could be done in a bulk way into a temporary buffer.

With ColorSpaceConverterOptions now we have the flexibility to add this later. I also consider it a time consuming, and low priority task, I just wanted the API to be future proof.

…crease tolerance because of failing test case
@antonfirsov
Copy link
Member

@JimBobSquarePants hope you are happy with the changes I just pushed.

@@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
internal class SRgbCompanding : ICompanding
public sealed class SRgbCompanding : ICompanding
Copy link
Member

Choose a reason for hiding this comment

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

We have the same code in Vector4Extensions. Might make sense to have a unified & expressive common API.

Copy link
Member Author

Choose a reason for hiding this comment

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

Agreed

{
/// <summary>
/// Pair of companding functions for <see cref="RgbWorkingSpace"/>.
/// Used for conversion to <see cref="CieXyz"/> and backwards.
/// See also: <seealso cref="RgbWorkingSpace.Companding"/>
/// </summary>
internal interface ICompanding
public interface ICompanding
Copy link
Member

@antonfirsov antonfirsov Oct 8, 2018

Choose a reason for hiding this comment

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

I wonder why do we have interfaces which are not used through the abstraction. I think they shouldn't be there, and the methods should be moved to static utilities. If they were being actually used, it would be very expensive to do non-inlinable virtual interface calls to convert only one float value.

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree. I’m glad you brought this up as they’ve never sat well with me. Will do that tomorrow

@JimBobSquarePants
Copy link
Member Author

Right... let’s get this merged.

@JimBobSquarePants JimBobSquarePants merged commit 13850d1 into master Oct 10, 2018
@JimBobSquarePants JimBobSquarePants deleted the colorspace-transforms branch September 3, 2019 11:12
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.

2 participants