Skip to content

Commit

Permalink
Merge branch '1.16-spiralhalo-LTS' into naive-shadow-2-LTS
Browse files Browse the repository at this point in the history
  • Loading branch information
spiralhalo committed May 6, 2021
2 parents 4836f4e + 5f1d485 commit 55ce118
Show file tree
Hide file tree
Showing 13 changed files with 223 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ public static SortedMap<RenderLayer, BufferBuilder> entityBuilders() {
});
}

public static SortedMap<RenderLayer, BufferBuilder> dummyBuilders() {
return new Object2ObjectLinkedOpenHashMap<>();
}

private static void assignBufferBuilder(Object2ObjectLinkedOpenHashMap<RenderLayer, BufferBuilder> builderStorage, RenderLayer layer) {
builderStorage.put(layer, new BufferBuilder(layer.getExpectedBufferSize()));
}
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/grondag/canvas/material/state/RenderState.java
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,18 @@ private void enableMaterial(int x, int y, int z) {
CanvasTextureState.activeTextureUnit(TextureData.MC_SPRITE_ATLAS);
}

if (Pipeline.config().materialProgram.samplerNames.length > 0) {
// Activate non-frex material program textures
for (int i = 0; i < Pipeline.config().materialProgram.samplerNames.length; i++) {
final int bindTarget = Pipeline.materialTextures().texTargets[i];
final int bind = Pipeline.materialTextures().texIds[i];
CanvasTextureState.activeTextureUnit(TextureData.PROGRAM_SAMPLERS + i);
CanvasTextureState.bindTexture(bindTarget, bind);
assert CanvasGlHelper.checkError();
}
CanvasTextureState.activeTextureUnit(TextureData.MC_SPRITE_ATLAS);
}

texture.enable(blur);
assert CanvasGlHelper.checkError();

Expand Down
7 changes: 7 additions & 0 deletions src/main/java/grondag/canvas/pipeline/Pipeline.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class Pipeline {
private static boolean reload = true;
private static int lastWidth;
private static int lastHeight;
private static ProgramTextureData materialTextures;
static Pass[] onWorldRenderStart = { };
static Pass[] afterRenderHand = { };
static Pass[] fabulous = { };
Expand Down Expand Up @@ -103,6 +104,10 @@ public static PipelineFramebuffer getFramebuffer(String name) {
return FRAMEBUFFERS.get(name);
}

public static ProgramTextureData materialTextures() {
return materialTextures;
}

static boolean needsReload() {
return reload;
}
Expand Down Expand Up @@ -229,6 +234,8 @@ private static void activateInner(PrimaryFrameBuffer primary, int width, int hei
defaultZenithAngle = 0f;
}

materialTextures = new ProgramTextureData(config.materialProgram.samplerImages);

isFabulous = config.fabulosity != null;

if (isFabulous) {
Expand Down
61 changes: 61 additions & 0 deletions src/main/java/grondag/canvas/pipeline/ProgramTextureData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package grondag.canvas.pipeline;

import grondag.canvas.pipeline.config.ImageConfig;
import grondag.canvas.pipeline.config.util.NamedDependency;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.texture.AbstractTexture;
import net.minecraft.client.texture.ResourceTexture;
import net.minecraft.client.texture.TextureManager;
import net.minecraft.util.Identifier;
import org.lwjgl.opengl.GL46;

public class ProgramTextureData {
final public int[] texIds;
final public int[] texTargets;

public ProgramTextureData(NamedDependency<ImageConfig>[] samplerImages) {
texIds = new int[samplerImages.length];
texTargets = new int[samplerImages.length];

for (int i = 0; i < samplerImages.length; ++i) {
final String imageName = samplerImages[i].name;

int imageBind = 0;
int bindTarget = GL46.GL_TEXTURE_2D;

if (imageName.contains(":")) {
final AbstractTexture tex = tryLoadResourceTexture(new Identifier(imageName));

if (tex != null) {
imageBind = tex.getGlId();
}
} else {
final Image img = Pipeline.getImage(imageName);

if (img != null) {
imageBind = img.glId();
bindTarget = img.config.target;
}
}

texIds[i] = imageBind;
texTargets[i] = bindTarget;
}
}

private static AbstractTexture tryLoadResourceTexture(Identifier identifier) {
final TextureManager textureManager = MinecraftClient.getInstance().getTextureManager();
final AbstractTexture existingTexture = textureManager.getTexture(identifier);

if (existingTexture != null) {
return existingTexture;
} else {
// NB: `registerTexture` will replace the texture with MissingSprite if not found. This is useful for
// pipeline developers.
// Additionally, TextureManager will handle removing missing textures on resource reload.
ResourceTexture resourceTexture = new ResourceTexture(identifier);
textureManager.registerTexture(identifier, resourceTexture);
return textureManager.getTexture(identifier);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,44 @@

package grondag.canvas.pipeline.config;

import blue.endless.jankson.JsonArray;
import blue.endless.jankson.JsonObject;

import grondag.canvas.CanvasMod;
import grondag.canvas.pipeline.config.util.ConfigContext;
import grondag.canvas.pipeline.config.util.NamedDependency;

public class MaterialProgramConfig extends ProgramConfig {
public final NamedDependency<ImageConfig>[] samplerImages;

public MaterialProgramConfig(ConfigContext ctx, JsonObject config) {
super(ctx, config, "materialProgram");

if (!config.containsKey("samplerImages")) {
samplerImages = new NamedDependency[0];
} else {
final JsonArray names = config.get(JsonArray.class, "samplerImages");
final int limit = names.size();
samplerImages = new NamedDependency[limit];

for (int i = 0; i < limit; ++i) {
samplerImages[i] = ctx.images.dependOn(names.get(i));
}
}
}

public MaterialProgramConfig(ConfigContext ctx) {
super(ctx, "materialProgram", "canvas:shaders/pipeline/standard.vert", "canvas:shaders/pipeline/standard.vert");
samplerImages = new NamedDependency[0];
}

@Override
public boolean validate() {
if (samplerImages.length != samplerNames.length) {
CanvasMod.LOG.warn(String.format("Material program is invalid because it expects %d samplers but the pass binds %d.",
samplerNames.length, samplerImages.length));
return false;
}
return super.validate();
}
}
43 changes: 5 additions & 38 deletions src/main/java/grondag/canvas/pipeline/pass/ProgramPass.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,59 +18,26 @@

import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.systems.RenderSystem;
import grondag.canvas.pipeline.ProgramTextureData;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL21;
import org.lwjgl.opengl.GL46;

import net.minecraft.client.MinecraftClient;
import net.minecraft.client.texture.AbstractTexture;
import net.minecraft.util.Identifier;

import grondag.canvas.pipeline.Image;
import grondag.canvas.pipeline.Pipeline;
import grondag.canvas.pipeline.PipelineManager;
import grondag.canvas.pipeline.config.PassConfig;
import grondag.canvas.render.CanvasTextureState;
import grondag.canvas.shader.ProcessShader;

class ProgramPass extends Pass {
final int[] binds;
final int[] bindTargets;
final ProgramTextureData textures;

ProcessShader shader;

ProgramPass(PassConfig config) {
super(config);

shader = Pipeline.getShader(config.program.name);

binds = new int[config.samplerImages.length];
bindTargets = new int[config.samplerImages.length];

for (int i = 0; i < config.samplerImages.length; ++i) {
final String imageName = config.samplerImages[i].name;

int imageBind = 0;
int bindTarget = GL46.GL_TEXTURE_2D;

if (imageName.contains(":")) {
final AbstractTexture tex = MinecraftClient.getInstance().getTextureManager().getTexture(new Identifier(imageName));

if (tex != null) {
imageBind = tex.getGlId();
}
} else {
final Image img = Pipeline.getImage(imageName);

if (img != null) {
imageBind = img.glId();
bindTarget = img.config.target;
}
}

binds[i] = imageBind;
bindTargets[i] = bindTarget;
}
textures = new ProgramTextureData(config.samplerImages);
}

@Override
Expand All @@ -91,11 +58,11 @@ public void run(int width, int height) {
PipelineManager.setProjection(width, height);
RenderSystem.viewport(0, 0, width, height);

final int slimit = binds.length;
final int slimit = textures.texIds.length;

for (int i = 0; i < slimit; ++i) {
CanvasTextureState.activeTextureUnit(GL21.GL_TEXTURE0 + i);
CanvasTextureState.bindTexture(bindTargets[i], binds[i]);
CanvasTextureState.bindTexture(textures.texTargets[i], textures.texIds[i]);
}

shader.activate().lod(config.lod).size(width, height);
Expand Down
26 changes: 19 additions & 7 deletions src/main/java/grondag/canvas/render/CanvasWorldRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ public class CanvasWorldRenderer extends WorldRenderer {

private final RenderContextState contextState = new RenderContextState();
public final CanvasImmediate worldRenderImmediate = new CanvasImmediate(new BufferBuilder(256), CanvasImmediate.entityBuilders(), contextState);
private final CanvasImmediate shadowExtrasProvider = new CanvasImmediate(new BufferBuilder(256), CanvasImmediate.dummyBuilders(), contextState);
private final CanvasParticleRenderer particleRenderer = new CanvasParticleRenderer();
public final WorldRenderContextImpl eventContext = new WorldRenderContextImpl();

Expand Down Expand Up @@ -494,16 +495,22 @@ public void renderWorld(MatrixStack viewMatrixStack, MatrixStack identityStack,
blockContext.collectors = immediate.collectors;

SkyShadowRenderer.suppressEntityShadows(mc);

// PERF: find way to reduce allocation for this and MatrixStack generally
while (entities.hasNext()) {
final Entity entity = entities.next();
if ((!entityRenderDispatcher.shouldRender(entity, frustum, cameraX, cameraY, cameraZ) && !entity.hasPassengerDeep(mc.player))
|| (entity == camera.getFocusedEntity() && !FirstPersonModelHolder.handler.isThirdPerson(this, camera, viewMatrixStack) && (!(camera.getFocusedEntity() instanceof LivingEntity) || !((LivingEntity) camera.getFocusedEntity()).isSleeping()))
|| (entity instanceof ClientPlayerEntity && camera.getFocusedEntity() != entity)) {
boolean isFirstPersonPlayer = false;
if (!entityRenderDispatcher.shouldRender(entity, frustum, cameraX, cameraY, cameraZ) && !entity.hasPassengerDeep(mc.player)) {
continue;
}

if ((entity == camera.getFocusedEntity() && !FirstPersonModelHolder.handler.isThirdPerson(this, camera, viewMatrixStack) && (!(camera.getFocusedEntity() instanceof LivingEntity) || !((LivingEntity) camera.getFocusedEntity()).isSleeping()))
|| (entity instanceof ClientPlayerEntity && camera.getFocusedEntity() != entity)) {
if (Pipeline.skyShadowFbo == null) {
continue;
}
isFirstPersonPlayer = true;
}

++entityCount;
contextState.setCurrentEntity(entity);

Expand All @@ -515,7 +522,10 @@ public void renderWorld(MatrixStack viewMatrixStack, MatrixStack identityStack,

VertexConsumerProvider renderProvider;

if (canDrawEntityOutlines && mc.hasOutline(entity)) {
if (isFirstPersonPlayer) {
// only render as shadow
renderProvider = shadowExtrasProvider;
} else if (canDrawEntityOutlines && mc.hasOutline(entity)) {
didRenderOutlines = true;
final OutlineVertexConsumerProvider outlineVertexConsumerProvider = bufferBuilders.getOutlineVertexConsumers();
renderProvider = outlineVertexConsumerProvider;
Expand Down Expand Up @@ -595,9 +605,11 @@ public void renderWorld(MatrixStack viewMatrixStack, MatrixStack identityStack,

contextState.setCurrentBlockEntity(null);

try (DrawableBuffer entityBuffer = immediate.prepareDrawable(MaterialTarget.MAIN)) {
try (DrawableBuffer entityBuffer = immediate.prepareDrawable(MaterialTarget.MAIN);
DrawableBuffer shadowExtrasBuffer = shadowExtrasProvider.prepareDrawable(MaterialTarget.MAIN)) {
profileSwap(profiler, ProfilerGroup.ShadowMap, "shadow_map");
SkyShadowRenderer.render(this, cameraX, cameraY, cameraZ, entityBuffer);
SkyShadowRenderer.render(this, cameraX, cameraY, cameraZ, entityBuffer, shadowExtrasBuffer);
shadowExtrasBuffer.close();

profileSwap(profiler, ProfilerGroup.EndWorld, "terrain_solid");
MatrixState.set(MatrixState.REGION);
Expand Down
7 changes: 4 additions & 3 deletions src/main/java/grondag/canvas/render/SkyShadowRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public static boolean isActive() {
return active;
}

public static void render(CanvasWorldRenderer canvasWorldRenderer, double cameraX, double cameraY, double cameraZ, DrawableBuffer entityBuffer) {
public static void render(CanvasWorldRenderer canvasWorldRenderer, double cameraX, double cameraY, double cameraZ, DrawableBuffer entityBuffer, DrawableBuffer shadowExtrasBuffer) {
if (Pipeline.skyShadowFbo != null) {
// Viewport call (or something else) seems to be messing up fixed-function matrix state
RenderSystem.pushMatrix();
Expand All @@ -61,7 +61,7 @@ public static void render(CanvasWorldRenderer canvasWorldRenderer, double camera
for (cascade = 0; cascade < MatrixState.CASCADE_COUNT; ++cascade) {
Pipeline.skyShadowFbo.bind();
GL46.glFramebufferTextureLayer(GL46.GL_FRAMEBUFFER, FramebufferInfo.DEPTH_ATTACHMENT, Pipeline.shadowMapDepth, 0, cascade);
renderInner(canvasWorldRenderer, cameraX, cameraY, cameraZ, entityBuffer);
renderInner(canvasWorldRenderer, cameraX, cameraY, cameraZ, entityBuffer, shadowExtrasBuffer);
}

Pipeline.defaultFbo.bind();
Expand All @@ -72,7 +72,7 @@ public static void render(CanvasWorldRenderer canvasWorldRenderer, double camera
}
}

private static void renderInner(CanvasWorldRenderer canvasWorldRenderer, double cameraX, double cameraY, double cameraZ, DrawableBuffer entityBuffer) {
private static void renderInner(CanvasWorldRenderer canvasWorldRenderer, double cameraX, double cameraY, double cameraZ, DrawableBuffer entityBuffer, DrawableBuffer shadowExtrasBuffer) {
Pipeline.skyShadowFbo.clear();

// WIP: will need purpose-specific methods for each frustum/render type
Expand All @@ -82,6 +82,7 @@ private static void renderInner(CanvasWorldRenderer canvasWorldRenderer, double

if (Pipeline.config().skyShadow.allowEntities && MinecraftClient.getInstance().options.entityShadows) {
entityBuffer.draw(true);
shadowExtrasBuffer.draw(true);
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/main/java/grondag/canvas/render/TerrainFrustum.java
Original file line number Diff line number Diff line change
Expand Up @@ -166,20 +166,20 @@ public void prepare(Matrix4f modelMatrix, float tickDelta, Camera camera) {
final double z = vec.z;

final long cameraBlockPos = camera.getBlockPos().asLong();
boolean movedOneBlock = false;
boolean cameraMoved = false;

if (cameraBlockPos != lastCameraBlockPos) {
lastCameraBlockPos = cameraBlockPos;
movedOneBlock = true;
cameraMoved = true;
} else {
// could move 1.0 or more diagonally within same block pos
// the assumption that occlusion data only needs updating if the camera moves 1 block doesn't hold up
final double dx = x - lastPositionX;
final double dy = y - lastPositionY;
final double dz = z - lastPositionZ;
movedOneBlock = dx * dx + dy * dy + dz * dz >= 1.0D;
cameraMoved = dx * dx + dy * dy + dz * dz >= 0.01D;
}

if (movedOneBlock) {
if (cameraMoved) {
++positionVersion;
lastPositionX = x;
lastPositionY = y;
Expand All @@ -201,7 +201,7 @@ public void prepare(Matrix4f modelMatrix, float tickDelta, Camera camera) {
modelMatrixUpdate = dPitch * dPitch + dYaw * dYaw >= paddingFov * paddingFov;
}

if (movedOneBlock || modelMatrixUpdate || !projectionMatrixExt.matches(occlusionProjMat)) {
if (cameraMoved || modelMatrixUpdate || !projectionMatrixExt.matches(occlusionProjMat)) {
++viewVersion;

lastViewX = x;
Expand Down
11 changes: 2 additions & 9 deletions src/main/java/grondag/canvas/shader/ProcessShader.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,8 @@ public ProcessShader activate() {

for (final String samplerName : samplers) {
final int n = tex++;

// PERF: should probably match on any sampler uniform type - names must be unique anyway
if (program.containsUniformSpec("sampler2DArray", samplerName)) {
program.uniformSampler("sampler2DArray", samplerName, UniformRefreshFrequency.ON_LOAD, u -> u.set(n));
} else if (program.containsUniformSpec("sampler2DArrayShadow", samplerName)) {
program.uniformSampler("sampler2DArrayShadow", samplerName, UniformRefreshFrequency.ON_LOAD, u -> u.set(n));
} else if (program.containsUniformSpec("sampler2D", samplerName)) {
program.uniformSampler("sampler2D", samplerName, UniformRefreshFrequency.ON_LOAD, u -> u.set(n));
}
final String samplerType = SamplerTypeHelper.getSamplerType(program, samplerName);
program.uniformSampler(samplerType, samplerName, UniformRefreshFrequency.ON_LOAD, u -> u.set(n));
}

program.load();
Expand Down
Loading

0 comments on commit 55ce118

Please sign in to comment.