Skip to content

Commit

Permalink
Partial cleanup of transparency, material semantics, add material deb…
Browse files Browse the repository at this point in the history
…ug code
  • Loading branch information
grondag committed Nov 1, 2020
1 parent b1a411c commit 11472c2
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.Map;
import java.util.SortedMap;

import grondag.canvas.material.property.MaterialTarget;
import grondag.canvas.material.state.RenderContextState;
import grondag.canvas.material.state.RenderLayerHelper;
import grondag.canvas.material.state.RenderMaterialImpl;
Expand Down Expand Up @@ -41,15 +42,16 @@ public VertexConsumer getBuffer(RenderLayer renderLayer) {
}
}

public void drawCollectors(boolean translucentTerrain) {
// WIP: need a way to ensure decal layers go last
public void drawCollectors(MaterialTarget target) {
final ObjectArrayList<VertexCollectorImpl> drawList = this.drawList;
final int limit = collectors.size();

if (limit != 0) {
for (int i = 0; i < limit; ++i) {
final VertexCollectorImpl collector = collectors.get(i);

if (collector.materialState.isTranslucentTerrain == translucentTerrain && !collector.isEmpty()) {
if (collector.materialState.target == target && !collector.isEmpty()) {
drawList.add(collector);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,6 @@ abstract class AbstractRenderState extends AbstractRenderStateView {
public final boolean hurtOverlay;
public final boolean flashOverlay;

/**
* True when translucent transparency and targets the terrain layer.
* Should not be rendered until that framebuffer is initialized in fabulous mode
* or should be delayed to render with other trasnslucent when not.
*/
public final boolean isTranslucentTerrain;

protected AbstractRenderState(int index, long bits) {
super(bits);
this.index = index;
Expand All @@ -92,9 +85,8 @@ protected AbstractRenderState(int index, long bits) {
fog = fog();
condition = condition();
transparency = TRANSPARENCY.getValue(bits);
sorted = transparency != MaterialTransparency.NONE && decal != MaterialDecal.TRANSLUCENT;
sorted = sorted();
shader = MaterialShaderManager.INSTANCE.get(SHADER.getValue(bits));
isTranslucentTerrain = (target == MaterialTarget.MAIN || target == MaterialTarget.TRANSLUCENT) && transparency == MaterialTransparency.TRANSLUCENT;
blendMode = blendMode();
emissive = emissive();
disableDiffuse = disableDiffuse();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ protected AbstractRenderStateView(long bits) {
}

public long collectorKey() {
return bits & COLLECTOR_KEY_MASK;
return sorted() ? (bits & SORTED_COLLECTOR_KEY_MASK) : (bits & UNSORTED_COLLECTOR_KEY_MASK);
}

public MaterialShaderImpl shader() {
Expand All @@ -55,6 +55,10 @@ public MaterialConditionImpl condition() {
return MaterialConditionImpl.fromIndex(CONDITION.getValue(bits));
}

public boolean sorted() {
return SORTED.getValue(bits);
}

public int conditionIndex() {
return CONDITION.getValue(bits);
}
Expand Down Expand Up @@ -162,6 +166,41 @@ public int shaderFlags() {
return (int) (bits >>> FLAG_SHIFT) & 0xFF;
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("bits: ").append(Long.toHexString(bits)).append(" ").append(Long.toBinaryString(bits)).append("\n");
sb.append("collectorKey: ").append(Long.toHexString(collectorKey())).append(" ").append(Long.toBinaryString(collectorKey())).append("\n");
sb.append("bilinear: ").append(bilinear()).append("\n");
sb.append("blendMode: ").append(blendMode().name()).append("\n");
sb.append("conditionIndex: ").append(conditionIndex()).append("\n");
sb.append("cull: ").append(cull()).append("\n");
sb.append("cutout: ").append(cutout()).append("\n");
sb.append("decal: ").append(decal().name()).append("\n");
sb.append("depthTest: ").append(depthTest().name()).append("\n");
sb.append("disableAo: ").append(disableAo()).append("\n");
sb.append("disableColorIndex: ").append(disableColorIndex()).append("\n");
sb.append("disableDiffuse: ").append(disableDiffuse()).append("\n");
sb.append("emissive: ").append(emissive()).append("\n");
sb.append("enableLightmap: ").append(enableLightmap()).append("\n");
sb.append("flashoverlay: ").append(flashOverlay()).append("\n");
sb.append("fog: ").append(fog().name()).append("\n");
sb.append("hurtOverlay: ").append(hurtOverlay()).append("\n");
sb.append("lines: ").append(lines()).append("\n");
sb.append("primitive: ").append(primitive()).append("\n");
sb.append("shader: [").append(shader().toString()).append("]\n");
sb.append("shaderFlags: ").append(Integer.toBinaryString(shaderFlags())).append("\n");
sb.append("sorted: ").append(sorted()).append("\n");
sb.append("target: ").append(target().name()).append("\n");
sb.append("texture: ").append(texture().index).append(" ").append(texture().id.toString()).append("\n");
sb.append("transparency: ").append(translucency().name()).append("\n");
sb.append("transparentCutout: ").append(translucentCutout()).append("\n");
sb.append("unmipped: ").append(unmipped()).append("\n");
sb.append("writeMask: ").append(writeMask().name()).append("\n");
return sb.toString();

}

static final BitPacker64<Void> PACKER = new BitPacker64<> (null, null);

// GL State comes first for sorting
Expand All @@ -174,20 +213,34 @@ public int shaderFlags() {
static final BitPacker64<Void>.EnumElement<MaterialWriteMask> WRITE_MASK = PACKER.createEnumElement(MaterialWriteMask.class);
static final BitPacker64.BooleanElement ENABLE_LIGHTMAP = PACKER.createBooleanElement();
// note that translucent decal is never persisted because it isn't part of GL state - that is indicated by SORTED
// WIP: move matrix-based decal out of render state
static final BitPacker64<Void>.EnumElement<MaterialDecal> DECAL = PACKER.createEnumElement(MaterialDecal.class);
static final BitPacker64<Void>.EnumElement<MaterialTarget> TARGET = PACKER.createEnumElement(MaterialTarget.class);
static final BitPacker64.BooleanElement LINES = PACKER.createBooleanElement();
static final BitPacker64<Void>.EnumElement<MaterialFog> FOG = PACKER.createEnumElement(MaterialFog.class);

// These don't affect GL state but must be collected and drawn separately
// They also generally won't change within a render state for any given context
// so they don't cause fragmentation except for sorted transparency, which is intended.
/** indicates sorted transparency - should be only one true value per render target */
static final BitPacker64.BooleanElement SORTED = PACKER.createBooleanElement();
static final BitPacker64.IntElement PRIMITIVE = PACKER.createIntElement(8);

public static final long SORTED_RENDER_STATE_MASK = PACKER.bitMask();

// WIP: simplify shaders - the actual programs really aren't variant except by sorting
// WIP: make vertex/uniform configurable for non-sorted layers

// Part of render state and collection key for non-sorted, not included in either for sorted
static final BitPacker64.IntElement SHADER = PACKER.createIntElement(4096);

public static final long RENDER_STATE_MASK = PACKER.bitMask();
public static final long UNSORTED_RENDER_STATE_MASK = PACKER.bitMask();
public static final long SORTED_COLLECTOR_KEY_MASK = PACKER.bitMask();

// These don't affect GL state but must be buffered separately
// Should always be zero in render state, only used in buffer key and material
static final BitPacker64.IntElement PRIMITIVE = PACKER.createIntElement(8);
// Can't be part of translucent collector key
static final BitPacker64.IntElement CONDITION = PACKER.createIntElement(MaterialConditionImpl.MAX_CONDITIONS);

public static final long COLLECTOR_KEY_MASK = PACKER.bitMask();
public static final long UNSORTED_COLLECTOR_KEY_MASK = PACKER.bitMask();

// here and below only used in material - holds vertex state - does not affect buffering or gl State
static final BitPacker64.BooleanElement DISABLE_COLOR_INDEX = PACKER.createBooleanElement();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ public T target(MaterialTarget target) {
return (T) this;
}

public T sorted(boolean sorted) {
bits = SORTED.setValue(sorted, bits);
return (T) this;
}

public T lines(boolean lines) {
bits = LINES.setValue(lines, bits);
return (T) this;
Expand Down Expand Up @@ -195,27 +200,35 @@ public T blendMode(BlendMode blendMode) {
cutout(true);
unmipped(true);
translucentCutout(false);
target(MaterialTarget.MAIN);
sorted(false);
bits = DEFAULT_BLEND_MODE.setValue(false, bits);
break;
case CUTOUT_MIPPED:
transparency(MaterialTransparency.NONE);
cutout(true);
unmipped(false);
translucentCutout(false);
target(MaterialTarget.MAIN);
sorted(false);
bits = DEFAULT_BLEND_MODE.setValue(false, bits);
break;
case TRANSLUCENT:
transparency(MaterialTransparency.TRANSLUCENT);
cutout(true);
cutout(false);
unmipped(false);
translucentCutout(true);
translucentCutout(false);
target(MaterialTarget.TRANSLUCENT);
sorted(true);
bits = DEFAULT_BLEND_MODE.setValue(false, bits);
break;
case DEFAULT:
transparency(MaterialTransparency.NONE);
cutout(false);
unmipped(false);
translucentCutout(false);
target(MaterialTarget.MAIN);
sorted(false);
bits = DEFAULT_BLEND_MODE.setValue(true, bits);
break;
default:
Expand All @@ -224,6 +237,8 @@ public T blendMode(BlendMode blendMode) {
cutout(false);
unmipped(false);
translucentCutout(false);
target(MaterialTarget.MAIN);
sorted(false);
bits = DEFAULT_BLEND_MODE.setValue(false, bits);
break;
}
Expand Down Expand Up @@ -256,11 +271,17 @@ public T copyFrom(RenderMaterial material) {

public V find() {
// WIP: need a way to ensure only one translucent buffer/render state per target
bits = SHADER.setValue(MaterialShaderManager.INSTANCE.find(vertexShaderIndex,fragmentShaderIndex, TRANSPARENCY.getValue(bits) == MaterialTransparency.TRANSLUCENT ? ProgramType.MATERIAL_VERTEX_LOGIC : ProgramType.MATERIAL_UNIFORM_LOGIC).index, bits);
bits = SHADER.setValue(MaterialShaderManager.INSTANCE.find(vertexShaderIndex,fragmentShaderIndex, sorted() ? ProgramType.MATERIAL_VERTEX_LOGIC : ProgramType.MATERIAL_UNIFORM_LOGIC).index, bits);
return findInner();
}

public V fromBits(long bits) {
if (SORTED.getValue(bits)) {
bits &= SORTED_RENDER_STATE_MASK;
} else {
bits &= UNSORTED_RENDER_STATE_MASK;
}

this.bits = bits;
return findInner();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import grondag.frex.api.material.MaterialFinder;

// WIP: expose attributes in FREX
// WIP: use decal layer in JMX, RenderBender and XB/XM to improve performance for mult-layer blocks
public class MaterialFinderImpl extends AbstractStateFinder<MaterialFinderImpl, RenderMaterialImpl> implements MaterialFinder {
@Override
protected synchronized RenderMaterialImpl findInner() {
Expand Down
27 changes: 18 additions & 9 deletions src/main/java/grondag/canvas/material/state/RenderLayerHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import grondag.canvas.mixin.AccessTexture;
import grondag.canvas.mixinterface.EntityRenderDispatcherExt;
import grondag.canvas.mixinterface.MultiPhaseExt;
import grondag.canvas.mixinterface.RenderLayerExt;
import it.unimi.dsi.fastutil.Hash;
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
import org.lwjgl.opengl.GL11;
Expand Down Expand Up @@ -65,16 +66,11 @@ public static boolean isExcluded(RenderLayer layer) {
return EXCLUSIONS.contains(layer);
}

public static RenderMaterialImpl copyFromLayer(RenderLayer layer) {
if (isExcluded(layer)) {
return RenderMaterialImpl.MISSING;
}

private static void copyFromLayer(MaterialFinderImpl finder, RenderLayer layer) {
final AccessMultiPhaseParameters params = ((MultiPhaseExt) layer).canvas_phases();
final AccessTexture tex = (AccessTexture) params.getTexture();

final MaterialFinderImpl finder = MaterialFinderImpl.threadLocal();

finder.sorted(((RenderLayerExt) layer).canvas_isTranslucent());
finder.primitive(GL11.GL_QUADS);
finder.texture(tex.getId().orElse(null));
finder.transparency(MaterialTransparency.fromPhase(params.getTransparency()));
Expand All @@ -87,10 +83,9 @@ public static RenderMaterialImpl copyFromLayer(RenderLayer layer) {
finder.lines(params.getLineWidth() != RenderPhase.FULL_LINE_WIDTH);
finder.fog(MaterialFog.fromPhase(params.getFog()));
finder.unmipped(!tex.getMipmap());
finder.disableDiffuse(params.getDiffuseLighting() == RenderPhase.DISABLE_DIFFUSE_LIGHTING);
finder.bilinear(tex.getBilinear());
finder.cutout(params.getAlpha() != RenderPhase.ZERO_ALPHA);
finder.translucentCutout(params.getAlpha() == RenderPhase.ONE_TENTH_ALPHA);
finder.disableAo(true);
finder.defaultBlendMode(false);

// vanilla sets these as part of draw process but we don't want special casing
Expand All @@ -99,7 +94,21 @@ public static RenderMaterialImpl copyFromLayer(RenderLayer layer) {
finder.texture(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE);
finder.writeMask(MaterialWriteMask.COLOR_DEPTH);
finder.enableLightmap(true);
finder.disableAo(false);
finder.disableDiffuse(false);
} else {
finder.disableAo(true);
finder.disableDiffuse(params.getDiffuseLighting() == RenderPhase.DISABLE_DIFFUSE_LIGHTING);
}
}

public static RenderMaterialImpl copyFromLayer(RenderLayer layer) {
if (isExcluded(layer)) {
return RenderMaterialImpl.MISSING;
}

final MaterialFinderImpl finder = MaterialFinderImpl.threadLocal();
copyFromLayer(finder, layer);

// WIP2: put in proper material map hooks
final String name = ((MultiPhaseExt) layer).canvas_name();
Expand Down
27 changes: 13 additions & 14 deletions src/main/java/grondag/canvas/render/CanvasWorldRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import grondag.canvas.compat.VoxelMapHolder;
import grondag.canvas.light.LightmapHdTexture;
import grondag.canvas.material.property.MaterialMatrixState;
import grondag.canvas.material.property.MaterialTarget;
import grondag.canvas.material.state.RenderContextState;
import grondag.canvas.material.state.RenderState;
import grondag.canvas.mixinterface.WorldRendererExt;
Expand Down Expand Up @@ -614,7 +615,7 @@ public void renderWorld(MatrixStack matrixStack, float tickDelta, long limitTime

assert matrixStack.isEmpty() : "Matrix stack not empty in world render when expected";

immediate.drawCollectors(false);
immediate.drawCollectors(MaterialTarget.MAIN);

bufferBuilders.getOutlineVertexConsumers().draw();

Expand Down Expand Up @@ -678,10 +679,8 @@ public void renderWorld(MatrixStack matrixStack, float tickDelta, long limitTime
mc.debugRenderer.render(matrixStack, immediate, cameraX, cameraY, cameraZ);
RenderSystem.popMatrix();

// Intention here seems to be to draw all the non-translucent layers before
// enabling the translucent target - this is a very brittle way of handling
// should be able to draw all layers for a given target
immediate.drawCollectors(false);
// Should generally not have anything here but draw in case content injected in hooks?
immediate.drawCollectors(MaterialTarget.MAIN);

immediate.draw(RenderLayer.getArmorGlint());
immediate.draw(RenderLayer.getArmorEntityGlint());
Expand All @@ -696,22 +695,22 @@ public void renderWorld(MatrixStack matrixStack, float tickDelta, long limitTime
if (advancedTranslucency) {
profiler.swap("translucent");

Framebuffer fb = mcwr.getTranslucentFramebuffer();
fb.clear(MinecraftClient.IS_SYSTEM_MAC);
fb.copyDepthFrom(mcfb);
fb.beginWrite(false);

// in fabulous mode, the only thing that renders to terrain translucency
// is terrain itself - so everything else can be rendered first

// Lines draw to entity (item) target
immediate.draw(RenderLayer.getLines());

immediate.drawCollectors(true);
immediate.drawCollectors(MaterialTarget.TRANSLUCENT);

// This presumably catches any remaining translucent layers in vanilla
// This catches entity layer and any remaining non-main layers
immediate.draw();

Framebuffer fb = mcwr.getTranslucentFramebuffer();
fb.clear(MinecraftClient.IS_SYSTEM_MAC);
fb.copyDepthFrom(mcfb);
fb.beginWrite(false);

MaterialMatrixState.set(MaterialMatrixState.REGION, null);
renderTerrainLayer(true, matrixStack, cameraX, cameraY, cameraZ);
MaterialMatrixState.set(MaterialMatrixState.ENTITY, matrixStack.peek().getNormal());
Expand Down Expand Up @@ -740,9 +739,9 @@ public void renderWorld(MatrixStack matrixStack, float tickDelta, long limitTime
// and other translucent elements get drawn on top of terrain
immediate.draw(RenderLayer.getLines());

immediate.drawCollectors(true);
immediate.drawCollectors(MaterialTarget.TRANSLUCENT);

// This presumably catches any remaining translucent layers in vanilla
// This catches entity layer and any remaining non-main layers
immediate.draw();

VoxelMapHolder.postRenderLayerHandler.render(this, RenderLayer.getTranslucent(), matrixStack, cameraX, cameraY, cameraZ);
Expand Down
Loading

0 comments on commit 11472c2

Please sign in to comment.