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