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