package com.mojang.blaze3d.opengl; import java.nio.ByteBuffer; import java.util.Set; import java.util.function.Supplier; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import org.jetbrains.annotations.Nullable; import org.lwjgl.opengl.GLCapabilities; import org.lwjgl.system.MemoryUtil; @Environment(EnvType.CLIENT) public abstract class BufferStorage { public static BufferStorage create(GLCapabilities capabilities, Set enabledExtensions) { if (capabilities.GL_ARB_buffer_storage && GlDevice.USE_GL_ARB_buffer_storage) { enabledExtensions.add("GL_ARB_buffer_storage"); return new BufferStorage.Immutable(); } else { return new BufferStorage.Mutable(); } } public abstract GlBuffer createBuffer(DirectStateAccess directStateAccess, @Nullable Supplier label, int usage, int size); public abstract GlBuffer createBuffer(DirectStateAccess directStateAccess, @Nullable Supplier label, int usage, ByteBuffer data); public abstract GlBuffer.GlMappedView mapBuffer(DirectStateAccess directStateAccess, GlBuffer buffer, int offset, int size, int usage); @Environment(EnvType.CLIENT) static class Immutable extends BufferStorage { @Override public GlBuffer createBuffer(DirectStateAccess directStateAccess, @Nullable Supplier label, int usage, int size) { int i = directStateAccess.createBuffer(); directStateAccess.bufferStorage(i, size, GlConst.bufferUsageToGlFlag(usage)); ByteBuffer byteBuffer = this.tryMapBufferPersistent(directStateAccess, usage, i, size); return new GlBuffer(label, directStateAccess, usage, size, i, byteBuffer); } @Override public GlBuffer createBuffer(DirectStateAccess directStateAccess, @Nullable Supplier label, int usage, ByteBuffer data) { int i = directStateAccess.createBuffer(); int j = data.remaining(); directStateAccess.bufferStorage(i, data, GlConst.bufferUsageToGlFlag(usage)); ByteBuffer byteBuffer = this.tryMapBufferPersistent(directStateAccess, usage, i, j); return new GlBuffer(label, directStateAccess, usage, j, i, byteBuffer); } @Nullable private ByteBuffer tryMapBufferPersistent(DirectStateAccess directStateAccess, int usage, int handle, int size) { int i = 0; if ((usage & 1) != 0) { i |= 1; } if ((usage & 2) != 0) { i |= 18; } ByteBuffer byteBuffer; if (i != 0) { GlStateManager.clearGlErrors(); byteBuffer = directStateAccess.mapBufferRange(handle, 0, size, i | 64); if (byteBuffer == null) { throw new IllegalStateException("Can't persistently map buffer, opengl error " + GlStateManager._getError()); } } else { byteBuffer = null; } return byteBuffer; } @Override public GlBuffer.GlMappedView mapBuffer(DirectStateAccess directStateAccess, GlBuffer buffer, int offset, int size, int usage) { if (buffer.persistentBuffer == null) { throw new IllegalStateException("Somehow trying to map an unmappable buffer"); } else { return new GlBuffer.GlMappedView(() -> { if ((usage & 2) != 0) { directStateAccess.flushMappedBufferRange(buffer.handle, offset, size); } }, buffer, MemoryUtil.memSlice(buffer.persistentBuffer, offset, size)); } } } @Environment(EnvType.CLIENT) static class Mutable extends BufferStorage { @Override public GlBuffer createBuffer(DirectStateAccess directStateAccess, @Nullable Supplier label, int usage, int size) { int i = directStateAccess.createBuffer(); directStateAccess.bufferData(i, size, GlConst.bufferUsageToGlEnum(usage)); return new GlBuffer(label, directStateAccess, usage, size, i, null); } @Override public GlBuffer createBuffer(DirectStateAccess directStateAccess, @Nullable Supplier label, int usage, ByteBuffer data) { int i = directStateAccess.createBuffer(); int j = data.remaining(); directStateAccess.bufferData(i, data, GlConst.bufferUsageToGlEnum(usage)); return new GlBuffer(label, directStateAccess, usage, j, i, null); } @Override public GlBuffer.GlMappedView mapBuffer(DirectStateAccess directStateAccess, GlBuffer buffer, int offset, int size, int usage) { GlStateManager.clearGlErrors(); ByteBuffer byteBuffer = directStateAccess.mapBufferRange(buffer.handle, offset, size, usage); if (byteBuffer == null) { throw new IllegalStateException("Can't map buffer, opengl error " + GlStateManager._getError()); } else { return new GlBuffer.GlMappedView(() -> directStateAccess.unmapBuffer(buffer.handle), buffer, byteBuffer); } } } }