VulkanShader_1.21.10-0.0.4-alpha.jar
Download file
package net.vulkanmod.render.chunk.buffer;
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
import java.nio.ByteBuffer;
import net.vulkanmod.Initializer;
import net.vulkanmod.render.chunk.util.Util;
import net.vulkanmod.vulkan.memory.MemoryManager;
import net.vulkanmod.vulkan.memory.MemoryType;
import net.vulkanmod.vulkan.memory.MemoryTypes;
import net.vulkanmod.vulkan.memory.buffer.Buffer;
import net.vulkanmod.vulkan.memory.buffer.IndexBuffer;
import net.vulkanmod.vulkan.memory.buffer.VertexBuffer;
import org.apache.logging.log4j.Logger;
public class AreaBuffer {
private static final boolean DEBUG = false;
private static final Logger LOGGER;
private static final MemoryType MEMORY_TYPE;
private final int usage;
private final int elementSize;
private final Int2ReferenceOpenHashMap<Segment> usedSegments = new Int2ReferenceOpenHashMap();
Segment first;
Segment last;
private Buffer buffer;
int size;
int used = 0;
int segments = 0;
public AreaBuffer(Usage usage, int elementCount, int elementSize) {
this.usage = usage.usage;
this.elementSize = elementSize;
this.size = elementCount * elementSize;
this.buffer = this.allocateBuffer();
Segment s = new Segment(0, this.size);
++this.segments;
this.last = this.first = s;
}
private Buffer allocateBuffer() {
Buffer buffer;
if (this.usage == AreaBuffer.Usage.VERTEX.usage) {
buffer = new VertexBuffer(this.size, MEMORY_TYPE);
} else {
buffer = new IndexBuffer(this.size, MEMORY_TYPE);
}
return buffer;
}
public Segment allocateSegment(int size) {
Segment segment = this.findSegment(size);
if (segment.size - size > 0) {
Segment s1 = new Segment(segment.offset + size, segment.size - size);
++this.segments;
if (segment.next != null) {
s1.bindNext(segment.next);
} else {
this.last = s1;
}
segment.bindNext(s1);
segment.size = size;
}
segment.free = false;
this.usedSegments.put(segment.offset, segment);
segment.paramsPtr = 0L;
this.used += size;
return segment;
}
public void freeSegment(int offset) {
if (offset != -1) {
MemoryManager.getInstance().addToFreeSegment(this, offset);
}
}
public void upload(Segment segment, ByteBuffer byteBuffer, int offset) {
int size = byteBuffer.remaining();
if (size + offset > segment.size) {
throw new RuntimeException("trying to upload %d at offset %d, but segment size is %d".formatted(size, offset, segment.size));
} else {
Buffer dst = this.buffer;
UploadManager.INSTANCE.recordUpload(dst, (long)(segment.offset + offset), (long)size, byteBuffer);
}
}
public Segment upload(ByteBuffer byteBuffer, int oldOffset, long paramsPtr) {
this.freeSegment(oldOffset);
int size = byteBuffer.remaining();
Segment segment = this.findSegment(size);
if (segment.size - size > 0) {
Segment s1 = new Segment(segment.offset + size, segment.size - size);
++this.segments;
if (segment.next != null) {
s1.bindNext(segment.next);
} else {
this.last = s1;
}
segment.bindNext(s1);
segment.size = size;
}
segment.free = false;
this.usedSegments.put(segment.offset, segment);
segment.paramsPtr = paramsPtr;
Buffer dst = this.buffer;
UploadManager.INSTANCE.recordUpload(dst, (long)segment.offset, (long)size, byteBuffer);
this.used += size;
return segment;
}
public Segment findSegment(int size) {
Segment segment = null;
for(Segment segment1 = this.first; segment1 != null; segment1 = segment1.next) {
if (segment1.isFree() && segment1.size >= size && (segment == null || segment1.size < segment.size)) {
segment = segment1;
}
}
if (segment != null && segment.size >= size) {
return segment;
} else {
return this.reallocate(size);
}
}
public Segment reallocate(int uploadSize) {
int oldSize = this.size;
int minIncrement = this.size >> 3;
minIncrement = (int)Util.align((long)minIncrement, this.elementSize);
int increment = Math.max(minIncrement, uploadSize);
if (increment < uploadSize) {
throw new RuntimeException(String.format("Size increment %d < %d (Upload size)", increment, uploadSize));
} else {
int newSize = oldSize + increment;
this.size = newSize;
Buffer dst = this.allocateBuffer();
UploadManager.INSTANCE.copyBuffer(this.buffer, dst);
this.buffer.scheduleFree();
this.buffer = dst;
if (this.last.isFree()) {
Segment var10000 = this.last;
var10000.size += increment;
} else {
int offset = this.last.offset + this.last.size;
Segment segment = new Segment(offset, newSize - offset);
++this.segments;
this.last.bindNext(segment);
this.last = segment;
}
return this.last;
}
}
void moveUsedSegments(Buffer dst) {
int usedCount = 0;
int dstOffset = 0;
int currOffset = dstOffset;
Segment segment = this.first;
Segment prevUsed = null;
int srcOffset = -1;
int uploadSize;
for(uploadSize = 0; segment != null; segment = segment.next) {
if (!segment.isFree()) {
++usedCount;
if (segment.offset != srcOffset + uploadSize) {
if (srcOffset == -1) {
dstOffset = 0;
this.first = segment;
segment.prev = null;
} else {
UploadManager.INSTANCE.copyBuffer(this.buffer, (long)srcOffset, dst, (long)dstOffset, (long)uploadSize);
dstOffset += uploadSize;
}
srcOffset = segment.offset;
uploadSize = segment.size;
} else {
uploadSize += segment.size;
}
this.usedSegments.remove(segment.offset);
segment.offset = currOffset;
currOffset += segment.size;
this.updateDrawParams(segment);
this.usedSegments.put(segment.offset, segment);
if (prevUsed != null) {
prevUsed.bindNext(segment);
}
prevUsed = segment;
}
}
if (uploadSize > 0) {
UploadManager.INSTANCE.copyBuffer(this.buffer, (long)srcOffset, dst, (long)dstOffset, (long)uploadSize);
}
if (prevUsed != null) {
prevUsed.next = null;
this.last = prevUsed;
this.segments = usedCount;
}
}
public void setSegmentFree(int offset) {
Segment segment = (Segment)this.usedSegments.remove(offset * this.elementSize);
if (segment != null) {
this.used -= segment.size;
segment.free = true;
segment.paramsPtr = -1L;
Segment next = segment.next;
if (next != null && next.isFree()) {
this.mergeSegments(segment, next);
}
Segment prev = segment.prev;
if (prev != null && prev.isFree()) {
this.mergeSegments(prev, segment);
}
}
}
private void mergeSegments(Segment segment, Segment next) {
segment.size += next.size;
if (next.next != null) {
next.next.prev = segment;
} else {
this.last = segment;
}
segment.next = next.next;
--this.segments;
}
private void updateDrawParams(Segment segment) {
int elementOffset = segment.offset / this.elementSize;
if (this.usage == AreaBuffer.Usage.VERTEX.usage) {
DrawParametersBuffer.setVertexOffset(segment.paramsPtr, elementOffset);
} else {
DrawParametersBuffer.setFirstIndex(segment.paramsPtr, elementOffset);
}
}
public long getId() {
return this.buffer.getId();
}
public void freeBuffer() {
this.buffer.scheduleFree();
}
public int fragmentation() {
return this.size - this.used - (this.last.isFree() ? this.last.size : 0);
}
public void checkSegments() {
Segment segment = this.first;
Segment prev = null;
int i = 0;
int usedSegments = 0;
if (segment.offset != 0) {
LOGGER.error(String.format("expected first offset 0 but got %d", segment.offset));
}
while(segment != null) {
if (i >= this.segments) {
LOGGER.error("Count is greater than segments");
break;
}
if (segment.prev != prev) {
LOGGER.error(String.format("expected previous segment not matching (segment %d)", i));
}
if (!segment.isFree()) {
++usedSegments;
}
if (segment.offset % this.elementSize != 0) {
LOGGER.error(String.format("offset %d misaligned (segment %d)", segment.offset, i));
}
Segment next = segment.next;
if (next != null) {
int offset = segment.offset + segment.size;
if (offset != next.offset) {
LOGGER.error(String.format("expected offset %d but got %d (segment %d)", offset, next.offset, i));
}
if (next.prev != segment) {
LOGGER.error(String.format("segment pointer not correct (segment %d)", i));
}
} else if (segment != this.last) {
LOGGER.error(String.format("segment has no next pointer and it's not last (segment %d)", i));
} else {
int segmentEnd = segment.offset + segment.size;
if (segment.offset + segment.size != this.size) {
LOGGER.error(String.format("last segment end (%d) does not match buffer size (%d)", segmentEnd, this.size));
}
if (segment.offset != this.used) {
LOGGER.error(String.format("last segment offset (%d) does not match buffer used size (%d)", segmentEnd, this.size));
}
}
prev = segment;
segment = next;
++i;
}
if (i != this.segments) {
LOGGER.error("Count do not match segments");
}
if (usedSegments != this.usedSegments.size()) {
LOGGER.error("Counted used segment do not match used segments map size");
}
}
public int getSize() {
return this.size;
}
public int getUsed() {
return this.used;
}
static {
LOGGER = Initializer.LOGGER;
MEMORY_TYPE = MemoryTypes.GPU_MEM;
}
public static class Segment {
int offset;
int size;
boolean free = true;
long paramsPtr;
Segment next;
Segment prev;
private Segment(int offset, int size) {
this.offset = offset;
this.size = size;
}
public int getOffset() {
return this.offset;
}
public int getSize() {
return this.size;
}
public boolean isFree() {
return this.free;
}
public void setFree(boolean free) {
this.free = free;
}
public void bindNext(Segment s) {
this.next = s;
s.prev = this;
}
}
public static enum Usage {
VERTEX(0),
INDEX(1);
final int usage;
private Usage(int i) {
this.usage = i;
}
// $FF: synthetic method
private static Usage[] $values() {
return new Usage[]{VERTEX, INDEX};
}
}
}
Download file