mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-11-15 01:34:48 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4910cfd6d3 | ||
|
|
d1c6677caf | ||
|
|
8cf0296284 | ||
|
|
4fd98e5026 | ||
|
|
8e293f13fb | ||
|
|
2db20ad866 | ||
|
|
10a5b550f2 | ||
|
|
c1403dcf13 |
No files matched your search
@@ -12,6 +12,7 @@ build/
|
||||
/config/
|
||||
/crash-reports/
|
||||
/logs/
|
||||
tmp/
|
||||
options.txt
|
||||
/saves/
|
||||
usernamecache.json
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ dependencies {
|
||||
compileOnly(rfg.deobf("curse.maven:campfirebackport-387444:4611675"))
|
||||
compileOnly(rfg.deobf("curse.maven:xaeros-minimap-263420:5060684"))
|
||||
compileOnly(rfg.deobf("curse.maven:security-craft-64760:2818228"))
|
||||
compileOnly(rfg.deobf("curse.maven:et-futurum-requiem-441392:5873837"))
|
||||
compileOnly("ganymedes01.etfuturum:Et-Futurum-Requiem:2.6.49-GTNH:dev")
|
||||
compileOnly(rfg.deobf("curse.maven:biomes-o-plenty-220318:2499612"))
|
||||
|
||||
devOnlyNonPublishable("com.github.GTNewHorizons:CosmeticArmorReworked:1.0.3-GTNH:dev")
|
||||
|
||||
@@ -877,9 +877,14 @@ public class DisplayListManager {
|
||||
// Empty display list - per OpenGL spec, still valid after glNewList/glEndList
|
||||
compiled = CompiledDisplayList.EMPTY;
|
||||
}
|
||||
final CompiledDisplayList previous = displayListCache.put(glListId, compiled);
|
||||
if (previous != null && previous != CompiledDisplayList.EMPTY && previous != compiled) {
|
||||
previous.delete();
|
||||
final boolean locked = GLStateManager.acquireDrawLock();
|
||||
try {
|
||||
final CompiledDisplayList previous = displayListCache.put(glListId, compiled);
|
||||
if (previous != null && previous != CompiledDisplayList.EMPTY && previous != compiled) {
|
||||
previous.delete();
|
||||
}
|
||||
} finally {
|
||||
if (locked) GLStateManager.releaseDrawLock();
|
||||
}
|
||||
|
||||
// Log compilation details if enabled (before context restoration changes glListId)
|
||||
@@ -1012,33 +1017,43 @@ public class DisplayListManager {
|
||||
}
|
||||
|
||||
private static void executeDisplayList(int list) {
|
||||
final CompiledDisplayList compiled = displayListCache.get(list);
|
||||
if (compiled != null) {
|
||||
compiled.render(list);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fall back to VBOManager or legacy display list
|
||||
if (list < 0) {
|
||||
// Negative IDs are VBOManager space (entity models, etc.)
|
||||
final VertexBuffer vbo = VBOManager.get(list);
|
||||
if (vbo != null) {
|
||||
vbo.render();
|
||||
final boolean locked = GLStateManager.acquireDrawLock();
|
||||
try {
|
||||
final CompiledDisplayList compiled = displayListCache.get(list);
|
||||
if (compiled != null) {
|
||||
compiled.render(list);
|
||||
return;
|
||||
}
|
||||
// Per OpenGL spec: if list is undefined, glCallList has no effect
|
||||
|
||||
// Fall back to VBOManager or legacy display list
|
||||
if (list < 0) {
|
||||
// Negative IDs are VBOManager space (entity models, etc.)
|
||||
final VertexBuffer vbo = VBOManager.get(list);
|
||||
if (vbo != null) {
|
||||
vbo.render();
|
||||
}
|
||||
// Per OpenGL spec: if list is undefined, glCallList has no effect
|
||||
}
|
||||
// An uncached positive-ID list = no-op (per OpenGL spec)
|
||||
} finally {
|
||||
if (locked) GLStateManager.releaseDrawLock();
|
||||
}
|
||||
// An uncached positive-ID list = no-op (per OpenGL spec)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete display lists and free their VBO resources.
|
||||
*/
|
||||
public static void glDeleteLists(int list, int range) {
|
||||
for (int i = list; i < list + range; i++) {
|
||||
CompiledDisplayList compiled = displayListCache.remove(i);
|
||||
if (compiled != null) {
|
||||
compiled.delete();
|
||||
final boolean locked = GLStateManager.acquireDrawLock();
|
||||
try {
|
||||
for (int i = list; i < list + range; i++) {
|
||||
CompiledDisplayList compiled = displayListCache.remove(i);
|
||||
if (compiled != null) {
|
||||
compiled.delete();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (locked) GLStateManager.releaseDrawLock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
@@ -96,6 +97,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.IntSupplier;
|
||||
|
||||
import static com.gtnewhorizons.angelica.glsm.Vendor.AMD;
|
||||
@@ -251,6 +253,18 @@ public class GLStateManager {
|
||||
// Reference to DrawableGL (main display context) - works with both FML and BLS splash
|
||||
@Setter private static Drawable drawableGL = null;
|
||||
|
||||
private static final ReentrantLock DRAW_LOCK = new ReentrantLock();
|
||||
|
||||
public static boolean acquireDrawLock() {
|
||||
if (splashComplete) return false;
|
||||
DRAW_LOCK.lock();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void releaseDrawLock() {
|
||||
DRAW_LOCK.unlock();
|
||||
}
|
||||
|
||||
public static boolean isCachingEnabled() {
|
||||
if (splashComplete) return true;
|
||||
return Thread.currentThread() == drawableGLHolder;
|
||||
@@ -2243,15 +2257,25 @@ public class GLStateManager {
|
||||
}
|
||||
|
||||
public static void preDraw(int drawMode) {
|
||||
prepareWideLineEmulation(drawMode);
|
||||
ShaderManager.getInstance().preDraw();
|
||||
prepareClientArrays();
|
||||
final boolean locked = acquireDrawLock();
|
||||
try {
|
||||
prepareWideLineEmulation(drawMode);
|
||||
ShaderManager.getInstance().preDraw();
|
||||
prepareClientArrays();
|
||||
} finally {
|
||||
if (locked) releaseDrawLock();
|
||||
}
|
||||
}
|
||||
|
||||
public static void preDraw() {
|
||||
disableWideLineEmulation();
|
||||
ShaderManager.getInstance().preDraw();
|
||||
prepareClientArrays();
|
||||
final boolean locked = acquireDrawLock();
|
||||
try {
|
||||
disableWideLineEmulation();
|
||||
ShaderManager.getInstance().preDraw();
|
||||
prepareClientArrays();
|
||||
} finally {
|
||||
if (locked) releaseDrawLock();
|
||||
}
|
||||
}
|
||||
|
||||
public static void glDrawElements(int mode, ByteBuffer indices) {
|
||||
@@ -3245,6 +3269,7 @@ public class GLStateManager {
|
||||
splashComplete = true;
|
||||
drawableGLHolder = null;
|
||||
drawableGL = null;
|
||||
ImmediateModeRecorder.cleanupOrphanTessellators();
|
||||
}
|
||||
|
||||
public static void glNewList(int list, int mode) {
|
||||
@@ -5174,6 +5199,12 @@ public class GLStateManager {
|
||||
RENDER_BACKEND.deleteBuffers(buffers);
|
||||
}
|
||||
|
||||
public static void glDeleteBuffers(int[] buffers) {
|
||||
for (int buffer : buffers) {
|
||||
glDeleteBuffers(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
private static void invalidateDeletedBuffer(int buffer) {
|
||||
if (buffer == 0) return;
|
||||
if (boundVBO == buffer) boundVBO = 0;
|
||||
@@ -5185,6 +5216,7 @@ public class GLStateManager {
|
||||
for (VAOManager.VAOData data : VAOManager.vaoMap.values()) {
|
||||
if (data.ebo == buffer) data.ebo = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void glBindBuffer(int target, int buffer) {
|
||||
@@ -5237,34 +5269,279 @@ public class GLStateManager {
|
||||
return RENDER_BACKEND.genBuffers();
|
||||
}
|
||||
|
||||
public static void glGenBuffers(IntBuffer buffers) {
|
||||
for (int i = buffers.position(); i < buffers.limit(); i++) buffers.put(i, RENDER_BACKEND.genBuffers());
|
||||
}
|
||||
|
||||
public static void glGenBuffers(int[] buffers) {
|
||||
for (int i = 0; i < buffers.length; i++) buffers[i] = RENDER_BACKEND.genBuffers();
|
||||
}
|
||||
|
||||
public static int glCreateBuffers() {
|
||||
return RENDER_BACKEND.createBuffers();
|
||||
}
|
||||
|
||||
public static void glCreateBuffers(IntBuffer buffers) {
|
||||
for (int i = buffers.position(); i < buffers.limit(); i++) buffers.put(i, RENDER_BACKEND.createBuffers());
|
||||
}
|
||||
|
||||
public static void glCreateBuffers(int[] buffers) {
|
||||
for (int i = 0; i < buffers.length; i++) buffers[i] = RENDER_BACKEND.createBuffers();
|
||||
}
|
||||
|
||||
public static void glBufferData(int target, long size, int usage) { RENDER_BACKEND.bufferData(target, size, usage); }
|
||||
public static void glBufferData(int target, ByteBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, ShortBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, IntBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, FloatBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, DoubleBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, LongBuffer data, int usage) { glBufferData(target, MemoryUtilities.memByteBuffer(data), usage); }
|
||||
public static void glBufferData(int target, int[] data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, float[] data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, java.nio.ByteBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, java.nio.ShortBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, java.nio.IntBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, java.nio.FloatBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferData(int target, java.nio.DoubleBuffer data, int usage) { RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
public static void glBufferSubData(int target, long offset, java.nio.ByteBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, java.nio.ShortBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, java.nio.IntBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, java.nio.FloatBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, java.nio.DoubleBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferData(int target, short[] data, int usage) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glBufferData(target, copy, usage);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glBufferData(int target, long[] data, int usage) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glBufferData(target, copy, usage);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glBufferData(int target, double[] data, int usage) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glBufferData(target, copy, usage);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
|
||||
public static void nglBufferData(int target, long size, long data, int usage) {
|
||||
if (data == 0L) {
|
||||
glBufferData(target, size, usage);
|
||||
return;
|
||||
}
|
||||
glBufferData(target, MemoryUtilities.memByteBuffer(data, checkedSize(size)), usage);
|
||||
}
|
||||
|
||||
public static void glBufferSubData(int target, long offset, ByteBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, ShortBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, IntBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, FloatBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, DoubleBuffer data) { RENDER_BACKEND.bufferSubData(target, offset, data); }
|
||||
public static void glBufferSubData(int target, long offset, LongBuffer data) { glBufferSubData(target, offset, MemoryUtilities.memByteBuffer(data)); }
|
||||
public static void glBufferSubData(int target, long offset, short[] data) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glBufferSubData(target, offset, copy);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glBufferSubData(int target, long offset, int[] data) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glBufferSubData(target, offset, copy);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glBufferSubData(int target, long offset, long[] data) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glBufferSubData(target, offset, copy);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glBufferSubData(int target, long offset, float[] data) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glBufferSubData(target, offset, copy);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glBufferSubData(int target, long offset, double[] data) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glBufferSubData(target, offset, copy);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
|
||||
public static void nglBufferSubData(int target, long offset, long size, long data) { glBufferSubData(target, offset, MemoryUtilities.memByteBuffer(data, checkedSize(size))); }
|
||||
|
||||
public static ByteBuffer glMapBuffer(int target, int access) { return RENDER_BACKEND.mapBuffer(target, access); }
|
||||
public static ByteBuffer glMapBuffer(int target, int access, ByteBuffer old_buffer) { return glMapBuffer(target, access); }
|
||||
public static ByteBuffer glMapBuffer(int target, int access, long length, ByteBuffer old_buffer) { return RENDER_BACKEND.mapBuffer(target, access, length, old_buffer); }
|
||||
public static ByteBuffer glMapBufferRange(int target, long offset, long length, int access) { return RENDER_BACKEND.mapBufferRange(target, offset, length, access); }
|
||||
public static ByteBuffer glMapBufferRange(int target, long offset, long length, int access, ByteBuffer old_buffer) { return glMapBufferRange(target, offset, length, access); }
|
||||
public static void glFlushMappedBufferRange(int target, long offset, long length) { RENDER_BACKEND.flushMappedBufferRange(target, offset, length); }
|
||||
public static boolean glUnmapBuffer(int target) { return RENDER_BACKEND.unmapBuffer(target); }
|
||||
public static void glGetBufferSubData(int target, long offset, java.nio.ByteBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
|
||||
public static void glGetBufferSubData(int target, long offset, java.nio.ShortBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
|
||||
public static void glGetBufferSubData(int target, long offset, java.nio.IntBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
|
||||
public static void glGetBufferSubData(int target, long offset, java.nio.FloatBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
|
||||
public static void glGetBufferSubData(int target, long offset, java.nio.DoubleBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
|
||||
|
||||
public static void glGetBufferSubData(int target, long offset, ByteBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
|
||||
public static void glGetBufferSubData(int target, long offset, ShortBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
|
||||
public static void glGetBufferSubData(int target, long offset, IntBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
|
||||
public static void glGetBufferSubData(int target, long offset, FloatBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
|
||||
public static void glGetBufferSubData(int target, long offset, DoubleBuffer data) { RENDER_BACKEND.getBufferSubData(target, offset, data); }
|
||||
public static void glGetBufferSubData(int target, long offset, LongBuffer data) { glGetBufferSubData(target, offset, MemoryUtilities.memByteBuffer(data)); }
|
||||
public static void glGetBufferSubData(int target, long offset, short[] data) {
|
||||
final ByteBuffer copy = MemoryUtilities.memAlloc(data.length << 1);
|
||||
glGetBufferSubData(target, offset, copy);
|
||||
copy.asShortBuffer().get(data);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glGetBufferSubData(int target, long offset, int[] data) {
|
||||
final ByteBuffer copy = MemoryUtilities.memAlloc(data.length << 2);
|
||||
glGetBufferSubData(target, offset, copy);
|
||||
copy.asIntBuffer().get(data);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glGetBufferSubData(int target, long offset, long[] data) {
|
||||
final ByteBuffer copy = MemoryUtilities.memAlloc(data.length << 3);
|
||||
glGetBufferSubData(target, offset, copy);
|
||||
copy.asLongBuffer().get(data);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glGetBufferSubData(int target, long offset, float[] data) {
|
||||
final ByteBuffer copy = MemoryUtilities.memAlloc(data.length << 2);
|
||||
glGetBufferSubData(target, offset, copy);
|
||||
copy.asFloatBuffer().get(data);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glGetBufferSubData(int target, long offset, double[] data) {
|
||||
final ByteBuffer copy = MemoryUtilities.memAlloc(data.length << 3);
|
||||
glGetBufferSubData(target, offset, copy);
|
||||
copy.asDoubleBuffer().get(data);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
|
||||
public static void nglGetBufferSubData(int target, long offset, long size, long data) { glGetBufferSubData(target, offset, MemoryUtilities.memByteBuffer(data, checkedSize(size))); }
|
||||
|
||||
public static int glGetBufferParameteri(int target, int pname) { return RENDER_BACKEND.getBufferParameteri(target, pname); }
|
||||
public static void glBufferStorage(int target, java.nio.ByteBuffer data, int flags) { RENDER_BACKEND.bufferStorage(target, data, flags); }
|
||||
public static int glGetBufferParameter(int target, int pname) { return glGetBufferParameteri(target, pname); }
|
||||
public static void glGetBufferParameter(int target, int pname, IntBuffer params) { params.put(params.position(), glGetBufferParameteri(target, pname)); }
|
||||
public static void glGetBufferParameteriv(int target, int pname, IntBuffer params) { params.put(params.position(), glGetBufferParameteri(target, pname)); }
|
||||
public static void glGetBufferParameteriv(int target, int pname, int[] params) { params[0] = glGetBufferParameteri(target, pname); }
|
||||
|
||||
public static void glBufferStorage(int target, long size, int flags) { RENDER_BACKEND.bufferStorage(target, size, flags); }
|
||||
public static void glClearBufferSubData(int target, int internalFormat, long offset, long size, int format, int type, java.nio.ByteBuffer data) { RENDER_BACKEND.clearBufferSubData(target, internalFormat, offset, size, format, type, data); }
|
||||
public static void glBufferStorage(int target, ByteBuffer data, int flags) { RENDER_BACKEND.bufferStorage(target, data, flags); }
|
||||
public static void glBufferStorage(int target, ShortBuffer data, int flags) { glBufferStorage(target, MemoryUtilities.memByteBuffer(data), flags); }
|
||||
public static void glBufferStorage(int target, IntBuffer data, int flags) { glBufferStorage(target, MemoryUtilities.memByteBuffer(data), flags); }
|
||||
public static void glBufferStorage(int target, FloatBuffer data, int flags) { glBufferStorage(target, MemoryUtilities.memByteBuffer(data), flags); }
|
||||
public static void glBufferStorage(int target, DoubleBuffer data, int flags) { glBufferStorage(target, MemoryUtilities.memByteBuffer(data), flags); }
|
||||
public static void glBufferStorage(int target, short[] data, int flags) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glBufferStorage(target, copy, flags);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glBufferStorage(int target, int[] data, int flags) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glBufferStorage(target, copy, flags);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glBufferStorage(int target, float[] data, int flags) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glBufferStorage(target, copy, flags);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glBufferStorage(int target, double[] data, int flags) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glBufferStorage(target, copy, flags);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
|
||||
public static void glNamedBufferData(int buffer, long size, int usage) { RENDER_BACKEND.namedBufferData(buffer, size, usage); }
|
||||
public static void glNamedBufferData(int buffer, ByteBuffer data, int usage) { RENDER_BACKEND.namedBufferData(buffer, data, usage); }
|
||||
public static void glNamedBufferData(int buffer, FloatBuffer data, int usage) { RENDER_BACKEND.namedBufferData(buffer, data, usage); }
|
||||
public static void glNamedBufferData(int buffer, ShortBuffer data, int usage) { glNamedBufferData(buffer, MemoryUtilities.memByteBuffer(data), usage); }
|
||||
public static void glNamedBufferData(int buffer, IntBuffer data, int usage) { glNamedBufferData(buffer, MemoryUtilities.memByteBuffer(data), usage); }
|
||||
public static void glNamedBufferData(int buffer, LongBuffer data, int usage) { glNamedBufferData(buffer, MemoryUtilities.memByteBuffer(data), usage); }
|
||||
public static void glNamedBufferData(int buffer, DoubleBuffer data, int usage) { glNamedBufferData(buffer, MemoryUtilities.memByteBuffer(data), usage); }
|
||||
public static void glNamedBufferData(int buffer, short[] data, int usage) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glNamedBufferData(buffer, copy, usage);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glNamedBufferData(int buffer, int[] data, int usage) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glNamedBufferData(buffer, copy, usage);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glNamedBufferData(int buffer, long[] data, int usage) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glNamedBufferData(buffer, copy, usage);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glNamedBufferData(int buffer, float[] data, int usage) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glNamedBufferData(buffer, copy, usage);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glNamedBufferData(int buffer, double[] data, int usage) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glNamedBufferData(buffer, copy, usage);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
|
||||
public static void glNamedBufferSubData(int buffer, long offset, ByteBuffer data) { RENDER_BACKEND.namedBufferSubData(buffer, offset, data); }
|
||||
public static void glNamedBufferSubData(int buffer, long offset, ShortBuffer data) { glNamedBufferSubData(buffer, offset, MemoryUtilities.memByteBuffer(data)); }
|
||||
public static void glNamedBufferSubData(int buffer, long offset, IntBuffer data) { glNamedBufferSubData(buffer, offset, MemoryUtilities.memByteBuffer(data)); }
|
||||
public static void glNamedBufferSubData(int buffer, long offset, LongBuffer data) { glNamedBufferSubData(buffer, offset, MemoryUtilities.memByteBuffer(data)); }
|
||||
public static void glNamedBufferSubData(int buffer, long offset, FloatBuffer data) { glNamedBufferSubData(buffer, offset, MemoryUtilities.memByteBuffer(data)); }
|
||||
public static void glNamedBufferSubData(int buffer, long offset, DoubleBuffer data) { glNamedBufferSubData(buffer, offset, MemoryUtilities.memByteBuffer(data)); }
|
||||
public static void glNamedBufferSubData(int buffer, long offset, short[] data) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glNamedBufferSubData(buffer, offset, copy);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glNamedBufferSubData(int buffer, long offset, int[] data) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glNamedBufferSubData(buffer, offset, copy);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glNamedBufferSubData(int buffer, long offset, long[] data) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glNamedBufferSubData(buffer, offset, copy);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glNamedBufferSubData(int buffer, long offset, float[] data) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glNamedBufferSubData(buffer, offset, copy);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
public static void glNamedBufferSubData(int buffer, long offset, double[] data) {
|
||||
final ByteBuffer copy = copyOf(data);
|
||||
glNamedBufferSubData(buffer, offset, copy);
|
||||
MemoryUtilities.memFree(copy);
|
||||
}
|
||||
|
||||
public static void glClearBufferSubData(int target, int internalFormat, long offset, long size, int format, int type, ByteBuffer data) { RENDER_BACKEND.clearBufferSubData(target, internalFormat, offset, size, format, type, data); }
|
||||
public static boolean glIsBuffer(int buffer) { return RENDER_BACKEND.isBuffer(buffer); }
|
||||
public static void glCopyBufferSubData(int readTarget, int writeTarget, long readOffset, long writeOffset, long size) { RENDER_BACKEND.copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); }
|
||||
|
||||
private static int checkedSize(long size) {
|
||||
if (size < 0 || size > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException("Buffer range does not fit a ByteBuffer wrapper: " + size);
|
||||
}
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
private static ByteBuffer copyOf(short[] data) {
|
||||
final ByteBuffer bb = MemoryUtilities.memAlloc(data.length << 1);
|
||||
bb.asShortBuffer().put(data);
|
||||
return bb;
|
||||
}
|
||||
|
||||
private static ByteBuffer copyOf(int[] data) {
|
||||
final ByteBuffer bb = MemoryUtilities.memAlloc(data.length << 2);
|
||||
bb.asIntBuffer().put(data);
|
||||
return bb;
|
||||
}
|
||||
|
||||
private static ByteBuffer copyOf(long[] data) {
|
||||
final ByteBuffer bb = MemoryUtilities.memAlloc(data.length << 3);
|
||||
bb.asLongBuffer().put(data);
|
||||
return bb;
|
||||
}
|
||||
|
||||
private static ByteBuffer copyOf(float[] data) {
|
||||
final ByteBuffer bb = MemoryUtilities.memAlloc(data.length << 2);
|
||||
bb.asFloatBuffer().put(data);
|
||||
return bb;
|
||||
}
|
||||
|
||||
private static ByteBuffer copyOf(double[] data) {
|
||||
final ByteBuffer bb = MemoryUtilities.memAlloc(data.length << 3);
|
||||
bb.asDoubleBuffer().put(data);
|
||||
return bb;
|
||||
}
|
||||
|
||||
public static void glBindVertexArray(int array) {
|
||||
if (DisplayListManager.isRecording()) {
|
||||
DisplayListManager.recordBindVAO(array);
|
||||
@@ -6165,7 +6442,7 @@ public class GLStateManager {
|
||||
RENDER_BACKEND.getUniformiv(program, location, params);
|
||||
}
|
||||
public static void glGetTexImage(int target, int level, int format, int type, long pixels) {
|
||||
GL11.glGetTexImage(target, level, format, type, pixels);
|
||||
RENDER_BACKEND.getTexImage(target, level, format, type, pixels);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -91,21 +91,26 @@ public final class QuadConverter {
|
||||
}
|
||||
|
||||
private static void drawSharedQuadEbo(int first, int vertexCount, int primcount, boolean instanced) {
|
||||
GLStateManager.preDraw();
|
||||
assert first % 4 == 0 : "QuadConverter: first (" + first + ") must be a multiple of 4";
|
||||
assert vertexCount % 4 == 0 : "QuadConverter: vertexCount (" + vertexCount + ") must be a multiple of 4";
|
||||
final int quadCount = vertexCount / 4;
|
||||
final int prevEbo = GLStateManager.getBoundEBO();
|
||||
ensureCapacity(first / 4 + quadCount);
|
||||
RENDER_BACKEND.bindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, eboId);
|
||||
// Index offset: first vertex / 4 quads * 6 indices * 4 bytes per int
|
||||
final long indexOffset = (long) (first / 4) * 6 * 4;
|
||||
if (instanced) {
|
||||
RENDER_BACKEND.drawElementsInstanced(GL11.GL_TRIANGLES, quadCount * 6, INDEX_TYPE, indexOffset, primcount);
|
||||
} else {
|
||||
RENDER_BACKEND.drawElements(GL11.GL_TRIANGLES, quadCount * 6, INDEX_TYPE, indexOffset);
|
||||
final boolean locked = GLStateManager.acquireDrawLock();
|
||||
try {
|
||||
GLStateManager.preDraw();
|
||||
assert first % 4 == 0 : "QuadConverter: first (" + first + ") must be a multiple of 4";
|
||||
assert vertexCount % 4 == 0 : "QuadConverter: vertexCount (" + vertexCount + ") must be a multiple of 4";
|
||||
final int quadCount = vertexCount / 4;
|
||||
final int prevEbo = GLStateManager.getBoundEBO();
|
||||
ensureCapacity(first / 4 + quadCount);
|
||||
RENDER_BACKEND.bindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, eboId);
|
||||
// Index offset: first vertex / 4 quads * 6 indices * 4 bytes per int
|
||||
final long indexOffset = (long) (first / 4) * 6 * 4;
|
||||
if (instanced) {
|
||||
RENDER_BACKEND.drawElementsInstanced(GL11.GL_TRIANGLES, quadCount * 6, INDEX_TYPE, indexOffset, primcount);
|
||||
} else {
|
||||
RENDER_BACKEND.drawElements(GL11.GL_TRIANGLES, quadCount * 6, INDEX_TYPE, indexOffset);
|
||||
}
|
||||
RENDER_BACKEND.bindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, prevEbo);
|
||||
} finally {
|
||||
if (locked) GLStateManager.releaseDrawLock();
|
||||
}
|
||||
RENDER_BACKEND.bindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, prevEbo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,32 +128,37 @@ public final class QuadConverter {
|
||||
}
|
||||
|
||||
private static void uploadAndDraw(ByteBuffer dst, int triIndexCount, int indexType, int bytesPerIndex, int primcount, boolean instanced) {
|
||||
GLStateManager.preDraw();
|
||||
final int needed = triIndexCount * bytesPerIndex;
|
||||
final int prevEbo = GLStateManager.getBoundEBO();
|
||||
final boolean locked = GLStateManager.acquireDrawLock();
|
||||
try {
|
||||
GLStateManager.preDraw();
|
||||
final int needed = triIndexCount * bytesPerIndex;
|
||||
final int prevEbo = GLStateManager.getBoundEBO();
|
||||
|
||||
if (scratchEboId == 0) {
|
||||
scratchEboId = RENDER_BACKEND.genBuffers();
|
||||
if (scratchEboId == 0) {
|
||||
scratchEboId = RENDER_BACKEND.genBuffers();
|
||||
}
|
||||
|
||||
RENDER_BACKEND.bindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, scratchEboId);
|
||||
|
||||
if (needed > scratchEboCapacity) {
|
||||
// Power-of-2 growth -- allocate full capacity, upload actual data
|
||||
int newCap = Math.max(4096, scratchEboCapacity);
|
||||
while (newCap < needed) newCap *= 2;
|
||||
RENDER_BACKEND.bufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, newCap, GL15.GL_STREAM_DRAW);
|
||||
scratchEboCapacity = newCap;
|
||||
}
|
||||
RENDER_BACKEND.bufferSubData(GL15.GL_ELEMENT_ARRAY_BUFFER, 0, dst);
|
||||
|
||||
if (instanced) {
|
||||
RENDER_BACKEND.drawElementsInstanced(GL11.GL_TRIANGLES, triIndexCount, indexType, 0L, primcount);
|
||||
} else {
|
||||
RENDER_BACKEND.drawElements(GL11.GL_TRIANGLES, triIndexCount, indexType, 0L);
|
||||
}
|
||||
|
||||
RENDER_BACKEND.bindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, prevEbo);
|
||||
} finally {
|
||||
if (locked) GLStateManager.releaseDrawLock();
|
||||
}
|
||||
|
||||
RENDER_BACKEND.bindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, scratchEboId);
|
||||
|
||||
if (needed > scratchEboCapacity) {
|
||||
// Power-of-2 growth — allocate full capacity, upload actual data
|
||||
int newCap = Math.max(4096, scratchEboCapacity);
|
||||
while (newCap < needed) newCap *= 2;
|
||||
RENDER_BACKEND.bufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, newCap, GL15.GL_STREAM_DRAW);
|
||||
scratchEboCapacity = newCap;
|
||||
}
|
||||
RENDER_BACKEND.bufferSubData(GL15.GL_ELEMENT_ARRAY_BUFFER, 0, dst);
|
||||
|
||||
if (instanced) {
|
||||
RENDER_BACKEND.drawElementsInstanced(GL11.GL_TRIANGLES, triIndexCount, indexType, 0L, primcount);
|
||||
} else {
|
||||
RENDER_BACKEND.drawElements(GL11.GL_TRIANGLES, triIndexCount, indexType, 0L);
|
||||
}
|
||||
|
||||
RENDER_BACKEND.bindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, prevEbo);
|
||||
memFree(dst);
|
||||
}
|
||||
|
||||
|
||||
@@ -146,6 +146,9 @@ public class RenderSystem {
|
||||
coreProfile = true;
|
||||
GLStateManager.LOGGER.info("GL 3.3 core profile detected, enabling FFP shader emulation.");
|
||||
ShaderManager.getInstance().enable();
|
||||
} else {
|
||||
throw new IllegalStateException("Non-core GL context (profile mask 0x" + Integer.toHexString(profileMask)
|
||||
+ "); FFP emulation requires a core profile and nothing would render. Context creation should have rejected this.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,7 +304,7 @@ public class RenderSystem {
|
||||
}
|
||||
|
||||
public static void bufferData(int target, FloatBuffer data, int usage) {
|
||||
RENDER_BACKEND.bufferData(target, data, usage);
|
||||
GLStateManager.glBufferData(target, data, usage);
|
||||
}
|
||||
|
||||
public static int bufferStorage(int target, FloatBuffer data, int usage) {
|
||||
@@ -447,7 +450,7 @@ public class RenderSystem {
|
||||
}
|
||||
|
||||
public static int createBuffers() {
|
||||
return RENDER_BACKEND.genBuffers();
|
||||
return GLStateManager.glGenBuffers();
|
||||
}
|
||||
|
||||
public static void bindBufferBase(int target, int index, int buffer) {
|
||||
@@ -455,13 +458,13 @@ public class RenderSystem {
|
||||
}
|
||||
|
||||
public static void bufferStorage(int target, long size, int flags) {
|
||||
RENDER_BACKEND.bufferStorage(target, size, flags);
|
||||
GLStateManager.glBufferStorage(target, size, flags);
|
||||
}
|
||||
|
||||
public static void clearBufferSubData(int target, int internalFormat, long offset, long size, int format, int type, int[] data) {
|
||||
final ByteBuffer buf = BufferUtils.createByteBuffer(data.length * 4);
|
||||
buf.asIntBuffer().put(data);
|
||||
RENDER_BACKEND.clearBufferSubData(target, internalFormat, offset, size, format, type, buf);
|
||||
GLStateManager.glClearBufferSubData(target, internalFormat, offset, size, format, type, buf);
|
||||
}
|
||||
|
||||
public static void deleteBuffers(int buffer) {
|
||||
@@ -549,7 +552,7 @@ public class RenderSystem {
|
||||
}
|
||||
}
|
||||
|
||||
/** Parse a GL version string (e.g. "4.6.0 NVIDIA ...") into concatenated digits "460". Inlined from StandardMacros.getGlVersion(). */
|
||||
/** Parse a GL version string (e.g. "4.6.0 NVIDIA ...") into concatenated digits "460" */
|
||||
static String parseGlVersionString(String info) {
|
||||
final Matcher matcher = SEMVER_PATTERN.matcher(Objects.requireNonNull(info));
|
||||
if (!matcher.matches()) {
|
||||
@@ -561,4 +564,18 @@ public class RenderSystem {
|
||||
if (bugfix == null || bugfix.isEmpty()) bugfix = "0";
|
||||
return major + minor + bugfix;
|
||||
}
|
||||
|
||||
/** Parse a GL version string into packed major*10+minor (e.g. "4.3.0 - Build ..." -> 43), or -1 if unparseable. */
|
||||
public static int parseMajorMinor(String glVersion) {
|
||||
if (glVersion == null) return -1;
|
||||
final Matcher matcher = SEMVER_PATTERN.matcher(glVersion.trim());
|
||||
if (!matcher.matches()) return -1;
|
||||
return Integer.parseInt(matcher.group("major")) * 10 + Integer.parseInt(matcher.group("minor"));
|
||||
}
|
||||
|
||||
public static boolean isContextValid(int requestedMajor, int requestedMinor, int actualVersion, boolean coreBitSet) {
|
||||
if (!coreBitSet) return false;
|
||||
if (actualVersion < 0) return true;
|
||||
return actualVersion >= requestedMajor * 10 + requestedMinor;
|
||||
}
|
||||
}
|
||||
+16
-1
@@ -327,7 +327,7 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
|
||||
|
||||
@Override
|
||||
public void copyBufferSubData(int readTarget, int writeTarget, long readOffset, long writeOffset, long size) {
|
||||
throw new UnsupportedOperationException("GLRenderBackend.copyBufferSubData should not be called — LWJGL service handles this");
|
||||
GL31.glCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -622,6 +622,11 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
|
||||
GL11.glGetTexImage(target, level, format, type, pixels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getTexImage(int target, int level, int format, int type, long pixelBufferOffset) {
|
||||
GL11.glGetTexImage(target, level, format, type, pixelBufferOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFramebufferAttachmentParameteri(int target, int attachment, int pname) {
|
||||
return GL30.glGetFramebufferAttachmentParameteri(target, attachment, pname);
|
||||
@@ -1058,6 +1063,11 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
|
||||
return GL30.glMapBufferRange(target, offset, length, access, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushMappedBufferRange(int target, long offset, long length) {
|
||||
GL30.glFlushMappedBufferRange(target, offset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int genVertexArrays() {
|
||||
return GL30.glGenVertexArrays();
|
||||
@@ -1249,6 +1259,11 @@ public final class Lwjgl2GLRenderBackend extends RenderBackend {
|
||||
return GL45.glCreateBuffers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void namedBufferData(int buffer, long size, int usage) {
|
||||
GL45.glNamedBufferData(buffer, size, usage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void namedBufferData(int buffer, ByteBuffer data, int usage) {
|
||||
GL45.glNamedBufferData(buffer, data, usage);
|
||||
|
||||
@@ -151,6 +151,7 @@ public abstract class RenderBackend {
|
||||
public abstract void readPixels(int x, int y, int width, int height, int format, int type, IntBuffer pixels);
|
||||
public abstract void getTexImage(int target, int level, int format, int type, ByteBuffer pixels);
|
||||
public abstract void getTexImage(int target, int level, int format, int type, IntBuffer pixels);
|
||||
public abstract void getTexImage(int target, int level, int format, int type, long pixelBufferOffset);
|
||||
public abstract int getFramebufferAttachmentParameteri(int target, int attachment, int pname);
|
||||
|
||||
public abstract int createShader(int type);
|
||||
@@ -249,6 +250,7 @@ public abstract class RenderBackend {
|
||||
public abstract int getBufferParameteri(int target, int pname);
|
||||
public abstract boolean isBuffer(int buffer);
|
||||
public abstract ByteBuffer mapBufferRange(int target, long offset, long length, int access);
|
||||
public abstract void flushMappedBufferRange(int target, long offset, long length);
|
||||
|
||||
public abstract int genVertexArrays();
|
||||
public abstract void deleteVertexArrays(int array);
|
||||
@@ -292,6 +294,7 @@ public abstract class RenderBackend {
|
||||
public abstract void namedFramebufferDrawBuffers(int framebuffer, IntBuffer bufs);
|
||||
public abstract void blitNamedFramebuffer(int readFramebuffer, int drawFramebuffer, int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter);
|
||||
public abstract int createBuffers();
|
||||
public abstract void namedBufferData(int buffer, long size, int usage);
|
||||
public abstract void namedBufferData(int buffer, ByteBuffer data, int usage);
|
||||
public abstract void namedBufferData(int buffer, FloatBuffer data, int usage);
|
||||
public abstract void namedBufferSubData(int buffer, long offset, ByteBuffer data);
|
||||
|
||||
@@ -104,8 +104,8 @@ public class DSAARB extends DSAUnsupported {
|
||||
|
||||
@Override
|
||||
public int bufferStorage(int target, FloatBuffer data, int usage) {
|
||||
final int buffer = RENDER_BACKEND.createBuffers();
|
||||
RENDER_BACKEND.namedBufferData(buffer, data, usage);
|
||||
final int buffer = GLStateManager.glCreateBuffers();
|
||||
GLStateManager.glNamedBufferData(buffer, data, usage);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
@@ -121,9 +121,9 @@ public class DSAUnsupported implements DSAAccess {
|
||||
|
||||
@Override
|
||||
public int bufferStorage(int target, FloatBuffer data, int usage) {
|
||||
final int buffer = RENDER_BACKEND.genBuffers();
|
||||
final int buffer = GLStateManager.glGenBuffers();
|
||||
GLStateManager.glBindBuffer(target, buffer);
|
||||
RENDER_BACKEND.bufferData(target, data, usage);
|
||||
GLStateManager.glBufferData(target, data, usage);
|
||||
GLStateManager.glBindBuffer(target, 0);
|
||||
|
||||
return buffer;
|
||||
|
||||
@@ -6,8 +6,10 @@ import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.DeferredBlendHandler;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMHooks;
|
||||
import com.gtnewhorizons.angelica.glsm.hooks.GLSMInitConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.QuadConverter;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.Vec3fStack;
|
||||
import com.gtnewhorizons.angelica.glsm.stacks.Vec4fStack;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.TessellatorStreamingDrawer;
|
||||
import lombok.Getter;
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector4f;
|
||||
@@ -66,11 +68,33 @@ public final class ShaderManager {
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
warmUp();
|
||||
enabled = true;
|
||||
|
||||
GLStateManager.LOGGER.info("FFP shader emulation enabled");
|
||||
}
|
||||
|
||||
// Force loading of classes before the SplashThread kicks off
|
||||
// Ensure it's GL free
|
||||
private static void warmUp() {
|
||||
try {
|
||||
final long[] fkScratch = new long[FragmentKey.MAX_UNITS];
|
||||
final int fkLen = FragmentKey.packFromState(fkScratch);
|
||||
final int fragMask = FragmentKey.unitMaskFromPacked(fkScratch, fkLen);
|
||||
final long vkPacked = VertexKey.packFromState(true, true, true, true, fragMask);
|
||||
final VertexKey vk = VertexKey.fromPacked(vkPacked);
|
||||
VertexShaderGenerator.generate(vk);
|
||||
FragmentShaderGenerator.generate(FragmentKey.fromPacked(fkScratch, fkLen));
|
||||
GeometryShaderGenerator.generate(vk);
|
||||
final Class<?>[] touched = { Program.class, ShaderCache.class, TessellatorStreamingDrawer.class, QuadConverter.class };
|
||||
for (Class<?> c : touched) {
|
||||
c.getName();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
GLStateManager.LOGGER.warn("FFP warmup failed; draw-path classes will resolve lazily", t);
|
||||
}
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
+22
-11
@@ -10,6 +10,8 @@ import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
/**
|
||||
* Records immediate mode GL calls (glBegin/glEnd/glVertex) via {@link DirectTessellator}.
|
||||
@@ -18,28 +20,37 @@ import java.util.Arrays;
|
||||
public final class ImmediateModeRecorder {
|
||||
private static final CallbackTessellator tessellator = new CallbackTessellator(TessellatorManager.DEFAULT_BUFFER_SIZE);
|
||||
|
||||
/** Separate tessellator for the splash thread. Nulled after splash completes. */
|
||||
private static DirectTessellator splashTessellator;
|
||||
private record ThreadTessellator(Thread thread, DirectTessellator tessellator) {}
|
||||
|
||||
private static final Queue<ThreadTessellator> threadTessellators = new ConcurrentLinkedQueue<>();
|
||||
private static final ThreadLocal<DirectTessellator> threadTessellator = ThreadLocal.withInitial(() -> {
|
||||
final DirectTessellator t = new DirectTessellator(TessellatorManager.DEFAULT_BUFFER_SIZE);
|
||||
threadTessellators.add(new ThreadTessellator(Thread.currentThread(), t));
|
||||
cleanupOrphanTessellators();
|
||||
return t;
|
||||
});
|
||||
|
||||
private ImmediateModeRecorder() {
|
||||
|
||||
}
|
||||
|
||||
public static void initSplashTessellator() {
|
||||
splashTessellator = new DirectTessellator(TessellatorManager.DEFAULT_BUFFER_SIZE);
|
||||
public static int getThreadTessellatorCount() {
|
||||
return threadTessellators.size();
|
||||
}
|
||||
|
||||
public static void destroySplashTessellator() {
|
||||
splashTessellator.delete();
|
||||
splashTessellator = null;
|
||||
public static synchronized void cleanupOrphanTessellators() {
|
||||
threadTessellators.removeIf(tt -> {
|
||||
if (tt.thread().isAlive()) return false;
|
||||
tt.tessellator().delete();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private static DirectTessellator tessellator() {
|
||||
final DirectTessellator splash = splashTessellator;
|
||||
if (splash != null && Thread.currentThread() != GLStateManager.getMainThread()) {
|
||||
return splash;
|
||||
if (Thread.currentThread() == GLStateManager.getMainThread()) {
|
||||
return tessellator;
|
||||
}
|
||||
return tessellator;
|
||||
return threadTessellator.get();
|
||||
}
|
||||
|
||||
public static DirectTessellator getInternalTessellator() {
|
||||
|
||||
@@ -48,6 +48,11 @@ public class GLSMRedirector {
|
||||
private static final String ARBInstancedArrays = "org/lwjgl/opengl/ARBInstancedArrays";
|
||||
private static final String ARBDrawInstanced = "org/lwjgl/opengl/ARBDrawInstanced";
|
||||
private static final String EXTDrawInstanced = "org/lwjgl/opengl/EXTDrawInstanced";
|
||||
private static final String ARBBufferObject = "org/lwjgl/opengl/ARBBufferObject";
|
||||
private static final String ARBVertexBufferObject = "org/lwjgl/opengl/ARBVertexBufferObject";
|
||||
private static final String ARBBufferStorage = "org/lwjgl/opengl/ARBBufferStorage";
|
||||
private static final String ARBCopyBuffer = "org/lwjgl/opengl/ARBCopyBuffer";
|
||||
private static final String ARBMapBufferRange = "org/lwjgl/opengl/ARBMapBufferRange";
|
||||
|
||||
// Redirect VAO related calls from NHLib
|
||||
private static final String UniversalVAO = "com/gtnewhorizon/gtnhlib/client/opengl/UniversalVAO";
|
||||
@@ -285,11 +290,16 @@ public class GLSMRedirector {
|
||||
.add("glBindBuffer")
|
||||
.add("glDeleteBuffers")
|
||||
.add("glBufferData")
|
||||
.add("nglBufferData")
|
||||
.add("glBufferSubData")
|
||||
.add("nglBufferSubData")
|
||||
.add("glMapBuffer")
|
||||
.add("glUnmapBuffer")
|
||||
.add("glGetBufferSubData")
|
||||
.add("nglGetBufferSubData")
|
||||
.add("glGetBufferParameteri")
|
||||
.add("glGetBufferParameter")
|
||||
.add("glGetBufferParameteriv")
|
||||
.add("glIsBuffer");
|
||||
final var gl20 = RedirectMap.newMap()
|
||||
.add("glBlendEquationSeparate")
|
||||
@@ -356,10 +366,13 @@ public class GLSMRedirector {
|
||||
.add("glVertexAttribIPointer")
|
||||
.add("glGenerateMipmap")
|
||||
.add("glGetFramebufferAttachmentParameteri")
|
||||
.add("glBlitFramebuffer");
|
||||
.add("glBlitFramebuffer")
|
||||
.add("glMapBufferRange")
|
||||
.add("glFlushMappedBufferRange");
|
||||
final var gl31 = RedirectMap.newMap()
|
||||
.add("glDrawElementsInstanced")
|
||||
.add("glDrawArraysInstanced");
|
||||
.add("glDrawArraysInstanced")
|
||||
.add("glCopyBufferSubData");
|
||||
final var gl32 = RedirectMap.newMap()
|
||||
.add("glFramebufferTexture");
|
||||
final var gl33 = RedirectMap.newMap()
|
||||
@@ -383,6 +396,10 @@ public class GLSMRedirector {
|
||||
final var gl44 = RedirectMap.newMap()
|
||||
.add("glBufferStorage")
|
||||
.add("glClearTexImage");
|
||||
final var gl45 = RedirectMap.newMap()
|
||||
.add("glCreateBuffers")
|
||||
.add("glNamedBufferData")
|
||||
.add("glNamedBufferSubData");
|
||||
|
||||
// Merge all GL version maps into the flat lookup
|
||||
glMethodRedirects.putAll(gl11);
|
||||
@@ -398,6 +415,7 @@ public class GLSMRedirector {
|
||||
glMethodRedirects.putAll(gl42);
|
||||
glMethodRedirects.putAll(gl43);
|
||||
glMethodRedirects.putAll(gl44);
|
||||
glMethodRedirects.putAll(gl45);
|
||||
|
||||
// MINECRAFT
|
||||
methodRedirects.put(OpenGlHelper, RedirectMap.newMap()
|
||||
@@ -470,6 +488,31 @@ public class GLSMRedirector {
|
||||
.add("glDrawArraysInstancedEXT", "glDrawArraysInstanced")
|
||||
.add("glDrawElementsInstancedEXT", "glDrawElementsInstanced")
|
||||
);
|
||||
final var arbBufferObject = RedirectMap.newMap()
|
||||
.add("glBindBufferARB", "glBindBuffer")
|
||||
.add("glGenBuffersARB", "glGenBuffers")
|
||||
.add("glDeleteBuffersARB", "glDeleteBuffers")
|
||||
.add("glIsBufferARB", "glIsBuffer")
|
||||
.add("glBufferDataARB", "glBufferData")
|
||||
.add("glBufferSubDataARB", "glBufferSubData")
|
||||
.add("glGetBufferSubDataARB", "glGetBufferSubData")
|
||||
.add("glMapBufferARB", "glMapBuffer")
|
||||
.add("glUnmapBufferARB", "glUnmapBuffer")
|
||||
.add("glGetBufferParameterARB", "glGetBufferParameter")
|
||||
.add("glGetBufferParameteriARB", "glGetBufferParameteri")
|
||||
.add("glGetBufferParameterivARB", "glGetBufferParameteriv");
|
||||
methodRedirects.put(ARBBufferObject, arbBufferObject);
|
||||
methodRedirects.put(ARBVertexBufferObject, arbBufferObject);
|
||||
methodRedirects.put(ARBBufferStorage, RedirectMap.newMap()
|
||||
.add("glBufferStorage")
|
||||
);
|
||||
methodRedirects.put(ARBCopyBuffer, RedirectMap.newMap()
|
||||
.add("glCopyBufferSubData")
|
||||
);
|
||||
methodRedirects.put(ARBMapBufferRange, RedirectMap.newMap()
|
||||
.add("glMapBufferRange")
|
||||
.add("glFlushMappedBufferRange")
|
||||
);
|
||||
|
||||
// APPLE
|
||||
methodRedirects.put(APPLEVertexArrayObject, RedirectMap.newMap()
|
||||
|
||||
+30
-20
@@ -88,13 +88,18 @@ public class TessellatorStreamingDrawer {
|
||||
final int vertexSize = format.getVertexSize();
|
||||
|
||||
final int requiredBytes = vertexCount * vertexSize;
|
||||
ensureRepackCapacity(requiredBytes);
|
||||
final boolean locked = GLStateManager.acquireDrawLock();
|
||||
try {
|
||||
ensureRepackCapacity(requiredBytes);
|
||||
|
||||
final long writePtr = format.writeToBuffer0(repackAddress, tess.rawBuffer, tess.rawBufferIndex);
|
||||
repackBuffer.position(0);
|
||||
repackBuffer.limit((int)(writePtr - repackAddress));
|
||||
final long writePtr = format.writeToBuffer0(repackAddress, tess.rawBuffer, tess.rawBufferIndex);
|
||||
repackBuffer.position(0);
|
||||
repackBuffer.limit((int)(writePtr - repackAddress));
|
||||
|
||||
uploadAndDraw(repackBuffer, flags, format, vertexSize, tess.drawMode, vertexCount);
|
||||
uploadAndDraw(repackBuffer, flags, format, vertexSize, tess.drawMode, vertexCount);
|
||||
} finally {
|
||||
if (locked) GLStateManager.releaseDrawLock();
|
||||
}
|
||||
|
||||
// Shrink rawBuffer if oversized
|
||||
if (tess.rawBufferSize > 0x20000 && tess.rawBufferIndex < (tess.rawBufferSize << 3)) {
|
||||
@@ -187,24 +192,29 @@ public class TessellatorStreamingDrawer {
|
||||
* Tries the persistent ring buffer first, falls back to orphan buffer on overflow.
|
||||
*/
|
||||
private static void uploadAndDraw(ByteBuffer packed, int flags, VertexFormat format, int vertexSize, int drawMode, int vertexCount) {
|
||||
ensureVAO(flags, format);
|
||||
final boolean locked = GLStateManager.acquireDrawLock();
|
||||
try {
|
||||
ensureVAO(flags, format);
|
||||
|
||||
int firstVertex = -1;
|
||||
int firstVertex = -1;
|
||||
|
||||
if (persistentBuffer != null) {
|
||||
firstVertex = persistentBuffer.upload(packed, vertexSize);
|
||||
if (persistentBuffer != null) {
|
||||
firstVertex = persistentBuffer.upload(packed, vertexSize);
|
||||
}
|
||||
|
||||
if (firstVertex >= 0) {
|
||||
GLStateManager.glBindVertexArray(persistentVAOs[flags]);
|
||||
} else {
|
||||
GLStateManager.glBindVertexArray(orphanVAOs[flags]);
|
||||
orphanBuffers[flags].upload(packed);
|
||||
firstVertex = 0;
|
||||
}
|
||||
|
||||
drawWithQuadConversion(drawMode, firstVertex, vertexCount);
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
} finally {
|
||||
if (locked) GLStateManager.releaseDrawLock();
|
||||
}
|
||||
|
||||
if (firstVertex >= 0) {
|
||||
GLStateManager.glBindVertexArray(persistentVAOs[flags]);
|
||||
} else {
|
||||
GLStateManager.glBindVertexArray(orphanVAOs[flags]);
|
||||
orphanBuffers[flags].upload(packed);
|
||||
firstVertex = 0;
|
||||
}
|
||||
|
||||
drawWithQuadConversion(drawMode, firstVertex, vertexCount);
|
||||
GLStateManager.glBindVertexArray(0);
|
||||
}
|
||||
|
||||
private static void drawWithQuadConversion(int drawMode, int firstVertex, int vertexCount) {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class GLVersionParseTest {
|
||||
|
||||
@Test
|
||||
void parseMajorMinor() {
|
||||
assertEquals(43, RenderSystem.parseMajorMinor("4.3.0 - Build 20.19.15.4835"));
|
||||
assertEquals(46, RenderSystem.parseMajorMinor("4.6.0 NVIDIA 551.61"));
|
||||
assertEquals(41, RenderSystem.parseMajorMinor("4.1 Metal - 88"));
|
||||
assertEquals(33, RenderSystem.parseMajorMinor("3.3"));
|
||||
assertEquals(46, RenderSystem.parseMajorMinor("4.6 (Core Profile) Mesa 24.0.3"));
|
||||
assertEquals(-1, RenderSystem.parseMajorMinor(null));
|
||||
assertEquals(-1, RenderSystem.parseMajorMinor(""));
|
||||
assertEquals(-1, RenderSystem.parseMajorMinor("garbage"));
|
||||
assertEquals(-1, RenderSystem.parseMajorMinor("OpenGL ES 3.2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void isContextValid() {
|
||||
assertTrue(RenderSystem.isContextValid(4, 4, 46, true));
|
||||
assertTrue(RenderSystem.isContextValid(4, 4, 44, true));
|
||||
assertFalse(RenderSystem.isContextValid(4, 4, 43, true));
|
||||
assertFalse(RenderSystem.isContextValid(4, 4, 44, false));
|
||||
assertTrue(RenderSystem.isContextValid(4, 4, -1, true));
|
||||
assertFalse(RenderSystem.isContextValid(4, 4, -1, false));
|
||||
assertTrue(RenderSystem.isContextValid(3, 3, 33, true));
|
||||
}
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.DirectTessellator;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.CompiledDisplayList;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.GLCommand;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.ImmediateModeRecorder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@ExtendWith(GLSMCoreExtension.class)
|
||||
class ImmediateModeThreadIsolationTest {
|
||||
|
||||
@Test
|
||||
void backgroundThreadsGetDistinctTessellators() throws Exception {
|
||||
final DirectTessellator mainTess = ImmediateModeRecorder.getInternalTessellator();
|
||||
final AtomicReference<DirectTessellator> bg1 = new AtomicReference<>();
|
||||
final AtomicReference<DirectTessellator> bg2 = new AtomicReference<>();
|
||||
|
||||
final Thread t1 = new Thread(() -> bg1.set(ImmediateModeRecorder.getInternalTessellator()), "iso-test-1");
|
||||
final Thread t2 = new Thread(() -> bg2.set(ImmediateModeRecorder.getInternalTessellator()), "iso-test-2");
|
||||
t1.start(); t2.start();
|
||||
t1.join(); t2.join();
|
||||
|
||||
assertNotNull(bg1.get());
|
||||
assertNotNull(bg2.get());
|
||||
assertNotSame(mainTess, bg1.get(), "background thread must not share the main-thread tessellator");
|
||||
assertNotSame(mainTess, bg2.get(), "background thread must not share the main-thread tessellator");
|
||||
assertNotSame(bg1.get(), bg2.get(), "background threads must not share a tessellator");
|
||||
}
|
||||
|
||||
@Test
|
||||
void concurrentImmediateModeDoesNotCorruptRecording() throws Exception {
|
||||
final List<Throwable> failures = new CopyOnWriteArrayList<>();
|
||||
final CountDownLatch start = new CountDownLatch(1);
|
||||
final AtomicBoolean stop = new AtomicBoolean(false);
|
||||
|
||||
final Runnable spam = () -> {
|
||||
try {
|
||||
start.await();
|
||||
while (!stop.get()) {
|
||||
GLStateManager.glBegin(GL11.GL_QUADS);
|
||||
GLStateManager.glVertex3f(0, 0, 0);
|
||||
GLStateManager.glVertex3f(1, 0, 0);
|
||||
GLStateManager.glVertex3f(1, 1, 0);
|
||||
GLStateManager.glVertex3f(0, 1, 0);
|
||||
GLStateManager.glEnd();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
failures.add(t);
|
||||
}
|
||||
};
|
||||
final Thread t1 = new Thread(spam, "iso-spam-1");
|
||||
final Thread t2 = new Thread(spam, "iso-spam-2");
|
||||
t1.start(); t2.start();
|
||||
start.countDown();
|
||||
|
||||
final List<Integer> lists = new ArrayList<>();
|
||||
try {
|
||||
for (int i = 0; i < 50; i++) {
|
||||
final int list = GLStateManager.glGenLists(1);
|
||||
GLStateManager.glNewList(list, GL11.GL_COMPILE);
|
||||
GLStateManager.glBegin(GL11.GL_QUADS);
|
||||
GLStateManager.glVertex3f(0, 0, 0);
|
||||
GLStateManager.glVertex3f(1, 0, 0);
|
||||
GLStateManager.glVertex3f(1, 1, 0);
|
||||
GLStateManager.glVertex3f(0, 1, 0);
|
||||
GLStateManager.glEnd();
|
||||
GLStateManager.glEndList();
|
||||
lists.add(list);
|
||||
}
|
||||
} finally {
|
||||
stop.set(true);
|
||||
t1.join(5000); t2.join(5000);
|
||||
}
|
||||
|
||||
assertTrue(failures.isEmpty(), "background immediate mode threw: " + failures);
|
||||
for (int list : lists) {
|
||||
final CompiledDisplayList compiled = DisplayListManager.getDisplayList(list);
|
||||
assertNotNull(compiled, "list " + list + " should be compiled");
|
||||
assertEquals(1, compiled.getCommandCounts().getOrDefault(GLCommand.DRAW_RANGE, 0), "list " + list + " should contain exactly the main thread's draw");
|
||||
GLStateManager.glDeleteLists(list, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void sweepFreesDeadThreadTessellators() throws Exception {
|
||||
final Thread t = new Thread(() -> ImmediateModeRecorder.getInternalTessellator(), "iso-sweep");
|
||||
t.start();
|
||||
t.join();
|
||||
final int before = ImmediateModeRecorder.getThreadTessellatorCount();
|
||||
assertTrue(before >= 1);
|
||||
ImmediateModeRecorder.cleanupOrphanTessellators();
|
||||
assertTrue(ImmediateModeRecorder.getThreadTessellatorCount() < before, "dead thread's tessellator should be swept");
|
||||
}
|
||||
|
||||
@Test
|
||||
void drawLockGatesOnSplashComplete() throws Exception {
|
||||
assertFalse(GLStateManager.acquireDrawLock(), "post-splash acquire must be a no-op");
|
||||
|
||||
final Field f = GLStateManager.class.getDeclaredField("splashComplete");
|
||||
f.setAccessible(true);
|
||||
f.set(null, false);
|
||||
try {
|
||||
assertTrue(GLStateManager.acquireDrawLock(), "during splash the lock must engage");
|
||||
GLStateManager.releaseDrawLock();
|
||||
} finally {
|
||||
f.set(null, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -659,6 +659,11 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
|
||||
GL11C.glGetTexImage(target, level, format, type, pixels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getTexImage(int target, int level, int format, int type, long pixelBufferOffset) {
|
||||
GL11C.glGetTexImage(target, level, format, type, pixelBufferOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFramebufferAttachmentParameteri(int target, int attachment, int pname) {
|
||||
return GL30C.glGetFramebufferAttachmentParameteri(target, attachment, pname);
|
||||
@@ -1096,6 +1101,11 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
|
||||
return GL30C.glMapBufferRange(target, offset, length, access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushMappedBufferRange(int target, long offset, long length) {
|
||||
GL30C.glFlushMappedBufferRange(target, offset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int genVertexArrays() {
|
||||
return GL30C.glGenVertexArrays();
|
||||
@@ -1281,6 +1291,11 @@ public final class Lwjgl3GLRenderBackend extends RenderBackend {
|
||||
return GL45C.glCreateBuffers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void namedBufferData(int buffer, long size, int usage) {
|
||||
GL45C.glNamedBufferData(buffer, size, usage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void namedBufferData(int buffer, ByteBuffer data, int usage) {
|
||||
GL45C.glNamedBufferData(buffer, data, usage);
|
||||
|
||||
@@ -327,6 +327,15 @@ public class BatchingFontRenderer {
|
||||
private int fontAAStrengthLast = -1;
|
||||
|
||||
private void flushBatch() {
|
||||
final boolean locked = GLStateManager.acquireDrawLock();
|
||||
try {
|
||||
flushBatchInner();
|
||||
} finally {
|
||||
if (locked) GLStateManager.releaseDrawLock();
|
||||
}
|
||||
}
|
||||
|
||||
private void flushBatchInner() {
|
||||
if (vertexDataPos == 0) {
|
||||
clearBatch();
|
||||
return;
|
||||
|
||||
@@ -2,17 +2,25 @@ package com.gtnewhorizons.angelica.client.font;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.IReloadableResourceManager;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.client.resources.IResourceManagerReloadListener;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public final class FontProviderUnicode implements FontProvider {
|
||||
public final class FontProviderUnicode implements FontProvider, IResourceManagerReloadListener {
|
||||
|
||||
private FontProviderUnicode() {
|
||||
onResourceManagerReload(Minecraft.getMinecraft().getResourceManager());
|
||||
((IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager()).registerReloadListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResourceManagerReload(IResourceManager resourceManager) {
|
||||
try {
|
||||
InputStream inputstream = Minecraft.getMinecraft().getResourceManager()
|
||||
.getResource(new ResourceLocation("font/glyph_sizes.bin")).getInputStream();
|
||||
InputStream inputstream = resourceManager.getResource(new ResourceLocation("font/glyph_sizes.bin")).getInputStream();
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
inputstream.read(this.glyphWidth);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.gtnewhorizons.angelica.compat.etfuturum;
|
||||
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import ganymedes01.etfuturum.api.client.EndFlashAPI;
|
||||
|
||||
/**
|
||||
* Use EFR to power End flash uniforms.
|
||||
*/
|
||||
public final class EndFlashCompat {
|
||||
|
||||
private static final boolean AVAILABLE = Loader.isModLoaded("etfuturum") && EndFlashCompat.class.getResource("/ganymedes01/etfuturum/api/client/EndFlashAPI.class") != null;
|
||||
|
||||
private EndFlashCompat() {}
|
||||
|
||||
public static boolean isAvailable() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
public static float getIntensity(float partialTicks) {
|
||||
return AVAILABLE ? EndFlashAPI.getIntensity(partialTicks) : 0.0F;
|
||||
}
|
||||
|
||||
public static float getXAngle() {
|
||||
return AVAILABLE ? EndFlashAPI.getXAngle() : 0.0F;
|
||||
}
|
||||
|
||||
public static float getYAngle() {
|
||||
return AVAILABLE ? EndFlashAPI.getYAngle() : 0.0F;
|
||||
}
|
||||
}
|
||||
@@ -170,6 +170,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
private final CloudSetting cloudSetting;
|
||||
private final boolean shouldRenderUnderwaterOverlay;
|
||||
private final boolean shouldRenderVignette;
|
||||
private final boolean supportsEndFlash;
|
||||
private final boolean shouldRenderSun;
|
||||
private final boolean shouldRenderMoon;
|
||||
private final boolean shouldRenderStars;
|
||||
@@ -231,6 +232,7 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
this.cloudSetting = programs.getPackDirectives().getCloudSetting();
|
||||
this.shouldRenderUnderwaterOverlay = programs.getPackDirectives().underwaterOverlay();
|
||||
this.shouldRenderVignette = programs.getPackDirectives().vignette();
|
||||
this.supportsEndFlash = programs.getPackDirectives().isSupportsEndFlash();
|
||||
this.shouldRenderSun = programs.getPackDirectives().shouldRenderSun();
|
||||
this.shouldRenderMoon = programs.getPackDirectives().shouldRenderMoon();
|
||||
this.shouldRenderStars = programs.getPackDirectives().shouldRenderStars();
|
||||
@@ -651,6 +653,11 @@ public class DeferredWorldRenderingPipeline implements WorldRenderingPipeline, R
|
||||
return shouldRenderVignette;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsEndFlash() {
|
||||
return supportsEndFlash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRenderSun() {
|
||||
return shouldRenderSun;
|
||||
|
||||
@@ -152,6 +152,11 @@ public class FixedFunctionWorldRenderingPipeline implements WorldRenderingPipeli
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsEndFlash() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CloudSetting getCloudSetting() {
|
||||
return CloudSetting.DEFAULT;
|
||||
|
||||
@@ -49,6 +49,7 @@ public interface WorldRenderingPipeline {
|
||||
|
||||
boolean shouldDisableVanillaEntityShadows();
|
||||
boolean shouldDisableDirectionalShading();
|
||||
boolean supportsEndFlash();
|
||||
CloudSetting getCloudSetting();
|
||||
boolean shouldRenderUnderwaterOverlay();
|
||||
boolean shouldRenderVignette();
|
||||
|
||||
@@ -48,6 +48,7 @@ public class PackDirectives {
|
||||
@Getter private boolean oldHandLight;
|
||||
@Getter private boolean prepareBeforeShadow;
|
||||
@Getter private boolean supportsColorCorrection;
|
||||
@Getter private boolean supportsEndFlash;
|
||||
@Getter private int fallbackTex;
|
||||
private Object2ObjectMap<String, Object2BooleanMap<String>> explicitFlips = new Object2ObjectOpenHashMap<>();
|
||||
private Object2ObjectMap<String, TextureScaleOverride> scaleOverrides = new Object2ObjectOpenHashMap<>();
|
||||
@@ -93,6 +94,7 @@ public class PackDirectives {
|
||||
oldLighting = properties.getOldLighting().orElse(false);
|
||||
fallbackTex = properties.getFallbackTex();
|
||||
supportsColorCorrection = properties.getSupportsColorCorrection().orElse(false);
|
||||
supportsEndFlash = properties.getSupportsEndFlash().orElse(false);
|
||||
concurrentCompute = properties.getConcurrentCompute().orElse(false);
|
||||
oldHandLight = properties.getOldHandLight().orElse(true);
|
||||
explicitFlips = properties.getExplicitFlips();
|
||||
@@ -112,6 +114,7 @@ public class PackDirectives {
|
||||
frustumCulling = directives.frustumCulling;
|
||||
occlusionCulling = directives.occlusionCulling;
|
||||
oldLighting = directives.oldLighting;
|
||||
supportsEndFlash = directives.supportsEndFlash;
|
||||
concurrentCompute = directives.concurrentCompute;
|
||||
explicitFlips = directives.explicitFlips;
|
||||
scaleOverrides = directives.scaleOverrides;
|
||||
|
||||
@@ -70,6 +70,7 @@ public class ShaderProperties {
|
||||
@Getter private OptionalBoolean shadowPlayer = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean shadowBlockEntities = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean shadowLightBlockEntities = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean supportsEndFlash = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean underwaterOverlay = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean sun = OptionalBoolean.DEFAULT;
|
||||
@Getter private OptionalBoolean moon = OptionalBoolean.DEFAULT;
|
||||
@@ -205,6 +206,7 @@ public class ShaderProperties {
|
||||
handleBooleanDirective(key, value, "shadowPlayer", bool -> shadowPlayer = bool);
|
||||
handleBooleanDirective(key, value, "shadowBlockEntities", bool -> shadowBlockEntities = bool);
|
||||
handleBooleanDirective(key, value, "shadowLightBlockEntities", bool -> shadowLightBlockEntities = bool);
|
||||
handleBooleanDirective(key, value, "endFlashShadows", bool -> supportsEndFlash = bool);
|
||||
handleBooleanDirective(key, value, "underwaterOverlay", bool -> underwaterOverlay = bool);
|
||||
handleBooleanDirective(key, value, "sun", bool -> sun = bool);
|
||||
handleBooleanDirective(key, value, "moon", bool -> moon = bool);
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
package net.coderbot.iris.shadow;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.etfuturum.EndFlashCompat;
|
||||
import com.gtnewhorizons.angelica.compat.toremove.MatrixStack;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.world.WorldProviderEnd;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
import static com.gtnewhorizons.angelica.compat.mojang.Constants.DEGREES_TO_RADIANS;
|
||||
@@ -40,23 +46,41 @@ public class ShadowMatrices {
|
||||
}
|
||||
|
||||
public static void createBaselineModelViewMatrix(MatrixStack target, float shadowAngle, float sunPathRotation) {
|
||||
final float skyAngle;
|
||||
|
||||
if (shadowAngle < 0.25f) {
|
||||
skyAngle = shadowAngle + 0.75f;
|
||||
} else {
|
||||
skyAngle = shadowAngle - 0.25f;
|
||||
}
|
||||
|
||||
target.peek().getNormal().identity();
|
||||
target.peek().getModel().identity();
|
||||
|
||||
target.peek().getModel().translate(0.0f, 0.0f, -100.0f);
|
||||
target.rotateX(90F * DEGREES_TO_RADIANS);
|
||||
target.rotateZ(skyAngle * -360.0f * DEGREES_TO_RADIANS);
|
||||
target.rotateX(sunPathRotation * DEGREES_TO_RADIANS);
|
||||
|
||||
if (isEndFlashShadow()) {
|
||||
// Project shadows from the End flash direction instead of the sun/moon.
|
||||
target.rotateX((0.0f - EndFlashCompat.getXAngle()) * DEGREES_TO_RADIANS);
|
||||
target.rotateY(EndFlashCompat.getYAngle() * DEGREES_TO_RADIANS);
|
||||
} else {
|
||||
final float skyAngle;
|
||||
|
||||
if (shadowAngle < 0.25f) {
|
||||
skyAngle = shadowAngle + 0.75f;
|
||||
} else {
|
||||
skyAngle = shadowAngle - 0.25f;
|
||||
}
|
||||
|
||||
target.rotateX(90F * DEGREES_TO_RADIANS);
|
||||
target.rotateZ(skyAngle * -360.0f * DEGREES_TO_RADIANS);
|
||||
target.rotateX(sunPathRotation * DEGREES_TO_RADIANS);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isEndFlashShadow() {
|
||||
final Minecraft mc = Minecraft.getMinecraft();
|
||||
if (mc == null) {
|
||||
return false;
|
||||
}
|
||||
final WorldClient world = mc.theWorld;
|
||||
return world != null && world.provider instanceof WorldProviderEnd
|
||||
&& EndFlashCompat.isAvailable()
|
||||
&& Iris.getPipelineManager().getPipeline().map(WorldRenderingPipeline::supportsEndFlash).orElse(false);
|
||||
}
|
||||
|
||||
public static void snapModelViewToGrid(MatrixStack target, float shadowIntervalSize, double cameraX, double cameraY, double cameraZ) {
|
||||
if (Math.abs(shadowIntervalSize) == 0.0F) {
|
||||
// Avoid a division by zero - semantically, this just means that the snapping does not take place,
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
package net.coderbot.iris.uniforms;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.etfuturum.EndFlashCompat;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.Constants;
|
||||
import com.gtnewhorizons.angelica.rendering.RenderingState;
|
||||
import net.coderbot.iris.Iris;
|
||||
import net.coderbot.iris.gl.uniform.UniformHolder;
|
||||
import net.coderbot.iris.pipeline.WorldRenderingPipeline;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.WorldClient;
|
||||
import net.minecraft.world.WorldProviderEnd;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
@@ -18,9 +22,12 @@ import static net.coderbot.iris.gl.uniform.UniformUpdateFrequency.PER_FRAME;
|
||||
public final class CelestialUniforms {
|
||||
private static final Vector4f upPositionCache = new Vector4f();
|
||||
private static final Matrix4f upMatrixCache = new Matrix4f();
|
||||
private static final Vector4f ZERO_VECTOR_4f = new Vector4f(0.0F, 0.0F, 0.0F, 0.0F);
|
||||
|
||||
private final Vector4f positionCache = new Vector4f();
|
||||
private final Matrix4f celestialMatrixCache = new Matrix4f();
|
||||
private final Vector4f endFlashPositionCache = new Vector4f();
|
||||
private final Matrix4f endFlashMatrixCache = new Matrix4f();
|
||||
private final float sunPathRotation;
|
||||
|
||||
public CelestialUniforms(float sunPathRotation) {
|
||||
@@ -34,9 +41,46 @@ public final class CelestialUniforms {
|
||||
.uniformTruncated3f(PER_FRAME, "moonPosition", this::getMoonPosition)
|
||||
.uniform1f(PER_FRAME, "shadowAngle", CelestialUniforms::getShadowAngle)
|
||||
.uniformTruncated3f(PER_FRAME, "shadowLightPosition", this::getShadowLightPosition)
|
||||
.uniformTruncated3f(PER_FRAME, "endFlashPosition", this::getEndFlashPosition)
|
||||
.uniformTruncated3f(PER_FRAME, "upPosition", CelestialUniforms::getUpPosition);
|
||||
}
|
||||
|
||||
private Vector4f getEndFlashPosition() {
|
||||
final WorldClient world = Minecraft.getMinecraft().theWorld;
|
||||
if (world == null || !(world.provider instanceof WorldProviderEnd) || !EndFlashCompat.isAvailable()) {
|
||||
return ZERO_VECTOR_4f;
|
||||
}
|
||||
|
||||
final float yAngle = EndFlashCompat.getYAngle();
|
||||
final float xAngle = EndFlashCompat.getXAngle();
|
||||
|
||||
endFlashPositionCache.set(0.0F, 100.0F, 0.0F, 0.0F);
|
||||
endFlashMatrixCache.set(RenderingState.INSTANCE.getModelViewMatrix());
|
||||
endFlashMatrixCache.rotateY((180.0F - yAngle) * Constants.DEGREES_TO_RADIANS);
|
||||
endFlashMatrixCache.rotateX((-90.0F - xAngle) * Constants.DEGREES_TO_RADIANS);
|
||||
endFlashMatrixCache.transform(endFlashPositionCache);
|
||||
return endFlashPositionCache;
|
||||
}
|
||||
|
||||
private Vector4f getEndFlashPositionInWorldSpace() {
|
||||
final float yAngle = EndFlashCompat.getYAngle();
|
||||
final float xAngle = EndFlashCompat.getXAngle();
|
||||
|
||||
endFlashPositionCache.set(0.0F, 100.0F, 0.0F, 0.0F);
|
||||
endFlashMatrixCache.identity();
|
||||
endFlashMatrixCache.rotateY((180.0F - yAngle) * Constants.DEGREES_TO_RADIANS);
|
||||
endFlashMatrixCache.rotateX((-90.0F - xAngle) * Constants.DEGREES_TO_RADIANS);
|
||||
endFlashMatrixCache.transform(endFlashPositionCache);
|
||||
return endFlashPositionCache;
|
||||
}
|
||||
|
||||
private static boolean isEndFlashShadowActive() {
|
||||
final WorldClient world = Minecraft.getMinecraft().theWorld;
|
||||
return world != null && world.provider instanceof WorldProviderEnd
|
||||
&& EndFlashCompat.isAvailable()
|
||||
&& Iris.getPipelineManager().getPipeline().map(WorldRenderingPipeline::supportsEndFlash).orElse(false);
|
||||
}
|
||||
|
||||
public static float getSunAngle() {
|
||||
final float skyAngle = getSkyAngle();
|
||||
|
||||
@@ -66,10 +110,16 @@ public final class CelestialUniforms {
|
||||
}
|
||||
|
||||
public Vector4f getShadowLightPosition() {
|
||||
if (isEndFlashShadowActive()) {
|
||||
return getEndFlashPosition();
|
||||
}
|
||||
return isDay() ? getSunPosition() : getMoonPosition();
|
||||
}
|
||||
|
||||
public Vector4f getShadowLightPositionInWorldSpace() {
|
||||
if (isEndFlashShadowActive()) {
|
||||
return getEndFlashPositionInWorldSpace();
|
||||
}
|
||||
return isDay() ? getCelestialPositionInWorldSpace(100.0F) : getCelestialPositionInWorldSpace(-100.0F);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ public final class CommonUniforms {
|
||||
SystemTimeUniforms.addSystemTimeUniforms(uniforms);
|
||||
BiomeUniforms.addBiomeUniforms(uniforms);
|
||||
new CelestialUniforms(directives.getSunPathRotation()).addCelestialUniforms(uniforms);
|
||||
IrisExclusiveUniforms.addIrisExclusiveUniforms(uniforms);
|
||||
IrisExclusiveUniforms.addIrisExclusiveUniforms(uniforms, updateNotifier);
|
||||
IdMapUniforms.addIdMapUniforms(updateNotifier, uniforms, idMap, directives.isOldHandLight());
|
||||
MatrixUniforms.addMatrixUniforms(uniforms, directives);
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package net.coderbot.iris.uniforms;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.etfuturum.EndFlashCompat;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Holds the current and previous-frame End flash intensity.
|
||||
*/
|
||||
@Getter
|
||||
public class EndFlashStorage {
|
||||
private float lastEndFlash;
|
||||
private float currentEndFlash;
|
||||
|
||||
public void tick() {
|
||||
lastEndFlash = currentEndFlash;
|
||||
currentEndFlash = EndFlashCompat.getIntensity(CapturedRenderingState.INSTANCE.getTickDelta());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.coderbot.iris.uniforms;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.etfuturum.EndFlashCompat;
|
||||
import com.gtnewhorizons.angelica.compat.etfuturum.EtFuturumCompat;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.Camera;
|
||||
import com.gtnewhorizons.angelica.compat.mojang.GameModeUtil;
|
||||
@@ -41,9 +42,15 @@ public class IrisExclusiveUniforms {
|
||||
private static int cachedSelectedFrame = -1;
|
||||
private static int cachedSelectedBlockId;
|
||||
|
||||
public static void addIrisExclusiveUniforms(UniformHolder uniforms) {
|
||||
public static void addIrisExclusiveUniforms(UniformHolder uniforms, FrameUpdateNotifier updateNotifier) {
|
||||
WorldInfoUniforms.addWorldInfoUniforms(uniforms);
|
||||
|
||||
// Et Futurum Requiem backports the End Flash
|
||||
final EndFlashStorage endFlashStorage = new EndFlashStorage();
|
||||
if (EndFlashCompat.isAvailable()) {
|
||||
updateNotifier.addListener(endFlashStorage::tick);
|
||||
}
|
||||
|
||||
//All Iris-exclusive uniforms (uniforms which do not exist in either OptiFine or ShadersMod) should be registered here.
|
||||
uniforms.uniform1f(UniformUpdateFrequency.PER_FRAME, "thunderStrength", IrisExclusiveUniforms::getThunderStrength);
|
||||
uniforms.uniform1f(UniformUpdateFrequency.PER_TICK, "currentPlayerHealth", IrisExclusiveUniforms::getCurrentHealth);
|
||||
@@ -59,6 +66,8 @@ public class IrisExclusiveUniforms {
|
||||
uniforms.uniform3d(UniformUpdateFrequency.PER_FRAME, "relativeEyePosition", IrisExclusiveUniforms::getRelativeEyePosition);
|
||||
uniforms.uniform4f(UniformUpdateFrequency.PER_TICK, "lightningBoltPosition", IrisExclusiveUniforms::getLightningBoltPosition);
|
||||
uniforms.uniform1f(UniformUpdateFrequency.PER_FRAME, "cloudTime", IrisExclusiveUniforms::getCloudTime);
|
||||
uniforms.uniform1f(UniformUpdateFrequency.PER_TICK, "endFlashIntensity", endFlashStorage::getCurrentEndFlash);
|
||||
uniforms.uniform1f(UniformUpdateFrequency.PER_TICK, "previousEndFlashIntensity", endFlashStorage::getLastEndFlash);
|
||||
uniforms.uniform1b(UniformUpdateFrequency.PER_TICK, "feetInWater", IrisExclusiveUniforms::isFeetInWater);
|
||||
uniforms.uniform1b(UniformUpdateFrequency.PER_TICK, "isRiding", IrisExclusiveUniforms::isRiding);
|
||||
uniforms.uniform1b(UniformUpdateFrequency.PER_TICK, "vehicleInWater", IrisExclusiveUniforms::isVehicleInWater);
|
||||
|
||||
@@ -12,9 +12,9 @@ public final class ExtendedDataHelper {
|
||||
|
||||
public static int computeMidBlock(float x, float y, float z, int localPosX, int localPosY, int localPosZ) {
|
||||
return packMidBlock(
|
||||
localPosX + 0.5f - x,
|
||||
localPosY + 0.5f - y,
|
||||
localPosZ + 0.5f - z
|
||||
(localPosX & 0xFFFF) + 0.5f - x,
|
||||
(localPosY & 0xFFFF) + 0.5f - y,
|
||||
(localPosZ & 0xFFFF) + 0.5f - z
|
||||
);
|
||||
}
|
||||
}
|
||||
+32
-3
@@ -3,6 +3,7 @@ package com.gtnewhorizons.angelica.mixins.early.angelica;
|
||||
import com.gtnewhorizon.gtnhlib.config.ConfigurationManager;
|
||||
import com.gtnewhorizons.angelica.AngelicaMod;
|
||||
import com.gtnewhorizons.angelica.config.AngelicaConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import net.minecraftforge.client.ForgeHooksClient;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -11,6 +12,7 @@ import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.opengl.ContextAttribs;
|
||||
import org.lwjgl.opengl.Display;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.opengl.PixelFormat;
|
||||
import org.lwjgl.LWJGLUtil;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -63,15 +65,22 @@ public abstract class MixinForgeHooksClient_CoreProfile {
|
||||
final int platformMaxMinor = (LWJGLUtil.getPlatform() == LWJGLUtil.PLATFORM_MACOSX) ? 1 : 6;
|
||||
final int platformMax = platformMaxMajor * 10 + platformMaxMinor;
|
||||
|
||||
int maxProbe = platformMax;
|
||||
|
||||
// Try pinned version first if configured
|
||||
final int pinned = angelica$clampPinned(AngelicaConfig.pinnedGLVersion, platformMax);
|
||||
if (pinned >= 33) {
|
||||
final Exception e = angelica$tryCreate(attribs, format, setMajor, setMinor, pinned / 10, pinned % 10);
|
||||
if (e == null) {
|
||||
LOGGER.info("Created GL {}.{} core profile context (pinned)", pinned / 10, pinned % 10);
|
||||
return;
|
||||
final int cap = angelica$validateContext(pinned / 10, pinned % 10);
|
||||
if (cap == 0) {
|
||||
LOGGER.info("Created GL {}.{} core profile context (pinned)", pinned / 10, pinned % 10);
|
||||
return;
|
||||
}
|
||||
maxProbe = Math.min(maxProbe, cap);
|
||||
} else {
|
||||
LOGGER.warn("Pinned GL version {}.{} failed, probing from highest", pinned / 10, pinned % 10);
|
||||
}
|
||||
LOGGER.warn("Pinned GL version {}.{} failed, probing from highest", pinned / 10, pinned % 10);
|
||||
}
|
||||
|
||||
// Probe from highest to lowest
|
||||
@@ -80,8 +89,14 @@ public abstract class MixinForgeHooksClient_CoreProfile {
|
||||
final int maxMinor = (major == 4) ? platformMaxMinor : 3;
|
||||
final int minMinor = (major == 3) ? 3 : 0;
|
||||
for (int minor = maxMinor; minor >= minMinor; --minor) {
|
||||
if (major * 10 + minor > maxProbe) continue;
|
||||
final Exception e = angelica$tryCreate(attribs, format, setMajor, setMinor, major, minor);
|
||||
if (e == null) {
|
||||
final int cap = angelica$validateContext(major, minor);
|
||||
if (cap != 0) {
|
||||
maxProbe = Math.min(maxProbe, cap);
|
||||
continue;
|
||||
}
|
||||
final int version = major * 10 + minor;
|
||||
LOGGER.info("Created GL {}.{} core profile context", major, minor);
|
||||
// Auto-pin if below platform max, or update a stale pin
|
||||
@@ -127,6 +142,20 @@ public abstract class MixinForgeHooksClient_CoreProfile {
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static int angelica$validateContext(int major, int minor) {
|
||||
final String glVersion = GLStateManager.glGetString(GL11.GL_VERSION);
|
||||
final int actual = RenderSystem.parseMajorMinor(glVersion);
|
||||
final boolean core = (GLStateManager.glGetInteger(GL32.GL_CONTEXT_PROFILE_MASK) & GL32.GL_CONTEXT_CORE_PROFILE_BIT) != 0;
|
||||
if (RenderSystem.isContextValid(major, minor, actual, core)) {
|
||||
return 0;
|
||||
}
|
||||
LOGGER.warn("Requested GL {}.{} core context but driver returned \"{}\" (core profile: {}, GPU: {}); falling back to a lower version", major, minor, glVersion, core, GLStateManager.glGetString(GL11.GL_RENDERER));
|
||||
try { Display.destroy(); } catch (Exception ignored) {}
|
||||
final int requested = major * 10 + minor;
|
||||
return (actual >= 0 && actual < requested) ? actual : requested - 1;
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static void angelica$savePin(int version) {
|
||||
AngelicaConfig.pinnedGLVersion = version;
|
||||
|
||||
-13
@@ -1,7 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.angelica.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.recording.ImmediateModeRecorder;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -27,14 +26,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
public class MixinSplashProgressCaching {
|
||||
private static final Logger LOGGER = LogManager.getLogger("Angelica");
|
||||
|
||||
/**
|
||||
* Before splash starts, create a separate DirectTessellator for the splash thread.
|
||||
*/
|
||||
@Inject(method = "start", at = @At("HEAD"))
|
||||
private static void angelica$initSplashTessellator(CallbackInfo ci) {
|
||||
ImmediateModeRecorder.initSplashTessellator();
|
||||
}
|
||||
|
||||
// VAOs aren't shared across GL contexts; the SharedDrawable the client thread just swapped
|
||||
// onto has none. Core profile (macOS) rejects glValidateProgram without one.
|
||||
@Inject(method = "start", at = @At("RETURN"))
|
||||
@@ -42,12 +33,8 @@ public class MixinSplashProgressCaching {
|
||||
GLStateManager.glBindVertexArray(GLStateManager.glGenVertexArrays());
|
||||
}
|
||||
|
||||
/**
|
||||
* On return from finish() - destroy splash tessellator and mark splash complete
|
||||
*/
|
||||
@Inject(method = "finish", at = @At("RETURN"))
|
||||
private static void angelica$enableCachingOnFinish(CallbackInfo ci) {
|
||||
ImmediateModeRecorder.destroySplashTessellator();
|
||||
GLStateManager.markSplashComplete();
|
||||
LOGGER.info("Splash Complete");
|
||||
}
|
||||
|
||||
+5
@@ -27,6 +27,7 @@ package com.gtnewhorizons.angelica.mixins.early.angelica.itemrenderer;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.DirectTessellator;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.TessellatorManager;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.rendering.items.ItemRenderListManager;
|
||||
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
@@ -43,6 +44,10 @@ public abstract class MixinItemRenderer {
|
||||
|
||||
@WrapMethod(method = "renderItemIn2D")
|
||||
private static void angelica$cacheItem(Tessellator tessellator, float minU, float minV, float maxU, float maxV, int widthSubdivisions, int heightSubdivisions, float thickness, Operation<Void> original) {
|
||||
if (GLStateManager.isRecordingDisplayList() || TessellatorManager.isCurrentlyCapturing() || TessellatorManager.shouldInterceptDraw(Tessellator.instance)) {
|
||||
original.call(tessellator, minU, minV, maxU, maxV, widthSubdivisions, heightSubdivisions, thickness);
|
||||
return;
|
||||
}
|
||||
final ItemRenderListManager.CachedVBO vbo = ItemRenderListManager.pre(minU, minV, maxU, maxV, widthSubdivisions, heightSubdivisions, thickness);
|
||||
if (vbo != null) {
|
||||
final DirectTessellator tess = TessellatorManager.startCapturingDirect();
|
||||
|
||||
+17
@@ -1,12 +1,15 @@
|
||||
package com.gtnewhorizons.angelica.mixins.early.angelica.itemrenderer;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.TessellatorManager;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.rendering.items.BlockRenderListManager;
|
||||
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
|
||||
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.renderer.RenderBlocks;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@@ -23,6 +26,15 @@ public abstract class MixinRenderBlocks {
|
||||
@Shadow
|
||||
public IIcon overrideBlockTexture;
|
||||
|
||||
@Shadow public IBlockAccess blockAccess;
|
||||
|
||||
@Shadow public int uvRotateEast;
|
||||
@Shadow public int uvRotateWest;
|
||||
@Shadow public int uvRotateSouth;
|
||||
@Shadow public int uvRotateNorth;
|
||||
@Shadow public int uvRotateTop;
|
||||
@Shadow public int uvRotateBottom;
|
||||
|
||||
@WrapMethod(method = "renderBlockAsItem")
|
||||
private void angelica$cacheBlockItemRenderer(Block block, int meta, float brightness, Operation<Void> original) {
|
||||
if (BlockRenderListManager.isISBRH(block.getRenderType())
|
||||
@@ -30,6 +42,11 @@ public abstract class MixinRenderBlocks {
|
||||
|| this.overrideBlockTexture != null
|
||||
|| brightness != 1.0F
|
||||
|| !this.useInventoryTint
|
||||
|| this.blockAccess != null
|
||||
|| (uvRotateEast | uvRotateWest | uvRotateSouth | uvRotateNorth | uvRotateTop | uvRotateBottom) != 0
|
||||
|| GLStateManager.isRecordingDisplayList()
|
||||
|| TessellatorManager.isCurrentlyCapturing()
|
||||
|| TessellatorManager.shouldInterceptDraw(Tessellator.instance)
|
||||
) {
|
||||
// Do not cache those
|
||||
original.call(block, meta, brightness);
|
||||
|
||||
+5
@@ -248,4 +248,9 @@ public abstract class MixinRenderBlocks implements ExtCeleritasRenderBlocks {
|
||||
private void compactCtm_resetAfterBlock(Block block, int x, int y, int z, CallbackInfoReturnable<Boolean> cir) {
|
||||
CTMUtils.clearCurrentCompact();
|
||||
}
|
||||
|
||||
@Inject(method = "renderBlockAsItem", at = @At("HEAD"))
|
||||
private void compactCtm_resetBeforeItem(Block block, int meta, float brightness, CallbackInfo ci) {
|
||||
CTMUtils.clearCurrentCompact();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user