From: Eunki, Hong Date: Mon, 31 Mar 2025 05:25:28 +0000 (+0900) Subject: [NUI.Palette] Make Palette.GenerateAsync() thread safe X-Git-Tag: submit/tizen/20250401.115655~1^2~8 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3f811fb9932138754c04dca81bd98f6e45e103c3;p=platform%2Fcore%2Fcsapi%2Ftizenfx.git [NUI.Palette] Make Palette.GenerateAsync() thread safe Until now, We use some static pointer at `ColorCutQuantizer` class. Since we could create that class at worker thread freely, we should not access static pointer without any locking points. And also, those static values should not be static. To fix this issue, let we make `ColorCutQuantizer.Vbox` hold it's parent, and remove static keyword. Signed-off-by: Eunki, Hong --- diff --git a/src/Tizen.NUI/src/internal/Utility/ColorCutQuantizer.cs b/src/Tizen.NUI/src/internal/Utility/ColorCutQuantizer.cs index 0a0fc31bf..e8023009c 100755 --- a/src/Tizen.NUI/src/internal/Utility/ColorCutQuantizer.cs +++ b/src/Tizen.NUI/src/internal/Utility/ColorCutQuantizer.cs @@ -24,7 +24,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Collections.Concurrent; using System.Linq; namespace Tizen.NUI @@ -37,8 +36,8 @@ namespace Tizen.NUI private const int componentGreen = -2; private const int componentBlue = -1; - private static ConcurrentDictionary colorPopulations; - private static int[] colors; + private Dictionary colorPopulations; + private int[] colors; private List quantizedColors; private float[] tempHsl = new float[3]; @@ -60,11 +59,11 @@ namespace Tizen.NUI // First, lets pack the populations into a SparseIntArray so that they can be easily // retrieved without knowing a color's index - colorPopulations = new ConcurrentDictionary(); + colorPopulations = new Dictionary(); for (int i = 0; i < rawColors.Length; i++) { - colorPopulations.TryAdd(rawColors[i], rawColorCounts[i]); + colorPopulations.Add(rawColors[i], rawColorCounts[i]); } // Now go through all of the colors and keep those which we do not want to ignore @@ -102,7 +101,7 @@ namespace Tizen.NUI /// /// Factory-method to generate a ColorCutQuantizer from a PixelBuffer object. /// - public static ColorCutQuantizer FromBitmap(PixelBuffer pixelBuffer, Rectangle region, int maxColors) + public static ColorCutQuantizer FromBitmap(PixelBuffer pixelBuffer, Rectangle region, int maxColors) { int width; int height; @@ -158,7 +157,7 @@ namespace Tizen.NUI // split the largest box in the queue CustomHeap customHeap = new CustomHeap(new VboxComparatorVolume()); // To start, offer a box which contains all of the colors - customHeap.Offer(new Vbox(0, maxColorIndex)); + customHeap.Offer(new Vbox(0, maxColorIndex, this)); // Now go through the boxes, splitting them until we have reached maxColors or there are no // more boxes to split SplitBoxes(customHeap, maxColors); @@ -407,10 +406,13 @@ namespace Tizen.NUI private int upperIndex; private int minRed, maxRed, minGreen, maxGreen, minBlue, maxBlue; - public Vbox(int lowerIndex, int upperIndex) + private ColorCutQuantizer colorCutQuantizer; // Keep owner to get raw color array and populations. + + public Vbox(int lowerIndex, int upperIndex, ColorCutQuantizer colorCutQuantizer) { this.lowerIndex = lowerIndex; this.upperIndex = upperIndex; + this.colorCutQuantizer = colorCutQuantizer; FitBox(); } @@ -434,6 +436,8 @@ namespace Tizen.NUI /// public void FitBox() { + var colors = colorCutQuantizer.colors; + // Reset the min and max to opposite values minRed = minGreen = minBlue = 0xff; maxRed = maxGreen = maxBlue = 0x0; @@ -467,7 +471,7 @@ namespace Tizen.NUI // find median along the longest dimension int splitPoint = FindSplitPoint(); - Vbox newBox = new Vbox(splitPoint + 1, upperIndex); + Vbox newBox = new Vbox(splitPoint + 1, upperIndex, colorCutQuantizer); // Now change this box's upperIndex and recompute the color boundaries upperIndex = splitPoint; FitBox(); @@ -516,8 +520,9 @@ namespace Tizen.NUI // it's most significant is the desired dimension ModifySignificantOctet(longestDimension, lowerIndex, upperIndex); + var colors = colorCutQuantizer.colors; Array.Sort(colors, lowerIndex, upperIndex + 1 - lowerIndex); - + // Now revert all of the colors so that they are packed as RGB again ModifySignificantOctet(longestDimension, lowerIndex, upperIndex); @@ -560,6 +565,9 @@ namespace Tizen.NUI int blueSum = 0; int totalPopulation = 0; + var colorPopulations = colorCutQuantizer.colorPopulations; + var colors = colorCutQuantizer.colors; + for (int i = lowerIndex; i <= upperIndex; i++) { int colorPopulation = colorPopulations[colors[i]]; @@ -604,10 +612,15 @@ namespace Tizen.NUI switch (dimension) { case componentRed: + { // Already in RGB, no need to do anything break; + } case componentGreen: + { // We need to do a RGB to GRB swap, or vice-versa + var colors = colorCutQuantizer.colors; + for (int i = lowIndex; i <= highIndex; i++) { int color = colors[i]; @@ -620,10 +633,13 @@ namespace Tizen.NUI colors[i] = (color >> 24 & 0xff) << 24 | (color >> 8 & 0xff) << 16 | (color >> 16 & 0xff) << 8 | (color & 0xff); } } - break; + } case componentBlue: + { // We need to do a RGB to BGR swap, or vice-versa + var colors = colorCutQuantizer.colors; + for (int i = lowIndex; i <= highIndex; i++) { int color = colors[i]; @@ -637,6 +653,7 @@ namespace Tizen.NUI } } break; + } } } }