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 jdk.internal.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 
RenderBuffer(int numBytes)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      */
allocate(int numBytes)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      */
getAddress()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 
capacity()101     public final int capacity() {
102         return capacity;
103     }
104 
remaining()105     public final int remaining() {
106         return (int)(endAddress - curAddress);
107     }
108 
position()109     public final int position() {
110         return (int)(curAddress - baseAddress);
111     }
112 
position(long numBytes)113     public final void position(long numBytes) {
114         curAddress = baseAddress + numBytes;
115     }
116 
clear()117     public final void clear() {
118         curAddress = baseAddress;
119     }
120 
skip(long numBytes)121     public final RenderBuffer skip(long numBytes) {
122         curAddress += numBytes;
123         return this;
124     }
125 
126     /**
127      * putByte() methods...
128      */
129 
putByte(byte x)130     public final RenderBuffer putByte(byte x) {
131         unsafe.putByte(curAddress, x);
132         curAddress += SIZEOF_BYTE;
133         return this;
134     }
135 
put(byte[] x)136     public RenderBuffer put(byte[] x) {
137         return put(x, 0, x.length);
138     }
139 
put(byte[] x, int offset, int length)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 
putShort(short x)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 
put(short[] x)166     public RenderBuffer put(short[] x) {
167         return put(x, 0, x.length);
168     }
169 
put(short[] x, int offset, int length)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 
putInt(int pos, int x)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 
putInt(int x)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 
put(int[] x)203     public RenderBuffer put(int[] x) {
204         return put(x, 0, x.length);
205     }
206 
put(int[] x, int offset, int length)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 
putFloat(float x)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 
put(float[] x)234     public RenderBuffer put(float[] x) {
235         return put(x, 0, x.length);
236     }
237 
put(float[] x, int offset, int length)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 
putLong(long x)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 
put(long[] x)265     public RenderBuffer put(long[] x) {
266         return put(x, 0, x.length);
267     }
268 
put(long[] x, int offset, int length)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 
putDouble(double x)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 }
296