Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import com.elfmcys.yesstevemodel.client.renderer.ModelPreviewRenderer;
import com.elfmcys.yesstevemodel.config.GeneralConfig;
import com.elfmcys.yesstevemodel.geckolib3.geo.render.built.GeoModel;
import com.elfmcys.yesstevemodel.util.log.ChatLogger;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
Expand Down Expand Up @@ -37,22 +36,22 @@ public static void renderMesh(VertexConsumer buffer, PoseStack.Pose pose, GeoMod
OculusCompat.updatePBRState();
RenderSystem.getProjectionMatrix().mul(RenderSystem.getModelViewMatrix(), projectionModelViewMatrix);
boolean isPreview = ModelPreviewRenderer.isPreview() || ModelPreviewRenderer.isExtraPlayer();
String gpuRenderContext = ModelPreviewRenderer.isExtraPlayer() ? "paperdoll" : (ModelPreviewRenderer.isPreview() ? "preview" : "world");

if (textureLocation != null && NativeLibLoader.isLoaded() && !GeneralConfig.USE_COMPATIBILITY_RENDERER.get() && GeneralConfig.USE_GPU_RENDERER.get()) {

if(!GpuCapability.isAvailable())
{
ChatLogger.INSTANCE.logFormatted("Disabled GPU renderer for: " + GpuCapability.getReason());
GeneralConfig.USE_GPU_RENDERER.set(false);
return;
}

if (OculusCompat.isShaderPackInUse() && !isPreview) {
if (!GpuCapability.isAvailable()) {
GpuRenderPath.debugFallback(gpuRenderContext, GpuCapability.getReason(), renderPartMask, packedLight, textureLocation);
} else if (!canDirectRenderTo(buffer)) {
if (GpuRenderPath.tryRenderToConsumer(buffer, model, pose, boneParams, stateBuffer, renderPartMask, packedLight, packedOverlay, red, green, blue, alpha, textureLocation, gpuRenderContext)) {
return;
}
} else if (OculusCompat.isShaderPackInUse() && !isPreview) {
if (IrisRenderPath.tryRender(model, pose, boneParams, renderPartMask, packedLight, packedOverlay, red, green, blue, alpha, textureLocation)) {
return;
}
} else {
if (GpuRenderPath.tryRender(model, pose, boneParams, stateBuffer, renderPartMask, packedLight, packedOverlay, red, green, blue, alpha, textureLocation)) {
if (GpuRenderPath.tryRender(model, pose, boneParams, stateBuffer, renderPartMask, packedLight, packedOverlay, red, green, blue, alpha, textureLocation, gpuRenderContext)) {
return;
}
}
Expand Down Expand Up @@ -93,6 +92,10 @@ public static void renderMesh(VertexConsumer buffer, PoseStack.Pose pose, GeoMod
}
}

private static boolean canDirectRenderTo(VertexConsumer buffer) {
return buffer != null && "com.mojang.blaze3d.vertex.BufferBuilder".equals(buffer.getClass().getName());
}

public static void renderModel(
VertexConsumer vertexConsumer,
PoseStack.Pose pose,
Expand Down Expand Up @@ -296,4 +299,4 @@ public static void nativeRenderModel( // TODO:
r, g, b, a
);
}
}
}
9 changes: 5 additions & 4 deletions common/src/main/java/rip/ysm/gpu/BoneSkinShader.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import com.elfmcys.yesstevemodel.YesSteveModel;
import com.elfmcys.yesstevemodel.util.log.ChatLogger;
import com.mojang.blaze3d.systems.RenderSystem;
import org.lwjgl.opengl.ARBProgramInterfaceQuery;
import org.lwjgl.opengl.ARBShaderStorageBufferObject;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL43;

public final class BoneSkinShader {
public static final int ssbo = 0;
Expand Down Expand Up @@ -37,9 +38,9 @@ public static synchronized boolean ensureCompiled() {
GL20.glBindAttribLocation(p, 4, "a_cullable");
}, vs, fs);

int ssboBlock = GL43.glGetProgramResourceIndex(prog, GL43.GL_SHADER_STORAGE_BLOCK, "BoneBlock");
if (ssboBlock != GL43.GL_INVALID_INDEX) {
GL43.glShaderStorageBlockBinding(prog, ssboBlock, ssbo);
int ssboBlock = ARBProgramInterfaceQuery.glGetProgramResourceIndex(prog, ARBProgramInterfaceQuery.GL_SHADER_STORAGE_BLOCK, "BoneBlock");
if (ssboBlock != -1) {
ARBShaderStorageBufferObject.glShaderStorageBlockBinding(prog, ssboBlock, ssbo);
}

locProj = GL20.glGetUniformLocation(prog, "u_proj");
Expand Down
37 changes: 18 additions & 19 deletions common/src/main/java/rip/ysm/gpu/GpuCapability.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ public static synchronized void check() {
checked = true;

if (System.getProperty("OYSM_DISABLE_GPU") != null) {
reason = "gpu renderer has been disabled";
unavailable("gpu renderer has been disabled");
return;
}
if (!NativeLibLoader.isLoaded()) {
reason = "native ysm-core not loaded";
unavailable("native ysm-core not loaded");
return;
}
String osName = System.getProperty("os.name", "").toLowerCase();
if (osName.contains("mac") || osName.contains("darwin")) {
reason = "macOS GL is capped at 4.1 and lacks GL_ARB_shader_storage_buffer_object";
unavailable("macOS GL is capped at 4.1 and lacks GL_ARB_shader_storage_buffer_object");
return;
}

Expand All @@ -52,52 +52,51 @@ public static synchronized void check() {
glVendor = GL11.glGetString(GL11.GL_VENDOR);
glslVersion = GL11.glGetString(0x8B8C);
} catch (Throwable t) {
reason = "GL capabilities not available: " + t.getMessage();
unavailable("GL capabilities not available: " + t.getMessage());
return;
}

if (glVersion == null) {
reason = "GL version not available";
unavailable("GL version not available");
return;
}

System.out.println("OpenGL version: " + glVersion);
System.out.println("OpenGL renderer version: " + glRenderer);
System.out.println("OpenGL vendor: " + glVendor);
System.out.println("OpenGL glsl version: " + glslVersion);
if (glVersion.regionMatches(true, 0, "OpenGL ES", 0, "OpenGL ES".length())) {
unavailable("OpenGL ES context is not supported by GPU renderer; desktop OpenGL 4.3 or ARB shader storage buffer support is required (got " + glVersion + ")");
return;
}

if (!caps.OpenGL30) {
reason = "OpenGL 3.0 not supported (got " + glVersion + ")";
unavailable("OpenGL 3.0 not supported (got " + glVersion + ")");
return;
}

boolean hasSsbo = caps.OpenGL43 || caps.GL_ARB_shader_storage_buffer_object;
boolean hasIfaceQuery = caps.OpenGL43 || caps.GL_ARB_program_interface_query;
boolean hasLayoutBinding = caps.OpenGL42 || caps.GL_ARB_shading_language_420pack;
boolean hasExplicitAttrib = caps.OpenGL33 || caps.GL_ARB_explicit_attrib_location;
boolean hasPackedNormal = caps.OpenGL33 || caps.GL_ARB_vertex_type_2_10_10_10_rev;
if (!hasSsbo) {
reason = "SSBO not supported, GL_VERSION=" + glVersion;
unavailable("SSBO not supported, GL_VERSION=" + glVersion);
return;
}
if (!hasIfaceQuery) {
reason = "GL_ARB_program_interface_query not supported; GL_VERSION=" + glVersion;
unavailable("GL_ARB_program_interface_query not supported; GL_VERSION=" + glVersion);
return;
}
if (!hasLayoutBinding) {
reason = "GL_ARB_shading_language_420pack not supported; GL_VERSION=" + glVersion;
return;
}
if (!hasExplicitAttrib) {
reason = "GL_ARB_explicit_attrib_location not supported; GL_VERSION=" + glVersion;
unavailable("GL_ARB_shading_language_420pack not supported; GL_VERSION=" + glVersion);
return;
}
if (!hasPackedNormal) {
reason = "GL_ARB_vertex_type_2_10_10_10_rev not supported; GL_VERSION=" + glVersion;
unavailable("GL_ARB_vertex_type_2_10_10_10_rev not supported; GL_VERSION=" + glVersion);
return;
}

available = true;
reason = "ok (GL " + glVersion + ", " + glRenderer + ")";
}

private static void unavailable(String unavailableReason) {
reason = unavailableReason;
}
}
54 changes: 45 additions & 9 deletions common/src/main/java/rip/ysm/gpu/GpuMesh.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
import org.lwjgl.system.MemoryUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public final class GpuMesh {
public final long pointer;
public final int vao;
public final int vbo;
public final int ibo;
public final int boneSsbo;
public final int[] boneSsbos;
public final int vertexCount;
public final int indexCount;
public final int boneCount;
Expand All @@ -23,14 +25,18 @@ public final class GpuMesh {

private int xformVbo = 0;
private int xformVao = 0;
private ByteBuffer xformReadbackBuffer;
private ByteBuffer indexReadbackBuffer;
private int nextBoneSsboIndex = 0;
private boolean disposed = false;

GpuMesh(long pointer, int vao, int vbo, int ibo, int boneSsbo, int vertexCount, int indexCount, int boneCount, int pm1s, int pm1c, int pm2s, int pm2c, int pm3s, int pm3c) {
GpuMesh(long pointer, int vao, int vbo, int ibo, int[] boneSsbos, int vertexCount, int indexCount, int boneCount, int pm1s, int pm1c, int pm2s, int pm2c, int pm3s, int pm3c) {
this.pointer = pointer;
this.vao = vao;
this.vbo = vbo;
this.ibo = ibo;
this.boneSsbo = boneSsbo;
this.boneSsbos = boneSsbos;
this.boneSsbo = boneSsbos[0];
this.vertexCount = vertexCount;
this.indexCount = indexCount;
this.boneCount = boneCount;
Expand All @@ -57,6 +63,12 @@ public int indexDrawCount(int renderPartMask) {
return self + partMask3Count;
}

public int nextBoneSsbo() {
int ssbo = boneSsbos[nextBoneSsboIndex];
nextBoneSsboIndex = (nextBoneSsboIndex + 1) % boneSsbos.length;
return ssbo;
}

public int xformVbo() {
return xformVbo;
}
Expand All @@ -69,9 +81,9 @@ public void ensureXformBuffers() {
if (xformVao != 0) return;
xformVbo = GlStateManager._glGenBuffers();
GlStateManager._glBindBuffer(GL15.GL_ARRAY_BUFFER, xformVbo);
GL45.glBufferData(GL15.GL_ARRAY_BUFFER, (long) vertexCount * 36, GL15.GL_DYNAMIC_DRAW);
xformVao = GL45.glGenVertexArrays();
GL45.glBindVertexArray(xformVao);
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, (long) vertexCount * 36, GL15.GL_DYNAMIC_DRAW);
xformVao = GL30.glGenVertexArrays();
GL30.glBindVertexArray(xformVao);
GlStateManager._glBindBuffer(GL15.GL_ARRAY_BUFFER, xformVbo);
GlStateManager._glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, ibo);
GL20.glEnableVertexAttribArray(0);
Expand All @@ -86,23 +98,47 @@ public void ensureXformBuffers() {
GL30.glVertexAttribIPointer(4, 2, GL11.GL_SHORT, 36, 28L);
GL20.glEnableVertexAttribArray(5);
GL20.glVertexAttribPointer(5, 3, GL11.GL_BYTE, true, 36, 32L);
GL45.glBindVertexArray(0);
GL30.glBindVertexArray(0);
GlStateManager._glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GlStateManager._glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);
}

public ByteBuffer xformReadbackBuffer() {
xformReadbackBuffer = ensureReadbackCapacity(xformReadbackBuffer, vertexCount * 36);
return xformReadbackBuffer;
}

public ByteBuffer indexReadbackBuffer(int indexBytes) {
indexReadbackBuffer = ensureReadbackCapacity(indexReadbackBuffer, indexBytes);
return indexReadbackBuffer;
}

private static ByteBuffer ensureReadbackCapacity(ByteBuffer buffer, int requiredBytes) {
if (buffer == null || buffer.capacity() < requiredBytes) {
if (buffer != null) MemoryUtil.memFree(buffer);
buffer = MemoryUtil.memAlloc(requiredBytes).order(ByteOrder.nativeOrder());
}
buffer.clear();
buffer.limit(requiredBytes);
return buffer;
}

public void dispose() {
if (disposed) return;
disposed = true;
GlStateManager._glDeleteBuffers(vbo);
GlStateManager._glDeleteBuffers(ibo);
GlStateManager._glDeleteBuffers(boneSsbo);
GL45.glDeleteVertexArrays(vao);
for (int ssbo : boneSsbos) {
GlStateManager._glDeleteBuffers(ssbo);
}
GL30.glDeleteVertexArrays(vao);
if (xformVbo != 0) GlStateManager._glDeleteBuffers(xformVbo);
if (xformVao != 0) GL45.glDeleteVertexArrays(xformVao);
if (xformVao != 0) GL30.glDeleteVertexArrays(xformVao);
if (pointer != 0) {
GeoModel.nFreeGpuMesh(pointer);
}
MemoryUtil.memFree(perFrameBoneBuffer);
if (xformReadbackBuffer != null) MemoryUtil.memFree(xformReadbackBuffer);
if (indexReadbackBuffer != null) MemoryUtil.memFree(indexReadbackBuffer);
}
}
18 changes: 13 additions & 5 deletions common/src/main/java/rip/ysm/gpu/GpuMeshBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@
import com.elfmcys.yesstevemodel.geckolib3.geo.render.built.GeoModel;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import org.lwjgl.opengl.ARBShaderStorageBufferObject;
import org.lwjgl.opengl.*;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

public final class GpuMeshBuilder {
// Four slots cover the typical 2-3 frame GPU pipeline depth plus the current upload.
// This relies on driver-side implicit synchronization instead of explicit GL fences.
private static final int BONE_SSBO_RING_SIZE = 4;

public static GpuMesh build(GeoModel model) {
if (model.bakedBones == null || model.bakedBones.isEmpty()) return null;
RenderSystem.assertOnRenderThread();
Expand All @@ -34,7 +39,7 @@ public static GpuMesh build(GeoModel model) {
int vao = GL30.glGenVertexArrays();
int vbo = GlStateManager._glGenBuffers();
int ibo = GlStateManager._glGenBuffers();
int ssbo = GlStateManager._glGenBuffers();
int[] boneSsbos = new int[BONE_SSBO_RING_SIZE];

GL30.glBindVertexArray(vao);
GlStateManager._glBindBuffer(GL15.GL_ARRAY_BUFFER, vbo);
Expand All @@ -58,12 +63,15 @@ public static GpuMesh build(GeoModel model) {
GlStateManager._glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
GlStateManager._glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, 0);

GlStateManager._glBindBuffer(GL43.GL_SHADER_STORAGE_BUFFER, ssbo);
GL45.glBufferData(GL43.GL_SHADER_STORAGE_BUFFER, (long) boneCount * 144, GL15.GL_DYNAMIC_DRAW);
GlStateManager._glBindBuffer(GL43.GL_SHADER_STORAGE_BUFFER, 0);
for (int i = 0; i < boneSsbos.length; i++) {
boneSsbos[i] = GlStateManager._glGenBuffers();
GlStateManager._glBindBuffer(ARBShaderStorageBufferObject.GL_SHADER_STORAGE_BUFFER, boneSsbos[i]);
GL15.glBufferData(ARBShaderStorageBufferObject.GL_SHADER_STORAGE_BUFFER, (long) boneCount * 144, GL15.GL_DYNAMIC_DRAW);
}
GlStateManager._glBindBuffer(ARBShaderStorageBufferObject.GL_SHADER_STORAGE_BUFFER, 0);
GeoModel.nReleaseGpuMeshScratch(handle);

return new GpuMesh(handle, vao, vbo, ibo, ssbo, vertexCount, indexCount, boneCount, meta[3], meta[4], meta[5], meta[6], meta[7], meta[8]);
return new GpuMesh(handle, vao, vbo, ibo, boneSsbos, vertexCount, indexCount, boneCount, meta[3], meta[4], meta[5], meta[6], meta[7], meta[8]);
}

private static ByteBuffer serializeModel(GeoModel model) {
Expand Down
Loading