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 }