Repository navigation
Build Okhsl and OkLCh planes three times faster, and share the dialog's work - #364
Merged
Merged
Conversation
A plane at one hue solved the same sRGB cusp for every one of its 65,536 colors, and the same gamut edge for every color along a row, though the cusp depends on the hue alone and the edge on the hue and lightness. The Okhsl plane took 30.5 ms to build and the OkLCh plane 32.0 ms, and a hue drag pays that at every step. Each thread now keeps its last cusp and its last sixteen outer edges, keyed by the exact bits asked with, so every answer is the one a fresh solve gives. At hue 200 on desktop, PlaneTimingTest measures the Okhsl plane at about 10 ms, OkLCh at 13 ms and Okhsv at 0.4 ms instead of 0.9. The memo is kept per thread and overwritten in place, so bulk conversions still allocate nothing per color, and no thread reads an entry another is writing. Chroma reduction takes the outer edge from it for a color at or past that edge, which is what its search would have found; only a color inside the sliver past pure blue still searches for the edge before it. LCH's constant-hue lines curve through Oklab and never meet the same edge twice, so its plane gains nothing and measures 36.5 ms instead of 35.0.
A gamut mapper took every color through the whole route into sRGB, three pow calls for the curve included, before finding it outside the cube and starting again from Oklab, so half an OkLCh or LCH plane paid for a curve it then threw away. For the sRGB curve, which Display P3 shares, the mapper now stops in linear light, where a channel below 0 or more than a trillionth past 1 is outside the cube whatever the curve does; within that band the curve decides as before, since encoding 1 gives 0.9999999999999999 and a channel a few ulps past 1 comes back inside. Every result is the one it was: colorsOnTheCubesSurfaceMapAsToGamutMapsThem fails without the band. At hue 200, PlaneTimingTest measures the OkLCh plane at 10.5 ms instead of 13 and LCH at 33.7 ms instead of 36.5.
A 256 x 256 plane filled a 1.5 MB array with three Doubles for every pixel before packing them into its 256 KB of pixels, and a hue drag builds such a plane at nearly every step, which on Android is garbage the collector pauses for. Each row is now converted into one reused row of colors and packed straight into the pixels, so a build allocates its pixels and a 6 KB row. The pixels are the same: thePixelsAreTheColorsPacked holds them to the packed colors, and the screenshots are unchanged.
Two planes over the same colors each built their own raster: the dialog laid out side by side keeps a stacked copy of its picker to measure, whose plane built every raster the plane on screen did, doubling the background work of a hue drag. Rasters now go through one place: a raster being built is awaited rather than built again, and the last three are kept, so switching back to the space just left builds nothing either. A plane that was waiting when the plane building it goes away builds it itself.
Laid out side by side, the dialog keeps its stacked form composed to measure whether it would fit, and every channel slider in that copy rebuilt its track gradient on each change of the color, 65 to 280 us a track on desktop, for a copy that is never drawn. While the dialog is side by side, the stacked copy is marked as measured only, and a BasicChannelSlider there hands its track a placeholder and builds neither the gradient nor the color under the thumb; neither changes its size. A slider an app draws without BasicChannelSlider builds what it always did.
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.
A hue drag rebuilds the plane at every step, and on desktop an Okhsl or OkLCh plane took over 30 ms to build, so the plane trailed the thumb; a phone is several times slower. Every change here keeps results bit for bit: the 30 screenshots validate unchanged, and new tests hold the colors to what they were.
PlaneTimingTest, desktop)color). A plane at one hue solved the same cusp for every color and the same edge along every row. Each thread now keeps its last cusp and last sixteen outer edges, keyed by the exact bits asked with, and overwritten in place, so bulk conversions still allocate nothing per color (BulkAllocationTest).RememberedGamutTestfails if a key leaves out the gamut or the lightness. LCH gains little: its constant-hue lines curve through Oklab and never meet the same edge twice.color). The mapper stops in linear light for the sRGB curve and encodes only what may be inside; within a trillionth of the cube's faces the curve still decides, because encoding 1 gives 0.9999999999999999.colorsOnTheCubesSurfaceMapAsToGamutMapsThemfails without that band.BasicChannelSliderin its stacked copy hands its track a placeholder instead of rebuilding a gradient no one sees.The
colormodule gains ajvmAndAndroidsource set for the memo'sThreadLocal, as foundation has for its number formatter, and one-line actuals for iOS and wasm. No public API changes; all targets' tests,apiCheck, the samples and the iOS compile pass. Not measured on a phone.