blob: 62026e490271cda78a81caf3bc83f7499ece0089 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.java2d.pipe;
27
28import 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 */
45public 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 = 28;
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 * Copies length bytes from the Java-level srcArray to the native
97 * memory located at dstAddr. Note that this method performs no bounds
98 * checking. Verification that the copy will not result in memory
99 * corruption should be done by the caller prior to invocation.
100 *
101 * @param srcArray the source array
102 * @param srcPos the starting position of the source array (in bytes)
103 * @param dstAddr pointer to the destination block of native memory
104 * @param length the number of bytes to copy from source to destination
105 */
106 private static native void copyFromArray(Object srcArray, long srcPos,
107 long dstAddr, long length);
108
109 /**
110 * The behavior (and names) of the following methods are nearly
111 * identical to their counterparts in the various NIO Buffer classes.
112 */
113
114 public final int capacity() {
115 return capacity;
116 }
117
118 public final int remaining() {
119 return (int)(endAddress - curAddress);
120 }
121
122 public final int position() {
123 return (int)(curAddress - baseAddress);
124 }
125
126 public final void position(long numBytes) {
127 curAddress = baseAddress + numBytes;
128 }
129
130 public final void clear() {
131 curAddress = baseAddress;
132 }
133
134 /**
135 * putByte() methods...
136 */
137
138 public final RenderBuffer putByte(byte x) {
139 unsafe.putByte(curAddress, x);
140 curAddress += SIZEOF_BYTE;
141 return this;
142 }
143
144 public RenderBuffer put(byte[] x) {
145 return put(x, 0, x.length);
146 }
147
148 public RenderBuffer put(byte[] x, int offset, int length) {
149 if (length > COPY_FROM_ARRAY_THRESHOLD) {
150 long offsetInBytes = offset * SIZEOF_BYTE;
151 long lengthInBytes = length * SIZEOF_BYTE;
152 copyFromArray(x, offsetInBytes, curAddress, lengthInBytes);
153 position(position() + lengthInBytes);
154 } else {
155 int end = offset + length;
156 for (int i = offset; i < end; i++) {
157 putByte(x[i]);
158 }
159 }
160 return this;
161 }
162
163 /**
164 * putShort() methods...
165 */
166
167 public final RenderBuffer putShort(short x) {
168 // assert (position() % SIZEOF_SHORT == 0);
169 unsafe.putShort(curAddress, x);
170 curAddress += SIZEOF_SHORT;
171 return this;
172 }
173
174 public RenderBuffer put(short[] x) {
175 return put(x, 0, x.length);
176 }
177
178 public RenderBuffer put(short[] x, int offset, int length) {
179 // assert (position() % SIZEOF_SHORT == 0);
180 if (length > COPY_FROM_ARRAY_THRESHOLD) {
181 long offsetInBytes = offset * SIZEOF_SHORT;
182 long lengthInBytes = length * SIZEOF_SHORT;
183 copyFromArray(x, offsetInBytes, curAddress, lengthInBytes);
184 position(position() + lengthInBytes);
185 } else {
186 int end = offset + length;
187 for (int i = offset; i < end; i++) {
188 putShort(x[i]);
189 }
190 }
191 return this;
192 }
193
194 /**
195 * putInt() methods...
196 */
197
198 public final RenderBuffer putInt(int pos, int x) {
199 // assert (baseAddress + pos % SIZEOF_INT == 0);
200 unsafe.putInt(baseAddress + pos, x);
201 return this;
202 }
203
204 public final RenderBuffer putInt(int x) {
205 // assert (position() % SIZEOF_INT == 0);
206 unsafe.putInt(curAddress, x);
207 curAddress += SIZEOF_INT;
208 return this;
209 }
210
211 public RenderBuffer put(int[] x) {
212 return put(x, 0, x.length);
213 }
214
215 public RenderBuffer put(int[] x, int offset, int length) {
216 // assert (position() % SIZEOF_INT == 0);
217 if (length > COPY_FROM_ARRAY_THRESHOLD) {
218 long offsetInBytes = offset * SIZEOF_INT;
219 long lengthInBytes = length * SIZEOF_INT;
220 copyFromArray(x, offsetInBytes, curAddress, lengthInBytes);
221 position(position() + lengthInBytes);
222 } else {
223 int end = offset + length;
224 for (int i = offset; i < end; i++) {
225 putInt(x[i]);
226 }
227 }
228 return this;
229 }
230
231 /**
232 * putFloat() methods...
233 */
234
235 public final RenderBuffer putFloat(float x) {
236 // assert (position() % SIZEOF_FLOAT == 0);
237 unsafe.putFloat(curAddress, x);
238 curAddress += SIZEOF_FLOAT;
239 return this;
240 }
241
242 public RenderBuffer put(float[] x) {
243 return put(x, 0, x.length);
244 }
245
246 public RenderBuffer put(float[] x, int offset, int length) {
247 // assert (position() % SIZEOF_FLOAT == 0);
248 if (length > COPY_FROM_ARRAY_THRESHOLD) {
249 long offsetInBytes = offset * SIZEOF_FLOAT;
250 long lengthInBytes = length * SIZEOF_FLOAT;
251 copyFromArray(x, offsetInBytes, curAddress, lengthInBytes);
252 position(position() + lengthInBytes);
253 } else {
254 int end = offset + length;
255 for (int i = offset; i < end; i++) {
256 putFloat(x[i]);
257 }
258 }
259 return this;
260 }
261
262 /**
263 * putLong() methods...
264 */
265
266 public final RenderBuffer putLong(long x) {
267 // assert (position() % SIZEOF_LONG == 0);
268 unsafe.putLong(curAddress, x);
269 curAddress += SIZEOF_LONG;
270 return this;
271 }
272
273 public RenderBuffer put(long[] x) {
274 return put(x, 0, x.length);
275 }
276
277 public RenderBuffer put(long[] x, int offset, int length) {
278 // assert (position() % SIZEOF_LONG == 0);
279 if (length > COPY_FROM_ARRAY_THRESHOLD) {
280 long offsetInBytes = offset * SIZEOF_LONG;
281 long lengthInBytes = length * SIZEOF_LONG;
282 copyFromArray(x, offsetInBytes, curAddress, lengthInBytes);
283 position(position() + lengthInBytes);
284 } else {
285 int end = offset + length;
286 for (int i = offset; i < end; i++) {
287 putLong(x[i]);
288 }
289 }
290 return this;
291 }
292
293 /**
294 * putDouble() method(s)...
295 */
296
297 public final RenderBuffer putDouble(double x) {
298 // assert (position() % SIZEOF_DOUBLE == 0);
299 unsafe.putDouble(curAddress, x);
300 curAddress += SIZEOF_DOUBLE;
301 return this;
302 }
303}