11/*
2- * Copyright (c) 2005, 2013 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2005, 2024 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
2525
2626package sun .java2d .pipe ;
2727
28- import jdk .internal .misc .Unsafe ;
28+ import java .lang .foreign .Arena ;
29+ import java .lang .foreign .MemorySegment ;
30+ import java .lang .foreign .ValueLayout ;
31+ import static java .lang .foreign .ValueLayout .*;
2932
3033
3134/**
32- * The RenderBuffer class is a simplified, high-performance, Unsafe wrapper
35+ * The RenderBuffer class is a simplified, high-performance class
3336 * used for buffering rendering operations in a single-threaded rendering
34- * environment. It's functionality is similar to the ByteBuffer and related
37+ * environment. Its functionality is similar to the ByteBuffer and related
3538 * NIO classes. However, the methods in this class perform little to no
3639 * alignment or bounds checks for performance reasons. Therefore, it is
3740 * the caller's responsibility to ensure that all put() calls are properly
3841 * aligned and within bounds:
3942 * - int and float values must be aligned on 4-byte boundaries
4043 * - long and double values must be aligned on 8-byte boundaries
44+ * Failure to do so will result in exceptions from the FFM API, or worse.
4145 *
4246 * This class only includes the bare minimum of methods to support
4347 * single-threaded rendering. For example, there is no put(double[]) method
4448 * because we currently have no need for such a method in the STR classes.
4549 */
46- public class RenderBuffer {
50+ public final class RenderBuffer {
4751
4852 /**
4953 * These constants represent the size of various data types (in bytes).
5054 */
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 ;
55+ private static final int SIZEOF_BYTE = Byte . BYTES ;
56+ private static final int SIZEOF_SHORT = Short . BYTES ;
57+ private static final int SIZEOF_INT = Integer . BYTES ;
58+ private static final int SIZEOF_FLOAT = Float . BYTES ;
59+ private static final int SIZEOF_LONG = Long . BYTES ;
60+ private static final int SIZEOF_DOUBLE = Double . BYTES ;
5761
5862 /**
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.)
63+ * Measurements show that using the copy API from a segment backed by a heap
64+ * array gets reliably faster than individual puts around a length of 10.
65+ * However the time is miniscule in the context of what it is used for
66+ * and much more than adequate, so no problem expected if this changes over time.
6667 */
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 ;
68+ private static final int COPY_FROM_ARRAY_THRESHOLD = 10 ;
69+
70+ private final MemorySegment segment ;
71+ private int curOffset ;
72+
73+ private RenderBuffer (int numBytes ) {
74+ segment = Arena .global ().allocate (numBytes , SIZEOF_DOUBLE );
75+ curOffset = 0 ;
8076 }
8177
8278 /**
@@ -90,7 +86,7 @@ public static RenderBuffer allocate(int numBytes) {
9086 * Returns the base address of the underlying memory buffer.
9187 */
9288 public final long getAddress () {
93- return baseAddress ;
89+ return segment . address () ;
9490 }
9591
9692 /**
@@ -99,27 +95,27 @@ public final long getAddress() {
9995 */
10096
10197 public final int capacity () {
102- return capacity ;
98+ return ( int ) segment . byteSize () ;
10399 }
104100
105101 public final int remaining () {
106- return (int )( endAddress - curAddress );
102+ return (capacity () - curOffset );
107103 }
108104
109105 public final int position () {
110- return ( int )( curAddress - baseAddress ) ;
106+ return curOffset ;
111107 }
112108
113- public final void position (long numBytes ) {
114- curAddress = baseAddress + numBytes ;
109+ public final void position (int bytePos ) {
110+ curOffset = bytePos ;
115111 }
116112
117113 public final void clear () {
118- curAddress = baseAddress ;
114+ curOffset = 0 ;
119115 }
120116
121- public final RenderBuffer skip (long numBytes ) {
122- curAddress += numBytes ;
117+ public final RenderBuffer skip (int numBytes ) {
118+ curOffset += numBytes ;
123119 return this ;
124120 }
125121
@@ -128,8 +124,8 @@ public final RenderBuffer skip(long numBytes) {
128124 */
129125
130126 public final RenderBuffer putByte (byte x ) {
131- unsafe . putByte ( curAddress , x );
132- curAddress += SIZEOF_BYTE ;
127+ segment . set ( JAVA_BYTE , curOffset , x );
128+ curOffset += SIZEOF_BYTE ;
133129 return this ;
134130 }
135131
@@ -139,10 +135,8 @@ public RenderBuffer put(byte[] x) {
139135
140136 public RenderBuffer put (byte [] x , int offset , int length ) {
141137 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 );
138+ MemorySegment .copy (x , offset , segment , JAVA_BYTE , curOffset , length );
139+ position (position () + length * SIZEOF_BYTE );
146140 } else {
147141 int end = offset + length ;
148142 for (int i = offset ; i < end ; i ++) {
@@ -158,8 +152,8 @@ public RenderBuffer put(byte[] x, int offset, int length) {
158152
159153 public final RenderBuffer putShort (short x ) {
160154 // assert (position() % SIZEOF_SHORT == 0);
161- unsafe . putShort ( curAddress , x );
162- curAddress += SIZEOF_SHORT ;
155+ segment . set ( JAVA_SHORT , curOffset , x );
156+ curOffset += SIZEOF_SHORT ;
163157 return this ;
164158 }
165159
@@ -170,10 +164,8 @@ public RenderBuffer put(short[] x) {
170164 public RenderBuffer put (short [] x , int offset , int length ) {
171165 // assert (position() % SIZEOF_SHORT == 0);
172166 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 );
167+ MemorySegment .copy (x , offset , segment , JAVA_SHORT , curOffset , length );
168+ position (position () + length * SIZEOF_SHORT );
177169 } else {
178170 int end = offset + length ;
179171 for (int i = offset ; i < end ; i ++) {
@@ -188,15 +180,15 @@ public RenderBuffer put(short[] x, int offset, int length) {
188180 */
189181
190182 public final RenderBuffer putInt (int pos , int x ) {
191- // assert (baseAddress + pos % SIZEOF_INT == 0);
192- unsafe . putInt ( baseAddress + pos , x );
183+ // assert (getAddress() + pos % SIZEOF_INT == 0);
184+ segment . set ( JAVA_INT , pos , x );
193185 return this ;
194186 }
195187
196188 public final RenderBuffer putInt (int x ) {
197189 // assert (position() % SIZEOF_INT == 0);
198- unsafe . putInt ( curAddress , x );
199- curAddress += SIZEOF_INT ;
190+ segment . set ( JAVA_INT , curOffset , x );
191+ curOffset += SIZEOF_INT ;
200192 return this ;
201193 }
202194
@@ -207,10 +199,8 @@ public RenderBuffer put(int[] x) {
207199 public RenderBuffer put (int [] x , int offset , int length ) {
208200 // assert (position() % SIZEOF_INT == 0);
209201 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 );
202+ MemorySegment .copy (x , offset , segment , JAVA_INT , curOffset , length );
203+ position (position () + length * SIZEOF_INT );
214204 } else {
215205 int end = offset + length ;
216206 for (int i = offset ; i < end ; i ++) {
@@ -226,8 +216,8 @@ public RenderBuffer put(int[] x, int offset, int length) {
226216
227217 public final RenderBuffer putFloat (float x ) {
228218 // assert (position() % SIZEOF_FLOAT == 0);
229- unsafe . putFloat ( curAddress , x );
230- curAddress += SIZEOF_FLOAT ;
219+ segment . set ( JAVA_FLOAT , curOffset , x );
220+ curOffset += SIZEOF_FLOAT ;
231221 return this ;
232222 }
233223
@@ -238,10 +228,8 @@ public RenderBuffer put(float[] x) {
238228 public RenderBuffer put (float [] x , int offset , int length ) {
239229 // assert (position() % SIZEOF_FLOAT == 0);
240230 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 );
231+ MemorySegment .copy (x , offset , segment , JAVA_FLOAT , curOffset , length );
232+ position (position () + length * SIZEOF_FLOAT );
245233 } else {
246234 int end = offset + length ;
247235 for (int i = offset ; i < end ; i ++) {
@@ -257,8 +245,8 @@ public RenderBuffer put(float[] x, int offset, int length) {
257245
258246 public final RenderBuffer putLong (long x ) {
259247 // assert (position() % SIZEOF_LONG == 0);
260- unsafe . putLong ( curAddress , x );
261- curAddress += SIZEOF_LONG ;
248+ segment . set ( JAVA_LONG , curOffset , x );
249+ curOffset += SIZEOF_LONG ;
262250 return this ;
263251 }
264252
@@ -269,10 +257,8 @@ public RenderBuffer put(long[] x) {
269257 public RenderBuffer put (long [] x , int offset , int length ) {
270258 // assert (position() % SIZEOF_LONG == 0);
271259 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 );
260+ MemorySegment .copy (x , offset , segment , JAVA_LONG , curOffset , length );
261+ position (position () + length * SIZEOF_LONG );
276262 } else {
277263 int end = offset + length ;
278264 for (int i = offset ; i < end ; i ++) {
@@ -288,8 +274,8 @@ public RenderBuffer put(long[] x, int offset, int length) {
288274
289275 public final RenderBuffer putDouble (double x ) {
290276 // assert (position() % SIZEOF_DOUBLE == 0);
291- unsafe . putDouble ( curAddress , x );
292- curAddress += SIZEOF_DOUBLE ;
277+ segment . set ( JAVA_DOUBLE , curOffset , x );
278+ curOffset += SIZEOF_DOUBLE ;
293279 return this ;
294280 }
295281}
0 commit comments