Ticket #23628: 23628.patch
File 23628.patch, 7.4 KB (added by , 13 months ago) |
---|
-
src/org/openstreetmap/josm/tools/ImageWarp.java
5 5 import java.awt.geom.Point2D; 6 6 import java.awt.geom.Rectangle2D; 7 7 import java.awt.image.BufferedImage; 8 import java.awt.image.DataBuffer; 8 9 import java.util.HashMap; 9 10 import java.util.HashSet; 10 11 import java.util.Map; … … 33 34 * @return transformed pixel coordinates 34 35 */ 35 36 Point2D transform(Point2D pt); 37 38 /** 39 * Translates pixel coordinates. 40 * @param x The x coordinate 41 * @param y The y coordinate 42 * @return transformed pixel coordinates 43 */ 44 default Point2D transform(double x, double y) { 45 return transform(new Point2D.Double(x, y)); 46 } 36 47 } 37 48 38 49 /** … … 75 86 76 87 @Override 77 88 public Point2D transform(Point2D pt) { 78 int xIdx = (int) Math.floor(pt.getX() / stride); 79 int yIdx = (int) Math.floor(pt.getY() / stride); 80 double dx = pt.getX() / stride - xIdx; 81 double dy = pt.getY() / stride - yIdx; 89 return transform(pt.getX(), pt.getY()); 90 } 91 92 @Override 93 public Point2D transform(double x, double y) { 94 int xIdx = (int) Math.floor(x / stride); 95 int yIdx = (int) Math.floor(y / stride); 96 double dx = x / stride - xIdx; 97 double dy = y / stride - yIdx; 82 98 Point2D value00 = getValue(xIdx, yIdx); 83 99 Point2D value01 = getValue(xIdx, yIdx + 1); 84 100 Point2D value10 = getValue(xIdx + 1, yIdx); … … 91 107 } 92 108 93 109 private Point2D getValue(int xIdx, int yIdx) { 94 return getRow(yIdx).computeIfAbsent(xIdx, k -> trfm.transform(new Point2D.Double(xIdx * stride, yIdx * stride))); 110 final Map<Integer, Point2D> rowMap = getRow(yIdx); 111 // This *was* computeIfAbsent. Unfortunately, it appears that it generated a ton of memory allocations. 112 // As in, this was ~50 GB memory allocations in a test, and converting to a non-lambda form made it 1.3GB. 113 // The primary culprit was LamdaForm#linkToTargetMethod 114 Point2D current = rowMap.get(xIdx); 115 if (current == null) { 116 current = transform(xIdx, yIdx); 117 rowMap.put(xIdx, current); 118 } 119 return current; 95 120 } 96 121 122 private Point2D transform(int xIdx, int yIdx) { 123 return trfm.transform(new Point2D.Double(xIdx * stride, yIdx * stride)); 124 } 125 97 126 private Map<Integer, Point2D> getRow(int yIdx) { 98 127 cleanUp(yIdx - 3); 99 128 Map<Integer, Point2D> row = cache.get(yIdx); 129 // Note: using computeIfAbsent will drastically increase memory allocations 100 130 if (row == null) { 101 row = new HashMap<>( );131 row = new HashMap<>(256); 102 132 cache.put(yIdx, row); 103 133 if (consistencyTest) { 104 134 // should not create a row that has been deleted before … … 152 182 public static BufferedImage warp(BufferedImage srcImg, Dimension targetDim, PointTransform invTransform, Interpolation interpolation) { 153 183 BufferedImage imgTarget = new BufferedImage(targetDim.width, targetDim.height, BufferedImage.TYPE_INT_ARGB); 154 184 Rectangle2D srcRect = new Rectangle2D.Double(0, 0, srcImg.getWidth(), srcImg.getHeight()); 185 // These arrays reduce the amount of memory allocations (getRGB and setRGB are 186 // collectively 40% of the memory cost, 78% if LambdaForm#linkToTargetMethod is 187 // ignored). We mostly want to decrease GC pauses here. 188 final int[] pixel = new int[1]; // Yes, this really does decrease memory allocations with TYPE_INT_ARGB. 189 final Object sharedArray = getSharedArray(srcImg); 155 190 for (int j = 0; j < imgTarget.getHeight(); j++) { 156 191 for (int i = 0; i < imgTarget.getWidth(); i++) { 157 Point2D srcCoord = invTransform.transform( new Point2D.Double(i, j));192 Point2D srcCoord = invTransform.transform(i, j); 158 193 if (srcRect.contains(srcCoord)) { 159 194 int rgba; 160 195 switch (interpolation) { 161 196 case NEAREST_NEIGHBOR: 162 rgba = getColor((int) Math.round(srcCoord.getX()), (int) Math.round(srcCoord.getY()), srcImg );197 rgba = getColor((int) Math.round(srcCoord.getX()), (int) Math.round(srcCoord.getY()), srcImg, sharedArray); 163 198 break; 164 199 case BILINEAR: 165 200 int x0 = (int) Math.floor(srcCoord.getX()); … … 166 201 double dx = srcCoord.getX() - x0; 167 202 int y0 = (int) Math.floor(srcCoord.getY()); 168 203 double dy = srcCoord.getY() - y0; 169 int c00 = getColor(x0, y0, srcImg );170 int c01 = getColor(x0, y0 + 1, srcImg );171 int c10 = getColor(x0 + 1, y0, srcImg );172 int c11 = getColor(x0 + 1, y0 + 1, srcImg );204 int c00 = getColor(x0, y0, srcImg, sharedArray); 205 int c01 = getColor(x0, y0 + 1, srcImg, sharedArray); 206 int c10 = getColor(x0 + 1, y0, srcImg, sharedArray); 207 int c11 = getColor(x0 + 1, y0 + 1, srcImg, sharedArray); 173 208 rgba = 0; 174 209 // loop over color components: blue, green, red, alpha 175 210 for (int ch = 0; ch <= 3; ch++) { … … 183 218 default: 184 219 throw new AssertionError(Objects.toString(interpolation)); 185 220 } 186 imgTarget. setRGB(i, j, rgba);221 imgTarget.getRaster().setDataElements(i, j, imgTarget.getColorModel().getDataElements(rgba, pixel)); 187 222 } 188 223 } 189 224 } … … 190 225 return imgTarget; 191 226 } 192 227 193 private static int getColor(int x, int y, BufferedImage img) { 228 private static Object getSharedArray(BufferedImage srcImg) { 229 final int numBands = srcImg.getRaster().getNumBands(); 230 // Add data types as needed (shown via profiling, look for getRGB). 231 switch (srcImg.getRaster().getDataBuffer().getDataType()) { 232 case DataBuffer.TYPE_BYTE: 233 return new byte[numBands]; 234 case DataBuffer.TYPE_INT: 235 return new int[numBands]; 236 default: 237 return null; 238 } 239 } 240 241 private static int getColor(int x, int y, BufferedImage img, Object sharedArray) { 194 242 // border strategy: continue with the color of the outermost pixel, 195 return img.getRGB( 196 Utils.clamp(x, 0, img.getWidth() - 1), 197 Utils.clamp(y, 0, img.getHeight() - 1)); 243 final int rx = Utils.clamp(x, 0, img.getWidth() - 1); 244 final int ry = Utils.clamp(y, 0, img.getHeight() - 1); 245 if (sharedArray == null) { 246 return img.getRGB(rx, ry); 247 } 248 return img.getColorModel().getRGB(img.getRaster().getDataElements(rx, ry, sharedArray)); 198 249 } 199 250 }