1 /* 2 * Copyright (c) 2016, 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 byte[] getAlphasNoClone() { 81 return alphas; 82 } 83 84 public int getAlphaLength() { 85 return alphas.length; 86 } 87 88 public MaskData getMaskData() { 89 return maskdata; 90 } 91 92 OffHeapArray ALPHA_MAP_USED = null; 93 94 @Override 95 public void setMaxAlpha(int maxalpha) { 96 ALPHA_MAP_USED = (maxalpha == 1) ? ALPHA_MAP_UNSAFE_NO_AA : ALPHA_MAP_UNSAFE; 97 } 98 99 // The alpha map used by this object (taken out of our map cache) to convert 100 // pixel coverage counts (which are in the range [0, maxalpha]) 101 // into alpha values, which are in [0,255]). 102 static final byte[] ALPHA_MAP; 103 static final OffHeapArray ALPHA_MAP_UNSAFE; 104 105 static final byte[] ALPHA_MAP_NO_AA; 106 static final OffHeapArray ALPHA_MAP_UNSAFE_NO_AA; 107 108 static { 109 final Unsafe _unsafe = OffHeapArray.UNSAFE; 110 111 // AA: 112 byte[] _ALPHA_MAP = buildAlphaMap(MarlinConst.MAX_AA_ALPHA); 113 ALPHA_MAP = _ALPHA_MAP; // Keep alive the OffHeapArray 114 ALPHA_MAP_UNSAFE = new OffHeapArray(ALPHA_MAP, ALPHA_MAP.length); // 1K 115 116 long addr = ALPHA_MAP_UNSAFE.address; 117 118 for (int i = 0; i < _ALPHA_MAP.length; i++) { 119 _unsafe.putByte(addr + i, _ALPHA_MAP[i]); 120 } 121 122 // NoAA: 123 byte[] _ALPHA_MAP_NO_AA = buildAlphaMap(1); 124 ALPHA_MAP_NO_AA = _ALPHA_MAP_NO_AA; // Keep alive the OffHeapArray 125 ALPHA_MAP_UNSAFE_NO_AA = new OffHeapArray(ALPHA_MAP_NO_AA, ALPHA_MAP_NO_AA.length); 126 127 addr = ALPHA_MAP_UNSAFE_NO_AA.address; 128 129 for (int i = 0; i < _ALPHA_MAP_NO_AA.length; i++) { 130 _unsafe.putByte(addr + i, _ALPHA_MAP_NO_AA[i]); 131 } 132 } 133 134 private static byte[] buildAlphaMap(final int maxalpha) { 135 final byte[] alMap = new byte[maxalpha << 1]; 136 final int halfmaxalpha = maxalpha >> 2; 137 for (int i = 0; i <= maxalpha; i++) { 138 alMap[i] = (byte) ((i * 255 + halfmaxalpha) / maxalpha); 139 // System.out.println("alphaMap[" + i + "] = " 140 // + Byte.toUnsignedInt(alMap[i])); 141 } 142 return alMap; 143 } 144 145 @Override 146 public boolean supportBlockFlags() { 147 return true; 148 } 149 150 @Override 151 public void clearAlphas(final int pix_y) { 152 final int w = width; 153 final int off = (pix_y - y) * w; 154 155 // Clear complete row: 156 Arrays.fill(this.alphas, off, off + w, (byte)0); 157 } 158 159 @Override 160 public void setAndClearRelativeAlphas(final int[] alphaDeltas, final int pix_y, 161 final int pix_from, final int pix_to) 162 { 163 // System.out.println("setting row "+(pix_y - y)+ 164 // " out of "+width+" x "+height); 165 166 final byte out[] = this.alphas; 167 final int w = width; 168 final int off = (pix_y - y) * w; 169 170 final Unsafe _unsafe = OffHeapArray.UNSAFE; 171 final long addr_alpha = ALPHA_MAP_USED.address; 172 173 final int from = pix_from - x; 174 175 // skip useless pixels above boundary 176 final int to = pix_to - x; 177 final int ato = Math.min(to, width); 178 179 // fast fill ? 180 final boolean fast = useFastFill && ((ato - from) < fastFillThreshold); 181 182 if (fast) { 183 // Zero-fill complete row: 184 Arrays.fill(out, off, off + w, (byte) 0); 185 186 int i = from; 187 int curAlpha = 0; 188 189 while (i < ato) { 190 curAlpha += alphaDeltas[i]; 191 192 out[off + i] = _unsafe.getByte(addr_alpha + curAlpha); // [0..255] 193 i++; 194 } 195 196 } else { 197 int i = 0; 198 199 while (i < from) { 200 out[off + i] = 0; 201 i++; 202 } 203 204 int curAlpha = 0; 205 206 while (i < ato) { 207 curAlpha += alphaDeltas[i]; 208 209 out[off + i] = _unsafe.getByte(addr_alpha + curAlpha); // [0..255] 210 i++; 211 } 212 213 while (i < w) { 214 out[off + i] = 0; 215 i++; 216 } 217 } 218 219 // Clear alpha row for reuse: 220 IntArrayCache.fill(alphaDeltas, from, to + 1, 0); 221 } 222 223 @Override 224 public void setAndClearRelativeAlphas(final int[] blkFlags, final int[] alphaDeltas, final int pix_y, 225 final int pix_from, final int pix_to) 226 { 227 // System.out.println("setting row "+(pix_y - y)+ 228 // " out of "+width+" x "+height); 229 230 final byte out[] = this.alphas; 231 final int w = width; 232 final int off = (pix_y - y) * w; 233 234 final Unsafe _unsafe = OffHeapArray.UNSAFE; 235 final long addr_alpha = ALPHA_MAP_USED.address; 236 237 final int from = pix_from - x; 238 239 // skip useless pixels above boundary 240 final int to = pix_to - x; 241 final int ato = Math.min(to, width); 242 243 // fast fill ? 244 final boolean fast = useFastFill && ((ato - from) < fastFillThreshold); 245 246 final int _BLK_SIZE_LG = MarlinConst.BLOCK_SIZE_LG; 247 248 // traverse flagged blocks: 249 final int blkW = (from >> _BLK_SIZE_LG); 250 final int blkE = (ato >> _BLK_SIZE_LG) + 1; 251 // ensure last block flag = 0 to process final block: 252 blkFlags[blkE] = 0; 253 254 // Perform run-length encoding and store results in the piscesCache 255 int curAlpha = 0; 256 257 final int _MAX_VALUE = Integer.MAX_VALUE; 258 int last_t0 = _MAX_VALUE; 259 byte val; 260 261 if (fast) { 262 int i = from; 263 264 // Zero-fill complete row: 265 Arrays.fill(out, off, off + w, (byte) 0); 266 267 for (int t = blkW, blk_x0, blk_x1, cx, delta; t <= blkE; t++) { 268 if (blkFlags[t] != 0) { 269 blkFlags[t] = 0; 270 271 if (last_t0 == _MAX_VALUE) { 272 last_t0 = t; 273 } 274 continue; 275 } 276 if (last_t0 != _MAX_VALUE) { 277 // emit blocks: 278 blk_x0 = FloatMath.max(last_t0 << _BLK_SIZE_LG, from); 279 last_t0 = _MAX_VALUE; 280 281 // (last block pixel+1) inclusive => +1 282 blk_x1 = FloatMath.min((t << _BLK_SIZE_LG) + 1, ato); 283 284 for (cx = blk_x0; cx < blk_x1; cx++) { 285 if ((delta = alphaDeltas[cx]) != 0) { 286 alphaDeltas[cx] = 0; 287 288 // fill span: 289 if (cx != i) { 290 // skip alpha = 0 291 if (curAlpha == 0) { 292 i = cx; 293 } else { 294 val = _unsafe.getByte(addr_alpha + curAlpha); 295 do { 296 out[off + i] = val; 297 i++; 298 } while (i < cx); 299 } 300 } 301 302 // alpha value = running sum of coverage delta: 303 curAlpha += delta; 304 } 305 } 306 } 307 } 308 309 // Process remaining span: 310 if (curAlpha != 0) { 311 val = _unsafe.getByte(addr_alpha + curAlpha); 312 while (i < ato) { 313 out[off + i] = val; 314 i++; 315 } 316 } 317 318 } else { 319 int i = 0; 320 321 while (i < from) { 322 out[off + i] = 0; 323 i++; 324 } 325 326 for (int t = blkW, blk_x0, blk_x1, cx, delta; t <= blkE; t++) { 327 if (blkFlags[t] != 0) { 328 blkFlags[t] = 0; 329 330 if (last_t0 == _MAX_VALUE) { 331 last_t0 = t; 332 } 333 continue; 334 } 335 if (last_t0 != _MAX_VALUE) { 336 // emit blocks: 337 blk_x0 = FloatMath.max(last_t0 << _BLK_SIZE_LG, from); 338 last_t0 = _MAX_VALUE; 339 340 // (last block pixel+1) inclusive => +1 341 blk_x1 = FloatMath.min((t << _BLK_SIZE_LG) + 1, ato); 342 343 for (cx = blk_x0; cx < blk_x1; cx++) { 344 if ((delta = alphaDeltas[cx]) != 0) { 345 alphaDeltas[cx] = 0; 346 347 // fill span: 348 if (cx != i) { 349 val = _unsafe.getByte(addr_alpha + curAlpha); 350 do { 351 out[off + i] = val; 352 i++; 353 } while (i < cx); 354 } 355 356 // alpha value = running sum of coverage delta: 357 curAlpha += delta; 358 } 359 } 360 } 361 } 362 363 // Process remaining span: 364 if (curAlpha != 0) { 365 val = _unsafe.getByte(addr_alpha + curAlpha); 366 while (i < ato) { 367 out[off + i] = val; 368 i++; 369 } 370 } 371 372 while (i < w) { 373 out[off + i] = 0; 374 i++; 375 } 376 } 377 378 // Clear alpha row for reuse: 379 alphaDeltas[ato] = 0; 380 381 if (MarlinConst.DO_CHECKS) { 382 IntArrayCache.check(blkFlags, blkW, blkE, 0); 383 IntArrayCache.check(alphaDeltas, from, to + 1, 0); 384 } 385 } 386 }