mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-11-08 12:35:01 +00:00
Fix some GLSM bypasses (#2099)
This commit is contained in:
1 parent
81b82748ce
commit
a07cecb879
39 files changed
+2176
-247
No files matched your search
@@ -27,6 +27,7 @@ import com.gtnewhorizons.angelica.glsm.states.ClipPlaneState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.Color4;
|
||||
import com.gtnewhorizons.angelica.glsm.states.PixelUnpackState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.ImageUnitArray;
|
||||
import com.gtnewhorizons.angelica.glsm.states.SamplerUnitArray;
|
||||
import com.gtnewhorizons.angelica.glsm.states.TextureUnitArray;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntStack;
|
||||
@@ -101,6 +102,7 @@ class GLContextState {
|
||||
public final IntegerStateStack shadeModelState = new IntegerStateStack(GL11.GL_SMOOTH);
|
||||
public final TextureUnitArray textures = new TextureUnitArray();
|
||||
public final ImageUnitArray imageUnits = new ImageUnitArray();
|
||||
public final SamplerUnitArray samplerUnits = new SamplerUnitArray();
|
||||
public final BlendStateStack blendState = new BlendStateStack();
|
||||
public final BooleanStateStack blendMode = track(new BooleanStateStack(GL11.GL_BLEND));
|
||||
public final BooleanStateStack scissorTest = track(new BooleanStateStack(GL11.GL_SCISSOR_TEST));
|
||||
|
||||
@@ -52,6 +52,7 @@ import com.gtnewhorizons.angelica.glsm.states.ClipPlaneState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.Color4;
|
||||
import com.gtnewhorizons.angelica.glsm.states.PixelUnpackState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.PolygonState;
|
||||
import com.gtnewhorizons.angelica.glsm.states.SamplerUnitArray;
|
||||
import com.gtnewhorizons.angelica.glsm.states.ImageUnitBinding;
|
||||
import com.gtnewhorizons.angelica.glsm.states.TextureBinding;
|
||||
import com.gtnewhorizons.angelica.glsm.states.TextureUnitArray;
|
||||
@@ -91,6 +92,7 @@ import org.lwjgl.opengl.GL21;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL31;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.opengl.GL33;
|
||||
import org.lwjgl.opengl.GLContext;
|
||||
import org.lwjgl.opengl.KHRDebug;
|
||||
import org.lwjgl.opengl.KHRDebugCallback;
|
||||
@@ -1054,6 +1056,8 @@ public class GLStateManager {
|
||||
case GL30.GL_DRAW_FRAMEBUFFER_BINDING -> glCtx.drawFramebuffer;
|
||||
case GL30.GL_READ_FRAMEBUFFER_BINDING -> glCtx.readFramebuffer;
|
||||
|
||||
case GL33.GL_SAMPLER_BINDING -> glCtx.samplerUnits.get(glCtx.activeTextureUnit.getValue());
|
||||
|
||||
default -> switch (pname) {
|
||||
case GL11.GL_FOG_MODE -> glCtx.fogState.getFogMode();
|
||||
case GL11.GL_LINE_STIPPLE_PATTERN -> glCtx.lineState.getStipplePattern() & 0xFFFF;
|
||||
@@ -1306,6 +1310,29 @@ public class GLStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
public static void glEnablei(int cap, int index) {
|
||||
RENDER_BACKEND.enablei(cap, index);
|
||||
markIndexedCapUnknown(cap);
|
||||
}
|
||||
|
||||
public static void glDisablei(int cap, int index) {
|
||||
RENDER_BACKEND.disablei(cap, index);
|
||||
markIndexedCapUnknown(cap);
|
||||
}
|
||||
|
||||
private static void markIndexedCapUnknown(int cap) {
|
||||
if (cap == GL11.GL_BLEND) {
|
||||
ctx().blendMode.setUnknownState();
|
||||
} else if (cap == GL11.GL_SCISSOR_TEST) {
|
||||
ctx().scissorTest.setUnknownState();
|
||||
}
|
||||
}
|
||||
|
||||
public static void glBlendFuncSeparatei(int buf, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) {
|
||||
RENDER_BACKEND.blendFuncSeparatei(buf, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
ctx().blendState.setFuncUnknownState();
|
||||
}
|
||||
|
||||
public static void enableBlend() {
|
||||
final RecordMode mode = DisplayListManager.getRecordMode();
|
||||
if (mode != RecordMode.NONE) {
|
||||
@@ -1451,6 +1478,7 @@ public class GLStateManager {
|
||||
final boolean caching = isCachingEnabled();
|
||||
if (GLSMConfig.hudCacheOverride) {
|
||||
glCtx.blendState.setAll(srcFactor, dstFactor, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
glCtx.blendState.clearFuncUnknownState();
|
||||
RENDER_BACKEND.blendFuncSeparate(srcFactor, dstFactor, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
if (GLSMHooks.BLEND_FUNC_CHANGE.hasListeners()) {
|
||||
GLSMHooks.blendFuncChangeEvent.srcRgb = srcFactor;
|
||||
@@ -1467,8 +1495,10 @@ public class GLStateManager {
|
||||
|| glCtx.blendState.getSrcRgb() != srcFactor
|
||||
|| glCtx.blendState.getDstRgb() != dstFactor
|
||||
|| glCtx.blendState.getSrcAlpha() != srcFactor
|
||||
|| glCtx.blendState.getDstAlpha() != dstFactor) {
|
||||
|| glCtx.blendState.getDstAlpha() != dstFactor
|
||||
|| glCtx.blendState.isFuncUnknown()) {
|
||||
glCtx.blendState.setAll(srcFactor, dstFactor, srcFactor, dstFactor);
|
||||
glCtx.blendState.clearFuncUnknownState();
|
||||
RENDER_BACKEND.blendFunc(srcFactor, dstFactor);
|
||||
if (GLSMHooks.BLEND_FUNC_CHANGE.hasListeners()) {
|
||||
GLSMHooks.blendFuncChangeEvent.srcRgb = srcFactor;
|
||||
@@ -1531,8 +1561,9 @@ public class GLStateManager {
|
||||
}
|
||||
final boolean caching = isCachingEnabled();
|
||||
final boolean bypass = !caching;
|
||||
if (bypass || glCtx.blendState.getSrcRgb() != srcRgb || glCtx.blendState.getDstRgb() != dstRgb || glCtx.blendState.getSrcAlpha() != srcAlpha || glCtx.blendState.getDstAlpha() != dstAlpha) {
|
||||
if (bypass || glCtx.blendState.getSrcRgb() != srcRgb || glCtx.blendState.getDstRgb() != dstRgb || glCtx.blendState.getSrcAlpha() != srcAlpha || glCtx.blendState.getDstAlpha() != dstAlpha || glCtx.blendState.isFuncUnknown()) {
|
||||
glCtx.blendState.setAll(srcRgb, dstRgb, srcAlpha, dstAlpha);
|
||||
glCtx.blendState.clearFuncUnknownState();
|
||||
RENDER_BACKEND.blendFuncSeparate(srcRgb, dstRgb, srcAlpha, dstAlpha);
|
||||
if (GLSMHooks.BLEND_FUNC_CHANGE.hasListeners()) {
|
||||
GLSMHooks.blendFuncChangeEvent.srcRgb = srcRgb;
|
||||
@@ -3756,6 +3787,7 @@ public class GLStateManager {
|
||||
RENDER_BACKEND.clearDepth(glCtx.depthState.getClearValue());
|
||||
|
||||
RENDER_BACKEND.blendFuncSeparate(glCtx.blendState.getSrcRgb(), glCtx.blendState.getDstRgb(), glCtx.blendState.getSrcAlpha(), glCtx.blendState.getDstAlpha());
|
||||
glCtx.blendState.clearFuncUnknownState();
|
||||
RENDER_BACKEND.blendEquationSeparate(glCtx.blendState.getEquationRgb(), glCtx.blendState.getEquationAlpha());
|
||||
RENDER_BACKEND.blendColor(glCtx.blendState.getBlendColorR(), glCtx.blendState.getBlendColorG(), glCtx.blendState.getBlendColorB(), glCtx.blendState.getBlendColorA());
|
||||
RENDER_BACKEND.colorMask(glCtx.colorMask.red, glCtx.colorMask.green, glCtx.colorMask.blue, glCtx.colorMask.alpha);
|
||||
@@ -3779,6 +3811,12 @@ public class GLStateManager {
|
||||
applyPolygonOffset(glCtx);
|
||||
RENDER_BACKEND.cullFace(glCtx.polygonState.getCullFaceMode());
|
||||
RENDER_BACKEND.frontFace(glCtx.polygonState.getFrontFace());
|
||||
|
||||
final SamplerUnitArray samplerUnits = glCtx.samplerUnits;
|
||||
for (int i = 0; i < samplerUnits.size(); i++) {
|
||||
final int sampler = samplerUnits.get(i);
|
||||
if (sampler != 0) RENDER_BACKEND.bindSampler(i, sampler);
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyPolygonOffset(GLContextState glCtx) {
|
||||
@@ -3803,13 +3841,18 @@ public class GLStateManager {
|
||||
RENDER_BACKEND.clearDepth(glCtx.depthState.getClearValue());
|
||||
}
|
||||
if ((mask & GL11.GL_COLOR_BUFFER_BIT) != 0) {
|
||||
if (glCtx.restoreBlendChanged) {
|
||||
final BlendStateStack blend = glCtx.blendState;
|
||||
if (glCtx.restoreBlendChanged || blend.isFuncUnknown()) {
|
||||
final DeferredBlendHandler restoreBlendHandler = GLSMHooks.blendHandler;
|
||||
if (restoreBlendHandler == null || !restoreBlendHandler.isOverrideHeld()) {
|
||||
RENDER_BACKEND.blendFuncSeparate(glCtx.blendState.getSrcRgb(), glCtx.blendState.getDstRgb(), glCtx.blendState.getSrcAlpha(), glCtx.blendState.getDstAlpha());
|
||||
RENDER_BACKEND.blendFuncSeparate(blend.getSrcRgb(), blend.getDstRgb(), blend.getSrcAlpha(), blend.getDstAlpha());
|
||||
blend.clearFuncUnknownState();
|
||||
}
|
||||
if (glCtx.restoreBlendChanged) {
|
||||
RENDER_BACKEND.blendEquationSeparate(blend.getEquationRgb(), blend.getEquationAlpha());
|
||||
RENDER_BACKEND.blendColor(
|
||||
blend.getBlendColorR(), blend.getBlendColorG(), blend.getBlendColorB(), blend.getBlendColorA());
|
||||
}
|
||||
RENDER_BACKEND.blendEquationSeparate(glCtx.blendState.getEquationRgb(), glCtx.blendState.getEquationAlpha());
|
||||
RENDER_BACKEND.blendColor(glCtx.blendState.getBlendColorR(), glCtx.blendState.getBlendColorG(), glCtx.blendState.getBlendColorB(), glCtx.blendState.getBlendColorA());
|
||||
}
|
||||
if (glCtx.restoreColorMaskChanged && !isDepthColorOverridden()) {
|
||||
RENDER_BACKEND.colorMask(glCtx.colorMask.red, glCtx.colorMask.green, glCtx.colorMask.blue, glCtx.colorMask.alpha);
|
||||
@@ -4721,8 +4764,61 @@ public class GLStateManager {
|
||||
public static void glClearTexImage(int texture, int level, int format, int type, ByteBuffer data) { RENDER_BACKEND.clearTexImage(texture, level, format, type); }
|
||||
|
||||
public static int glGenSamplers() { return RENDER_BACKEND.genSamplers(); }
|
||||
public static void glDeleteSamplers(int sampler) { RENDER_BACKEND.deleteSamplers(sampler); }
|
||||
public static void glBindSampler(int unit, int sampler) { RENDER_BACKEND.bindSampler(unit, sampler); }
|
||||
|
||||
public static void glGenSamplers(IntBuffer samplers) {
|
||||
for (int i = samplers.position(); i < samplers.limit(); i++) samplers.put(i, RENDER_BACKEND.genSamplers());
|
||||
}
|
||||
|
||||
public static void glGenSamplers(int[] samplers) {
|
||||
for (int i = 0; i < samplers.length; i++) samplers[i] = RENDER_BACKEND.genSamplers();
|
||||
}
|
||||
|
||||
public static void glDeleteSamplers(int sampler) {
|
||||
if (sampler == 0) return;
|
||||
ctx().samplerUnits.unbindEverywhere(sampler);
|
||||
RENDER_BACKEND.deleteSamplers(sampler);
|
||||
}
|
||||
|
||||
public static void glDeleteSamplers(IntBuffer samplers) {
|
||||
for (int i = samplers.position(); i < samplers.limit(); i++) glDeleteSamplers(samplers.get(i));
|
||||
}
|
||||
|
||||
public static void glDeleteSamplers(int[] samplers) {
|
||||
for (int sampler : samplers) glDeleteSamplers(sampler);
|
||||
}
|
||||
|
||||
public static void glBindSampler(int unit, int sampler) {
|
||||
final SamplerUnitArray units = ctx().samplerUnits;
|
||||
if (isCachingEnabled() && unit >= 0 && unit < units.size() && units.get(unit) == sampler) return;
|
||||
if (!units.set(unit, sampler)) {
|
||||
warnOnce("samplerUnitRange", "glBindSampler unit {} exceeds GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS {}", unit, units.size());
|
||||
}
|
||||
RENDER_BACKEND.bindSampler(unit, sampler);
|
||||
}
|
||||
|
||||
public static void glBindSamplers(int first, int count, IntBuffer samplers) {
|
||||
if (samplers == null) {
|
||||
for (int i = 0; i < count; i++) glBindSampler(first + i, 0);
|
||||
return;
|
||||
}
|
||||
if (samplers.remaining() < count) {
|
||||
throw new IllegalArgumentException("Number of remaining buffer elements is " + samplers.remaining() + ", must be at least " + count);
|
||||
}
|
||||
final int base = samplers.position();
|
||||
for (int i = 0; i < count; i++) glBindSampler(first + i, samplers.get(base + i));
|
||||
}
|
||||
|
||||
public static void glBindSamplers(int first, IntBuffer samplers) {
|
||||
if (samplers != null) glBindSamplers(first, samplers.remaining(), samplers);
|
||||
}
|
||||
|
||||
public static void glBindSamplers(int first, int[] samplers) {
|
||||
if (samplers == null) return;
|
||||
for (int i = 0; i < samplers.length; i++) glBindSampler(first + i, samplers[i]);
|
||||
}
|
||||
|
||||
public static int getSamplerBinding(int unit) { return ctx().samplerUnits.get(unit); }
|
||||
public static int getSamplerUnitCount() { return ctx().samplerUnits.size(); }
|
||||
public static void glSamplerParameteri(int sampler, int pname, int param) { RENDER_BACKEND.samplerParameteri(sampler, pname, param); }
|
||||
public static void glSamplerParameterf(int sampler, int pname, float param) { RENDER_BACKEND.samplerParameterf(sampler, pname, param); }
|
||||
|
||||
@@ -6173,6 +6269,10 @@ public class GLStateManager {
|
||||
public static ByteBuffer glMapBuffer(int target, int access, long length, ByteBuffer old_buffer) { onBufferMap(target, access); return RENDER_BACKEND.mapBuffer(target, access, length, old_buffer); }
|
||||
public static ByteBuffer glMapBufferRange(int target, long offset, long length, int access) { onBufferMapRange(target, 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 long glMapBufferRangeAddress(int target, long offset, long length, int access) {
|
||||
onBufferMapRange(target, access);
|
||||
return RENDER_BACKEND.mapBufferRangeAddress(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) { onBufferUnmap(target); return RENDER_BACKEND.unmapBuffer(target); }
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ public class RenderSystem {
|
||||
private static boolean supportsTesselation;
|
||||
private static boolean supportsSamplerObjects;
|
||||
private static int maxImageUnits;
|
||||
@Getter private static int maxCombinedTextureImageUnits;
|
||||
private static int maxSSBOBindings;
|
||||
private static int maxGlslVersion;
|
||||
private static boolean supportsGpuShader4;
|
||||
@@ -64,9 +65,6 @@ public class RenderSystem {
|
||||
private static volatile boolean isLTW;
|
||||
private static volatile boolean ltwDetected;
|
||||
|
||||
// Sampler object state tracking (null if unsupported)
|
||||
private static int[] samplers;
|
||||
|
||||
private static final Pattern SEMVER_PATTERN = Pattern.compile("(?<major>\\d+)\\.(?<minor>\\d+)\\.*(?<bugfix>\\d*)(.*)");
|
||||
|
||||
private RenderSystem() {}
|
||||
@@ -158,7 +156,7 @@ public class RenderSystem {
|
||||
// Check for sampler objects support (GL 3.3+ or ARB extension)
|
||||
supportsSamplerObjects = GLStateManager.capabilities.OpenGL33 || GLStateManager.capabilities.GL_ARB_sampler_objects;
|
||||
if (supportsSamplerObjects) {
|
||||
samplers = new int[RENDER_BACKEND.getInteger(GL20.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)];
|
||||
maxCombinedTextureImageUnits = RENDER_BACKEND.getInteger(GL20.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
|
||||
}
|
||||
|
||||
maxGlslVersion = Integer.parseInt(parseGlVersionString(RENDER_BACKEND.getString(GL20.GL_SHADING_LANGUAGE_VERSION)));
|
||||
@@ -486,17 +484,15 @@ public class RenderSystem {
|
||||
}
|
||||
|
||||
public static void disableBufferBlend(int buffer) {
|
||||
RENDER_BACKEND.disablei(GL11.GL_BLEND, buffer);
|
||||
GLStateManager.getBlendMode().setUnknownState();
|
||||
GLStateManager.glDisablei(GL11.GL_BLEND, buffer);
|
||||
}
|
||||
|
||||
public static void enableBufferBlend(int buffer) {
|
||||
RENDER_BACKEND.enablei(GL11.GL_BLEND, buffer);
|
||||
GLStateManager.getBlendMode().setUnknownState();
|
||||
GLStateManager.glEnablei(GL11.GL_BLEND, buffer);
|
||||
}
|
||||
|
||||
public static void blendFuncSeparatei(int buffer, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) {
|
||||
RENDER_BACKEND.blendFuncSeparatei(buffer, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
GLStateManager.glBlendFuncSeparatei(buffer, srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
}
|
||||
|
||||
public static void bindTextureToUnit(int unit, int texture) {
|
||||
@@ -628,7 +624,7 @@ public class RenderSystem {
|
||||
|
||||
public static int genSampler() {
|
||||
if (!supportsSamplerObjects) return 0;
|
||||
return RENDER_BACKEND.genSamplers();
|
||||
return GLStateManager.glGenSamplers();
|
||||
}
|
||||
|
||||
public static void destroySampler(int sampler) {
|
||||
@@ -638,22 +634,20 @@ public class RenderSystem {
|
||||
|
||||
public static void samplerParameteri(int sampler, int pname, int param) {
|
||||
if (!supportsSamplerObjects || sampler == 0) return;
|
||||
RENDER_BACKEND.samplerParameteri(sampler, pname, param);
|
||||
GLStateManager.glSamplerParameteri(sampler, pname, param);
|
||||
}
|
||||
|
||||
public static void bindSamplerToUnit(int unit, int sampler) {
|
||||
if (!supportsSamplerObjects) return;
|
||||
if (samplers[unit] == sampler) return;
|
||||
RENDER_BACKEND.bindSampler(unit, sampler);
|
||||
samplers[unit] = sampler;
|
||||
GLStateManager.glBindSampler(unit, sampler);
|
||||
}
|
||||
|
||||
public static void unbindAllSamplers() {
|
||||
if (!supportsSamplerObjects) return;
|
||||
for (int i = 0; i < samplers.length; i++) {
|
||||
if (samplers[i] != 0) {
|
||||
RENDER_BACKEND.bindSampler(i, 0);
|
||||
samplers[i] = 0;
|
||||
final int count = GLStateManager.getSamplerUnitCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (GLStateManager.getSamplerBinding(i) != 0) {
|
||||
GLStateManager.glBindSampler(i, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ public abstract class RenderBackend {
|
||||
|
||||
public String getTransferDebugInfo() { return null; }
|
||||
|
||||
public boolean bindVoxelizationRegion(int ssboBinding, int vertexBufferGlId, long openPass, float x, float y, float z) { return false; }
|
||||
public boolean bindVoxelizationRegion(int ssboBinding, long openPass, float x, float y, float z) { return false; }
|
||||
public long beginVoxelizationBatch(int ssboBinding) { return 0L; }
|
||||
public void voxelizeRange(long pass, int vertexOffset, int vertexCount) {}
|
||||
public void endVoxelizationBatch(long pass) {}
|
||||
|
||||
@@ -164,6 +164,8 @@ public class GLSMRedirector {
|
||||
private static final String EXTGPUShader4 = "org/lwjgl/opengl/EXTGPUShader4";
|
||||
private static final String ARBTimerQuery = "org/lwjgl/opengl/ARBTimerQuery";
|
||||
private static final String EXTTimerQuery = "org/lwjgl/opengl/EXTTimerQuery";
|
||||
private static final String ARBSamplerObjects = "org/lwjgl/opengl/ARBSamplerObjects";
|
||||
private static final String ARBMultiBind = "org/lwjgl/opengl/ARBMultiBind";
|
||||
|
||||
// Redirect VAO related calls from NHLib
|
||||
private static final String UniversalVAO = "com/gtnewhorizon/gtnhlib/client/opengl/UniversalVAO";
|
||||
@@ -555,6 +557,7 @@ public class GLSMRedirector {
|
||||
.add("glMultiDrawElementsIndirect");
|
||||
final var gl44 = RedirectMap.newMap()
|
||||
.add("glBufferStorage")
|
||||
.add("glBindSamplers")
|
||||
.add("glClearTexImage");
|
||||
final var gl45 = RedirectMap.newMap()
|
||||
.add("glCreateBuffers")
|
||||
@@ -767,6 +770,17 @@ public class GLSMRedirector {
|
||||
.add("glMapBufferRange")
|
||||
.add("glFlushMappedBufferRange")
|
||||
);
|
||||
methodRedirects.put(ARBSamplerObjects, RedirectMap.newMap()
|
||||
.add("glGenSamplers")
|
||||
.add("glDeleteSamplers")
|
||||
.add("glIsSampler")
|
||||
.add("glBindSampler")
|
||||
.add("glSamplerParameteri")
|
||||
.add("glSamplerParameterf")
|
||||
);
|
||||
methodRedirects.put(ARBMultiBind, RedirectMap.newMap()
|
||||
.add("glBindSamplers")
|
||||
);
|
||||
|
||||
// APPLE
|
||||
methodRedirects.put(APPLEVertexArrayObject, RedirectMap.newMap()
|
||||
|
||||
@@ -12,6 +12,8 @@ public class BlendStateStack extends BlendState implements IStateStack<BlendStat
|
||||
|
||||
protected int pointer;
|
||||
|
||||
private boolean funcUnknown;
|
||||
|
||||
@Setter private VanillaStateLayer<BlendState> vanillaLayer;
|
||||
|
||||
public BlendStateStack() {
|
||||
@@ -44,6 +46,18 @@ public class BlendStateStack extends BlendState implements IStateStack<BlendStat
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setFuncUnknownState() {
|
||||
funcUnknown = true;
|
||||
}
|
||||
|
||||
public boolean isFuncUnknown() {
|
||||
return funcUnknown;
|
||||
}
|
||||
|
||||
public void clearFuncUnknownState() {
|
||||
funcUnknown = false;
|
||||
}
|
||||
|
||||
public BlendState readEffective(BlendState out) {
|
||||
out.set(this);
|
||||
VanillaStateLayer.capture(vanillaLayer, out);
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.gtnewhorizons.angelica.glsm.states;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
|
||||
public class SamplerUnitArray {
|
||||
|
||||
private static final int MIN_UNITS = 16;
|
||||
|
||||
private int[] samplers;
|
||||
|
||||
public int get(int unit) {
|
||||
final int[] local = samplers;
|
||||
return local != null && unit >= 0 && unit < local.length ? local[unit] : 0;
|
||||
}
|
||||
|
||||
public boolean set(int unit, int sampler) {
|
||||
if (unit < 0) return false;
|
||||
int[] local = samplers;
|
||||
if (local == null) {
|
||||
local = new int[Math.max(MIN_UNITS, RenderSystem.getMaxCombinedTextureImageUnits())];
|
||||
samplers = local;
|
||||
}
|
||||
if (unit >= local.length) return false;
|
||||
local[unit] = sampler;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void unbindEverywhere(int sampler) {
|
||||
final int[] local = samplers;
|
||||
if (local == null) return;
|
||||
for (int i = 0; i < local.length; i++) {
|
||||
if (local[i] == sampler) local[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int size() {
|
||||
final int[] local = samplers;
|
||||
return local == null ? 0 : local.length;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,8 @@ package com.gtnewhorizons.angelica.glsm.streaming;
|
||||
import com.gtnewhorizons.angelica.config.SystemProperties;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayFIFOQueue;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue;
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.opengl.GL44;
|
||||
@@ -11,7 +12,6 @@ import org.lwjgl.opengl.GL44;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAddress0;
|
||||
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
|
||||
|
||||
/**
|
||||
* Persistent-mapped fence-reclaimed ring over any buffer target. Callers reserve a range and
|
||||
@@ -28,7 +28,8 @@ final class GlStreamingRing {
|
||||
private static final long SYNC_WAIT_SLICE_NANOS = 10_000_000L;
|
||||
private static final long SYNC_WAIT_TOTAL_NANOS = 5_000_000_000L;
|
||||
|
||||
private final ObjectArrayFIFOQueue<FencedRegion> fenceQueue = new ObjectArrayFIFOQueue<>();
|
||||
private final LongArrayFIFOQueue fenceIds = new LongArrayFIFOQueue();
|
||||
private final IntArrayFIFOQueue fenceBytes = new IntArrayFIFOQueue();
|
||||
private int writePos;
|
||||
private int remaining;
|
||||
private int pendingBytes;
|
||||
@@ -51,13 +52,13 @@ final class GlStreamingRing {
|
||||
|
||||
static GlStreamingRing create(int target, int capacity, boolean forceOrphan) {
|
||||
if (forceOrphan || !RenderSystem.supportsBufferStorage()) return null;
|
||||
final int id = RENDER_BACKEND.genBuffers();
|
||||
RENDER_BACKEND.bindBuffer(target, id);
|
||||
final int id = GLStateManager.glGenBuffers();
|
||||
GLStateManager.glBindBuffer(target, id);
|
||||
final int storageFlags = GL44.GL_MAP_PERSISTENT_BIT | GL30.GL_MAP_WRITE_BIT | GL44.GL_MAP_COHERENT_BIT | GL44.GL_CLIENT_STORAGE_BIT;
|
||||
RenderSystem.bufferStorage(target, capacity, storageFlags);
|
||||
final int mapFlags = GL44.GL_MAP_PERSISTENT_BIT | GL30.GL_MAP_WRITE_BIT | GL44.GL_MAP_COHERENT_BIT;
|
||||
final ByteBuffer mapped = RENDER_BACKEND.mapBufferRange(target, 0, capacity, mapFlags);
|
||||
RENDER_BACKEND.bindBuffer(target, 0);
|
||||
final ByteBuffer mapped = GLStateManager.glMapBufferRange(target, 0, capacity, mapFlags);
|
||||
GLStateManager.glBindBuffer(target, 0);
|
||||
if (mapped == null) {
|
||||
GLStateManager.glDeleteBuffers(id);
|
||||
GLStateManager.LOGGER.warn("Persistent map failed for streaming ring (target=0x{}, {} bytes)", Integer.toHexString(target), capacity);
|
||||
@@ -92,7 +93,7 @@ final class GlStreamingRing {
|
||||
|
||||
private boolean ensureRemaining(int needed) {
|
||||
while (remaining < needed) {
|
||||
if (fenceQueue.isEmpty()) {
|
||||
if (fenceIds.isEmpty()) {
|
||||
if (pendingBytes == 0) return false;
|
||||
fence();
|
||||
}
|
||||
@@ -103,7 +104,8 @@ final class GlStreamingRing {
|
||||
|
||||
private void fence() {
|
||||
if (pendingBytes > 0) {
|
||||
fenceQueue.enqueue(new FencedRegion(RENDER_BACKEND.fenceSync(GL32.GL_SYNC_GPU_COMMANDS_COMPLETE, 0), pendingBytes));
|
||||
fenceIds.enqueue(GLStateManager.glFenceSync(GL32.GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
|
||||
fenceBytes.enqueue(pendingBytes);
|
||||
pendingBytes = 0;
|
||||
fencesIssued++;
|
||||
}
|
||||
@@ -114,30 +116,32 @@ final class GlStreamingRing {
|
||||
}
|
||||
|
||||
private void reclaim() {
|
||||
while (!fenceQueue.isEmpty()) {
|
||||
final FencedRegion region = fenceQueue.first();
|
||||
if (!signaled(RENDER_BACKEND.clientWaitSync(region.fenceId, 0, 0L))) break;
|
||||
GLStateManager.glDeleteSync(region.fenceId);
|
||||
fenceQueue.dequeue();
|
||||
remaining += region.bytes;
|
||||
while (!fenceIds.isEmpty()) {
|
||||
final long fenceId = fenceIds.firstLong();
|
||||
if (!signaled(GLStateManager.glClientWaitSync(fenceId, 0, 0L))) break;
|
||||
GLStateManager.glDeleteSync(fenceId);
|
||||
fenceIds.dequeueLong();
|
||||
remaining += fenceBytes.dequeueInt();
|
||||
}
|
||||
}
|
||||
|
||||
private void syncOldest() {
|
||||
final FencedRegion region = fenceQueue.dequeue();
|
||||
final long fenceId = fenceIds.dequeueLong();
|
||||
final int bytes = fenceBytes.dequeueInt();
|
||||
forcedReclaims++;
|
||||
final long deadline = System.nanoTime() + SYNC_WAIT_TOTAL_NANOS;
|
||||
long remainingNanos = SYNC_WAIT_TOTAL_NANOS;
|
||||
int status;
|
||||
do {
|
||||
status = RENDER_BACKEND.clientWaitSync(region.fenceId, GL32.GL_SYNC_FLUSH_COMMANDS_BIT, Math.min(SYNC_WAIT_SLICE_NANOS, remainingNanos));
|
||||
status = GLStateManager.glClientWaitSync(fenceId, GL32.GL_SYNC_FLUSH_COMMANDS_BIT,
|
||||
Math.min(SYNC_WAIT_SLICE_NANOS, remainingNanos));
|
||||
remainingNanos = deadline - System.nanoTime();
|
||||
} while (status == GL32.GL_TIMEOUT_EXPIRED && remainingNanos > 0);
|
||||
if (!signaled(status)) {
|
||||
GLStateManager.LOGGER.warn("Streaming ring fence wait did not signal (status=0x{}); reclaiming anyway", Integer.toHexString(status));
|
||||
}
|
||||
GLStateManager.glDeleteSync(region.fenceId);
|
||||
remaining += region.bytes;
|
||||
GLStateManager.glDeleteSync(fenceId);
|
||||
remaining += bytes;
|
||||
reclaim();
|
||||
}
|
||||
|
||||
@@ -156,17 +160,16 @@ final class GlStreamingRing {
|
||||
int forcedReclaims() { return forcedReclaims; }
|
||||
|
||||
void destroy() {
|
||||
while (!fenceQueue.isEmpty()) {
|
||||
GLStateManager.glDeleteSync(fenceQueue.dequeue().fenceId);
|
||||
while (!fenceIds.isEmpty()) {
|
||||
GLStateManager.glDeleteSync(fenceIds.dequeueLong());
|
||||
}
|
||||
fenceBytes.clear();
|
||||
if (bufferId != 0) {
|
||||
RENDER_BACKEND.bindBuffer(target, bufferId);
|
||||
RENDER_BACKEND.unmapBuffer(target);
|
||||
RENDER_BACKEND.bindBuffer(target, 0);
|
||||
GLStateManager.glBindBuffer(target, bufferId);
|
||||
GLStateManager.glUnmapBuffer(target);
|
||||
GLStateManager.glBindBuffer(target, 0);
|
||||
GLStateManager.glDeleteBuffers(bufferId);
|
||||
bufferId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private record FencedRegion(long fenceId, int bytes) {}
|
||||
}
|
||||
+5
-7
@@ -5,8 +5,6 @@ import org.lwjgl.opengl.GL15;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
|
||||
|
||||
/**
|
||||
* Streaming buffer using the classic orphan pattern.
|
||||
*/
|
||||
@@ -16,19 +14,19 @@ public final class OrphanStreamingBuffer {
|
||||
private int capacity;
|
||||
|
||||
public OrphanStreamingBuffer() {
|
||||
this.bufferId = RENDER_BACKEND.genBuffers();
|
||||
this.bufferId = GLStateManager.glGenBuffers();
|
||||
}
|
||||
|
||||
public void upload(ByteBuffer data) {
|
||||
RENDER_BACKEND.bindBuffer(GL15.GL_ARRAY_BUFFER, bufferId);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, bufferId);
|
||||
capacity = StreamingUploader.upload(data, capacity);
|
||||
RENDER_BACKEND.bindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
void upload(StreamingUploader.UploadStrategy strategy, ByteBuffer data) {
|
||||
RENDER_BACKEND.bindBuffer(GL15.GL_ARRAY_BUFFER, bufferId);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, bufferId);
|
||||
capacity = StreamingUploader.upload(strategy, data, capacity);
|
||||
RENDER_BACKEND.bindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
public int getCapacity() {
|
||||
|
||||
@@ -7,7 +7,6 @@ import org.lwjgl.opengl.GL30;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAddress0;
|
||||
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memCopy;
|
||||
|
||||
|
||||
@@ -28,30 +27,30 @@ public final class StreamingUploader {
|
||||
public static int upload(UploadStrategy strategy, ByteBuffer data, int capacity) {
|
||||
switch (strategy) {
|
||||
case BUFFER_DATA -> {
|
||||
RENDER_BACKEND.bufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STREAM_DRAW);
|
||||
GLStateManager.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STREAM_DRAW);
|
||||
return data.remaining();
|
||||
}
|
||||
case BUFFER_SUB_DATA -> {
|
||||
if (data.remaining() > capacity) {
|
||||
RENDER_BACKEND.bufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STREAM_DRAW);
|
||||
GLStateManager.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STREAM_DRAW);
|
||||
return data.remaining();
|
||||
}
|
||||
RENDER_BACKEND.bufferSubData(GL15.GL_ARRAY_BUFFER, 0, data);
|
||||
GLStateManager.glBufferSubData(GL15.GL_ARRAY_BUFFER, 0, data);
|
||||
return capacity;
|
||||
}
|
||||
case MAP_BUFFER_RANGE -> {
|
||||
if (data.remaining() > capacity) {
|
||||
RENDER_BACKEND.bufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STREAM_DRAW);
|
||||
GLStateManager.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STREAM_DRAW);
|
||||
return data.remaining();
|
||||
}
|
||||
final int dataSize = data.remaining();
|
||||
final long dst = RENDER_BACKEND.mapBufferRangeAddress(GL15.GL_ARRAY_BUFFER, 0, dataSize, MAP_WRITE_INVALIDATE_BUFFER);
|
||||
final long dst = GLStateManager.glMapBufferRangeAddress(GL15.GL_ARRAY_BUFFER, 0, dataSize, MAP_WRITE_INVALIDATE_BUFFER);
|
||||
if (dst == 0L) {
|
||||
RENDER_BACKEND.bufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STREAM_DRAW);
|
||||
GLStateManager.glBufferData(GL15.GL_ARRAY_BUFFER, data, GL15.GL_STREAM_DRAW);
|
||||
return data.remaining();
|
||||
}
|
||||
memCopy(memAddress0(data), dst, dataSize);
|
||||
RENDER_BACKEND.unmapBuffer(GL15.GL_ARRAY_BUFFER);
|
||||
GLStateManager.glUnmapBuffer(GL15.GL_ARRAY_BUFFER);
|
||||
return capacity;
|
||||
}
|
||||
default -> throw new UnsupportedOperationException();
|
||||
|
||||
+9
-10
@@ -10,7 +10,6 @@ import java.nio.ByteBuffer;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAddress0;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memCopy;
|
||||
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
|
||||
|
||||
public final class UniformRingBuffer {
|
||||
|
||||
@@ -35,10 +34,10 @@ public final class UniformRingBuffer {
|
||||
this.stride = (blockSize + OFFSET_ALIGNMENT - 1) & -OFFSET_ALIGNMENT;
|
||||
this.ring = GlStreamingRing.create(GL31.GL_UNIFORM_BUFFER, capacity, forceOrphan);
|
||||
if (ring == null) {
|
||||
orphanBufferId = RENDER_BACKEND.genBuffers();
|
||||
RENDER_BACKEND.bindBuffer(GL31.GL_UNIFORM_BUFFER, orphanBufferId);
|
||||
RENDER_BACKEND.bufferData(GL31.GL_UNIFORM_BUFFER, capacity, GL15.GL_STREAM_DRAW);
|
||||
RENDER_BACKEND.bindBuffer(GL31.GL_UNIFORM_BUFFER, 0);
|
||||
orphanBufferId = GLStateManager.glGenBuffers();
|
||||
GLStateManager.glBindBuffer(GL31.GL_UNIFORM_BUFFER, orphanBufferId);
|
||||
GLStateManager.glBufferData(GL31.GL_UNIFORM_BUFFER, capacity, GL15.GL_STREAM_DRAW);
|
||||
GLStateManager.glBindBuffer(GL31.GL_UNIFORM_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,20 +55,20 @@ public final class UniformRingBuffer {
|
||||
}
|
||||
|
||||
private int writeOrphan(long srcAddress) {
|
||||
RENDER_BACKEND.bindBuffer(GL31.GL_UNIFORM_BUFFER, orphanBufferId);
|
||||
GLStateManager.glBindBuffer(GL31.GL_UNIFORM_BUFFER, orphanBufferId);
|
||||
int offset = writePos;
|
||||
if (offset + stride > capacity) {
|
||||
RENDER_BACKEND.bufferData(GL31.GL_UNIFORM_BUFFER, capacity, GL15.GL_STREAM_DRAW);
|
||||
GLStateManager.glBufferData(GL31.GL_UNIFORM_BUFFER, capacity, GL15.GL_STREAM_DRAW);
|
||||
offset = 0;
|
||||
orphanWraps++;
|
||||
}
|
||||
final long dst = RENDER_BACKEND.mapBufferRangeAddress(GL31.GL_UNIFORM_BUFFER, offset, blockSize, GL30.GL_MAP_WRITE_BIT | GL30.GL_MAP_INVALIDATE_RANGE_BIT | GL30.GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
final long dst = GLStateManager.glMapBufferRangeAddress(GL31.GL_UNIFORM_BUFFER, offset, blockSize, GL30.GL_MAP_WRITE_BIT | GL30.GL_MAP_INVALIDATE_RANGE_BIT | GL30.GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
if (dst == 0L) {
|
||||
throw new IllegalStateException("mapBufferRange failed on uniform ring (offset=" + offset + ")");
|
||||
}
|
||||
memCopy(srcAddress, dst, blockSize);
|
||||
RENDER_BACKEND.unmapBuffer(GL31.GL_UNIFORM_BUFFER);
|
||||
RENDER_BACKEND.bindBuffer(GL31.GL_UNIFORM_BUFFER, 0);
|
||||
GLStateManager.glUnmapBuffer(GL31.GL_UNIFORM_BUFFER);
|
||||
GLStateManager.glBindBuffer(GL31.GL_UNIFORM_BUFFER, 0);
|
||||
writePos = offset + stride;
|
||||
return offset;
|
||||
}
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL14;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
@GLCoreTest
|
||||
class GLSM_BlendFuncUnknownState_GLTest {
|
||||
|
||||
private static final int VANILLA_SRC_RGB = GL11.GL_SRC_ALPHA;
|
||||
private static final int VANILLA_DST_RGB = GL11.GL_ONE_MINUS_SRC_ALPHA;
|
||||
private static final int VANILLA_SRC_ALPHA = GL11.GL_ONE;
|
||||
private static final int VANILLA_DST_ALPHA = GL11.GL_ZERO;
|
||||
|
||||
@BeforeEach
|
||||
void requireBufferBlending() {
|
||||
assumeTrue(RenderSystem.supportsBufferBlending());
|
||||
drainGlErrors();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void restoreDefaultBlendFunc() {
|
||||
if (!RenderSystem.supportsBufferBlending()) return;
|
||||
GLStateManager.tryBlendFuncSeparate(GL11.GL_ZERO, GL11.GL_ZERO, GL11.GL_ZERO, GL11.GL_ZERO);
|
||||
GLStateManager.tryBlendFuncSeparate(GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
drainGlErrors();
|
||||
}
|
||||
|
||||
private static void drainGlErrors() {
|
||||
while (GL11.glGetError() != GL11.GL_NO_ERROR) {}
|
||||
}
|
||||
|
||||
private static void seedVanillaSeparate() {
|
||||
GLStateManager.tryBlendFuncSeparate(GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE);
|
||||
GLStateManager.tryBlendFuncSeparate(VANILLA_SRC_RGB, VANILLA_DST_RGB, VANILLA_SRC_ALPHA, VANILLA_DST_ALPHA);
|
||||
}
|
||||
|
||||
private static void overrideBufferZero() {
|
||||
RenderSystem.blendFuncSeparatei(0, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE);
|
||||
assertBufferBlend(0, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE);
|
||||
}
|
||||
|
||||
private static void assertBufferBlend(int buffer, int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) {
|
||||
assertEquals(srcRgb, GL30.glGetInteger(GL14.GL_BLEND_SRC_RGB, buffer), "buffer " + buffer + " src rgb");
|
||||
assertEquals(dstRgb, GL30.glGetInteger(GL14.GL_BLEND_DST_RGB, buffer), "buffer " + buffer + " dst rgb");
|
||||
assertEquals(srcAlpha, GL30.glGetInteger(GL14.GL_BLEND_SRC_ALPHA, buffer), "buffer " + buffer + " src alpha");
|
||||
assertEquals(dstAlpha, GL30.glGetInteger(GL14.GL_BLEND_DST_ALPHA, buffer), "buffer " + buffer + " dst alpha");
|
||||
}
|
||||
|
||||
private static void assertVanillaOnBothBuffers() {
|
||||
for (int buffer = 0; buffer < 2; buffer++) {
|
||||
assertBufferBlend(buffer, VANILLA_SRC_RGB, VANILLA_DST_RGB, VANILLA_SRC_ALPHA, VANILLA_DST_ALPHA);
|
||||
}
|
||||
assertFalse(GLStateManager.getBlendState().isFuncUnknown(), "forward must clear the unknown flag");
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError());
|
||||
}
|
||||
|
||||
@Test
|
||||
void tryBlendFuncSeparateForwardsAfterIndexedOverride() {
|
||||
seedVanillaSeparate();
|
||||
overrideBufferZero();
|
||||
|
||||
GLStateManager.tryBlendFuncSeparate(VANILLA_SRC_RGB, VANILLA_DST_RGB, VANILLA_SRC_ALPHA, VANILLA_DST_ALPHA);
|
||||
|
||||
assertVanillaOnBothBuffers();
|
||||
}
|
||||
|
||||
@Test
|
||||
void glBlendFuncForwardsAfterIndexedOverride() {
|
||||
GLStateManager.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE);
|
||||
GLStateManager.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
overrideBufferZero();
|
||||
|
||||
GLStateManager.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
for (int buffer = 0; buffer < 2; buffer++) {
|
||||
assertBufferBlend(buffer, GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
assertFalse(GLStateManager.getBlendState().isFuncUnknown(), "forward must clear the unknown flag");
|
||||
}
|
||||
|
||||
@Test
|
||||
void popAttribForwardsAfterIndexedOverride() {
|
||||
seedVanillaSeparate();
|
||||
|
||||
GLStateManager.glPushAttrib(GL11.GL_COLOR_BUFFER_BIT);
|
||||
try {
|
||||
overrideBufferZero();
|
||||
} finally {
|
||||
GLStateManager.glPopAttrib();
|
||||
}
|
||||
|
||||
assertVanillaOnBothBuffers();
|
||||
}
|
||||
|
||||
@Test
|
||||
void displayListReplayForwardsAfterIndexedOverride() {
|
||||
final int list = GLStateManager.glGenLists(1);
|
||||
try {
|
||||
GLStateManager.glNewList(list, GL11.GL_COMPILE);
|
||||
GLStateManager.tryBlendFuncSeparate(VANILLA_SRC_RGB, VANILLA_DST_RGB, VANILLA_SRC_ALPHA, VANILLA_DST_ALPHA);
|
||||
GLStateManager.glEndList();
|
||||
|
||||
seedVanillaSeparate();
|
||||
overrideBufferZero();
|
||||
|
||||
GLStateManager.glCallList(list);
|
||||
|
||||
assertVanillaOnBothBuffers();
|
||||
} finally {
|
||||
GLStateManager.glDeleteLists(list, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
package com.gtnewhorizons.angelica.glsm;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL33;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
@GLCoreTest
|
||||
class GLSM_SamplerBinding_GLTest {
|
||||
|
||||
private static final int UNITS = 4;
|
||||
|
||||
@BeforeEach
|
||||
void requireSamplerObjects() {
|
||||
assumeTrue(RenderSystem.supportsSamplerObjects());
|
||||
drainGlErrors();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void unbindTestUnits() {
|
||||
if (!RenderSystem.supportsSamplerObjects()) return;
|
||||
for (int unit = 0; unit < UNITS; unit++) {
|
||||
GLStateManager.glBindSampler(unit, 0);
|
||||
GL33.glBindSampler(unit, 0);
|
||||
}
|
||||
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
drainGlErrors();
|
||||
}
|
||||
|
||||
private static void drainGlErrors() {
|
||||
while (GL11.glGetError() != GL11.GL_NO_ERROR) {}
|
||||
}
|
||||
|
||||
private static int driverBinding(int unit) {
|
||||
final int saved = GL11.glGetInteger(GL13.GL_ACTIVE_TEXTURE);
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0 + unit);
|
||||
final int binding = GL11.glGetInteger(GL33.GL_SAMPLER_BINDING);
|
||||
GL13.glActiveTexture(saved);
|
||||
return binding;
|
||||
}
|
||||
|
||||
private static void assertUnits(String context, int... expected) {
|
||||
for (int unit = 0; unit < expected.length; unit++) {
|
||||
assertEquals(expected[unit], GLStateManager.getSamplerBinding(unit), context + ": cache unit " + unit);
|
||||
assertEquals(expected[unit], driverBinding(unit), context + ": driver unit " + unit);
|
||||
}
|
||||
}
|
||||
|
||||
private static IntBuffer ints(int... values) {
|
||||
final IntBuffer buf = ByteBuffer.allocateDirect(values.length * 4).order(ByteOrder.nativeOrder()).asIntBuffer();
|
||||
buf.put(values).flip();
|
||||
return buf;
|
||||
}
|
||||
|
||||
@Test
|
||||
void renderSystemRebindAfterGlsmUnbindReachesDriver() {
|
||||
final int sampler = RenderSystem.genSampler();
|
||||
try {
|
||||
RenderSystem.bindSamplerToUnit(0, sampler);
|
||||
GLStateManager.glBindSampler(0, 0);
|
||||
assertEquals(0, driverBinding(0), "setup: GLSM unbind must reach the driver");
|
||||
|
||||
RenderSystem.bindSamplerToUnit(0, sampler);
|
||||
|
||||
assertEquals(sampler, driverBinding(0), "RenderSystem skipped a bind the driver no longer holds");
|
||||
} finally {
|
||||
RenderSystem.destroySampler(sampler);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteClearsEveryUnitAndTheNextBindReachesDriver() {
|
||||
final int sampler = RenderSystem.genSampler();
|
||||
GLStateManager.glBindSampler(1, sampler);
|
||||
GLStateManager.glBindSampler(3, sampler);
|
||||
|
||||
GLStateManager.glDeleteSamplers(sampler);
|
||||
|
||||
assertUnits("after delete", 0, 0, 0, 0);
|
||||
|
||||
final int next = RenderSystem.genSampler();
|
||||
try {
|
||||
GLStateManager.glBindSampler(1, next);
|
||||
assertEquals(next, driverBinding(1), "bind after delete never reached the driver");
|
||||
} finally {
|
||||
RenderSystem.destroySampler(next);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void samplerBindingQueryAnswersForTheActiveUnit() {
|
||||
final int sampler = RenderSystem.genSampler();
|
||||
try {
|
||||
GLStateManager.glBindSampler(1, sampler);
|
||||
|
||||
GLStateManager.glActiveTexture(GL13.GL_TEXTURE1);
|
||||
assertEquals(GL11.glGetInteger(GL33.GL_SAMPLER_BINDING),
|
||||
GLStateManager.glGetInteger(GL33.GL_SAMPLER_BINDING));
|
||||
assertEquals(sampler, GLStateManager.glGetInteger(GL33.GL_SAMPLER_BINDING));
|
||||
|
||||
GLStateManager.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
assertEquals(GL11.glGetInteger(GL33.GL_SAMPLER_BINDING),
|
||||
GLStateManager.glGetInteger(GL33.GL_SAMPLER_BINDING));
|
||||
assertEquals(0, GLStateManager.glGetInteger(GL33.GL_SAMPLER_BINDING));
|
||||
} finally {
|
||||
RenderSystem.destroySampler(sampler);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void unbindAllSamplersClearsUnitsBoundThroughGlsm() {
|
||||
final int sampler = RenderSystem.genSampler();
|
||||
try {
|
||||
GLStateManager.glBindSampler(1, sampler);
|
||||
GLStateManager.glBindSampler(3, sampler);
|
||||
|
||||
RenderSystem.unbindAllSamplers();
|
||||
|
||||
assertEquals(0, driverBinding(1), "unit 1 still bound on the driver");
|
||||
assertEquals(0, driverBinding(3), "unit 3 still bound on the driver");
|
||||
assertEquals(0, GLStateManager.getSamplerBinding(1));
|
||||
assertEquals(0, GLStateManager.getSamplerBinding(3));
|
||||
} finally {
|
||||
RenderSystem.destroySampler(sampler);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void replayForwardsCachedSamplerBindings() {
|
||||
final int sampler = RenderSystem.genSampler();
|
||||
try {
|
||||
GLStateManager.glBindSampler(2, sampler);
|
||||
GL33.glBindSampler(2, 0);
|
||||
assertEquals(0, driverBinding(2), "setup failed to diverge the driver");
|
||||
|
||||
GLStateManager.replayStateToBackend();
|
||||
|
||||
assertEquals(sampler, driverBinding(2), "replay dropped a cached sampler binding");
|
||||
} finally {
|
||||
RenderSystem.destroySampler(sampler);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void intBufferGenFillsFromPositionWithBindableSamplers() {
|
||||
final IntBuffer buf = ints(-1, 0, 0);
|
||||
buf.position(1);
|
||||
GLStateManager.glGenSamplers(buf);
|
||||
final int a = buf.get(1);
|
||||
final int b = buf.get(2);
|
||||
try {
|
||||
assertEquals(-1, buf.get(0), "slot before position was overwritten");
|
||||
assertEquals(1, buf.position(), "gen must not move the buffer position");
|
||||
assertNotEquals(0, a);
|
||||
assertNotEquals(0, b);
|
||||
assertNotEquals(a, b);
|
||||
|
||||
GLStateManager.glBindSampler(0, a);
|
||||
GLStateManager.glBindSampler(1, b);
|
||||
|
||||
assertEquals(GL11.GL_NO_ERROR, GL11.glGetError(), "generated name rejected by the driver");
|
||||
assertEquals(a, driverBinding(0));
|
||||
assertEquals(b, driverBinding(1));
|
||||
} finally {
|
||||
GLStateManager.glDeleteSamplers(a);
|
||||
GLStateManager.glDeleteSamplers(b);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindSamplersFormsBindFromPosition() {
|
||||
final int a = RenderSystem.genSampler();
|
||||
final int b = RenderSystem.genSampler();
|
||||
try {
|
||||
final IntBuffer buf = ints(-1, a, b);
|
||||
buf.position(1);
|
||||
|
||||
GLStateManager.glBindSamplers(1, 2, buf);
|
||||
assertEquals(1, buf.position(), "count form must not move the buffer position");
|
||||
assertUnits("count form", 0, a, b, 0);
|
||||
|
||||
GLStateManager.glBindSampler(1, 0);
|
||||
GLStateManager.glBindSampler(2, 0);
|
||||
buf.position(1);
|
||||
|
||||
GLStateManager.glBindSamplers(1, buf);
|
||||
assertEquals(1, buf.position(), "remaining form must not move the buffer position");
|
||||
assertUnits("remaining form", 0, a, b, 0);
|
||||
|
||||
GLStateManager.glBindSamplers(1, (IntBuffer) null);
|
||||
assertUnits("null remaining form", 0, a, b, 0);
|
||||
|
||||
GLStateManager.glBindSamplers(2, new int[]{a, b});
|
||||
assertUnits("int[] form", 0, a, a, b);
|
||||
} finally {
|
||||
RenderSystem.destroySampler(a);
|
||||
RenderSystem.destroySampler(b);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindSamplersNullUnbindsRangeAndShortBufferThrows() {
|
||||
final int prior = RenderSystem.genSampler();
|
||||
final int next = RenderSystem.genSampler();
|
||||
try {
|
||||
for (int unit = 0; unit < UNITS; unit++) GLStateManager.glBindSampler(unit, prior);
|
||||
|
||||
GLStateManager.glBindSamplers(1, 2, (IntBuffer) null);
|
||||
|
||||
assertUnits("null count form", prior, 0, 0, prior);
|
||||
|
||||
for (int unit = 0; unit < UNITS; unit++) GLStateManager.glBindSampler(unit, prior);
|
||||
final IntBuffer buf = ints(next, next);
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> GLStateManager.glBindSamplers(0, UNITS, buf));
|
||||
|
||||
assertEquals(0, buf.position());
|
||||
assertUnits("short buffer", prior, prior, prior, prior);
|
||||
} finally {
|
||||
RenderSystem.destroySampler(prior);
|
||||
RenderSystem.destroySampler(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,8 @@ import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -300,6 +302,74 @@ class GLSMRedirectorTest {
|
||||
assertTrue(unmappedSeen().isEmpty(), owner + "." + name + " should not be recorded");
|
||||
}
|
||||
|
||||
private static boolean glsmDeclares(String name, String desc) throws ClassNotFoundException {
|
||||
final Class<?> glsm = Class.forName(GLSM.replace('/', '.'), false, GLSMRedirectorTest.class.getClassLoader());
|
||||
for (Method m : glsm.getDeclaredMethods()) {
|
||||
final int mods = m.getModifiers();
|
||||
if (!Modifier.isPublic(mods) || !Modifier.isStatic(mods) || !m.getName().equals(name)) continue;
|
||||
if (Type.getMethodDescriptor(m).equals(desc)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void assertRedirectedToDeclaredTarget(String[][] cases) throws ClassNotFoundException {
|
||||
for (boolean aware : new boolean[]{false, true}) {
|
||||
for (String[] c : cases) {
|
||||
final String call = c[0] + "." + c[1] + c[2] + (aware ? " aware" : "");
|
||||
final ClassNode cn = makeClassWithMethodCall(c[0], c[1], c[2]);
|
||||
assertTrue(new GLSMRedirector().transformClassNode("com.example.TestClass", cn, aware), call);
|
||||
final MethodInsnNode target = firstCall(cn);
|
||||
assertEquals(GLSM, target.owner, call);
|
||||
assertEquals(c[1], target.name, call);
|
||||
assertEquals(c[2], target.desc, call);
|
||||
assertTrue(glsmDeclares(target.name, target.desc), () -> "GLStateManager lacks the target of " + call);
|
||||
}
|
||||
}
|
||||
assertTrue(unmappedSeen().isEmpty(), () -> "unexpected reports: " + unmappedSeen());
|
||||
}
|
||||
|
||||
@Test
|
||||
void samplerGenDeleteOverloadsHaveDeclaredTargets() throws Exception {
|
||||
assertRedirectedToDeclaredTarget(new String[][]{
|
||||
{"org/lwjgl/opengl/GL33", "glGenSamplers", "()I"},
|
||||
{"org/lwjgl/opengl/GL33", "glGenSamplers", "(Ljava/nio/IntBuffer;)V"},
|
||||
{"org/lwjgl/opengl/GL33C", "glGenSamplers", "([I)V"},
|
||||
{"org/lwjgl/opengl/GL33", "glGenSamplers", "([I)V"},
|
||||
{"org/lwjgl/opengl/GL33", "glDeleteSamplers", "(I)V"},
|
||||
{"org/lwjgl/opengl/GL33", "glDeleteSamplers", "(Ljava/nio/IntBuffer;)V"},
|
||||
{"org/lwjgl/opengl/GL33C", "glDeleteSamplers", "([I)V"},
|
||||
{"org/lwjgl/opengl/GL33", "glDeleteSamplers", "([I)V"},
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindSamplersHasDeclaredTargets() throws Exception {
|
||||
assertRedirectedToDeclaredTarget(new String[][]{
|
||||
{"org/lwjgl/opengl/GL44", "glBindSamplers", "(IILjava/nio/IntBuffer;)V"},
|
||||
{"org/lwjgl/opengl/GL44C", "glBindSamplers", "(ILjava/nio/IntBuffer;)V"},
|
||||
{"org/lwjgl/opengl/GL44", "glBindSamplers", "(I[I)V"},
|
||||
{"org/lwjgl/opengl/ARBMultiBind", "glBindSamplers", "(IILjava/nio/IntBuffer;)V"},
|
||||
{"org/lwjgl/opengl/ARBMultiBind", "glBindSamplers", "(ILjava/nio/IntBuffer;)V"},
|
||||
{"org/lwjgl/opengl/ARBMultiBind", "glBindSamplers", "(I[I)V"},
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void arbSamplerObjectsHasDeclaredTargets() throws Exception {
|
||||
assertRedirectedToDeclaredTarget(new String[][]{
|
||||
{"org/lwjgl/opengl/ARBSamplerObjects", "glGenSamplers", "()I"},
|
||||
{"org/lwjgl/opengl/ARBSamplerObjects", "glGenSamplers", "(Ljava/nio/IntBuffer;)V"},
|
||||
{"org/lwjgl/opengl/ARBSamplerObjects", "glGenSamplers", "([I)V"},
|
||||
{"org/lwjgl/opengl/ARBSamplerObjects", "glDeleteSamplers", "(I)V"},
|
||||
{"org/lwjgl/opengl/ARBSamplerObjects", "glDeleteSamplers", "(Ljava/nio/IntBuffer;)V"},
|
||||
{"org/lwjgl/opengl/ARBSamplerObjects", "glDeleteSamplers", "([I)V"},
|
||||
{"org/lwjgl/opengl/ARBSamplerObjects", "glIsSampler", "(I)Z"},
|
||||
{"org/lwjgl/opengl/ARBSamplerObjects", "glBindSampler", "(II)V"},
|
||||
{"org/lwjgl/opengl/ARBSamplerObjects", "glSamplerParameteri", "(III)V"},
|
||||
{"org/lwjgl/opengl/ARBSamplerObjects", "glSamplerParameterf", "(IIF)V"},
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void descKeyedSyncRedirectsOnlyLongForm() {
|
||||
assertRedirected("org/lwjgl/opengl/GL32C", "glFenceSync", "(II)J", "glFenceSync");
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
package com.gtnewhorizons.angelica.glsm.streaming;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLCoreTest;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FfpExtendedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.StreamingUploader.UploadStrategy;
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL31;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memAlloc;
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.memFree;
|
||||
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.assertTrue;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
@GLCoreTest
|
||||
class StreamingBindingCacheGLTest {
|
||||
|
||||
private static ByteBuffer filled(int bytes) {
|
||||
final ByteBuffer data = memAlloc(bytes);
|
||||
for (int i = 0; i < bytes; i++) {
|
||||
data.put(i, (byte) i);
|
||||
}
|
||||
data.position(0).limit(bytes);
|
||||
return data;
|
||||
}
|
||||
|
||||
private static int glsmUniformBufferBinding() {
|
||||
final Object ctx = Reflect.invokeStatic(GLStateManager.class, "ctx", new Class<?>[0]);
|
||||
final Int2IntMap bound = Reflect.get(ctx, "boundOtherBuffers");
|
||||
return bound.get(GL31.GL_UNIFORM_BUFFER);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(UploadStrategy.class)
|
||||
void orphanUploadLeavesTheArrayBufferCacheMatchingTheDriver(UploadStrategy strategy) {
|
||||
final int other = GLStateManager.glGenBuffers();
|
||||
final OrphanStreamingBuffer buf = new OrphanStreamingBuffer();
|
||||
final ByteBuffer data = filled(64);
|
||||
try {
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, other);
|
||||
buf.upload(strategy, data);
|
||||
assertEquals(GL11.glGetInteger(GL15.GL_ARRAY_BUFFER_BINDING), GLStateManager.getBoundVBO(), "first upload respecifies the buffer");
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, other);
|
||||
buf.upload(strategy, data);
|
||||
assertEquals(GL11.glGetInteger(GL15.GL_ARRAY_BUFFER_BINDING), GLStateManager.getBoundVBO(), "second upload takes the in-capacity path");
|
||||
} finally {
|
||||
memFree(data);
|
||||
buf.destroy();
|
||||
GLStateManager.glDeleteBuffers(other);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void uniformRingOrphanPathLeavesTheUniformBufferCacheMatchingTheDriver() {
|
||||
final int other = GLStateManager.glGenBuffers();
|
||||
final ByteBuffer src = filled(64);
|
||||
UniformRingBuffer ring = null;
|
||||
try {
|
||||
GLStateManager.glBindBuffer(GL31.GL_UNIFORM_BUFFER, other);
|
||||
ring = new UniformRingBuffer(1024, 64, true);
|
||||
assertFalse(ring.isPersistent());
|
||||
assertEquals(GL11.glGetInteger(GL31.GL_UNIFORM_BUFFER_BINDING), glsmUniformBufferBinding(), "constructor allocation");
|
||||
GLStateManager.glBindBuffer(GL31.GL_UNIFORM_BUFFER, other);
|
||||
ring.writeBlock(src);
|
||||
assertEquals(GL11.glGetInteger(GL31.GL_UNIFORM_BUFFER_BINDING), glsmUniformBufferBinding(), "writeBlock");
|
||||
} finally {
|
||||
if (ring != null) ring.destroy();
|
||||
GLStateManager.glDeleteBuffers(other);
|
||||
memFree(src);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void persistentRingMarksItsOwnBufferAndLeavesTheCacheMatchingTheDriver() {
|
||||
assumeTrue(RenderSystem.supportsBufferStorage(), "GL4.4+ required");
|
||||
final int other = GLStateManager.glGenBuffers();
|
||||
PersistentStreamingBuffer ring = null;
|
||||
try {
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, other);
|
||||
ring = PersistentStreamingBuffer.createOrNull(4096, false);
|
||||
assertNotNull(ring);
|
||||
final IntSet persistent = Reflect.getStatic(FfpExtendedAttribs.class, "persistentSources");
|
||||
assertTrue(persistent.contains(ring.getBufferId()), "the ring buffer is the persistent source");
|
||||
assertFalse(persistent.contains(other), "the previously bound buffer is not persistent");
|
||||
assertEquals(GL11.glGetInteger(GL15.GL_ARRAY_BUFFER_BINDING), GLStateManager.getBoundVBO());
|
||||
} finally {
|
||||
if (ring != null) ring.destroy();
|
||||
GLStateManager.glDeleteBuffers(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,39 +75,58 @@ public final class SDLGPULWJGLService implements LWJGLService {
|
||||
|
||||
@Override public int getPointerSize() { return 8; } // 64-bit
|
||||
|
||||
@Override public int glGenBuffers() { return BackendManager.RENDER_BACKEND.genBuffers(); }
|
||||
@Override public void glDeleteBuffers(int buffer) { BackendManager.RENDER_BACKEND.deleteBuffers(buffer); }
|
||||
@Override public int glGenBuffers() { return GLStateManager.glGenBuffers(); }
|
||||
@Override public void glDeleteBuffers(int buffer) { GLStateManager.glDeleteBuffers(buffer); }
|
||||
@Override public void glBindBuffer(int target, int buffer) { GLStateManager.glBindBuffer(target, buffer); }
|
||||
@Override public void glBufferData(int target, long size, int usage) { BackendManager.RENDER_BACKEND.bufferData(target, size, usage); }
|
||||
@Override public void glBufferData(int target, ByteBuffer data, int usage) { BackendManager.RENDER_BACKEND.bufferData(target, data, usage); }
|
||||
@Override public void glBufferData(int target, long size, int usage) {
|
||||
GLStateManager.glBufferData(target, size, usage);
|
||||
}
|
||||
@Override public void glBufferData(int target, ByteBuffer data, int usage) {
|
||||
GLStateManager.glBufferData(target, data, usage);
|
||||
}
|
||||
@Override public void glBufferData(int target, long size, long data, int usage) {
|
||||
if (data != 0) {
|
||||
BackendManager.RENDER_BACKEND.bufferData(target, MemoryUtil.memByteBuffer(data, (int) size), usage);
|
||||
GLStateManager.nglBufferData(target, size, data, usage);
|
||||
} else {
|
||||
BackendManager.RENDER_BACKEND.bufferData(target, size, usage);
|
||||
GLStateManager.glBufferData(target, size, usage);
|
||||
}
|
||||
}
|
||||
@Override public void glBufferStorage(int target, long size, int flags) { BackendManager.RENDER_BACKEND.bufferStorage(target, size, flags); }
|
||||
@Override public void glBlitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) {
|
||||
BackendManager.RENDER_BACKEND.blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
@Override public void glBufferStorage(int target, long size, int flags) {
|
||||
GLStateManager.glBufferStorage(target, size, flags);
|
||||
}
|
||||
@Override public void glBlitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter) {
|
||||
GLStateManager.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
|
||||
}
|
||||
@Override public void glDrawArrays(int mode, int first, int count) {
|
||||
GLStateManager.glDrawArrays(mode, first, count);
|
||||
}
|
||||
@Override public void glDrawArrays(int mode, int first, int count) { BackendManager.RENDER_BACKEND.drawArrays(mode, first, count); }
|
||||
@Override public void glDrawBuffers(int[] buffers) {
|
||||
try (var stack = MemoryStack.stackPush()) {
|
||||
BackendManager.RENDER_BACKEND.drawBuffers(stack.ints(buffers));
|
||||
GLStateManager.glDrawBuffers(stack.ints(buffers));
|
||||
}
|
||||
}
|
||||
@Override public void glTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, ByteBuffer pixels) {
|
||||
GLStateManager.glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels);
|
||||
}
|
||||
@Override public void glTexParameteri(int target, int pname, int param) { GLStateManager.glTexParameteri(target, pname, param); }
|
||||
@Override public ByteBuffer glMapBufferRange(int target, long offset, long length, int flags) { return BackendManager.RENDER_BACKEND.mapBufferRange(target, offset, length, flags); }
|
||||
@Override public ByteBuffer glMapBufferRange(int target, long offset, long length, int flags) {
|
||||
return GLStateManager.glMapBufferRange(target, offset, length, flags);
|
||||
}
|
||||
@Override public long nglMapBuffer(int target, int access) { return 0; }
|
||||
@Override public ByteBuffer glMapBuffer(int target, int access) { return BackendManager.RENDER_BACKEND.mapBuffer(target, access); }
|
||||
@Override public void glUnmapBuffer(int target) { BackendManager.RENDER_BACKEND.unmapBuffer(target); }
|
||||
@Override public void glFlushMappedBufferRange(int target, long offset, long length) { BackendManager.RENDER_BACKEND.flushMappedBufferRange(target, offset, length); }
|
||||
@Override public void glCopyBufferSubData(int readTarget, int writeTarget, long readOffset, long writeOffset, long size) { BackendManager.RENDER_BACKEND.copyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size); }
|
||||
@Override public void glBindBufferBase(int target, int index, int buffer) { BackendManager.RENDER_BACKEND.bindBufferBase(target, index, buffer); }
|
||||
@Override public ByteBuffer glMapBuffer(int target, int access) {
|
||||
return GLStateManager.glMapBuffer(target, access);
|
||||
}
|
||||
@Override public void glUnmapBuffer(int target) { GLStateManager.glUnmapBuffer(target); }
|
||||
@Override public void glFlushMappedBufferRange(int target, long offset, long length) {
|
||||
GLStateManager.glFlushMappedBufferRange(target, offset, length);
|
||||
}
|
||||
@Override public void glCopyBufferSubData(int readTarget, int writeTarget, long readOffset, long writeOffset,
|
||||
long size) {
|
||||
GLStateManager.glCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
|
||||
}
|
||||
@Override public void glBindBufferBase(int target, int index, int buffer) {
|
||||
GLStateManager.glBindBufferBase(target, index, buffer);
|
||||
}
|
||||
|
||||
@Override public int glGenVertexArrays() { return GLStateManager.glGenVertexArrays(); }
|
||||
@Override public void glDeleteVertexArrays(int array) { GLStateManager.glDeleteVertexArrays(array); }
|
||||
@@ -117,63 +136,80 @@ public final class SDLGPULWJGLService implements LWJGLService {
|
||||
@Override public void glEnableVertexAttribArray(int index) { GLStateManager.glEnableVertexAttribArray(index); }
|
||||
@Override public void glVertexAttribDivisor(int index, int divisor) { GLStateManager.glVertexAttribDivisor(index, divisor); }
|
||||
|
||||
@Override public int glCreateShader(int type) { return BackendManager.RENDER_BACKEND.createShader(type); }
|
||||
@Override public void glShaderSource(int shader, CharSequence source) { BackendManager.RENDER_BACKEND.shaderSource(shader, source); }
|
||||
@Override public void glShaderSourceSafe(int shader, CharSequence source) { BackendManager.RENDER_BACKEND.shaderSource(shader, source); }
|
||||
@Override public void glCompileShader(int shader) { BackendManager.RENDER_BACKEND.compileShader(shader); }
|
||||
@Override public String glGetShaderInfoLog(int shader, int maxLength) { return BackendManager.RENDER_BACKEND.getShaderInfoLog(shader, maxLength); }
|
||||
@Override public int glGetShaderi(int shader, int pname) { return BackendManager.RENDER_BACKEND.getShaderi(shader, pname); }
|
||||
@Override public void glDeleteShader(int shader) { BackendManager.RENDER_BACKEND.deleteShader(shader); }
|
||||
@Override public int glCreateShader(int type) { return GLStateManager.glCreateShader(type); }
|
||||
@Override public void glShaderSource(int shader, CharSequence source) {
|
||||
GLStateManager.glShaderSource(shader, source);
|
||||
}
|
||||
@Override public void glShaderSourceSafe(int shader, CharSequence source) {
|
||||
GLStateManager.glShaderSource(shader, source);
|
||||
}
|
||||
@Override public void glCompileShader(int shader) { GLStateManager.glCompileShader(shader); }
|
||||
@Override public String glGetShaderInfoLog(int shader, int maxLength) {
|
||||
return GLStateManager.glGetShaderInfoLog(shader, maxLength);
|
||||
}
|
||||
@Override public int glGetShaderi(int shader, int pname) { return GLStateManager.glGetShaderi(shader, pname); }
|
||||
@Override public void glDeleteShader(int shader) { GLStateManager.glDeleteShader(shader); }
|
||||
|
||||
@Override public int glCreateProgram() { return BackendManager.RENDER_BACKEND.createProgram(); }
|
||||
@Override public void glAttachShader(int program, int shader) { BackendManager.RENDER_BACKEND.attachShader(program, shader); }
|
||||
@Override public void glLinkProgram(int program) { BackendManager.RENDER_BACKEND.linkProgram(program); }
|
||||
@Override public String glGetProgramInfoLog(int program, int maxLength) { return BackendManager.RENDER_BACKEND.getProgramInfoLog(program, maxLength); }
|
||||
@Override public int glGetProgrami(int program, int pname) { return BackendManager.RENDER_BACKEND.getProgrami(program, pname); }
|
||||
@Override public int glCreateProgram() { return GLStateManager.glCreateProgram(); }
|
||||
@Override public void glAttachShader(int program, int shader) { GLStateManager.glAttachShader(program, shader); }
|
||||
@Override public void glLinkProgram(int program) { GLStateManager.glLinkProgram(program); }
|
||||
@Override public String glGetProgramInfoLog(int program, int maxLength) {
|
||||
return GLStateManager.glGetProgramInfoLog(program, maxLength);
|
||||
}
|
||||
@Override public int glGetProgrami(int program, int pname) { return GLStateManager.glGetProgrami(program, pname); }
|
||||
@Override public void glUseProgram(int program) { GLStateManager.glUseProgram(program); }
|
||||
@Override public void glDeleteProgram(int program) { BackendManager.RENDER_BACKEND.deleteProgram(program); }
|
||||
@Override public void glBindAttribLocation(int program, int index, CharSequence name) { BackendManager.RENDER_BACKEND.bindAttribLocation(program, index, name); }
|
||||
@Override public void glDeleteProgram(int program) { GLStateManager.glDeleteProgram(program); }
|
||||
@Override public void glBindAttribLocation(int program, int index, CharSequence name) {
|
||||
GLStateManager.glBindAttribLocation(program, index, name);
|
||||
}
|
||||
@Override public void glBindFragDataLocation(int program, int colorNumber, CharSequence name) {}
|
||||
|
||||
@Override public int glGetUniformLocation(int program, CharSequence name) { return BackendManager.RENDER_BACKEND.getUniformLocation(program, name); }
|
||||
@Override public int glGetUniformLocation(int program, CharSequence name) {
|
||||
return GLStateManager.glGetUniformLocation(program, name);
|
||||
}
|
||||
@Override public int glGetUniformBlockIndex(int program, CharSequence name) { return -1; /* TODO */ }
|
||||
@Override public void glUniformBlockBinding(int program, int blockIndex, int blockBinding) { /* TODO */ }
|
||||
@Override public void glUniform1f(int location, float v0) { BackendManager.RENDER_BACKEND.uniform1f(location, v0); }
|
||||
@Override public void glUniform1i(int location, int v0) { BackendManager.RENDER_BACKEND.uniform1i(location, v0); }
|
||||
@Override public void glUniform1fv(int location, FloatBuffer value) { BackendManager.RENDER_BACKEND.uniform1fv(location, value); }
|
||||
@Override public void glUniform2i(int location, int v0, int v1) { BackendManager.RENDER_BACKEND.uniform2i(location, v0, v1); }
|
||||
@Override public void glUniform3f(int location, float v0, float v1, float v2) { BackendManager.RENDER_BACKEND.uniform3f(location, v0, v1, v2); }
|
||||
@Override public void glUniform3fv(int location, FloatBuffer value) { BackendManager.RENDER_BACKEND.uniform3(location, value); }
|
||||
@Override public void glUniform3fv(int location, float[] value) {
|
||||
try (var stack = MemoryStack.stackPush()) {
|
||||
final FloatBuffer buf = stack.floats(value);
|
||||
BackendManager.RENDER_BACKEND.uniform3(location, buf);
|
||||
}
|
||||
@Override public void glUniform1f(int location, float v0) { GLStateManager.glUniform1f(location, v0); }
|
||||
@Override public void glUniform1i(int location, int v0) { GLStateManager.glUniform1i(location, v0); }
|
||||
@Override public void glUniform1fv(int location, FloatBuffer value) { GLStateManager.glUniform1(location, value); }
|
||||
@Override public void glUniform2i(int location, int v0, int v1) { GLStateManager.glUniform2i(location, v0, v1); }
|
||||
@Override public void glUniform3f(int location, float v0, float v1, float v2) {
|
||||
GLStateManager.glUniform3f(location, v0, v1, v2);
|
||||
}
|
||||
@Override public void glUniform4fv(int location, FloatBuffer value) { BackendManager.RENDER_BACKEND.uniform4(location, value); }
|
||||
@Override public void glUniform4fv(int location, float[] value) {
|
||||
try (var stack = MemoryStack.stackPush()) {
|
||||
final FloatBuffer buf = stack.floats(value);
|
||||
BackendManager.RENDER_BACKEND.uniform4(location, buf);
|
||||
}
|
||||
@Override public void glUniform3fv(int location, FloatBuffer value) { GLStateManager.glUniform3(location, value); }
|
||||
@Override public void glUniform3fv(int location, float[] value) { GLStateManager.glUniform3(location, value); }
|
||||
@Override public void glUniform4fv(int location, FloatBuffer value) { GLStateManager.glUniform4(location, value); }
|
||||
@Override public void glUniform4fv(int location, float[] value) { GLStateManager.glUniform4(location, value); }
|
||||
@Override public void glUniformMatrix3fv(int location, boolean transpose, FloatBuffer value) {
|
||||
GLStateManager.glUniformMatrix3(location, transpose, value);
|
||||
}
|
||||
@Override public void glUniformMatrix4fv(int location, boolean transpose, FloatBuffer value) {
|
||||
GLStateManager.glUniformMatrix4(location, transpose, value);
|
||||
}
|
||||
@Override public void glUniformMatrix3fv(int location, boolean transpose, FloatBuffer value) { BackendManager.RENDER_BACKEND.uniformMatrix3(location, transpose, value); }
|
||||
@Override public void glUniformMatrix4fv(int location, boolean transpose, FloatBuffer value) { BackendManager.RENDER_BACKEND.uniformMatrix4(location, transpose, value); }
|
||||
|
||||
@Override public void glDrawElementsBaseVertex(int mode, int count, int type, long indices, int basevertex) { BackendManager.RENDER_BACKEND.drawElementsBaseVertex(mode, count, type, indices, basevertex); }
|
||||
@Override public void glMultiDrawElementsBaseVertex(int mode, long pCount, int type, long pIndices, int drawcount, long pBaseVertex) { BackendManager.RENDER_BACKEND.multiDrawElementsBaseVertex(mode, pCount, type, pIndices, drawcount, pBaseVertex); }
|
||||
@Override public void glMultiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride) { BackendManager.RENDER_BACKEND.multiDrawElementsIndirect(mode, type, indirect, drawcount, stride); }
|
||||
@Override public void glDrawElementsBaseVertex(int mode, int count, int type, long indices, int basevertex) {
|
||||
GLStateManager.glDrawElementsBaseVertex(mode, count, type, indices, basevertex);
|
||||
}
|
||||
@Override public void glMultiDrawElementsBaseVertex(int mode, long pCount, int type, long pIndices, int drawcount,
|
||||
long pBaseVertex) {
|
||||
GLStateManager.glMultiDrawElementsBaseVertex(mode, pCount, type, pIndices, drawcount, pBaseVertex);
|
||||
}
|
||||
@Override public void glMultiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride) {
|
||||
GLStateManager.glMultiDrawElementsIndirect(mode, type, indirect, drawcount, stride);
|
||||
}
|
||||
|
||||
@Override public long glFenceSync(int condition, int flags) { return BackendManager.RENDER_BACKEND.fenceSync(condition, flags); }
|
||||
@Override public int glClientWaitSync(long sync, int flags, long timeout) { return BackendManager.RENDER_BACKEND.clientWaitSync(sync, flags, timeout); }
|
||||
@Override public long glFenceSync(int condition, int flags) { return GLStateManager.glFenceSync(condition, flags); }
|
||||
@Override public int glClientWaitSync(long sync, int flags, long timeout) {
|
||||
return GLStateManager.glClientWaitSync(sync, flags, timeout);
|
||||
}
|
||||
@Override public int glGetSynci(long sync, int pname, IntBuffer length) {
|
||||
if (length != null && length.remaining() > 0) length.put(0, 1);
|
||||
return ((SDLGPURenderBackend) BackendManager.RENDER_BACKEND).getSyncStatus(sync);
|
||||
}
|
||||
@Override public void glWaitSync(long sync, int flags, long timeout) {
|
||||
((SDLGPURenderBackend) BackendManager.RENDER_BACKEND).waitSync(sync, flags, timeout);
|
||||
GLStateManager.glWaitSync(sync, flags, timeout);
|
||||
}
|
||||
@Override public void glDeleteSync(long sync) { BackendManager.RENDER_BACKEND.deleteSync(sync); }
|
||||
@Override public void glDeleteSync(long sync) { GLStateManager.glDeleteSync(sync); }
|
||||
|
||||
private long[] queryElapsed = new long[64];
|
||||
private int activeQueryId = -1;
|
||||
@@ -185,7 +221,7 @@ public final class SDLGPULWJGLService implements LWJGLService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public int glGenQueries() { return BackendManager.RENDER_BACKEND.genQueries(); }
|
||||
@Override public int glGenQueries() { return GLStateManager.glGenQueries(); }
|
||||
@Override public void glDeleteQueries(int query) { }
|
||||
@Override public void glBeginQuery(int target, int id) {
|
||||
ensureQueryCapacity(id);
|
||||
@@ -204,29 +240,42 @@ public final class SDLGPULWJGLService implements LWJGLService {
|
||||
|
||||
@Override public int setupDebugCallback(DebugMessageHandler handler) { return 0; }
|
||||
@Override public void disableDebugCallback() { }
|
||||
@Override public void glObjectLabel(int identifier, int name, CharSequence label) { BackendManager.RENDER_BACKEND.objectLabel(identifier, name, label); }
|
||||
@Override public void glPushDebugGroup(int source, int id, CharSequence message) { BackendManager.RENDER_BACKEND.pushDebugGroup(source, id, message); }
|
||||
@Override public void glPopDebugGroup() { BackendManager.RENDER_BACKEND.popDebugGroup(); }
|
||||
|
||||
@Override public int glGenTextures() { return BackendManager.RENDER_BACKEND.genTextures(); }
|
||||
@Override public void glGenTextures(int[] textures) {
|
||||
for (int i = 0; i < textures.length; i++) textures[i] = BackendManager.RENDER_BACKEND.genTextures();
|
||||
@Override public void glObjectLabel(int identifier, int name, CharSequence label) {
|
||||
GLStateManager.glObjectLabel(identifier, name, label);
|
||||
}
|
||||
@Override public void glDeleteTextures(int texture) { BackendManager.RENDER_BACKEND.deleteTextures(texture); }
|
||||
@Override public void glPushDebugGroup(int source, int id, CharSequence message) {
|
||||
GLStateManager.glPushDebugGroup(source, id, message);
|
||||
}
|
||||
@Override public void glPopDebugGroup() { GLStateManager.glPopDebugGroup(); }
|
||||
|
||||
@Override public int glGenTextures() { return GLStateManager.glGenTextures(); }
|
||||
@Override public void glGenTextures(int[] textures) {
|
||||
for (int i = 0; i < textures.length; i++) textures[i] = GLStateManager.glGenTextures();
|
||||
}
|
||||
@Override public void glDeleteTextures(int texture) { GLStateManager.glDeleteTextures(texture); }
|
||||
@Override public void glDeleteTextures(int[] textures) {
|
||||
for (int t : textures) BackendManager.RENDER_BACKEND.deleteTextures(t);
|
||||
for (int t : textures) GLStateManager.glDeleteTextures(t);
|
||||
}
|
||||
@Override public void glBindTexture(int target, int texture) { GLStateManager.glBindTexture(target, texture); }
|
||||
@Override public void glActiveTexture(int texture) { GLStateManager.glActiveTexture(texture); }
|
||||
@Override public int glGetTexLevelParameteri(int target, int level, int pname) { return BackendManager.RENDER_BACKEND.getTexLevelParameteri(target, level, pname); }
|
||||
@Override public void glCopyTexSubImage2D(int target, int level, int xoffset, int yoffset, int x, int y, int width, int height) { BackendManager.RENDER_BACKEND.copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); }
|
||||
@Override public void glPixelStorei(int pname, int param) { BackendManager.RENDER_BACKEND.pixelStorei(pname, param); }
|
||||
@Override public int glGetTexLevelParameteri(int target, int level, int pname) {
|
||||
return GLStateManager.glGetTexLevelParameteri(target, level, pname);
|
||||
}
|
||||
@Override public void glCopyTexSubImage2D(int target, int level, int xoffset, int yoffset, int x, int y, int width,
|
||||
int height) {
|
||||
GLStateManager.glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
|
||||
}
|
||||
@Override public void glPixelStorei(int pname, int param) { GLStateManager.glPixelStorei(pname, param); }
|
||||
|
||||
@Override public int glGenFramebuffers() { return BackendManager.RENDER_BACKEND.genFramebuffers(); }
|
||||
@Override public void glDeleteFramebuffers(int framebuffer) { BackendManager.RENDER_BACKEND.deleteFramebuffers(framebuffer); }
|
||||
@Override public int glGenFramebuffers() { return GLStateManager.glGenFramebuffers(); }
|
||||
@Override public void glDeleteFramebuffers(int framebuffer) { GLStateManager.glDeleteFramebuffers(framebuffer); }
|
||||
@Override public void glBindFramebuffer(int target, int framebuffer) { GLStateManager.glBindFramebuffer(target, framebuffer); }
|
||||
@Override public int glCheckFramebufferStatus(int target) { return BackendManager.RENDER_BACKEND.checkFramebufferStatus(target); }
|
||||
@Override public void glFramebufferTexture2D(int target, int attachment, int textarget, int texture, int level) { BackendManager.RENDER_BACKEND.framebufferTexture2D(target, attachment, textarget, texture, level); }
|
||||
@Override public int glCheckFramebufferStatus(int target) {
|
||||
return GLStateManager.glCheckFramebufferStatus(target);
|
||||
}
|
||||
@Override public void glFramebufferTexture2D(int target, int attachment, int textarget, int texture, int level) {
|
||||
GLStateManager.glFramebufferTexture2D(target, attachment, textarget, texture, level);
|
||||
}
|
||||
|
||||
@Override public void glEnable(int cap) { GLStateManager.glEnable(cap); }
|
||||
@Override public void glDisable(int cap) { GLStateManager.glDisable(cap); }
|
||||
@@ -236,20 +285,22 @@ public final class SDLGPULWJGLService implements LWJGLService {
|
||||
@Override public void glDepthMask(boolean flag) { GLStateManager.glDepthMask(flag); }
|
||||
@Override public void glColorMask(boolean red, boolean green, boolean blue, boolean alpha) { GLStateManager.glColorMask(red, green, blue, alpha); }
|
||||
@Override public void glViewport(int x, int y, int width, int height) { GLStateManager.glViewport(x, y, width, height); }
|
||||
@Override public void glClear(int mask) { BackendManager.RENDER_BACKEND.clear(mask); }
|
||||
@Override public void glClearColor(float red, float green, float blue, float alpha) { BackendManager.RENDER_BACKEND.clearColor(red, green, blue, alpha); }
|
||||
@Override public int glGetError() { return BackendManager.RENDER_BACKEND.getError(); }
|
||||
|
||||
@Override public void glMatrixMode(int mode) { /* Handled by GLSM FFP emulation */ }
|
||||
@Override public void glLoadMatrixf(FloatBuffer m) { /* Handled by GLSM FFP emulation */ }
|
||||
|
||||
@Override public int glGetInteger(int pname) { return BackendManager.RENDER_BACKEND.getInteger(pname); }
|
||||
@Override public void glGetIntegerv(int pname, int[] params) {
|
||||
if (params.length > 0) params[0] = BackendManager.RENDER_BACKEND.getInteger(pname);
|
||||
@Override public void glClear(int mask) { GLStateManager.glClear(mask); }
|
||||
@Override public void glClearColor(float red, float green, float blue, float alpha) {
|
||||
GLStateManager.glClearColor(red, green, blue, alpha);
|
||||
}
|
||||
@Override public int glGetError() { return GLStateManager.glGetError(); }
|
||||
|
||||
@Override public void glMatrixMode(int mode) { GLStateManager.glMatrixMode(mode); }
|
||||
@Override public void glLoadMatrixf(FloatBuffer m) { GLStateManager.glLoadMatrix(m); }
|
||||
|
||||
@Override public int glGetInteger(int pname) { return GLStateManager.glGetInteger(pname); }
|
||||
@Override public void glGetIntegerv(int pname, int[] params) { GLStateManager.glGetInteger(pname, params); }
|
||||
@Override public boolean glGetBoolean(int pname) { return GLStateManager.glGetBoolean(pname); }
|
||||
@Override public String glGetString(int pname) { return GLStateManager.glGetString(pname); }
|
||||
@Override public int glGetAttribLocation(int program, CharSequence name) {
|
||||
return GLStateManager.glGetAttribLocation(program, name);
|
||||
}
|
||||
@Override public boolean glGetBoolean(int pname) { return BackendManager.RENDER_BACKEND.getBoolean(pname); }
|
||||
@Override public String glGetString(int pname) { return BackendManager.RENDER_BACKEND.getString(pname); }
|
||||
@Override public int glGetAttribLocation(int program, CharSequence name) { return BackendManager.RENDER_BACKEND.getAttribLocation(program, name); }
|
||||
|
||||
@Override public MemoryStack stackPush() {
|
||||
org.lwjgl.system.MemoryStack.stackPush();
|
||||
|
||||
@@ -760,8 +760,8 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
final ContextState cs = s();
|
||||
if (cap == GL11.GL_BLEND) {
|
||||
if (index < 0 || index >= ContextState.MAX_COLOR_ATTACHMENTS) return;
|
||||
if (cs.pipeline.blendEnabledPerAttachment[index] != on) {
|
||||
cs.pipeline.blendEnabledPerAttachment[index] = on;
|
||||
if (cs.pipeline.blendEnabledPerDrawBuffer[index] != on) {
|
||||
cs.pipeline.blendEnabledPerDrawBuffer[index] = on;
|
||||
cs.pipeline.markOutputDirty();
|
||||
}
|
||||
return;
|
||||
@@ -775,8 +775,8 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
case GL11.GL_BLEND -> {
|
||||
boolean changed = false;
|
||||
for (int i = 0; i < ContextState.MAX_COLOR_ATTACHMENTS; i++) {
|
||||
if (cs.pipeline.blendEnabledPerAttachment[i] != on) {
|
||||
cs.pipeline.blendEnabledPerAttachment[i] = on;
|
||||
if (cs.pipeline.blendEnabledPerDrawBuffer[i] != on) {
|
||||
cs.pipeline.blendEnabledPerDrawBuffer[i] = on;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -805,21 +805,12 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
}
|
||||
|
||||
@Override public void blendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) {
|
||||
final ContextState cs = s();
|
||||
final int sc = FormatMap.mapBlendFactor(srcRGB);
|
||||
final int dc = FormatMap.mapBlendFactor(dstRGB);
|
||||
final int sa = FormatMap.mapBlendFactor(srcAlpha);
|
||||
final int da = FormatMap.mapBlendFactor(dstAlpha);
|
||||
if (sc == cs.pipeline.srcColorFactor && dc == cs.pipeline.dstColorFactor && sa == cs.pipeline.srcAlphaFactor && da == cs.pipeline.dstAlphaFactor) return;
|
||||
cs.pipeline.srcColorFactor = sc;
|
||||
cs.pipeline.dstColorFactor = dc;
|
||||
cs.pipeline.srcAlphaFactor = sa;
|
||||
cs.pipeline.dstAlphaFactor = da;
|
||||
cs.pipeline.markOutputDirty();
|
||||
s().pipeline.setBlendFactors(FormatMap.mapBlendFactor(srcRGB), FormatMap.mapBlendFactor(dstRGB), FormatMap.mapBlendFactor(srcAlpha), FormatMap.mapBlendFactor(dstAlpha));
|
||||
}
|
||||
|
||||
@Override public void blendFuncSeparatei(int buf, int srcRGB, int dstRGB, int srcAlpha, int dstAlpha) {
|
||||
blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
|
||||
if (buf < 0 || buf >= ContextState.MAX_COLOR_ATTACHMENTS) return;
|
||||
s().pipeline.setBlendFactors(buf, FormatMap.mapBlendFactor(srcRGB), FormatMap.mapBlendFactor(dstRGB), FormatMap.mapBlendFactor(srcAlpha), FormatMap.mapBlendFactor(dstAlpha));
|
||||
}
|
||||
|
||||
@Override public void blendEquation(int mode) {
|
||||
@@ -1755,6 +1746,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
|
||||
private void applyDrawBuffersFromIntBuffer(FboState fbo, IntBuffer bufs, boolean isBound) {
|
||||
final int count = bufs.remaining();
|
||||
if (count > ContextState.MAX_COLOR_ATTACHMENTS) return;
|
||||
final int basePos = bufs.position();
|
||||
if (fbo.drawBuffers.length == count) {
|
||||
boolean same = true;
|
||||
@@ -2018,10 +2010,8 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
cs.pipeline.fragmentShader = prog.sdlFragmentShader;
|
||||
cs.pipeline.programId = program;
|
||||
cs.pipeline.maxFragOutputLocation = prog.maxFragOutputLocation;
|
||||
cs.pipeline.shaderInputMask = prog.vertexInputMask;
|
||||
cs.pipeline.shaderInputVecSize = prog.vertexInputVecSize;
|
||||
cs.pipeline.shaderInputBaseType = prog.vertexInputBaseType;
|
||||
cs.pipeline.shaderInputName = prog.vertexInputName;
|
||||
cs.pipeline.setVertexInputs(prog.vertexInputMask, prog.vertexInputVecSize, prog.vertexInputBaseType, prog.vertexInputName);
|
||||
cs.pipeline.markInputDirty();
|
||||
cs.pipeline.markShaderDirty();
|
||||
}
|
||||
@Override public void useProgram(int program) {
|
||||
@@ -2071,10 +2061,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
cs.pipeline.fragmentShader = prog.sdlFragmentShader;
|
||||
cs.pipeline.programId = program;
|
||||
cs.pipeline.maxFragOutputLocation = prog.maxFragOutputLocation;
|
||||
cs.pipeline.shaderInputMask = prog.vertexInputMask;
|
||||
cs.pipeline.shaderInputVecSize = prog.vertexInputVecSize;
|
||||
cs.pipeline.shaderInputBaseType = prog.vertexInputBaseType;
|
||||
cs.pipeline.shaderInputName = prog.vertexInputName;
|
||||
cs.pipeline.setVertexInputs(prog.vertexInputMask, prog.vertexInputVecSize, prog.vertexInputBaseType, prog.vertexInputName);
|
||||
cs.pipeline.markShaderDirty();
|
||||
}
|
||||
|
||||
@@ -2282,6 +2269,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
LOG.warn("uniform1i: loc={} val={} -- NO program bound", location, v0);
|
||||
}
|
||||
final float[] a = pipelineApplier.reuseOrAlloc(st, location, 1);
|
||||
if (a == null) return;
|
||||
a[0] = Float.intBitsToFloat(v0);
|
||||
pipelineApplier.putUniform(st, location, a);
|
||||
}
|
||||
@@ -2289,6 +2277,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
if (location < 0) return;
|
||||
final ContextState st = s();
|
||||
final float[] a = pipelineApplier.reuseOrAlloc(st, location, 1);
|
||||
if (a == null) return;
|
||||
a[0] = v0;
|
||||
pipelineApplier.putUniform(st, location, a);
|
||||
}
|
||||
@@ -2296,6 +2285,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
if (location < 0) return;
|
||||
final ContextState st = s();
|
||||
final float[] a = pipelineApplier.reuseOrAlloc(st, location, 2);
|
||||
if (a == null) return;
|
||||
a[0] = v0; a[1] = v1;
|
||||
pipelineApplier.putUniform(st, location, a);
|
||||
}
|
||||
@@ -2303,6 +2293,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
if (location < 0) return;
|
||||
final ContextState st = s();
|
||||
final float[] a = pipelineApplier.reuseOrAlloc(st, location, 2);
|
||||
if (a == null) return;
|
||||
a[0] = Float.intBitsToFloat(v0); a[1] = Float.intBitsToFloat(v1);
|
||||
pipelineApplier.putUniform(st, location, a);
|
||||
}
|
||||
@@ -2310,6 +2301,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
if (location < 0) return;
|
||||
final ContextState st = s();
|
||||
final float[] a = pipelineApplier.reuseOrAlloc(st, location, 3);
|
||||
if (a == null) return;
|
||||
a[0] = v0; a[1] = v1; a[2] = v2;
|
||||
pipelineApplier.putUniform(st, location, a);
|
||||
}
|
||||
@@ -2317,6 +2309,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
if (location < 0) return;
|
||||
final ContextState st = s();
|
||||
final float[] a = pipelineApplier.reuseOrAlloc(st, location, 3);
|
||||
if (a == null) return;
|
||||
a[0] = Float.intBitsToFloat(v0); a[1] = Float.intBitsToFloat(v1); a[2] = Float.intBitsToFloat(v2);
|
||||
pipelineApplier.putUniform(st, location, a);
|
||||
}
|
||||
@@ -2324,6 +2317,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
if (location < 0) return;
|
||||
final ContextState st = s();
|
||||
final float[] a = pipelineApplier.reuseOrAlloc(st, location, 4);
|
||||
if (a == null) return;
|
||||
a[0] = v0; a[1] = v1; a[2] = v2; a[3] = v3;
|
||||
pipelineApplier.putUniform(st, location, a);
|
||||
}
|
||||
@@ -2331,6 +2325,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
if (location < 0) return;
|
||||
final ContextState st = s();
|
||||
final float[] a = pipelineApplier.reuseOrAlloc(st, location, 4);
|
||||
if (a == null) return;
|
||||
a[0] = Float.intBitsToFloat(v0); a[1] = Float.intBitsToFloat(v1);
|
||||
a[2] = Float.intBitsToFloat(v2); a[3] = Float.intBitsToFloat(v3);
|
||||
pipelineApplier.putUniform(st, location, a);
|
||||
@@ -2352,6 +2347,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
final int n = value.remaining();
|
||||
final int pos = value.position();
|
||||
final float[] v = pipelineApplier.reuseOrAlloc(st, location, n);
|
||||
if (v == null) return;
|
||||
for (int i = 0; i < n; i++) v[i] = Float.intBitsToFloat(value.get(pos + i));
|
||||
pipelineApplier.putUniform(st, location, v);
|
||||
}
|
||||
@@ -2361,8 +2357,16 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
@Override public void uniform4(int location, FloatBuffer value) {
|
||||
pipelineApplier.putUniformFv(s(), location, value);
|
||||
}
|
||||
@Override public void uniform3fv(int location, float[] values) { pipelineApplier.putUniform(s(), location, values); }
|
||||
@Override public void uniform4fv(int location, float[] values) { pipelineApplier.putUniform(s(), location, values); }
|
||||
@Override public void uniform3fv(int location, float[] values) { storeFloatUniform(location, values); }
|
||||
@Override public void uniform4fv(int location, float[] values) { storeFloatUniform(location, values); }
|
||||
private void storeFloatUniform(int location, float[] values) {
|
||||
if (location < 0) return;
|
||||
final ContextState st = s();
|
||||
final float[] a = pipelineApplier.reuseOrAlloc(st, location, values.length);
|
||||
if (a == null) return;
|
||||
System.arraycopy(values, 0, a, 0, values.length);
|
||||
pipelineApplier.putUniform(st, location, a);
|
||||
}
|
||||
@Override public void uniformMatrix2(int location, boolean transpose, FloatBuffer value) {
|
||||
pipelineApplier.storeMatrix(s(), location, transpose, value, 2);
|
||||
}
|
||||
@@ -2405,16 +2409,62 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
}
|
||||
|
||||
@Override public int genBuffers() { return resourceManager.genBuffer(); }
|
||||
@Override public void deleteBuffers(int buffer) { dropMappingFor(buffer); readbackShadows.release(buffer); resourceManager.deleteBuffer(buffer); }
|
||||
@Override public void deleteBuffers(int buffer) { deleteBuffer(buffer); }
|
||||
@Override public void deleteBuffers(IntBuffer buffers) {
|
||||
for (int i = 0; i < buffers.remaining(); i++) {
|
||||
final int buffer = buffers.get(buffers.position() + i);
|
||||
dropMappingFor(buffer);
|
||||
readbackShadows.release(buffer);
|
||||
resourceManager.deleteBuffer(buffer);
|
||||
deleteBuffer(buffers.get(buffers.position() + i));
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteBuffer(int buffer) {
|
||||
dropMappingFor(buffer);
|
||||
if (buffer != 0) unbindDeletedBuffer(s(), buffer);
|
||||
readbackShadows.release(buffer);
|
||||
resourceManager.deleteBuffer(buffer);
|
||||
}
|
||||
|
||||
private static void unbindDeletedBuffer(ContextState st, int buffer) {
|
||||
final ContextState.VAOState vao = st.currentVao;
|
||||
boolean vaoChanged = false;
|
||||
for (int i = 0; i < ContextState.MAX_VERTEX_ATTRIBS; i++) {
|
||||
if (vao.bindingBuffer[i] == buffer) {
|
||||
vao.bindingBuffer[i] = 0;
|
||||
vaoChanged = true;
|
||||
}
|
||||
if (vao.attribVBO[i] == buffer) vao.attribVBO[i] = 0;
|
||||
}
|
||||
if (vao.elementBuffer == buffer) {
|
||||
vao.elementBuffer = 0;
|
||||
vaoChanged = true;
|
||||
}
|
||||
if (vaoChanged) st.bumpAttribStateGen();
|
||||
if (st.boundArrayBuffer == buffer) st.boundArrayBuffer = 0;
|
||||
if (st.boundIndirectBuffer == buffer) st.boundIndirectBuffer = 0;
|
||||
if (st.boundDispatchIndirectBuffer == buffer) st.boundDispatchIndirectBuffer = 0;
|
||||
if (st.boundCopyReadBuffer == buffer) st.boundCopyReadBuffer = 0;
|
||||
if (st.boundCopyWriteBuffer == buffer) st.boundCopyWriteBuffer = 0;
|
||||
if (st.boundUniformBuffer == buffer) st.boundUniformBuffer = 0;
|
||||
if (st.boundSSBO == buffer) st.boundSSBO = 0;
|
||||
if (st.boundPixelPackBuffer == buffer) st.boundPixelPackBuffer = 0;
|
||||
if (st.boundPixelUnpackBuffer == buffer) st.boundPixelUnpackBuffer = 0;
|
||||
boolean uboChanged = false;
|
||||
boolean ssboChanged = false;
|
||||
for (int i = 0; i < ContextState.MAX_INDEXED_BUFFERS; i++) {
|
||||
if (st.boundUboByIndex[i] == buffer) {
|
||||
st.boundUboByIndex[i] = 0;
|
||||
st.uboRangeOffset[i] = 0;
|
||||
st.uboRangeSize[i] = 0;
|
||||
uboChanged = true;
|
||||
}
|
||||
if (st.boundSsboByIndex[i] == buffer) {
|
||||
st.boundSsboByIndex[i] = 0;
|
||||
ssboChanged = true;
|
||||
}
|
||||
}
|
||||
if (uboChanged) st.uboRangeGen++;
|
||||
if (ssboChanged) st.ssboBindGen++;
|
||||
}
|
||||
|
||||
private static void dropMappingFor(int buffer) {
|
||||
final ContextState st = s();
|
||||
if (buffer == 0 || st.mappedBufferGlId != buffer || st.mappedStagingBuffer == null) return;
|
||||
@@ -3606,7 +3656,7 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
final ContextState cs = s();
|
||||
return switch (pname) {
|
||||
case GL11.GL_DEPTH_TEST -> cs.pipeline.depthTestEnabled;
|
||||
case GL11.GL_BLEND -> cs.pipeline.blendEnabledPerAttachment[0];
|
||||
case GL11.GL_BLEND -> cs.pipeline.blendEnabledPerDrawBuffer[0];
|
||||
case GL11.GL_CULL_FACE -> cs.pipeline.cullEnabled;
|
||||
case GL11.GL_SCISSOR_TEST -> cs.scissorEnabled;
|
||||
case GL11.GL_STENCIL_TEST -> cs.pipeline.stencilTestEnabled;
|
||||
@@ -3848,11 +3898,11 @@ public class SDLGPURenderBackend extends RenderBackend {
|
||||
private int voxLocStart = -1;
|
||||
private int voxLocCount = -1;
|
||||
|
||||
@Override public boolean bindVoxelizationRegion(int ssboBinding, int vertexBufferGlId, long openPass, float x, float y, float z) {
|
||||
if (ssboBinding < 0 || ssboBinding >= ContextState.MAX_INDEXED_BUFFERS || vertexBufferGlId == 0) return false;
|
||||
@Override public boolean bindVoxelizationRegion(int ssboBinding, long openPass, float x, float y, float z) {
|
||||
if (ssboBinding < 0 || ssboBinding >= ContextState.MAX_INDEXED_BUFFERS) return false;
|
||||
final ContextState st = s();
|
||||
if (st.boundProgram == 0) return false;
|
||||
bindBufferBase(GL43.GL_SHADER_STORAGE_BUFFER, ssboBinding, vertexBufferGlId);
|
||||
if (st.boundSsboByIndex[ssboBinding] == 0) return false;
|
||||
final int loc = shaderManager.getUniformLocation(st.boundProgram, "u_RegionOffset");
|
||||
if (loc >= 0) GLStateManager.glUniform3f(loc, x, y, z);
|
||||
if (openPass != 0) voxelizationDispatcher.rebindVertexBuffer(st, openPass);
|
||||
|
||||
@@ -104,9 +104,9 @@ public final class FFPTrace {
|
||||
.append("/front=").append(p.frontFace).append("/all=").append(p.cullAll);
|
||||
sb.append(" depth=").append(p.depthTestEnabled).append("/func=").append(p.depthCompareOp)
|
||||
.append("/write=").append(p.depthWriteEnabled);
|
||||
sb.append(" blend=").append(p.blendEnabledPerAttachment[0])
|
||||
.append("/src=").append(p.srcColorFactor).append("/dst=").append(p.dstColorFactor)
|
||||
.append("/srcA=").append(p.srcAlphaFactor).append("/dstA=").append(p.dstAlphaFactor)
|
||||
sb.append(" blend=").append(p.blendEnabledPerDrawBuffer[0])
|
||||
.append("/src=").append(p.srcColorFactors[0]).append("/dst=").append(p.dstColorFactors[0])
|
||||
.append("/srcA=").append(p.srcAlphaFactors[0]).append("/dstA=").append(p.dstAlphaFactors[0])
|
||||
.append("/op=").append(p.colorBlendOp).append('/').append(p.alphaBlendOp);
|
||||
sb.append(" colorMask=0x").append(Integer.toHexString(p.colorWriteMask));
|
||||
sb.append(" primitiveType=").append(p.primitiveType);
|
||||
|
||||
+5
-4
@@ -677,10 +677,9 @@ public final class PipelineApplier {
|
||||
|
||||
public float[] reuseOrAlloc(ContextState st, int location, int length) {
|
||||
final ShaderManager.ProgramObject prog = st.boundProgramObj;
|
||||
if (prog != null && location >= 0 && location < prog.uniformSlotCount) {
|
||||
final float[] existing = st.uniformStaging(prog).uniformDataBySlot[location];
|
||||
if (existing != null && existing.length == length) return existing;
|
||||
}
|
||||
if (prog == null || location < 0 || location >= prog.uniformSlotCount) return null;
|
||||
final float[] existing = st.uniformStaging(prog).uniformDataBySlot[location];
|
||||
if (existing != null && existing.length == length) return existing;
|
||||
return new float[length];
|
||||
}
|
||||
|
||||
@@ -828,11 +827,13 @@ public final class PipelineApplier {
|
||||
final int count = n / floatsPerMatrix;
|
||||
if (count == 0) {
|
||||
final float[] v = reuseOrAlloc(st, location, n);
|
||||
if (v == null) return;
|
||||
value.get(value.position(), v);
|
||||
putUniform(st, location, v);
|
||||
return;
|
||||
}
|
||||
final float[] out = reuseOrAlloc(st, location, count * floatsPerMatrix);
|
||||
if (out == null) return;
|
||||
MatrixMarshal.marshalMatrixToColumnMajor(value, value.position(), count, size, transpose, out, 0);
|
||||
putUniform(st, location, out);
|
||||
}
|
||||
|
||||
+59
-21
@@ -59,11 +59,11 @@ public final class PipelineCache {
|
||||
|
||||
public int primitiveType = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
|
||||
|
||||
public final boolean[] blendEnabledPerAttachment = new boolean[ContextState.MAX_COLOR_ATTACHMENTS];
|
||||
public int srcColorFactor = SDL_GPU_BLENDFACTOR_ONE;
|
||||
public int dstColorFactor = SDL_GPU_BLENDFACTOR_ZERO;
|
||||
public int srcAlphaFactor = SDL_GPU_BLENDFACTOR_ONE;
|
||||
public int dstAlphaFactor = SDL_GPU_BLENDFACTOR_ZERO;
|
||||
public final boolean[] blendEnabledPerDrawBuffer = new boolean[ContextState.MAX_COLOR_ATTACHMENTS];
|
||||
public final int[] srcColorFactors = new int[ContextState.MAX_COLOR_ATTACHMENTS];
|
||||
public final int[] dstColorFactors = new int[ContextState.MAX_COLOR_ATTACHMENTS];
|
||||
public final int[] srcAlphaFactors = new int[ContextState.MAX_COLOR_ATTACHMENTS];
|
||||
public final int[] dstAlphaFactors = new int[ContextState.MAX_COLOR_ATTACHMENTS];
|
||||
public int colorBlendOp = SDL_GPU_BLENDOP_ADD;
|
||||
public int alphaBlendOp = SDL_GPU_BLENDOP_ADD;
|
||||
|
||||
@@ -160,15 +160,35 @@ public final class PipelineCache {
|
||||
return true;
|
||||
}
|
||||
|
||||
private int attachmentForSlot(int slot) {
|
||||
final int[] db = drawBuffers;
|
||||
if (db == null || slot < 0 || slot >= db.length) return 0;
|
||||
final int idx = db[slot];
|
||||
return (idx >= 0 && idx < ContextState.MAX_COLOR_ATTACHMENTS) ? idx : 0;
|
||||
private boolean blendEnabledForSlot(int slot) {
|
||||
return slot >= 0 && slot < ContextState.MAX_COLOR_ATTACHMENTS && blendEnabledPerDrawBuffer[slot];
|
||||
}
|
||||
|
||||
private boolean blendEnabledForSlot(int slot) {
|
||||
return blendEnabledPerAttachment[attachmentForSlot(slot)];
|
||||
public boolean setBlendFactors(int sc, int dc, int sa, int da) {
|
||||
boolean changed = false;
|
||||
for (int i = 0; i < ContextState.MAX_COLOR_ATTACHMENTS; i++) {
|
||||
if (srcColorFactors[i] != sc || dstColorFactors[i] != dc || srcAlphaFactors[i] != sa || dstAlphaFactors[i] != da) {
|
||||
srcColorFactors[i] = sc;
|
||||
dstColorFactors[i] = dc;
|
||||
srcAlphaFactors[i] = sa;
|
||||
dstAlphaFactors[i] = da;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) markOutputDirty();
|
||||
return changed;
|
||||
}
|
||||
|
||||
public boolean setBlendFactors(int drawBuffer, int sc, int dc, int sa, int da) {
|
||||
if (srcColorFactors[drawBuffer] == sc && dstColorFactors[drawBuffer] == dc && srcAlphaFactors[drawBuffer] == sa && dstAlphaFactors[drawBuffer] == da) {
|
||||
return false;
|
||||
}
|
||||
srcColorFactors[drawBuffer] = sc;
|
||||
dstColorFactors[drawBuffer] = dc;
|
||||
srcAlphaFactors[drawBuffer] = sa;
|
||||
dstAlphaFactors[drawBuffer] = da;
|
||||
markOutputDirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
public int maxAttribs;
|
||||
@@ -183,6 +203,10 @@ public final class PipelineCache {
|
||||
|
||||
public PipelineCache() {
|
||||
this.maxAttribs = ContextState.MAX_VERTEX_ATTRIBS;
|
||||
Arrays.fill(srcColorFactors, SDL_GPU_BLENDFACTOR_ONE);
|
||||
Arrays.fill(dstColorFactors, SDL_GPU_BLENDFACTOR_ZERO);
|
||||
Arrays.fill(srcAlphaFactors, SDL_GPU_BLENDFACTOR_ONE);
|
||||
Arrays.fill(dstAlphaFactors, SDL_GPU_BLENDFACTOR_ZERO);
|
||||
}
|
||||
|
||||
long lastKey() {
|
||||
@@ -199,6 +223,16 @@ public final class PipelineCache {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setVertexInputs(int mask, int[] vecSize, int[] baseType, String[] names) {
|
||||
if (shaderInputMask != mask || !Arrays.equals(shaderInputVecSize, vecSize) || !Arrays.equals(shaderInputBaseType, baseType)) {
|
||||
markInputDirty();
|
||||
}
|
||||
shaderInputMask = mask;
|
||||
shaderInputVecSize = vecSize;
|
||||
shaderInputBaseType = baseType;
|
||||
shaderInputName = names;
|
||||
}
|
||||
|
||||
public void markOutputDirty() { outputDirty = true; lastKey = 0L; }
|
||||
public void markShaderDirty() { shaderDirty = true; lastKey = 0L; }
|
||||
|
||||
@@ -296,9 +330,11 @@ public final class PipelineCache {
|
||||
| (((long) blendBits & 0xFFFFFFFFL) << 32);
|
||||
long h = OUTPUT_SEED;
|
||||
h = Hashing.fmix64(h, bits);
|
||||
h = Hashing.fmix64(h, Hashing.packHiLo(primitiveType, srcColorFactor));
|
||||
h = Hashing.fmix64(h, Hashing.packHiLo(dstColorFactor, srcAlphaFactor));
|
||||
h = Hashing.fmix64(h, Hashing.packHiLo(dstAlphaFactor, colorBlendOp));
|
||||
h = Hashing.fmix64(h, Hashing.packHiLo(primitiveType, colorBlendOp));
|
||||
for (int i = 0; i < ctfLen; i++) {
|
||||
h = Hashing.fmix64(h, Hashing.packHiLo(srcColorFactors[i], dstColorFactors[i]));
|
||||
h = Hashing.fmix64(h, Hashing.packHiLo(srcAlphaFactors[i], dstAlphaFactors[i]));
|
||||
}
|
||||
h = Hashing.fmix64(h, Hashing.packHiLo(alphaBlendOp, depthCompareOp));
|
||||
h = Hashing.fmix64(h, Hashing.packHiLo(stencilFrontCompareOp, stencilFrontFailOp));
|
||||
h = Hashing.fmix64(h, Hashing.packHiLo(stencilFrontDepthFailOp, stencilFrontPassOp));
|
||||
@@ -390,11 +426,11 @@ public final class PipelineCache {
|
||||
desc.format(colorTargetFormats()[i]);
|
||||
desc.blend_state()
|
||||
.enable_blend(blendEnabledForSlot(i))
|
||||
.src_color_blendfactor(srcColorFactor)
|
||||
.dst_color_blendfactor(dstColorFactor)
|
||||
.src_color_blendfactor(srcColorFactors[i])
|
||||
.dst_color_blendfactor(dstColorFactors[i])
|
||||
.color_blend_op(colorBlendOp)
|
||||
.src_alpha_blendfactor(srcAlphaFactor)
|
||||
.dst_alpha_blendfactor(dstAlphaFactor)
|
||||
.src_alpha_blendfactor(srcAlphaFactors[i])
|
||||
.dst_alpha_blendfactor(dstAlphaFactors[i])
|
||||
.alpha_blend_op(alphaBlendOp)
|
||||
.color_write_mask((byte) colorWriteMask)
|
||||
.enable_color_write_mask(true);
|
||||
@@ -504,8 +540,10 @@ public final class PipelineCache {
|
||||
.append(" backCmp=").append(stencilBackCompareOp).append('\n');
|
||||
}
|
||||
sb.append(" Blend: enabled=").append(blendEnabledForSlot(0))
|
||||
.append(" srcColor=").append(srcColorFactor).append(" dstColor=").append(dstColorFactor).append(" colorOp=").append(colorBlendOp)
|
||||
.append(" srcAlpha=").append(srcAlphaFactor).append(" dstAlpha=").append(dstAlphaFactor).append(" alphaOp=").append(alphaBlendOp)
|
||||
.append(" srcColor=").append(srcColorFactors[0]).append(" dstColor=").append(dstColorFactors[0])
|
||||
.append(" colorOp=").append(colorBlendOp)
|
||||
.append(" srcAlpha=").append(srcAlphaFactors[0]).append(" dstAlpha=").append(dstAlphaFactors[0])
|
||||
.append(" alphaOp=").append(alphaBlendOp)
|
||||
.append(" mask=0x").append(Integer.toHexString(colorWriteMask)).append('\n');
|
||||
sb.append(" Rasterizer: cull=").append(getEffectiveCullMode())
|
||||
.append(" front=").append(effectiveFrontFace())
|
||||
|
||||
+10
-8
@@ -1,8 +1,9 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu.resource;
|
||||
|
||||
import com.gtnewhorizons.angelica.sdlgpu.device.Device;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.lwjgl.sdl.SDLError;
|
||||
@@ -86,13 +87,14 @@ public final class ReadbackShadows {
|
||||
}
|
||||
|
||||
public void release(int glId) {
|
||||
final LongArrayList doomed = new LongArrayList();
|
||||
for (long k : slots.keySet()) {
|
||||
if ((int) (k >>> 32) == glId) doomed.add(k);
|
||||
}
|
||||
for (int i = 0; i < doomed.size(); i++) {
|
||||
final Slot slot = slots.remove(doomed.getLong(i));
|
||||
if (slot != null) releaseSlot(slot);
|
||||
if (slots.isEmpty()) return;
|
||||
final ObjectIterator<Long2ObjectMap.Entry<Slot>> it = slots.long2ObjectEntrySet().fastIterator();
|
||||
while (it.hasNext()) {
|
||||
final Long2ObjectMap.Entry<Slot> entry = it.next();
|
||||
if ((int) (entry.getLongKey() >>> 32) == glId) {
|
||||
releaseSlot(entry.getValue());
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu;
|
||||
|
||||
import com.gtnewhorizons.angelica.sdlgpu.frame.ContextState;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL31;
|
||||
import org.lwjgl.opengl.GL40;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
|
||||
class BufferDeleteUnbindTest {
|
||||
|
||||
private static final int BUFFER = 7001;
|
||||
private static final int OTHER = 7002;
|
||||
private static final int UBO_INDEX = 3;
|
||||
private static final int SSBO_INDEX = 5;
|
||||
private static final int VERTEX_BINDING = 2;
|
||||
private static final int ATTRIB = 4;
|
||||
|
||||
private static SDLGPURenderBackend backend;
|
||||
|
||||
private ContextState st;
|
||||
|
||||
@BeforeAll
|
||||
static void createBackend() {
|
||||
backend = new SDLGPURenderBackend();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
st = SdlTestRig.contextState();
|
||||
backend.bindBufferRange(GL31.GL_UNIFORM_BUFFER, UBO_INDEX, BUFFER, 16L, 64L);
|
||||
backend.bindBufferBase(GL43.GL_SHADER_STORAGE_BUFFER, SSBO_INDEX, BUFFER);
|
||||
backend.bindBuffer(GL40.GL_DRAW_INDIRECT_BUFFER, BUFFER);
|
||||
backend.bindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, BUFFER);
|
||||
backend.bindVertexBuffer(VERTEX_BINDING, BUFFER, 8L, 12);
|
||||
backend.bindBuffer(GL15.GL_ARRAY_BUFFER, BUFFER);
|
||||
backend.bindBuffer(GL43.GL_DISPATCH_INDIRECT_BUFFER, BUFFER);
|
||||
backend.bindBuffer(GL31.GL_COPY_READ_BUFFER, BUFFER);
|
||||
backend.bindBuffer(GL31.GL_COPY_WRITE_BUFFER, BUFFER);
|
||||
backend.bindBuffer(GL30.GL_PIXEL_PACK_BUFFER, BUFFER);
|
||||
backend.bindBuffer(GL30.GL_PIXEL_UNPACK_BUFFER, BUFFER);
|
||||
st.currentVao.attribVBO[ATTRIB] = BUFFER;
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
backend.bindBufferBase(GL31.GL_UNIFORM_BUFFER, UBO_INDEX, 0);
|
||||
backend.bindBufferBase(GL43.GL_SHADER_STORAGE_BUFFER, SSBO_INDEX, 0);
|
||||
backend.bindBuffer(GL40.GL_DRAW_INDIRECT_BUFFER, 0);
|
||||
backend.bindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
backend.bindVertexBuffer(VERTEX_BINDING, 0, 0L, 0);
|
||||
backend.bindBuffer(GL15.GL_ARRAY_BUFFER, 0);
|
||||
backend.bindBuffer(GL43.GL_DISPATCH_INDIRECT_BUFFER, 0);
|
||||
backend.bindBuffer(GL31.GL_COPY_READ_BUFFER, 0);
|
||||
backend.bindBuffer(GL31.GL_COPY_WRITE_BUFFER, 0);
|
||||
backend.bindBuffer(GL30.GL_PIXEL_PACK_BUFFER, 0);
|
||||
backend.bindBuffer(GL30.GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
st.currentVao.attribVBO[ATTRIB] = 0;
|
||||
}
|
||||
|
||||
private void assertAllCleared() {
|
||||
assertEquals(0, st.boundUboByIndex[UBO_INDEX]);
|
||||
assertEquals(0, st.uboRangeOffset[UBO_INDEX]);
|
||||
assertEquals(0, st.uboRangeSize[UBO_INDEX]);
|
||||
assertEquals(0, st.boundUniformBuffer);
|
||||
assertEquals(0, st.boundSsboByIndex[SSBO_INDEX]);
|
||||
assertEquals(0, st.boundSSBO);
|
||||
assertEquals(0, st.boundIndirectBuffer);
|
||||
assertEquals(0, st.currentVao.elementBuffer);
|
||||
assertEquals(0, st.currentVao.bindingBuffer[VERTEX_BINDING]);
|
||||
assertEquals(0, st.currentVao.attribVBO[ATTRIB]);
|
||||
assertEquals(0, st.boundArrayBuffer);
|
||||
assertEquals(0, st.boundDispatchIndirectBuffer);
|
||||
assertEquals(0, st.boundCopyReadBuffer);
|
||||
assertEquals(0, st.boundCopyWriteBuffer);
|
||||
assertEquals(0, st.boundPixelPackBuffer);
|
||||
assertEquals(0, st.boundPixelUnpackBuffer);
|
||||
}
|
||||
|
||||
private void assertAllBound() {
|
||||
assertEquals(BUFFER, st.boundUboByIndex[UBO_INDEX]);
|
||||
assertEquals(16, st.uboRangeOffset[UBO_INDEX]);
|
||||
assertEquals(64, st.uboRangeSize[UBO_INDEX]);
|
||||
assertEquals(BUFFER, st.boundUniformBuffer);
|
||||
assertEquals(BUFFER, st.boundSsboByIndex[SSBO_INDEX]);
|
||||
assertEquals(BUFFER, st.boundSSBO);
|
||||
assertEquals(BUFFER, st.boundIndirectBuffer);
|
||||
assertEquals(BUFFER, st.currentVao.elementBuffer);
|
||||
assertEquals(BUFFER, st.currentVao.bindingBuffer[VERTEX_BINDING]);
|
||||
assertEquals(BUFFER, st.currentVao.attribVBO[ATTRIB]);
|
||||
assertEquals(BUFFER, st.boundArrayBuffer);
|
||||
assertEquals(BUFFER, st.boundDispatchIndirectBuffer);
|
||||
assertEquals(BUFFER, st.boundCopyReadBuffer);
|
||||
assertEquals(BUFFER, st.boundCopyWriteBuffer);
|
||||
assertEquals(BUFFER, st.boundPixelPackBuffer);
|
||||
assertEquals(BUFFER, st.boundPixelUnpackBuffer);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteClearsEveryBindingOfTheDeletedBuffer() {
|
||||
assertAllBound();
|
||||
final int uboGen = st.uboRangeGen;
|
||||
final int ssboGen = st.ssboBindGen;
|
||||
final long attribGen = st.attribStateGen;
|
||||
|
||||
backend.deleteBuffers(BUFFER);
|
||||
|
||||
assertAllCleared();
|
||||
assertEquals(8L, st.currentVao.bindingOffset[VERTEX_BINDING]);
|
||||
assertEquals(12, st.currentVao.bindingStride[VERTEX_BINDING]);
|
||||
assertNotEquals(uboGen, st.uboRangeGen);
|
||||
assertNotEquals(ssboGen, st.ssboBindGen);
|
||||
assertNotEquals(attribGen, st.attribStateGen);
|
||||
}
|
||||
|
||||
@Test
|
||||
void intBufferDeleteClearsEveryBindingOfTheDeletedBuffer() {
|
||||
final int uboGen = st.uboRangeGen;
|
||||
final int ssboGen = st.ssboBindGen;
|
||||
final long attribGen = st.attribStateGen;
|
||||
final IntBuffer ids = MemoryUtil.memAllocInt(2);
|
||||
try {
|
||||
ids.put(0, OTHER).put(1, BUFFER);
|
||||
backend.deleteBuffers(ids);
|
||||
} finally {
|
||||
MemoryUtil.memFree(ids);
|
||||
}
|
||||
|
||||
assertAllCleared();
|
||||
assertNotEquals(uboGen, st.uboRangeGen);
|
||||
assertNotEquals(ssboGen, st.ssboBindGen);
|
||||
assertNotEquals(attribGen, st.attribStateGen);
|
||||
}
|
||||
|
||||
@Test
|
||||
void deletingAnUnrelatedBufferChangesNothing() {
|
||||
final int uboGen = st.uboRangeGen;
|
||||
final int ssboGen = st.ssboBindGen;
|
||||
final long attribGen = st.attribStateGen;
|
||||
|
||||
backend.deleteBuffers(OTHER);
|
||||
backend.deleteBuffers(0);
|
||||
|
||||
assertAllBound();
|
||||
assertEquals(uboGen, st.uboRangeGen);
|
||||
assertEquals(ssboGen, st.ssboBindGen);
|
||||
assertEquals(attribGen, st.attribStateGen);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.frame.ContextState;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.resource.FboState;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.resource.ResourceManager;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
|
||||
class DrawBuffersLimitTest {
|
||||
|
||||
private static final int BOUND_FBO = 901;
|
||||
private static final int UNBOUND_FBO = 902;
|
||||
|
||||
private static SDLGPURenderBackend backend;
|
||||
private static ResourceManager resourceManager;
|
||||
|
||||
private ContextState st;
|
||||
private int savedFbo;
|
||||
|
||||
@BeforeAll
|
||||
static void createBackend() {
|
||||
backend = new SDLGPURenderBackend();
|
||||
resourceManager = Reflect.get(backend, "resourceManager");
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
st = SdlTestRig.contextState();
|
||||
savedFbo = st.boundFboId;
|
||||
st.boundFboId = BOUND_FBO;
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
st.boundFboId = savedFbo;
|
||||
resourceManager.deleteFbo(BOUND_FBO);
|
||||
resourceManager.deleteFbo(UNBOUND_FBO);
|
||||
}
|
||||
|
||||
private static IntBuffer attachments(int count) {
|
||||
final int[] bufs = new int[count];
|
||||
for (int i = 0; i < count; i++) bufs[i] = GL30.GL_COLOR_ATTACHMENT0 + i;
|
||||
return IntBuffer.wrap(bufs);
|
||||
}
|
||||
|
||||
@Test
|
||||
void namedDrawBuffersOverTheLimitAreIgnored() {
|
||||
final FboState fbo = resourceManager.createFbo(UNBOUND_FBO);
|
||||
backend.namedFramebufferDrawBuffers(UNBOUND_FBO, attachments(2));
|
||||
final int[] before = fbo.drawBuffers;
|
||||
assertArrayEquals(new int[]{0, 1}, before, "a legal count must apply, or the refusal proves nothing");
|
||||
|
||||
backend.namedFramebufferDrawBuffers(UNBOUND_FBO, attachments(ContextState.MAX_COLOR_ATTACHMENTS + 1));
|
||||
assertSame(before, fbo.drawBuffers, "a count above MAX_DRAW_BUFFERS must leave the draw buffers untouched");
|
||||
assertArrayEquals(new int[]{0, 1}, fbo.drawBuffers);
|
||||
|
||||
backend.namedFramebufferDrawBuffers(UNBOUND_FBO, attachments(ContextState.MAX_COLOR_ATTACHMENTS));
|
||||
assertEquals(ContextState.MAX_COLOR_ATTACHMENTS, fbo.drawBuffers.length, "exactly the limit is legal");
|
||||
}
|
||||
|
||||
@Test
|
||||
void boundDrawBuffersOverTheLimitAreIgnored() {
|
||||
final FboState fbo = resourceManager.createFbo(BOUND_FBO);
|
||||
assertSame(fbo, resourceManager.getFbo(st.boundFboId));
|
||||
final int[] before = fbo.drawBuffers;
|
||||
|
||||
backend.drawBuffers(attachments(ContextState.MAX_COLOR_ATTACHMENTS + 1));
|
||||
assertSame(before, fbo.drawBuffers, "a count above MAX_DRAW_BUFFERS must leave the draw buffers untouched");
|
||||
assertArrayEquals(new int[]{0}, fbo.drawBuffers);
|
||||
assertNull(fbo.cachedColorFormats, "an ignored call must not reach the pipeline color formats");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu;
|
||||
|
||||
import com.gtnewhorizons.angelica.sdlgpu.pipeline.PipelineCache;
|
||||
import com.sun.management.ThreadMXBean;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
public final class SdlAsserts {
|
||||
|
||||
private static final int WARMUP_ROUNDS = 50_000;
|
||||
private static final int MEASURED_ROUNDS = 100_000;
|
||||
private static final long ALLOCATION_BUDGET_BYTES = 256L * 1024L;
|
||||
|
||||
private SdlAsserts() {}
|
||||
|
||||
public static void assertBlendFactors(PipelineCache p, int drawBuffer, int sc, int dc, int sa, int da, String when) {
|
||||
assertEquals(sc, p.srcColorFactors[drawBuffer], when + ": srcColor of draw buffer " + drawBuffer);
|
||||
assertEquals(dc, p.dstColorFactors[drawBuffer], when + ": dstColor of draw buffer " + drawBuffer);
|
||||
assertEquals(sa, p.srcAlphaFactors[drawBuffer], when + ": srcAlpha of draw buffer " + drawBuffer);
|
||||
assertEquals(da, p.dstAlphaFactors[drawBuffer], when + ": dstAlpha of draw buffer " + drawBuffer);
|
||||
}
|
||||
|
||||
public static void assertAllocationFree(Runnable round, String what) {
|
||||
assumeTrue(ManagementFactory.getThreadMXBean() instanceof ThreadMXBean);
|
||||
final ThreadMXBean bean = (ThreadMXBean) ManagementFactory.getThreadMXBean();
|
||||
assumeTrue(bean.isThreadAllocatedMemorySupported() && bean.isThreadAllocatedMemoryEnabled());
|
||||
for (int i = 0; i < WARMUP_ROUNDS; i++) round.run();
|
||||
final long before = bean.getCurrentThreadAllocatedBytes();
|
||||
for (int i = 0; i < MEASURED_ROUNDS; i++) round.run();
|
||||
final long allocated = bean.getCurrentThreadAllocatedBytes() - before;
|
||||
assertTrue(allocated < ALLOCATION_BUDGET_BYTES, allocated + " bytes allocated across " + MEASURED_ROUNDS + " rounds of " + what);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu;
|
||||
|
||||
import com.gtnewhorizons.angelica.sdlgpu.frame.ContextState;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.shader.ShaderManager;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.shader.UniformStaging;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class UniformStoreTest {
|
||||
|
||||
private static final int VEC4 = 0;
|
||||
private static final int OUT_OF_RANGE = 7;
|
||||
private static final float[] VALUES = {5f, 6f, 7f, 8f};
|
||||
|
||||
private static SDLGPURenderBackend backend;
|
||||
|
||||
private ContextState st;
|
||||
private ShaderManager.ProgramObject prog;
|
||||
private ShaderManager.ProgramObject savedProgramObj;
|
||||
private int savedProgram;
|
||||
private IntBuffer ints;
|
||||
|
||||
@BeforeAll
|
||||
static void createBackend() {
|
||||
backend = new SDLGPURenderBackend();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
st = SdlTestRig.contextState();
|
||||
savedProgramObj = st.boundProgramObj;
|
||||
savedProgram = st.boundProgram;
|
||||
prog = new ShaderManager.ProgramObject();
|
||||
prog.linked = true;
|
||||
prog.vertexUboSize = 16;
|
||||
prog.nextUniformLocation = 1;
|
||||
prog.vertexMemberInfo.put(VEC4, new ShaderManager.UniformMemberInfo(0, 16, 0, true, 4, 1, 0, 1));
|
||||
prog.buildUniformSlotArrays();
|
||||
st.boundProgramObj = prog;
|
||||
st.boundProgram = 1;
|
||||
ints = MemoryUtil.memAllocInt(4);
|
||||
ints.put(0, 1).put(1, 2).put(2, 3).put(3, 4);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
MemoryUtil.memFree(ints);
|
||||
st.releaseUniformStaging(prog);
|
||||
st.boundProgramObj = savedProgramObj;
|
||||
st.boundProgram = savedProgram;
|
||||
}
|
||||
|
||||
private void writeAll(int location) {
|
||||
backend.uniform4f(location, 1f, 2f, 3f, 4f);
|
||||
backend.uniform4fv(location, VALUES);
|
||||
backend.uniform4i(location, 1, 2, 3, 4);
|
||||
backend.uniform4iv(location, ints);
|
||||
}
|
||||
|
||||
private void dropRound() {
|
||||
st.boundProgramObj = null;
|
||||
writeAll(VEC4);
|
||||
st.boundProgramObj = prog;
|
||||
writeAll(OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
private void assertNothingStaged() {
|
||||
final UniformStaging us = st.uniformStaging(prog);
|
||||
assertNull(us.uniformDataBySlot[VEC4]);
|
||||
assertEquals(0L, us.uniformValueHashBySlot[VEC4]);
|
||||
assertFalse(us.vsUniformDirty);
|
||||
}
|
||||
|
||||
private float[] staged(int location) {
|
||||
return st.uniformStaging(prog).uniformDataBySlot[location];
|
||||
}
|
||||
|
||||
@Test
|
||||
void noProgramBoundStoresNothing() {
|
||||
st.boundProgramObj = null;
|
||||
assertDoesNotThrow(() -> writeAll(VEC4));
|
||||
st.boundProgramObj = prog;
|
||||
assertNothingStaged();
|
||||
}
|
||||
|
||||
@Test
|
||||
void outOfRangeLocationStoresNothing() {
|
||||
assertEquals(1, prog.uniformSlotCount);
|
||||
assertDoesNotThrow(() -> writeAll(OUT_OF_RANGE));
|
||||
assertNothingStaged();
|
||||
}
|
||||
|
||||
@Test
|
||||
void droppedStoresDoNotAllocate() {
|
||||
SdlAsserts.assertAllocationFree(this::dropRound, "dropped uniform stores");
|
||||
assertNothingStaged();
|
||||
}
|
||||
|
||||
@Test
|
||||
void boundProgramWriteStillStores() {
|
||||
backend.uniform4f(VEC4, 1f, 2f, 3f, 4f);
|
||||
assertArrayEquals(new float[]{1f, 2f, 3f, 4f}, staged(VEC4));
|
||||
|
||||
backend.uniform4fv(VEC4, VALUES);
|
||||
assertArrayEquals(VALUES, staged(VEC4));
|
||||
|
||||
backend.uniform4iv(VEC4, ints);
|
||||
final float[] stagedValues = staged(VEC4);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
assertEquals(i + 1, Float.floatToRawIntBits(stagedValues[i]));
|
||||
}
|
||||
assertTrue(st.uniformStaging(prog).vsUniformDirty);
|
||||
}
|
||||
|
||||
@Test
|
||||
void vectorWriteCopiesTheCallerArrayAndReusesTheSlot() {
|
||||
final float[] first = {5f, 6f, 7f, 8f};
|
||||
backend.uniform4fv(VEC4, first);
|
||||
final float[] slot = staged(VEC4);
|
||||
assertNotSame(first, slot, "the staging must not hold the caller's array");
|
||||
assertArrayEquals(new float[]{5f, 6f, 7f, 8f}, slot);
|
||||
|
||||
final float[] second = {9f, 10f, 11f, 12f};
|
||||
backend.uniform4fv(VEC4, second);
|
||||
assertSame(slot, staged(VEC4), "same-length writes must reuse the slot array");
|
||||
assertNotSame(second, staged(VEC4));
|
||||
assertArrayEquals(new float[]{9f, 10f, 11f, 12f}, slot);
|
||||
|
||||
final float[] equalValues = second.clone();
|
||||
backend.uniform4fv(VEC4, equalValues);
|
||||
assertSame(slot, staged(VEC4), "an equal-valued caller array must not replace the slot array");
|
||||
|
||||
backend.uniform4f(VEC4, 1f, 2f, 3f, 4f);
|
||||
assertArrayEquals(new float[]{5f, 6f, 7f, 8f}, first);
|
||||
assertArrayEquals(new float[]{9f, 10f, 11f, 12f}, second);
|
||||
assertArrayEquals(new float[]{9f, 10f, 11f, 12f}, equalValues);
|
||||
assertArrayEquals(new float[]{1f, 2f, 3f, 4f}, slot);
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import com.gtnewhorizons.angelica.sdlgpu.SDLGPURenderBackend;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SdlTestRig;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.pipeline.PipelineCache;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.resource.ResourceManager;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
@@ -85,6 +86,12 @@ public final class GlsmSdlHeadlessRig {
|
||||
endFrame();
|
||||
}
|
||||
|
||||
public static int glsmBufferBinding(int target) {
|
||||
final Object ctx = Reflect.getStatic(GLStateManager.class, "primaryContext");
|
||||
final Int2IntMap bound = Reflect.get(ctx, "boundOtherBuffers");
|
||||
return bound.get(target);
|
||||
}
|
||||
|
||||
private static int colorTargetSdlFormat() {
|
||||
final ResourceManager rm = Reflect.get(BackendManager.RENDER_BACKEND, "resourceManager");
|
||||
final ResourceManager.TextureMeta meta = rm.getTextureMeta(colorTexture);
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SDLGPURenderBackend;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SdlAsserts;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.frame.ContextState;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.pipeline.PipelineCache;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.lwjgl.sdl.SDLGPU.SDL_GPU_BLENDFACTOR_ONE;
|
||||
import static org.lwjgl.sdl.SDLGPU.SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
import static org.lwjgl.sdl.SDLGPU.SDL_GPU_BLENDFACTOR_SRC_ALPHA;
|
||||
|
||||
@Tag("glsm-sdl")
|
||||
@ExtendWith(GlsmSdlFrameExtension.class)
|
||||
class GlsmSdlIndexedBlendRestoreTest {
|
||||
|
||||
@BeforeAll
|
||||
static void boot() {
|
||||
GlsmSdlHeadlessRig.boot();
|
||||
}
|
||||
|
||||
private static PipelineCache pipeline() {
|
||||
final ContextState st = Reflect.invokeStatic(SDLGPURenderBackend.class, "s", new Class<?>[0]);
|
||||
return st.pipeline;
|
||||
}
|
||||
|
||||
private static void vanillaBlendFunc() {
|
||||
GLStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
@Test
|
||||
void vanillaBlendFuncAfterIndexedOverrideReachesEveryDrawBuffer() {
|
||||
try {
|
||||
vanillaBlendFunc();
|
||||
RenderSystem.blendFuncSeparatei(1, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE);
|
||||
|
||||
final PipelineCache p = pipeline();
|
||||
SdlAsserts.assertBlendFactors(p, 1, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ONE, "override");
|
||||
SdlAsserts.assertBlendFactors(p, 0, SDL_GPU_BLENDFACTOR_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, "override");
|
||||
|
||||
vanillaBlendFunc();
|
||||
|
||||
for (int i = 0; i < ContextState.MAX_COLOR_ATTACHMENTS; i++) {
|
||||
SdlAsserts.assertBlendFactors(p, i, SDL_GPU_BLENDFACTOR_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, "restore");
|
||||
}
|
||||
assertFalse(GLStateManager.getBlendState().isFuncUnknown(), "restore forward must clear the unknown flag");
|
||||
} finally {
|
||||
GLStateManager.tryBlendFuncSeparate(GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
}
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.states.PixelUnpackState;
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SDLGPULWJGLService;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL31;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
|
||||
@Tag("glsm-sdl")
|
||||
@ExtendWith(GlsmSdlFrameExtension.class)
|
||||
class GlsmSdlLWJGLServiceRoutingTest {
|
||||
|
||||
private static final int UBO_INDEX = 3;
|
||||
|
||||
private static SDLGPULWJGLService svc;
|
||||
|
||||
@BeforeAll
|
||||
static void boot() {
|
||||
GlsmSdlHeadlessRig.boot();
|
||||
svc = SDLGPULWJGLService.create();
|
||||
}
|
||||
|
||||
private static Object glsmContext() {
|
||||
return Reflect.getStatic(GLStateManager.class, "primaryContext");
|
||||
}
|
||||
|
||||
private static int glsmUnpackAlignment() {
|
||||
final PixelUnpackState state = Reflect.get(glsmContext(), "pixelUnpackState");
|
||||
return state.alignment();
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteBuffersClearsTheGlsmArrayBufferBinding() {
|
||||
final int buffer = svc.glGenBuffers();
|
||||
svc.glBindBuffer(GL15.GL_ARRAY_BUFFER, buffer);
|
||||
svc.glBufferData(GL15.GL_ARRAY_BUFFER, 64L, GL15.GL_STATIC_DRAW);
|
||||
assertEquals(buffer, GLStateManager.getBoundVBO());
|
||||
|
||||
svc.glDeleteBuffers(buffer);
|
||||
|
||||
assertEquals(0, GLStateManager.getBoundVBO());
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindBufferBaseUpdatesTheGlsmGenericBinding() {
|
||||
final int buffer = svc.glGenBuffers();
|
||||
svc.glBindBuffer(GL31.GL_UNIFORM_BUFFER, buffer);
|
||||
svc.glBufferData(GL31.GL_UNIFORM_BUFFER, 64L, GL15.GL_DYNAMIC_DRAW);
|
||||
svc.glBindBuffer(GL31.GL_UNIFORM_BUFFER, 0);
|
||||
assertEquals(0, GlsmSdlHeadlessRig.glsmBufferBinding(GL31.GL_UNIFORM_BUFFER));
|
||||
|
||||
try {
|
||||
svc.glBindBufferBase(GL31.GL_UNIFORM_BUFFER, UBO_INDEX, buffer);
|
||||
assertEquals(buffer, GlsmSdlHeadlessRig.glsmBufferBinding(GL31.GL_UNIFORM_BUFFER));
|
||||
} finally {
|
||||
svc.glBindBufferBase(GL31.GL_UNIFORM_BUFFER, UBO_INDEX, 0);
|
||||
svc.glDeleteBuffers(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void clearColorUpdatesTheGlsmCache() {
|
||||
svc.glClearColor(0.25f, 0.5f, 0.75f, 1.0f);
|
||||
|
||||
assertEquals(0.25f, GLStateManager.getClearColor().getRed());
|
||||
assertEquals(0.5f, GLStateManager.getClearColor().getGreen());
|
||||
assertEquals(0.75f, GLStateManager.getClearColor().getBlue());
|
||||
}
|
||||
|
||||
@Test
|
||||
void pixelStoreiUpdatesTheGlsmUnpackState() {
|
||||
assertNotEquals(1, glsmUnpackAlignment());
|
||||
try {
|
||||
svc.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1);
|
||||
assertEquals(1, glsmUnpackAlignment());
|
||||
} finally {
|
||||
svc.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 4);
|
||||
}
|
||||
assertEquals(4, glsmUnpackAlignment());
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteFramebuffersClearsTheGlsmDrawFramebuffer() {
|
||||
final int framebuffer = svc.glGenFramebuffers();
|
||||
try {
|
||||
svc.glBindFramebuffer(GL30.GL_FRAMEBUFFER, framebuffer);
|
||||
assertEquals(framebuffer, GLStateManager.getDrawFramebuffer());
|
||||
|
||||
svc.glDeleteFramebuffers(framebuffer);
|
||||
|
||||
assertEquals(0, GLStateManager.getDrawFramebuffer());
|
||||
} finally {
|
||||
GlsmSdlHeadlessRig.bindTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SdlTestRig;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.frame.ContextState;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@Tag("glsm-sdl")
|
||||
@ExtendWith(GlsmSdlFrameExtension.class)
|
||||
class GlsmSdlSamplerBindingTest {
|
||||
|
||||
private static final int UNIT = 3;
|
||||
|
||||
@BeforeAll
|
||||
static void boot() {
|
||||
GlsmSdlHeadlessRig.boot();
|
||||
}
|
||||
|
||||
@Test
|
||||
void glsmDeleteClearsBothCaches() {
|
||||
final ContextState st = SdlTestRig.contextState();
|
||||
final int sampler = GLStateManager.glGenSamplers();
|
||||
GLStateManager.glBindSampler(UNIT, sampler);
|
||||
assertEquals(sampler, st.boundSamplerObjects[UNIT], "SDL unit binding");
|
||||
assertEquals(sampler, GLStateManager.getSamplerBinding(UNIT), "GLSM unit binding");
|
||||
|
||||
GLStateManager.glDeleteSamplers(sampler);
|
||||
|
||||
assertEquals(0, st.boundSamplerObjects[UNIT], "SDL must drop the deleted sampler");
|
||||
assertEquals(0, GLStateManager.getSamplerBinding(UNIT), "GLSM must drop the deleted sampler");
|
||||
}
|
||||
|
||||
@Test
|
||||
void renderSystemRebindAfterGlsmUnbindReachesSdl() {
|
||||
assertTrue(RenderSystem.supportsSamplerObjects(), "RenderSystem sampler calls would no-op and prove nothing");
|
||||
final ContextState st = SdlTestRig.contextState();
|
||||
final int sampler = RenderSystem.genSampler();
|
||||
try {
|
||||
RenderSystem.bindSamplerToUnit(UNIT, sampler);
|
||||
GLStateManager.glBindSampler(UNIT, 0);
|
||||
assertEquals(0, st.boundSamplerObjects[UNIT], "setup: GLSM unbind must reach SDL");
|
||||
|
||||
RenderSystem.bindSamplerToUnit(UNIT, sampler);
|
||||
|
||||
assertEquals(sampler, st.boundSamplerObjects[UNIT], "RenderSystem skipped a bind SDL no longer holds");
|
||||
} finally {
|
||||
RenderSystem.destroySampler(sampler);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void unitCountMatchesTheSdlSamplerArray() {
|
||||
GLStateManager.glBindSampler(0, 0);
|
||||
assertEquals(SdlTestRig.contextState().boundSamplerObjects.length, GLStateManager.getSamplerUnitCount());
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.RenderSystem;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.FfpExtendedAttribs;
|
||||
import com.gtnewhorizons.angelica.glsm.streaming.PersistentStreamingBuffer;
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
|
||||
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
|
||||
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.assertTrue;
|
||||
|
||||
@Tag("glsm-sdl")
|
||||
@ExtendWith(GlsmSdlFrameExtension.class)
|
||||
class GlsmSdlStreamingRingTest {
|
||||
|
||||
@BeforeAll
|
||||
static void boot() {
|
||||
GlsmSdlHeadlessRig.boot();
|
||||
}
|
||||
|
||||
@Test
|
||||
void ringCreationLeavesTheGlsmArrayBufferCacheMatchingSdl() {
|
||||
assertTrue(RenderSystem.supportsBufferStorage(), "SDL-GPU must advertise buffer storage");
|
||||
final int other = GLStateManager.glGenBuffers();
|
||||
PersistentStreamingBuffer ring = null;
|
||||
try {
|
||||
GLStateManager.glBindBuffer(GL15.GL_ARRAY_BUFFER, other);
|
||||
ring = PersistentStreamingBuffer.createOrNull(4096);
|
||||
assertNotNull(ring);
|
||||
final IntSet persistent = Reflect.getStatic(FfpExtendedAttribs.class, "persistentSources");
|
||||
assertTrue(persistent.contains(ring.getBufferId()), "the ring buffer is the persistent source");
|
||||
assertFalse(persistent.contains(other), "the previously bound buffer is not persistent");
|
||||
assertEquals(RENDER_BACKEND.getInteger(GL15.GL_ARRAY_BUFFER_BINDING), GLStateManager.getBoundVBO(), "SDL ContextState.boundArrayBuffer must equal the GLSM cache after ring creation");
|
||||
} finally {
|
||||
if (ring != null) ring.destroy();
|
||||
GLStateManager.glDeleteBuffers(other);
|
||||
}
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu.glsm;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SdlTestRig;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.frame.ContextState;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
import static com.gtnewhorizons.angelica.glsm.backend.BackendManager.RENDER_BACKEND;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@Tag("glsm-sdl")
|
||||
@ExtendWith(GlsmSdlFrameExtension.class)
|
||||
class GlsmSdlVoxelRegionBindTest {
|
||||
|
||||
private static final int BOUND_SLOT = 5;
|
||||
private static final int EMPTY_SLOT = 6;
|
||||
private static final int UNLINKED_PROGRAM = Integer.MAX_VALUE;
|
||||
|
||||
@BeforeAll
|
||||
static void boot() {
|
||||
GlsmSdlHeadlessRig.boot();
|
||||
}
|
||||
|
||||
private static int glsmGenericSsbo() {
|
||||
return GlsmSdlHeadlessRig.glsmBufferBinding(GL43.GL_SHADER_STORAGE_BUFFER);
|
||||
}
|
||||
|
||||
private static void unbind(int slot) {
|
||||
GLStateManager.glBindBufferBase(GL43.GL_SHADER_STORAGE_BUFFER, slot, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
void glsmBindBufferBaseReachesBothCaches() {
|
||||
final ContextState st = SdlTestRig.contextState();
|
||||
final int buf = GLStateManager.glGenBuffers();
|
||||
try {
|
||||
GLStateManager.glBindBufferBase(GL43.GL_SHADER_STORAGE_BUFFER, BOUND_SLOT, buf);
|
||||
assertEquals(buf, st.boundSsboByIndex[BOUND_SLOT], "SDL indexed SSBO slot");
|
||||
assertEquals(buf, glsmGenericSsbo(), "GLSM generic SSBO binding");
|
||||
} finally {
|
||||
unbind(BOUND_SLOT);
|
||||
GLStateManager.glDeleteBuffers(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void regionHookRefusesWithoutProgramOrBoundSlotAndNeverRebinds() {
|
||||
final ContextState st = SdlTestRig.contextState();
|
||||
final int savedProgram = st.boundProgram;
|
||||
final int buf = GLStateManager.glGenBuffers();
|
||||
try {
|
||||
unbind(EMPTY_SLOT);
|
||||
GLStateManager.glBindBufferBase(GL43.GL_SHADER_STORAGE_BUFFER, BOUND_SLOT, buf);
|
||||
|
||||
st.boundProgram = 0;
|
||||
assertFalse(RENDER_BACKEND.bindVoxelizationRegion(BOUND_SLOT, 0L, 0f, 0f, 0f), "no program bound");
|
||||
assertEquals(buf, st.boundSsboByIndex[BOUND_SLOT], "refusal must leave the slot alone");
|
||||
|
||||
st.boundProgram = UNLINKED_PROGRAM;
|
||||
assertFalse(RENDER_BACKEND.bindVoxelizationRegion(EMPTY_SLOT, 0L, 0f, 0f, 0f), "slot has no buffer");
|
||||
assertEquals(0, st.boundSsboByIndex[EMPTY_SLOT], "the hook must not bind a buffer itself");
|
||||
|
||||
assertTrue(RENDER_BACKEND.bindVoxelizationRegion(BOUND_SLOT, 0L, 1f, 2f, 3f), "a GLSM-bound slot with a program must be accepted, or the refusals prove nothing");
|
||||
assertEquals(buf, st.boundSsboByIndex[BOUND_SLOT]);
|
||||
assertEquals(buf, glsmGenericSsbo(), "GLSM and SDL must still agree after the hook");
|
||||
} finally {
|
||||
st.boundProgram = savedProgram;
|
||||
unbind(BOUND_SLOT);
|
||||
GLStateManager.glDeleteBuffers(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void deletingTheRegionBufferClearsTheGlsmGenericBinding() {
|
||||
final int buf = GLStateManager.glGenBuffers();
|
||||
try {
|
||||
GLStateManager.glBindBufferBase(GL43.GL_SHADER_STORAGE_BUFFER, BOUND_SLOT, buf);
|
||||
assertEquals(buf, glsmGenericSsbo());
|
||||
GLStateManager.glDeleteBuffers(buf);
|
||||
assertEquals(0, glsmGenericSsbo(), "delete must see the tracked SSBO binding");
|
||||
} finally {
|
||||
unbind(BOUND_SLOT);
|
||||
}
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu.pipeline;
|
||||
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SDLGPURenderBackend;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SdlAsserts;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SdlTestRig;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.frame.ContextState;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.lwjgl.sdl.SDLGPU.SDL_GPU_BLENDFACTOR_ONE;
|
||||
import static org.lwjgl.sdl.SDLGPU.SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
import static org.lwjgl.sdl.SDLGPU.SDL_GPU_BLENDFACTOR_SRC_ALPHA;
|
||||
import static org.lwjgl.sdl.SDLGPU.SDL_GPU_BLENDFACTOR_ZERO;
|
||||
|
||||
class IndexedBlendStateTest {
|
||||
|
||||
private SDLGPURenderBackend backend;
|
||||
private ContextState st;
|
||||
|
||||
@BeforeEach
|
||||
void resetBlend() {
|
||||
backend = new SDLGPURenderBackend();
|
||||
st = SdlTestRig.contextState();
|
||||
backend.blendFuncSeparate(GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
backend.disable(GL11.GL_BLEND);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void restoreBlend() {
|
||||
backend.blendFuncSeparate(GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
backend.disable(GL11.GL_BLEND);
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexedBlendFuncChangesOnlyThatDrawBuffer() {
|
||||
backend.blendFuncSeparatei(1, GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE);
|
||||
|
||||
for (int i = 0; i < ContextState.MAX_COLOR_ATTACHMENTS; i++) {
|
||||
if (i == 1) {
|
||||
SdlAsserts.assertBlendFactors(st.pipeline, i, SDL_GPU_BLENDFACTOR_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ONE, "indexed override");
|
||||
} else {
|
||||
SdlAsserts.assertBlendFactors(st.pipeline, i, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO, "indexed override");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void globalBlendFuncSetsEveryDrawBuffer() {
|
||||
backend.blendFuncSeparatei(2, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE);
|
||||
backend.blendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
|
||||
for (int i = 0; i < ContextState.MAX_COLOR_ATTACHMENTS; i++) {
|
||||
SdlAsserts.assertBlendFactors(st.pipeline, i, SDL_GPU_BLENDFACTOR_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO, "global set");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexedEnableSetsOnlyThatDrawBuffer() {
|
||||
backend.enablei(GL11.GL_BLEND, 2);
|
||||
|
||||
for (int i = 0; i < ContextState.MAX_COLOR_ATTACHMENTS; i++) {
|
||||
assertEquals(i == 2, st.pipeline.blendEnabledPerDrawBuffer[i], "blend enable of draw buffer " + i);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void outOfRangeIndexedBlendFuncIsIgnored() {
|
||||
final int pastEnd = ContextState.MAX_COLOR_ATTACHMENTS;
|
||||
backend.blendFuncSeparatei(pastEnd, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE);
|
||||
backend.blendFuncSeparatei(-1, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE, GL11.GL_ONE);
|
||||
|
||||
for (int i = 0; i < ContextState.MAX_COLOR_ATTACHMENTS; i++) {
|
||||
SdlAsserts.assertBlendFactors(st.pipeline, i, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO, "out of range ignored");
|
||||
}
|
||||
}
|
||||
}
|
||||
+67
-3
@@ -8,6 +8,7 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.lwjgl.sdl.SDLGPU.*;
|
||||
@@ -45,7 +46,7 @@ class PipelineCacheKeyTest {
|
||||
void testBlendChangeProducesDifferentKey() {
|
||||
final PipelineCache a = createCache();
|
||||
final PipelineCache b = createCache();
|
||||
b.blendEnabledPerAttachment[0] = true;
|
||||
b.blendEnabledPerDrawBuffer[0] = true;
|
||||
|
||||
assertNotEquals(computeKey(a), computeKey(b), "Blend state change should produce different key");
|
||||
}
|
||||
@@ -105,12 +106,75 @@ class PipelineCacheKeyTest {
|
||||
void testBlendFactorChangeProducesDifferentKey() {
|
||||
final PipelineCache a = createCache();
|
||||
final PipelineCache b = createCache();
|
||||
b.srcColorFactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA;
|
||||
b.dstColorFactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
b.setBlendFactors(SDL_GPU_BLENDFACTOR_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO);
|
||||
|
||||
assertNotEquals(computeKey(a), computeKey(b), "Blend factor change should produce different key");
|
||||
}
|
||||
|
||||
@Test
|
||||
void perDrawBufferFactorOnLiveSlotChangesKey() {
|
||||
final PipelineCache a = createCache();
|
||||
final PipelineCache b = createCache();
|
||||
b.setBlendFactors(0, SDL_GPU_BLENDFACTOR_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO);
|
||||
|
||||
assertNotEquals(computeKey(a), computeKey(b), "factor on the only color target must change the key");
|
||||
}
|
||||
|
||||
@Test
|
||||
void perDrawBufferFactorOnUnusedSlotKeepsKey() {
|
||||
final PipelineCache a = createCache();
|
||||
final PipelineCache b = createCache();
|
||||
b.setBlendFactors(1, SDL_GPU_BLENDFACTOR_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO);
|
||||
|
||||
assertEquals(computeKey(a), computeKey(b), "factor on a draw buffer with no color target must keep the key");
|
||||
}
|
||||
|
||||
@Test
|
||||
void globalFactorsAfterIndexedSetMatchFreshCache() {
|
||||
final PipelineCache fresh = createCache();
|
||||
final PipelineCache b = createCache();
|
||||
b.setBlendFactors(0, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ONE);
|
||||
b.setBlendFactors(3, SDL_GPU_BLENDFACTOR_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ONE);
|
||||
b.setBlendFactors(SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO);
|
||||
|
||||
final int[] fourTargets = new int[4];
|
||||
Arrays.fill(fourTargets, SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM);
|
||||
fresh.setColorTargetFormats(fourTargets);
|
||||
b.setColorTargetFormats(fourTargets);
|
||||
assertEquals(computeKey(fresh), computeKey(b), "a global blend func must overwrite every indexed entry");
|
||||
}
|
||||
|
||||
@Test
|
||||
void blendFactorSettersReportNoChangeForIdenticalValues() {
|
||||
final PipelineCache c = createCache();
|
||||
assertFalse(c.setBlendFactors(SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO));
|
||||
assertFalse(c.setBlendFactors(2, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO));
|
||||
assertTrue(c.setBlendFactors(2, SDL_GPU_BLENDFACTOR_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ZERO, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO));
|
||||
assertFalse(c.setBlendFactors(2, SDL_GPU_BLENDFACTOR_SRC_ALPHA, SDL_GPU_BLENDFACTOR_ZERO, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO));
|
||||
assertTrue(c.setBlendFactors(SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO, SDL_GPU_BLENDFACTOR_ONE, SDL_GPU_BLENDFACTOR_ZERO));
|
||||
}
|
||||
|
||||
@Test
|
||||
void blendEnableIsIndexedByDrawBufferNotAttachment() {
|
||||
final int[] twoTargets = {SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM, SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT};
|
||||
final PipelineCache base = createCache();
|
||||
base.setColorTargetFormats(twoTargets);
|
||||
base.setDrawBuffers(new int[]{3, 5});
|
||||
|
||||
final PipelineCache slot0 = createCache();
|
||||
slot0.setColorTargetFormats(twoTargets);
|
||||
slot0.setDrawBuffers(new int[]{3, 5});
|
||||
slot0.blendEnabledPerDrawBuffer[0] = true;
|
||||
|
||||
final PipelineCache attachment3 = createCache();
|
||||
attachment3.setColorTargetFormats(twoTargets);
|
||||
attachment3.setDrawBuffers(new int[]{3, 5});
|
||||
attachment3.blendEnabledPerDrawBuffer[3] = true;
|
||||
|
||||
assertNotEquals(computeKey(base), computeKey(slot0), "draw buffer 0 is the first color target");
|
||||
assertEquals(computeKey(base), computeKey(attachment3), "index 3 is a draw buffer past the two targets");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testColorWriteMaskChangeProducesDifferentKey() {
|
||||
final PipelineCache a = createCache();
|
||||
|
||||
+42
@@ -2,6 +2,7 @@ package com.gtnewhorizons.angelica.sdlgpu.pipeline;
|
||||
|
||||
import com.gtnewhorizons.angelica.sdlgpu.frame.ContextState;
|
||||
import com.gtnewhorizons.angelica.glsm.ffp.VAOManager;
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.shader.ShaderManager;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -454,6 +455,47 @@ class PipelineCacheVertexInputTest {
|
||||
assertFalse(c.markInputDirtyIfLivenessChanged(store, 42, 7), "swapping two live buffers must not force an input rehash");
|
||||
}
|
||||
|
||||
@Test
|
||||
void programInputSignatureChangeInvalidatesInputHash() {
|
||||
final int[] vecSizesA = new int[ContextState.MAX_VERTEX_ATTRIBS];
|
||||
vecSizesA[0] = 3;
|
||||
final int[] baseTypesA = new int[ContextState.MAX_VERTEX_ATTRIBS];
|
||||
baseTypesA[0] = Spvc.SPVC_BASETYPE_FP32;
|
||||
final String[] namesA = new String[ContextState.MAX_VERTEX_ATTRIBS];
|
||||
namesA[0] = "a_Pos";
|
||||
final PipelineCache c = cache(0x1, vecSizesA, baseTypesA);
|
||||
c.shaderInputName = namesA;
|
||||
|
||||
final ContextState cs = new ContextState();
|
||||
enableFloatAttrib(cs, 0, 3, 12);
|
||||
|
||||
final long keyA = Reflect.invoke(c, "currentKey", new Class<?>[] { PipelineStore.class, ContextState.class }, store, cs);
|
||||
final boolean dirtyAfterKeyA = Reflect.get(c, "inputDirty");
|
||||
assertFalse(dirtyAfterKeyA, "currentKey must clear the dirty flag once recomputed");
|
||||
|
||||
c.setVertexInputs(0x1, vecSizesA, baseTypesA, namesA);
|
||||
final boolean dirtyAfterSameSignature = Reflect.get(c, "inputDirty");
|
||||
assertFalse(dirtyAfterSameSignature, "an identical signature must not force a rehash");
|
||||
|
||||
c.setVertexInputs(0x1, vecSizesA.clone(), baseTypesA.clone(), namesA.clone());
|
||||
final boolean dirtyAfterEqualCopies = Reflect.get(c, "inputDirty");
|
||||
assertFalse(dirtyAfterEqualCopies, "another program with an equal signature must not force a rehash");
|
||||
|
||||
final int[] vecSizesB = new int[ContextState.MAX_VERTEX_ATTRIBS];
|
||||
vecSizesB[0] = 3; vecSizesB[1] = 4;
|
||||
final int[] baseTypesB = new int[ContextState.MAX_VERTEX_ATTRIBS];
|
||||
baseTypesB[0] = Spvc.SPVC_BASETYPE_FP32; baseTypesB[1] = Spvc.SPVC_BASETYPE_FP32;
|
||||
final String[] namesB = new String[ContextState.MAX_VERTEX_ATTRIBS];
|
||||
namesB[0] = "a_Pos"; namesB[1] = "a_Extra";
|
||||
|
||||
c.setVertexInputs(0x3, vecSizesB, baseTypesB, namesB);
|
||||
final boolean dirtyAfterChangedSignature = Reflect.get(c, "inputDirty");
|
||||
assertTrue(dirtyAfterChangedSignature, "a changed vertex-input signature must invalidate the cached input hash");
|
||||
|
||||
final long keyB = Reflect.invoke(c, "currentKey", new Class<?>[] { PipelineStore.class, ContextState.class }, store, cs);
|
||||
assertTrue(keyA != keyB, "currentKey must reflect the new signature, not a stale cached input hash");
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindingsArrayIsDenseIndexedBySlot() {
|
||||
// D3D12 requirement: SDL's D3D12 backend reads vertex_buffer_descriptions[buffer_slot] as a flat array, so bindings.get(i).slot() must equal i
|
||||
|
||||
+41
@@ -1,16 +1,22 @@
|
||||
package com.gtnewhorizons.angelica.sdlgpu.resource;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import com.gtnewhorizons.angelica.sdlgpu.SdlAsserts;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Map;
|
||||
|
||||
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 ReadbackShadowsTest {
|
||||
|
||||
private static final long SENTINEL_HANDLE = 0xBEEFL;
|
||||
private static final int SLOTS_PER_BUFFER = 32;
|
||||
private static final int SLOT_STRIDE = 64;
|
||||
|
||||
private static ReadbackShadows shadows() {
|
||||
return new ReadbackShadows(null);
|
||||
@@ -62,4 +68,39 @@ class ReadbackShadowsTest {
|
||||
assertFalse(shadows.hasSlotsFor(7), "deleting a buffer must drop all of its ring slots");
|
||||
assertTrue(shadows.hasSlotsFor(8), "deleting one buffer must not drop another's slots");
|
||||
}
|
||||
|
||||
private static int slotCount(ReadbackShadows shadows) {
|
||||
return Reflect.<Map<Long, Object>>get(shadows, "slots").size();
|
||||
}
|
||||
|
||||
private static ReadbackShadows ringShadows(int... glIds) {
|
||||
final ReadbackShadows shadows = shadows();
|
||||
for (int glId : glIds) {
|
||||
for (int i = 0; i < SLOTS_PER_BUFFER; i++) {
|
||||
SdlReflect.putReadbackSlot(shadows, glId, (long) i * SLOT_STRIDE, 0L, SLOT_STRIDE, true);
|
||||
}
|
||||
}
|
||||
return shadows;
|
||||
}
|
||||
|
||||
@Test
|
||||
void releaseRemovesExactlyTheSlotsOfItsBuffer() {
|
||||
final ReadbackShadows shadows = ringShadows(1, 2, 3);
|
||||
|
||||
shadows.release(2);
|
||||
|
||||
assertFalse(shadows.hasSlotsFor(2));
|
||||
assertEquals(2 * SLOTS_PER_BUFFER, slotCount(shadows));
|
||||
for (int glId = 1; glId <= 3; glId += 2) {
|
||||
for (int i = 0; i < SLOTS_PER_BUFFER; i++) {
|
||||
assertTrue(SdlReflect.readbackSlotValid(shadows, glId, (long) i * SLOT_STRIDE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void releaseWithNoSlotsDoesNotAllocate() {
|
||||
final ReadbackShadows shadows = shadows();
|
||||
SdlAsserts.assertAllocationFree(() -> shadows.release(7), "releases with no readback slots");
|
||||
}
|
||||
}
|
||||
+4
-6
@@ -10,6 +10,7 @@ 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.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@@ -118,13 +119,10 @@ class SDLGPUUniformDedupTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void noProgramBound_reuseOrAllocReturnsFresh_putIsNoOp() {
|
||||
void noProgramBound_reuseOrAllocReturnsNull_putIsNoOp() {
|
||||
st.boundProgramObj = null;
|
||||
final float[] a = applier.reuseOrAlloc(st, 0, 4);
|
||||
assertEquals(4, a.length);
|
||||
final float[] b = applier.reuseOrAlloc(st, 0, 4);
|
||||
assertNotSame(a, b, "no caching without bound program");
|
||||
applier.putUniform(st, 0, a);
|
||||
assertNull(applier.reuseOrAlloc(st, 0, 4), "no program means nowhere to store");
|
||||
applier.putUniform(st, 0, new float[4]);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+4
-1
@@ -1,5 +1,6 @@
|
||||
package com.gtnewhorizons.angelica.rendering.voxelization;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.BackendManager;
|
||||
import com.gtnewhorizons.angelica.glsm.backend.RenderBackend;
|
||||
import net.coderbot.iris.pipeline.transform.RwImageStoreExtractor;
|
||||
@@ -8,6 +9,7 @@ import org.embeddedt.embeddium.impl.gl.buffer.GlBuffer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.embeddedt.embeddium.impl.render.chunk.region.RenderRegion;
|
||||
import org.lwjgl.opengl.GL43;
|
||||
|
||||
public final class SdlShadowVoxelizationSink implements ShadowVoxelizer.Sink {
|
||||
|
||||
@@ -47,7 +49,8 @@ public final class SdlShadowVoxelizationSink implements ShadowVoxelizer.Sink {
|
||||
@Override
|
||||
public boolean range(int vertexOffset, int vertexCount) {
|
||||
if (pendingVertexBuffer != 0) {
|
||||
if (!sdl().bindVoxelizationRegion(SSBO_BINDING, pendingVertexBuffer, pass, pendingX, pendingY, pendingZ)) {
|
||||
GLStateManager.glBindBufferBase(GL43.GL_SHADER_STORAGE_BUFFER, SSBO_BINDING, pendingVertexBuffer);
|
||||
if (!sdl().bindVoxelizationRegion(SSBO_BINDING, pass, pendingX, pendingY, pendingZ)) {
|
||||
if (!warnedBindFailure) {
|
||||
warnedBindFailure = true;
|
||||
LOG.warn("shadow voxelization: could not bind region vertex buffer {} at SSBO slot {}", pendingVertexBuffer, SSBO_BINDING);
|
||||
|
||||
@@ -85,11 +85,15 @@ public class BlendModeStorage {
|
||||
}
|
||||
|
||||
public static void deferBlendModeToggle(boolean enabled) {
|
||||
if (enabled == vanillaBlendEnable) return;
|
||||
vanillaBlendEnable = enabled;
|
||||
hasDeferredChanges = true;
|
||||
}
|
||||
|
||||
public static void deferBlendFunc(int srcRgb, int dstRgb, int srcAlpha, int dstAlpha) {
|
||||
if (vanillaBlend.getSrcRgb() == srcRgb && vanillaBlend.getDstRgb() == dstRgb && vanillaBlend.getSrcAlpha() == srcAlpha && vanillaBlend.getDstAlpha() == dstAlpha) {
|
||||
return;
|
||||
}
|
||||
vanillaBlend.setAll(srcRgb, dstRgb, srcAlpha, dstAlpha);
|
||||
hasDeferredChanges = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package net.coderbot.iris.gl.blending;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.states.BlendState;
|
||||
import com.gtnewhorizons.angelica.glsm.testutil.Reflect;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
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 BlendModeStorageDeferDedupeTest {
|
||||
|
||||
@BeforeEach
|
||||
@AfterEach
|
||||
void resetStorage() {
|
||||
BlendModeStorage.restoreBlend();
|
||||
Reflect.setStatic(BlendModeStorage.class, "hasDeferredChanges", false);
|
||||
Reflect.setStatic(BlendModeStorage.class, "vanillaBlendEnable", false);
|
||||
vanillaBlend().setAll(GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
}
|
||||
|
||||
private static BlendState vanillaBlend() {
|
||||
return Reflect.getStatic(BlendModeStorage.class, "vanillaBlend");
|
||||
}
|
||||
|
||||
private static boolean hasDeferredChanges() {
|
||||
return Reflect.<Boolean>getStatic(BlendModeStorage.class, "hasDeferredChanges");
|
||||
}
|
||||
|
||||
@Test
|
||||
void blendFuncDefersOnlyOnChange() {
|
||||
BlendModeStorage.deferBlendFunc(GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
assertFalse(hasDeferredChanges());
|
||||
|
||||
BlendModeStorage.deferBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
assertTrue(hasDeferredChanges());
|
||||
assertEquals(GL11.GL_SRC_ALPHA, vanillaBlend().getSrcRgb());
|
||||
assertEquals(GL11.GL_ONE_MINUS_SRC_ALPHA, vanillaBlend().getDstRgb());
|
||||
|
||||
BlendModeStorage.deferBlendFunc(GL11.GL_ONE, GL11.GL_ZERO, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
assertTrue(hasDeferredChanges());
|
||||
assertEquals(GL11.GL_ONE, vanillaBlend().getSrcRgb());
|
||||
}
|
||||
|
||||
@Test
|
||||
void toggleDefersOnlyOnChange() {
|
||||
BlendModeStorage.deferBlendModeToggle(false);
|
||||
assertFalse(hasDeferredChanges());
|
||||
|
||||
BlendModeStorage.deferBlendModeToggle(true);
|
||||
assertTrue(hasDeferredChanges());
|
||||
assertTrue(Reflect.<Boolean>getStatic(BlendModeStorage.class, "vanillaBlendEnable"));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user