1 /* 2 * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.marlin; 27 28 import com.sun.prism.impl.shape.MaskData; 29 import java.nio.ByteBuffer; 30 import java.util.Arrays; 31 import jdk.internal.misc.Unsafe; 32 33 public final class MaskMarlinAlphaConsumer implements MarlinAlphaConsumer { 34 int x, y, width, height; 35 final byte alphas[]; 36 final ByteBuffer alphabuffer; 37 final MaskData maskdata = new MaskData(); 38 39 boolean useFastFill; 40 int fastFillThreshold; 41 42 public MaskMarlinAlphaConsumer(int alphalen) { 43 this.alphas = new byte[alphalen]; 44 alphabuffer = ByteBuffer.wrap(alphas); 45 } 46 47 public void setBoundsNoClone(int x, int y, int w, int h) { 48 this.x = x; 49 this.y = y; 50 this.width = w; 51 this.height = h; 52 maskdata.update(alphabuffer, x, y, w, h); 53 54 useFastFill = (w >= 32); 55 if (useFastFill) { 56 fastFillThreshold = (w >= 128) ? (w >> 1) : (w >> 2); 57 } 58 } 59 60 @Override 61 public int getOriginX() { 62 return x; 63 } 64 65 @Override 66 public int getOriginY() { 67 return y; 68 } 69 70 @Override 71 public int getWidth() { 72 return width; 73 } 74 75 @Override 76 public int getHeight() { 77 return height; 78 } 79 80 public int getAlphaLength() { 81 return alphas.length; 82 } 83 84 public MaskData getMaskData() { 85 return maskdata; 86 } 87 88 OffHeapArray ALPHA_MAP_USED = null; 89 90 @Override 91 public void setMaxAlpha(int maxalpha) { 92 ALPHA_MAP_USED = (maxalpha == 1) ? ALPHA_MAP_UNSAFE_NO_AA : ALPHA_MAP_UNSAFE; 93 } 94 95 // The alpha map used by this object (taken out of our map cache) to convert 96 // pixel coverage counts (which are in the range [0, maxalpha]) 97 // into alpha values, which are in [0,255]). 98 static final byte[] ALPHA_MAP; 99 static final OffHeapArray ALPHA_MAP_UNSAFE; 100 101 static final byte[] ALPHA_MAP_NO_AA; 102 static final OffHeapArray ALPHA_MAP_UNSAFE_NO_AA; 103 104 static { 105 final Unsafe _unsafe = OffHeapArray.UNSAFE; 106 107 // AA: 108 byte[] _ALPHA_MAP = buildAlphaMap(MarlinConst.MAX_AA_ALPHA); 109 ALPHA_MAP = _ALPHA_MAP; // Keep alive the OffHeapArray 110 ALPHA_MAP_UNSAFE = new OffHeapArray(ALPHA_MAP, ALPHA_MAP.length); // 1K 111 112 long addr = ALPHA_MAP_UNSAFE.address; 113 114 for (int i = 0; i < _ALPHA_MAP.length; i++) { 115 _unsafe.putByte(addr + i, _ALPHA_MAP[i]); 116 } 117 118 // NoAA: 119 byte[] _ALPHA_MAP_NO_AA = buildAlphaMap(1); 120 ALPHA_MAP_NO_AA = _ALPHA_MAP_NO_AA; // Keep alive the OffHeapArray 121 ALPHA_MAP_UNSAFE_NO_AA = new OffHeapArray(ALPHA_MAP_NO_AA, ALPHA_MAP_NO_AA.length); 122 123 addr = ALPHA_MAP_UNSAFE_NO_AA.address; 124 125 for (int i = 0; i < _ALPHA_MAP_NO_AA.length; i++) { 126 _unsafe.putByte(addr + i, _ALPHA_MAP_NO_AA[i]); 127 } 128 } 129 130 private static byte[] buildAlphaMap(final int maxalpha) { 131 final byte[] alMap = new byte[maxalpha << 1]; 132 final int halfmaxalpha = maxalpha >> 2; 133 for (int i = 0; i <= maxalpha; i++) { 134 alMap[i] = (byte) ((i * 255 + halfmaxalpha) / maxalpha); 135 // System.out.println("alphaMap[" + i + "] = " 136 // + Byte.toUnsignedInt(alMap[i])); 137 } 138 return alMap; 139 } 140 141 @Override 142 public boolean supportBlockFlags() { 143 return true; 144 } 145 146 @Override 147 public void clearAlphas(final int pix_y) { 148 final int w = width; 149 final int off = (pix_y - y) * w; 150 151 // Clear complete row: 152 Arrays.fill(this.alphas, off, off + w, (byte)0); 153 } 154 155 @Override 156 public void setAndClearRelativeAlphas(final int[] alphaDeltas, final int pix_y, 157 final int pix_from, final int pix_to) 158 { 159 // System.out.println("setting row "+(pix_y - y)+ 160 // " out of "+width+" x "+height); 161 162 final byte[] out = this.alphas; 163 final int w = width; 164 final int off = (pix_y - y) * w; 165 166 final Unsafe _unsafe = OffHeapArray.UNSAFE; 167 final long addr_alpha = ALPHA_MAP_USED.address; 168 169 final int from = pix_from - x; 170 171 // skip useless pixels above boundary 172 final int to = pix_to - x; 173 final int ato = Math.min(to, width); 174 175 // fast fill ? 176 final boolean fast = useFastFill && ((ato - from) < fastFillThreshold); 177 178 if (fast) { 179 // Zero-fill complete row: 180 Arrays.fill(out, off, off + w, (byte) 0); 181 182 int i = from; 183 int curAlpha = 0; 184 185 while (i < ato) { 186 curAlpha += alphaDeltas[i]; 187 188 out[off + i] = _unsafe.getByte(addr_alpha + curAlpha); // [0..255] 189 i++; 190 } 191 192 } else { 193 int i = 0; 194 195 while (i < from) { 196 out[off + i] = 0; 197 i++; 198 } 199 200 int curAlpha = 0; 201 202 while (i < ato) { 203 curAlpha += alphaDeltas[i]; 204 205 out[off + i] = _unsafe.getByte(addr_alpha + curAlpha); // [0..255] 206 i++; 207 } 208 209 while (i < w) { 210 out[off + i] = 0; 211 i++; 212 } 213 } 214 215 // Clear alpha row for reuse: 216 IntArrayCache.fill(alphaDeltas, from, to + 1, 0); 217 } 218 219 @Override 220 public void setAndClearRelativeAlphas(final int[] blkFlags, final int[] alphaDeltas, final int pix_y, 221 final int pix_from, final int pix_to) 222 { 223 // System.out.println("setting row "+(pix_y - y)+ 224 // " out of "+width+" x "+height); 225 226 final byte[] out = this.alphas; 227 final int w = width; 228 final int off = (pix_y - y) * w; 229 230 final Unsafe _unsafe = OffHeapArray.UNSAFE; 231 final long addr_alpha = ALPHA_MAP_USED.address; 232 233 final int from = pix_from - x; 234 235 // skip useless pixels above boundary 236 final int to = pix_to - x; 237 final int ato = Math.min(to, width); 238 239 // fast fill ? 240 final boolean fast = useFastFill && ((ato - from) < fastFillThreshold); 241 242 final int _BLK_SIZE_LG = MarlinConst.BLOCK_SIZE_LG; 243 244 // traverse flagged blocks: 245 final int blkW = (from >> _BLK_SIZE_LG); 246 final int blkE = (ato >> _BLK_SIZE_LG) + 1; 247 // ensure last block flag = 0 to process final block: 248 blkFlags[blkE] = 0; 249 250 // Perform run-length encoding and store results in the piscesCache 251 int curAlpha = 0; 252 253 final int _MAX_VALUE = Integer.MAX_VALUE; 254 int last_t0 = _MAX_VALUE; 255 byte val; 256 257 if (fast) { 258 int i = from; 259 260 // Zero-fill complete row: 261 Arrays.fill(out, off, off + w, (byte) 0); 262 263 for (int t = blkW, blk_x0, blk_x1, cx, delta; t <= blkE; t++) { 264 if (blkFlags[t] != 0) { 265 blkFlags[t] = 0; 266 267 if (last_t0 == _MAX_VALUE) { 268 last_t0 = t; 269 } 270 continue; 271 } 272 if (last_t0 != _MAX_VALUE) { 273 // emit blocks: 274 blk_x0 = FloatMath.max(last_t0 << _BLK_SIZE_LG, from); 275 last_t0 = _MAX_VALUE; 276 277 // (last block pixel+1) inclusive => +1 278 blk_x1 = FloatMath.min((t << _BLK_SIZE_LG) + 1, ato); 279 280 for (cx = blk_x0; cx < blk_x1; cx++) { 281 if ((delta = alphaDeltas[cx]) != 0) { 282 alphaDeltas[cx] = 0; 283 284 // fill span: 285 if (cx != i) { 286 // skip alpha = 0 287 if (curAlpha == 0) { 288 i = cx; 289 } else { 290 val = _unsafe.getByte(addr_alpha + curAlpha); 291 do { 292 out[off + i] = val; 293 i++; 294 } while (i < cx); 295 } 296 } 297 298 // alpha value = running sum of coverage delta: 299 curAlpha += delta; 300 } 301 } 302 } 303 } 304 305 // Process remaining span: 306 if (curAlpha != 0) { 307 val = _unsafe.getByte(addr_alpha + curAlpha); 308 while (i < ato) { 309 out[off + i] = val; 310 i++; 311 } 312 } 313 314 } else { 315 int i = 0; 316 317 while (i < from) { 318 out[off + i] = 0; 319 i++; 320 } 321 322 for (int t = blkW, blk_x0, blk_x1, cx, delta; t <= blkE; t++) { 323 if (blkFlags[t] != 0) { 324 blkFlags[t] = 0; 325 326 if (last_t0 == _MAX_VALUE) { 327 last_t0 = t; 328 } 329 continue; 330 } 331 if (last_t0 != _MAX_VALUE) { 332 // emit blocks: 333 blk_x0 = FloatMath.max(last_t0 << _BLK_SIZE_LG, from); 334 last_t0 = _MAX_VALUE; 335 336 // (last block pixel+1) inclusive => +1 337 blk_x1 = FloatMath.min((t << _BLK_SIZE_LG) + 1, ato); 338 339 for (cx = blk_x0; cx < blk_x1; cx++) { 340 if ((delta = alphaDeltas[cx]) != 0) { 341 alphaDeltas[cx] = 0; 342 343 // fill span: 344 if (cx != i) { 345 val = _unsafe.getByte(addr_alpha + curAlpha); 346 do { 347 out[off + i] = val; 348 i++; 349 } while (i < cx); 350 } 351 352 // alpha value = running sum of coverage delta: 353 curAlpha += delta; 354 } 355 } 356 } 357 } 358 359 // Process remaining span: 360 if (curAlpha != 0) { 361 val = _unsafe.getByte(addr_alpha + curAlpha); 362 while (i < ato) { 363 out[off + i] = val; 364 i++; 365 } 366 } 367 368 while (i < w) { 369 out[off + i] = 0; 370 i++; 371 } 372 } 373 374 // Clear alpha row for reuse: 375 alphaDeltas[ato] = 0; 376 377 if (MarlinConst.DO_CHECKS) { 378 IntArrayCache.check(blkFlags, blkW, blkE, 0); 379 IntArrayCache.check(alphaDeltas, from, to + 1, 0); 380 } 381 } 382 }