View Javadoc
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 }