minecraft-src/com/mojang/blaze3d/buffers/GpuBuffer.java
2025-07-04 02:00:41 +03:00

136 lines
3.9 KiB
Java

package com.mojang.blaze3d.buffers;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.jtracy.MemoryPool;
import com.mojang.jtracy.TracyClient;
import java.nio.ByteBuffer;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import org.jetbrains.annotations.Nullable;
@Environment(EnvType.CLIENT)
public class GpuBuffer implements AutoCloseable {
private static final MemoryPool MEMORY_POOl = TracyClient.createMemoryPool("GPU Buffers");
private final BufferType type;
private final BufferUsage usage;
private boolean closed;
private boolean initialized = false;
public final int handle;
public int size;
public GpuBuffer(BufferType bufferType, BufferUsage bufferUsage, int i) {
this.type = bufferType;
this.size = i;
this.usage = bufferUsage;
this.handle = GlStateManager._glGenBuffers();
}
public GpuBuffer(BufferType bufferType, BufferUsage bufferUsage, ByteBuffer byteBuffer) {
this(bufferType, bufferUsage, byteBuffer.remaining());
this.write(byteBuffer, 0);
}
public void resize(int i) {
if (this.closed) {
throw new IllegalStateException("Buffer already closed");
} else {
if (this.initialized) {
MEMORY_POOl.free(this.handle);
}
this.size = i;
if (this.usage.writable) {
this.initialized = false;
} else {
this.bind();
GlStateManager._glBufferData(this.type.id, i, this.usage.id);
MEMORY_POOl.malloc(this.handle, i);
this.initialized = true;
}
}
}
public void write(ByteBuffer byteBuffer, int i) {
if (this.closed) {
throw new IllegalStateException("Buffer already closed");
} else if (!this.usage.writable) {
throw new IllegalStateException("Buffer is not writable");
} else {
int j = byteBuffer.remaining();
if (j + i > this.size) {
throw new IllegalArgumentException(
"Cannot write more data than this buffer can hold (attempting to write " + j + " bytes at offset " + i + " to " + this.size + " size buffer)"
);
} else {
this.bind();
if (this.initialized) {
GlStateManager._glBufferSubData(this.type.id, i, byteBuffer);
} else if (i == 0 && j == this.size) {
GlStateManager._glBufferData(this.type.id, byteBuffer, this.usage.id);
MEMORY_POOl.malloc(this.handle, this.size);
this.initialized = true;
} else {
GlStateManager._glBufferData(this.type.id, this.size, this.usage.id);
GlStateManager._glBufferSubData(this.type.id, i, byteBuffer);
MEMORY_POOl.malloc(this.handle, this.size);
this.initialized = true;
}
}
}
}
@Nullable
public GpuBuffer.ReadView read() {
return this.read(0, this.size);
}
@Nullable
public GpuBuffer.ReadView read(int i, int j) {
if (this.closed) {
throw new IllegalStateException("Buffer already closed");
} else if (!this.usage.readable) {
throw new IllegalStateException("Buffer is not readable");
} else if (i + j > this.size) {
throw new IllegalArgumentException(
"Cannot read more data than this buffer can hold (attempting to read " + j + " bytes at offset " + i + " from " + this.size + " size buffer)"
);
} else {
this.bind();
ByteBuffer byteBuffer = GlStateManager._glMapBufferRange(this.type.id, i, j, 1);
return byteBuffer == null ? null : new GpuBuffer.ReadView(this.type.id, byteBuffer);
}
}
public void close() {
if (!this.closed) {
this.closed = true;
GlStateManager._glDeleteBuffers(this.handle);
if (this.initialized) {
MEMORY_POOl.free(this.handle);
}
}
}
public void bind() {
GlStateManager._glBindBuffer(this.type.id, this.handle);
}
@Environment(EnvType.CLIENT)
public static class ReadView implements AutoCloseable {
private final int target;
private final ByteBuffer data;
protected ReadView(int i, ByteBuffer byteBuffer) {
this.target = i;
this.data = byteBuffer;
}
public ByteBuffer data() {
return this.data;
}
public void close() {
GlStateManager._glUnmapBuffer(this.target);
}
}
}