| /* |
| * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package sun.java2d.pipe; |
| |
| import jdk.internal.misc.Unsafe; |
| |
| |
| /** |
| * The RenderBuffer class is a simplified, high-performance, Unsafe wrapper |
| * used for buffering rendering operations in a single-threaded rendering |
| * environment. It's functionality is similar to the ByteBuffer and related |
| * NIO classes. However, the methods in this class perform little to no |
| * alignment or bounds checks for performance reasons. Therefore, it is |
| * the caller's responsibility to ensure that all put() calls are properly |
| * aligned and within bounds: |
| * - int and float values must be aligned on 4-byte boundaries |
| * - long and double values must be aligned on 8-byte boundaries |
| * |
| * This class only includes the bare minimum of methods to support |
| * single-threaded rendering. For example, there is no put(double[]) method |
| * because we currently have no need for such a method in the STR classes. |
| */ |
| public class RenderBuffer { |
| |
| /** |
| * These constants represent the size of various data types (in bytes). |
| */ |
| protected static final long SIZEOF_BYTE = 1L; |
| protected static final long SIZEOF_SHORT = 2L; |
| protected static final long SIZEOF_INT = 4L; |
| protected static final long SIZEOF_FLOAT = 4L; |
| protected static final long SIZEOF_LONG = 8L; |
| protected static final long SIZEOF_DOUBLE = 8L; |
| |
| /** |
| * Represents the number of elements at which we have empirically |
| * determined that the average cost of a JNI call exceeds the expense |
| * of an element by element copy. In other words, if the number of |
| * elements in an array to be copied exceeds this value, then we should |
| * use the copyFromArray() method to complete the bulk put operation. |
| * (This value can be adjusted if the cost of JNI downcalls is reduced |
| * in a future release.) |
| */ |
| private static final int COPY_FROM_ARRAY_THRESHOLD = 6; |
| |
| protected final Unsafe unsafe; |
| protected final long baseAddress; |
| protected final long endAddress; |
| protected long curAddress; |
| protected final int capacity; |
| |
| protected RenderBuffer(int numBytes) { |
| unsafe = Unsafe.getUnsafe(); |
| curAddress = baseAddress = unsafe.allocateMemory(numBytes); |
| endAddress = baseAddress + numBytes; |
| capacity = numBytes; |
| } |
| |
| /** |
| * Allocates a fresh buffer using the machine endianness. |
| */ |
| public static RenderBuffer allocate(int numBytes) { |
| return new RenderBuffer(numBytes); |
| } |
| |
| /** |
| * Returns the base address of the underlying memory buffer. |
| */ |
| public final long getAddress() { |
| return baseAddress; |
| } |
| |
| /** |
| * The behavior (and names) of the following methods are nearly |
| * identical to their counterparts in the various NIO Buffer classes. |
| */ |
| |
| public final int capacity() { |
| return capacity; |
| } |
| |
| public final int remaining() { |
| return (int)(endAddress - curAddress); |
| } |
| |
| public final int position() { |
| return (int)(curAddress - baseAddress); |
| } |
| |
| public final void position(long numBytes) { |
| curAddress = baseAddress + numBytes; |
| } |
| |
| public final void clear() { |
| curAddress = baseAddress; |
| } |
| |
| public final RenderBuffer skip(long numBytes) { |
| curAddress += numBytes; |
| return this; |
| } |
| |
| /** |
| * putByte() methods... |
| */ |
| |
| public final RenderBuffer putByte(byte x) { |
| unsafe.putByte(curAddress, x); |
| curAddress += SIZEOF_BYTE; |
| return this; |
| } |
| |
| public RenderBuffer put(byte[] x) { |
| return put(x, 0, x.length); |
| } |
| |
| public RenderBuffer put(byte[] x, int offset, int length) { |
| if (length > COPY_FROM_ARRAY_THRESHOLD) { |
| long offsetInBytes = offset * SIZEOF_BYTE + Unsafe.ARRAY_BYTE_BASE_OFFSET; |
| long lengthInBytes = length * SIZEOF_BYTE; |
| unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); |
| position(position() + lengthInBytes); |
| } else { |
| int end = offset + length; |
| for (int i = offset; i < end; i++) { |
| putByte(x[i]); |
| } |
| } |
| return this; |
| } |
| |
| /** |
| * putShort() methods... |
| */ |
| |
| public final RenderBuffer putShort(short x) { |
| // assert (position() % SIZEOF_SHORT == 0); |
| unsafe.putShort(curAddress, x); |
| curAddress += SIZEOF_SHORT; |
| return this; |
| } |
| |
| public RenderBuffer put(short[] x) { |
| return put(x, 0, x.length); |
| } |
| |
| public RenderBuffer put(short[] x, int offset, int length) { |
| // assert (position() % SIZEOF_SHORT == 0); |
| if (length > COPY_FROM_ARRAY_THRESHOLD) { |
| long offsetInBytes = offset * SIZEOF_SHORT + Unsafe.ARRAY_SHORT_BASE_OFFSET; |
| long lengthInBytes = length * SIZEOF_SHORT; |
| unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); |
| position(position() + lengthInBytes); |
| } else { |
| int end = offset + length; |
| for (int i = offset; i < end; i++) { |
| putShort(x[i]); |
| } |
| } |
| return this; |
| } |
| |
| /** |
| * putInt() methods... |
| */ |
| |
| public final RenderBuffer putInt(int pos, int x) { |
| // assert (baseAddress + pos % SIZEOF_INT == 0); |
| unsafe.putInt(baseAddress + pos, x); |
| return this; |
| } |
| |
| public final RenderBuffer putInt(int x) { |
| // assert (position() % SIZEOF_INT == 0); |
| unsafe.putInt(curAddress, x); |
| curAddress += SIZEOF_INT; |
| return this; |
| } |
| |
| public RenderBuffer put(int[] x) { |
| return put(x, 0, x.length); |
| } |
| |
| public RenderBuffer put(int[] x, int offset, int length) { |
| // assert (position() % SIZEOF_INT == 0); |
| if (length > COPY_FROM_ARRAY_THRESHOLD) { |
| long offsetInBytes = offset * SIZEOF_INT + Unsafe.ARRAY_INT_BASE_OFFSET; |
| long lengthInBytes = length * SIZEOF_INT; |
| unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); |
| position(position() + lengthInBytes); |
| } else { |
| int end = offset + length; |
| for (int i = offset; i < end; i++) { |
| putInt(x[i]); |
| } |
| } |
| return this; |
| } |
| |
| /** |
| * putFloat() methods... |
| */ |
| |
| public final RenderBuffer putFloat(float x) { |
| // assert (position() % SIZEOF_FLOAT == 0); |
| unsafe.putFloat(curAddress, x); |
| curAddress += SIZEOF_FLOAT; |
| return this; |
| } |
| |
| public RenderBuffer put(float[] x) { |
| return put(x, 0, x.length); |
| } |
| |
| public RenderBuffer put(float[] x, int offset, int length) { |
| // assert (position() % SIZEOF_FLOAT == 0); |
| if (length > COPY_FROM_ARRAY_THRESHOLD) { |
| long offsetInBytes = offset * SIZEOF_FLOAT + Unsafe.ARRAY_FLOAT_BASE_OFFSET; |
| long lengthInBytes = length * SIZEOF_FLOAT; |
| unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); |
| position(position() + lengthInBytes); |
| } else { |
| int end = offset + length; |
| for (int i = offset; i < end; i++) { |
| putFloat(x[i]); |
| } |
| } |
| return this; |
| } |
| |
| /** |
| * putLong() methods... |
| */ |
| |
| public final RenderBuffer putLong(long x) { |
| // assert (position() % SIZEOF_LONG == 0); |
| unsafe.putLong(curAddress, x); |
| curAddress += SIZEOF_LONG; |
| return this; |
| } |
| |
| public RenderBuffer put(long[] x) { |
| return put(x, 0, x.length); |
| } |
| |
| public RenderBuffer put(long[] x, int offset, int length) { |
| // assert (position() % SIZEOF_LONG == 0); |
| if (length > COPY_FROM_ARRAY_THRESHOLD) { |
| long offsetInBytes = offset * SIZEOF_LONG + Unsafe.ARRAY_LONG_BASE_OFFSET; |
| long lengthInBytes = length * SIZEOF_LONG; |
| unsafe.copyMemory(x, offsetInBytes, null, curAddress, lengthInBytes); |
| position(position() + lengthInBytes); |
| } else { |
| int end = offset + length; |
| for (int i = offset; i < end; i++) { |
| putLong(x[i]); |
| } |
| } |
| return this; |
| } |
| |
| /** |
| * putDouble() method(s)... |
| */ |
| |
| public final RenderBuffer putDouble(double x) { |
| // assert (position() % SIZEOF_DOUBLE == 0); |
| unsafe.putDouble(curAddress, x); |
| curAddress += SIZEOF_DOUBLE; |
| return this; |
| } |
| } |