2025-11-24 22:52:51 +03:00

187 lines
6.2 KiB
Java

/*
* Decompiled with CFR 0.152.
*
* Could not load the following classes:
* com.mojang.jtracy.MemoryPool
* com.mojang.jtracy.TracyClient
* com.mojang.logging.LogUtils
* org.jspecify.annotations.Nullable
* org.lwjgl.system.MemoryUtil
* org.lwjgl.system.MemoryUtil$MemoryAllocator
* org.slf4j.Logger
*/
package com.mojang.blaze3d.vertex;
import com.mojang.jtracy.MemoryPool;
import com.mojang.jtracy.TracyClient;
import com.mojang.logging.LogUtils;
import java.nio.ByteBuffer;
import net.minecraft.util.Mth;
import org.jspecify.annotations.Nullable;
import org.lwjgl.system.MemoryUtil;
import org.slf4j.Logger;
public class ByteBufferBuilder
implements AutoCloseable {
private static final MemoryPool MEMORY_POOL = TracyClient.createMemoryPool((String)"ByteBufferBuilder");
private static final Logger LOGGER = LogUtils.getLogger();
private static final MemoryUtil.MemoryAllocator ALLOCATOR = MemoryUtil.getAllocator((boolean)false);
private static final long DEFAULT_MAX_CAPACITY = 0xFFFFFFFFL;
private static final int MAX_GROWTH_SIZE = 0x200000;
private static final int BUFFER_FREED_GENERATION = -1;
private long pointer;
private long capacity;
private final long maxCapacity;
private long writeOffset;
private long nextResultOffset;
private int resultCount;
private int generation;
public ByteBufferBuilder(int initialCapacity, long maxCapacity) {
this.capacity = initialCapacity;
this.maxCapacity = maxCapacity;
this.pointer = ALLOCATOR.malloc((long)initialCapacity);
MEMORY_POOL.malloc(this.pointer, initialCapacity);
if (this.pointer == 0L) {
throw new OutOfMemoryError("Failed to allocate " + initialCapacity + " bytes");
}
}
public ByteBufferBuilder(int initialCapacity) {
this(initialCapacity, 0xFFFFFFFFL);
}
public static ByteBufferBuilder exactlySized(int capacity) {
return new ByteBufferBuilder(capacity, capacity);
}
public long reserve(int size) {
long offset = this.writeOffset;
long nextOffset = Math.addExact(offset, (long)size);
this.ensureCapacity(nextOffset);
this.writeOffset = nextOffset;
return Math.addExact(this.pointer, offset);
}
private void ensureCapacity(long requiredCapacity) {
if (requiredCapacity > this.capacity) {
if (requiredCapacity > this.maxCapacity) {
throw new IllegalArgumentException("Maximum capacity of ByteBufferBuilder (" + this.maxCapacity + ") exceeded, required " + requiredCapacity);
}
long preferredGrowth = Math.min(this.capacity, 0x200000L);
long newCapacity = Mth.clamp(this.capacity + preferredGrowth, requiredCapacity, this.maxCapacity);
this.resize(newCapacity);
}
}
private void resize(long newCapacity) {
MEMORY_POOL.free(this.pointer);
this.pointer = ALLOCATOR.realloc(this.pointer, newCapacity);
MEMORY_POOL.malloc(this.pointer, (int)Math.min(newCapacity, Integer.MAX_VALUE));
LOGGER.debug("Needed to grow BufferBuilder buffer: Old size {} bytes, new size {} bytes.", (Object)this.capacity, (Object)newCapacity);
if (this.pointer == 0L) {
throw new OutOfMemoryError("Failed to resize buffer from " + this.capacity + " bytes to " + newCapacity + " bytes");
}
this.capacity = newCapacity;
}
public @Nullable Result build() {
this.checkOpen();
long offset = this.nextResultOffset;
long size = this.writeOffset - offset;
if (size == 0L) {
return null;
}
if (size > Integer.MAX_VALUE) {
throw new IllegalStateException("Cannot build buffer larger than 2147483647 bytes (was " + size + ")");
}
this.nextResultOffset = this.writeOffset;
++this.resultCount;
return new Result(offset, (int)size, this.generation);
}
public void clear() {
if (this.resultCount > 0) {
LOGGER.warn("Clearing BufferBuilder with unused batches");
}
this.discard();
}
public void discard() {
this.checkOpen();
if (this.resultCount > 0) {
this.discardResults();
this.resultCount = 0;
}
}
private boolean isValid(int generation) {
return generation == this.generation;
}
private void freeResult() {
if (--this.resultCount <= 0) {
this.discardResults();
}
}
private void discardResults() {
long currentSize = this.writeOffset - this.nextResultOffset;
if (currentSize > 0L) {
MemoryUtil.memCopy((long)(this.pointer + this.nextResultOffset), (long)this.pointer, (long)currentSize);
}
this.writeOffset = currentSize;
this.nextResultOffset = 0L;
++this.generation;
}
@Override
public void close() {
if (this.pointer != 0L) {
MEMORY_POOL.free(this.pointer);
ALLOCATOR.free(this.pointer);
this.pointer = 0L;
this.generation = -1;
}
}
private void checkOpen() {
if (this.pointer == 0L) {
throw new IllegalStateException("Buffer has been freed");
}
}
public class Result
implements AutoCloseable {
private final long offset;
private final int capacity;
private final int generation;
private boolean closed;
private Result(long offset, int capacity, int generation) {
this.offset = offset;
this.capacity = capacity;
this.generation = generation;
}
public ByteBuffer byteBuffer() {
if (!ByteBufferBuilder.this.isValid(this.generation)) {
throw new IllegalStateException("Buffer is no longer valid");
}
return MemoryUtil.memByteBuffer((long)(ByteBufferBuilder.this.pointer + this.offset), (int)this.capacity);
}
@Override
public void close() {
if (this.closed) {
return;
}
this.closed = true;
if (ByteBufferBuilder.this.isValid(this.generation)) {
ByteBufferBuilder.this.freeResult();
}
}
}
}