1 /* 2 * Copyright (c) 2005, 2013, 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 sun.java2d.pipe; 27 28 import sun.misc.Unsafe; 29 30 31 /** 32 * The RenderBuffer class is a simplified, high-performance, Unsafe wrapper 33 * used for buffering rendering operations in a single-threaded rendering 34 * environment. It's functionality is similar to the ByteBuffer and related 35 * NIO classes. However, the methods in this class perform little to no 36 * alignment or bounds checks for performance reasons. Therefore, it is 37 * the caller's responsibility to ensure that all put() calls are properly 38 * aligned and within bounds: 39 * - int and float values must be aligned on 4-byte boundaries 40 * - long and double values must be aligned on 8-byte boundaries 41 * 42 * This class only includes the bare minimum of methods to support 43 * single-threaded rendering. For example, there is no put(double[]) method 44 * because we currently have no need for such a method in the STR classes. 45 */ 46 public class RenderBuffer { 47 48 /** 49 * These constants represent the size of various data types (in bytes). 50 */ 51 protected static final long SIZEOF_BYTE = 1L; 52 protected static final long SIZEOF_SHORT = 2L; 53 protected static final long SIZEOF_INT = 4L; 54 protected static final long SIZEOF_FLOAT = 4L; 55 protected static final long SIZEOF_LONG = 8L; 56 protected static final long SIZEOF_DOUBLE = 8L; 57 58 /** 59 * Represents the number of elements at which we have empirically 60 * determined that the average cost of a JNI call exceeds the expense 61 * of an element by element copy. In other words, if the number of 62 * elements in an array to be copied exceeds this value, then we should 63 * use the copyFromArray() method to complete the bulk put operation. 64 * (This value can be adjusted if the cost of JNI downcalls is reduced 65 * in a future release.) 66 */ 67 private static final int COPY_FROM_ARRAY_THRESHOLD = 6; 68 69 protected final Unsafe unsafe; 70 protected final long baseAddress; 71 protected final long endAddress; 72 protected long curAddress; 73 protected final int capacity; 74 75 protected RenderBuffer(int numBytes) { 76 unsafe = Unsafe.getUnsafe(); 77 curAddress = baseAddress = unsafe.allocateMemory(numBytes); 78 endAddress = baseAddress + numBytes; 79 capacity = numBytes; 80 } 81 82 /** 83 * Allocates a fresh buffer using the machine endianness. 84 */ 85 public static RenderBuffer allocate(int numBytes) { 86 return new RenderBuffer(numBytes); 87 } 88 89 /** 90 * Returns the base address of the underlying memory buffer. 91 */ 92 public final long getAddress() { 93 return baseAddress; 94 } 95 96 /** 97 * The behavior (and names) of the following methods are nearly 98 * identical to their counterparts in the various NIO Buffer classes. 99 */ 100 101 public final int capacity() { 102 return capacity; 103 } 104 105 public final int remaining() { 106 return (int)(endAddress - curAddress); 107 } 108 109 public final int position() { 110 return (int)(curAddress - baseAddress); 111 } 112 113 public final void position(long numBytes) { 114 curAddress = baseAddress + numBytes; 115 } 116 117 public final void clear() { 118 curAddress = baseAddress; 119 } 120 121 public final RenderBuffer skip(long numBytes) { 122 curAddress += numBytes; 123 return this; 124 } 125 126 /** 127 * putByte() methods... 128 */ 129 130 public final RenderBuffer putByte(byte x) { 131 unsafe.putByte(curAddress, x); 132 curAddress += SIZEOF_BYTE; 133 return this; 134 } 135 136 public RenderBuffer put(byte[] x) { 137 return put(x, 0, x.length); 138 } 139 140 public RenderBuffer put(byte[] x, int offset, int length) { 141 if (length > COPY_FROM_ARRAY_THRESHOLD) { 142 long offsetInBytes = offset * SIZEOF_BYTE + Unsafe.ARRAY_BYTE_BASE_OFFSET; 143 long lengthInBytes = length * SIZEOF_BYTE; 144 unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); 145 position(position() + lengthInBytes); 146 } else { 147 int end = offset + length; 148 for (int i = offset; i < end; i++) { 149 putByte(x[i]); 150 } 151 } 152 return this; 153 } 154 155 /** 156 * putShort() methods... 157 */ 158 159 public final RenderBuffer putShort(short x) { 160 // assert (position() % SIZEOF_SHORT == 0); 161 unsafe.putShort(curAddress, x); 162 curAddress += SIZEOF_SHORT; 163 return this; 164 } 165 166 public RenderBuffer put(short[] x) { 167 return put(x, 0, x.length); 168 } 169 170 public RenderBuffer put(short[] x, int offset, int length) { 171 // assert (position() % SIZEOF_SHORT == 0); 172 if (length > COPY_FROM_ARRAY_THRESHOLD) { 173 long offsetInBytes = offset * SIZEOF_SHORT + Unsafe.ARRAY_SHORT_BASE_OFFSET; 174 long lengthInBytes = length * SIZEOF_SHORT; 175 unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); 176 position(position() + lengthInBytes); 177 } else { 178 int end = offset + length; 179 for (int i = offset; i < end; i++) { 180 putShort(x[i]); 181 } 182 } 183 return this; 184 } 185 186 /** 187 * putInt() methods... 188 */ 189 190 public final RenderBuffer putInt(int pos, int x) { 191 // assert (baseAddress + pos % SIZEOF_INT == 0); 192 unsafe.putInt(baseAddress + pos, x); 193 return this; 194 } 195 196 public final RenderBuffer putInt(int x) { 197 // assert (position() % SIZEOF_INT == 0); 198 unsafe.putInt(curAddress, x); 199 curAddress += SIZEOF_INT; 200 return this; 201 } 202 203 public RenderBuffer put(int[] x) { 204 return put(x, 0, x.length); 205 } 206 207 public RenderBuffer put(int[] x, int offset, int length) { 208 // assert (position() % SIZEOF_INT == 0); 209 if (length > COPY_FROM_ARRAY_THRESHOLD) { 210 long offsetInBytes = offset * SIZEOF_INT + Unsafe.ARRAY_INT_BASE_OFFSET; 211 long lengthInBytes = length * SIZEOF_INT; 212 unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); 213 position(position() + lengthInBytes); 214 } else { 215 int end = offset + length; 216 for (int i = offset; i < end; i++) { 217 putInt(x[i]); 218 } 219 } 220 return this; 221 } 222 223 /** 224 * putFloat() methods... 225 */ 226 227 public final RenderBuffer putFloat(float x) { 228 // assert (position() % SIZEOF_FLOAT == 0); 229 unsafe.putFloat(curAddress, x); 230 curAddress += SIZEOF_FLOAT; 231 return this; 232 } 233 234 public RenderBuffer put(float[] x) { 235 return put(x, 0, x.length); 236 } 237 238 public RenderBuffer put(float[] x, int offset, int length) { 239 // assert (position() % SIZEOF_FLOAT == 0); 240 if (length > COPY_FROM_ARRAY_THRESHOLD) { 241 long offsetInBytes = offset * SIZEOF_FLOAT + Unsafe.ARRAY_FLOAT_BASE_OFFSET; 242 long lengthInBytes = length * SIZEOF_FLOAT; 243 unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); 244 position(position() + lengthInBytes); 245 } else { 246 int end = offset + length; 247 for (int i = offset; i < end; i++) { 248 putFloat(x[i]); 249 } 250 } 251 return this; 252 } 253 254 /** 255 * putLong() methods... 256 */ 257 258 public final RenderBuffer putLong(long x) { 259 // assert (position() % SIZEOF_LONG == 0); 260 unsafe.putLong(curAddress, x); 261 curAddress += SIZEOF_LONG; 262 return this; 263 } 264 265 public RenderBuffer put(long[] x) { 266 return put(x, 0, x.length); 267 } 268 269 public RenderBuffer put(long[] x, int offset, int length) { 270 // assert (position() % SIZEOF_LONG == 0); 271 if (length > COPY_FROM_ARRAY_THRESHOLD) { 272 long offsetInBytes = offset * SIZEOF_LONG + Unsafe.ARRAY_LONG_BASE_OFFSET; 273 long lengthInBytes = length * SIZEOF_LONG; 274 unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); 275 position(position() + lengthInBytes); 276 } else { 277 int end = offset + length; 278 for (int i = offset; i < end; i++) { 279 putLong(x[i]); 280 } 281 } 282 return this; 283 } 284 285 /** 286 * putDouble() method(s)... 287 */ 288 289 public final RenderBuffer putDouble(double x) { 290 // assert (position() % SIZEOF_DOUBLE == 0); 291 unsafe.putDouble(curAddress, x); 292 curAddress += SIZEOF_DOUBLE; 293 return this; 294 } 295 }