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