From 567e03498eff71b36aae358d44336d79f9f56757 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 25 Aug 2024 18:33:24 +0700 Subject: [PATCH] Kind of update dynamic buffer source, but question is, do we still need it --- .../otm/client/render/DynamicBufferSource.kt | 274 +++++++----------- 1 file changed, 105 insertions(+), 169 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/DynamicBufferSource.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/DynamicBufferSource.kt index d8b1c49c4..86e4da4d1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/DynamicBufferSource.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/DynamicBufferSource.kt @@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.client.render import com.google.common.collect.ImmutableList import com.mojang.blaze3d.vertex.BufferBuilder +import com.mojang.blaze3d.vertex.ByteBufferBuilder import com.mojang.blaze3d.vertex.VertexConsumer import com.mojang.blaze3d.vertex.VertexSorting import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap @@ -9,6 +10,10 @@ import it.unimi.dsi.fastutil.objects.ReferenceArraySet import net.minecraft.client.renderer.MultiBufferSource import net.minecraft.client.renderer.RenderType import net.minecraft.client.renderer.Sheets +import net.minecraft.client.resources.model.ModelBakery +import net.neoforged.fml.ModLoader +import net.neoforged.neoforge.client.event.RegisterRenderBuffersEvent +import java.io.Closeable private fun equals(existing: ImmutableList?, types: Array): Boolean { if (types.isEmpty()) { @@ -63,7 +68,11 @@ private fun equals(existing: ImmutableList?, types: ImmutableList= 0) { "Invalid minimal buffer size $minimalInitialBufferSize" } require(maximalInitialBufferSize >= minimalInitialBufferSize) { "Maximal buffer size $maximalInitialBufferSize must be greater or equal to minimal buffer size $minimalInitialBufferSize" } @@ -73,16 +82,17 @@ class DynamicBufferSource(val minimalInitialBufferSize: Int = 0, val maximalInit val type: RenderType, var after: ImmutableList? = null, immutableAfter: Boolean = false, - chained: Boolean = true + chained: Boolean = true, + private val byteBuffer: ByteBufferBuilder = ByteBufferBuilder(type.bufferSize().coerceIn(minimalInitialBufferSize, maximalInitialBufferSize)) ) { val immutableAfter: Boolean val chained: Boolean init { if ( - type.name == "forge_text" || + type.name == "neoforge_text" || type.name == "text_intensity" || - type.name == "forge_text_see_through" || + type.name == "neoforge_text_see_through" || type.name.contains("font_") || type.name.contains("text_") || type.name.contains("_text") || @@ -95,54 +105,87 @@ class DynamicBufferSource(val minimalInitialBufferSize: Int = 0, val maximalInit this.immutableAfter = immutableAfter this.chained = chained } + + buffers[type] = this + bufferList.add(this) } val dependants = ArrayList(0) var priority = -1 - var dirty: Boolean = false - val builder by lazy(LazyThreadSafetyMode.NONE) { - BufferBuilder(type.bufferSize().coerceAtLeast(minimalInitialBufferSize).coerceAtMost(maximalInitialBufferSize)) + + private var buffer: BufferBuilder? = null + + fun begin(): BufferBuilder { + var buffer = buffer + + if (buffer != null) { + return buffer + } + + buffer = BufferBuilder(byteBuffer, type.mode, type.format) + this.buffer = buffer + return buffer + } + + fun finish() { + val built = buffer?.build() + + if (built != null) { + if (type.sortOnUpload()) { + built.sortQuads(byteBuffer, vertexSorting) + } + + type.draw(built) + } + + this.buffer = null + } + + fun finishChain() { + finish() + dependants.forEach { it.finishChain() } + } + + fun close() { + byteBuffer.close() } } - @Suppress("BooleanLiteralArgument") - private val bufferList = ArrayList().also { - var next = State(Sheets.solidBlockSheet(), null, true, false) - it.add(next) - next = State(Sheets.cutoutBlockSheet(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(Sheets.bannerSheet(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(Sheets.translucentCullBlockSheet(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(Sheets.shieldSheet(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(Sheets.bedSheet(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(Sheets.shulkerBoxSheet(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(Sheets.signSheet(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(Sheets.chestSheet(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(RenderType.translucentNoCrumbling(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(RenderType.armorGlint(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(RenderType.armorEntityGlint(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(RenderType.glint(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(RenderType.glintDirect(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(RenderType.glintTranslucent(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(RenderType.entityGlint(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(RenderType.entityGlintDirect(), ImmutableList.of(next.type), true, false) - it.add(next) - next = State(RenderType.waterMask(), ImmutableList.of(next.type), true, false) - it.add(next) + private val buffers = Reference2ObjectOpenHashMap() + private val bufferList = ArrayList() + + init { + var next = State(Sheets.solidBlockSheet(), null, immutableAfter = true, chained = false) + next = State(Sheets.cutoutBlockSheet(), ImmutableList.of(next.type), immutableAfter = true, chained = false) + next = State(Sheets.bannerSheet(), ImmutableList.of(next.type), immutableAfter = true, chained = false) + next = State(Sheets.translucentCullBlockSheet(), ImmutableList.of(next.type), immutableAfter = true, chained = false) + + next = State(Sheets.shieldSheet(), ImmutableList.of(next.type), immutableAfter = true, chained = false) + next = State(Sheets.bedSheet(), ImmutableList.of(next.type), immutableAfter = true, chained = false) + next = State(Sheets.shulkerBoxSheet(), ImmutableList.of(next.type), immutableAfter = true, chained = false) + next = State(Sheets.signSheet(), ImmutableList.of(next.type), immutableAfter = true, chained = false) + next = State(Sheets.hangingSignSheet(), ImmutableList.of(next.type), immutableAfter = true, chained = false) + next = State(Sheets.chestSheet(), ImmutableList.of(next.type), immutableAfter = true, chained = false) + next = State(RenderType.armorEntityGlint(), ImmutableList.of(next.type), immutableAfter = true, chained = false) + next = State(RenderType.glint(), ImmutableList.of(next.type), immutableAfter = true, chained = false) + next = State(RenderType.glintTranslucent(), ImmutableList.of(next.type), immutableAfter = true, chained = false) + next = State(RenderType.entityGlint(), ImmutableList.of(next.type), immutableAfter = true, chained = false) + next = State(RenderType.entityGlintDirect(), ImmutableList.of(next.type), immutableAfter = true, chained = false) + next = State(RenderType.waterMask(), ImmutableList.of(next.type), immutableAfter = true, chained = false) + + ModelBakery.DESTROY_TYPES.forEach { + next = State(it, ImmutableList.of(next.type), immutableAfter = true, chained = false) + } + + val modBuffers = LinkedHashMap() + ModLoader.postEvent(RegisterRenderBuffersEvent(modBuffers)) + + for ((type, buffer) in modBuffers) { + // TODO: determine whenever other mods render types should be chained + next = State(type, ImmutableList.of(next.type), immutableAfter = false, chained = true, buffer) + } + + sortBufferList() } private fun determineHeight(input: State, seen: MutableSet) { @@ -194,10 +237,6 @@ class DynamicBufferSource(val minimalInitialBufferSize: Int = 0, val maximalInit } } - private val buffers = Reference2ObjectOpenHashMap().also { - for (v in bufferList) it[v.type] = v - } - init { sortBufferList() } @@ -207,20 +246,9 @@ class DynamicBufferSource(val minimalInitialBufferSize: Int = 0, val maximalInit if (getState == null) { getState = State(renderType) - buffers[renderType] = getState - bufferList.add(getState) - getState.dirty = true - return getState.builder.also { - it.begin(renderType.mode(), renderType.format()) - } } - if (!getState.dirty) { - getState.dirty = true - getState.builder.begin(renderType.mode(), renderType.format()) - } - - return getState.builder + return getState.begin() } fun getBuffer(renderType: RenderType, after: RenderType): VertexConsumer { @@ -228,13 +256,8 @@ class DynamicBufferSource(val minimalInitialBufferSize: Int = 0, val maximalInit if (getState == null) { getState = State(renderType, ImmutableList.of(after)) - buffers[renderType] = getState - bufferList.add(getState) - getState.dirty = true sortBufferList() - return getState.builder.also { - it.begin(renderType.mode(), renderType.format()) - } + return getState.begin() } if (!getState.immutableAfter && getState.after?.getOrNull(0) !== after) { @@ -242,12 +265,7 @@ class DynamicBufferSource(val minimalInitialBufferSize: Int = 0, val maximalInit sortBufferList() } - if (!getState.dirty) { - getState.dirty = true - getState.builder.begin(renderType.mode(), renderType.format()) - } - - return getState.builder + return getState.begin() } fun getBuffer(renderType: RenderType, vararg after: RenderType): VertexConsumer { @@ -255,13 +273,8 @@ class DynamicBufferSource(val minimalInitialBufferSize: Int = 0, val maximalInit if (getState == null) { getState = State(renderType, ImmutableList.copyOf(after)) - buffers[renderType] = getState - bufferList.add(getState) - getState.dirty = true sortBufferList() - return getState.builder.also { - it.begin(renderType.mode(), renderType.format()) - } + return getState.begin() } if (!getState.immutableAfter && !equals(getState.after, after)) { @@ -269,123 +282,46 @@ class DynamicBufferSource(val minimalInitialBufferSize: Int = 0, val maximalInit sortBufferList() } - if (!getState.dirty) { - getState.dirty = true - getState.builder.begin(renderType.mode(), renderType.format()) - } - - return getState.builder - } - - fun getBuffer(renderType: RenderType, after: ImmutableList): VertexConsumer { - var getState = buffers[renderType] - - if (getState == null) { - getState = State(renderType, after) - buffers[renderType] = getState - bufferList.add(getState) - getState.dirty = true - sortBufferList() - return getState.builder.also { - it.begin(renderType.mode(), renderType.format()) - } - } - - if (!getState.immutableAfter && !equals(getState.after, after)) { - getState.after = after - sortBufferList() - } - - if (!getState.dirty) { - getState.dirty = true - getState.builder.begin(renderType.mode(), renderType.format()) - } - - return getState.builder + return getState.begin() } fun registerType(renderType: RenderType, after: RenderType) { - var getState = buffers[renderType] - - if (getState == null) { - getState = State(renderType, ImmutableList.of(after), immutableAfter = true) - buffers[renderType] = getState - bufferList.add(getState) - sortBufferList() - } else if (!getState.immutableAfter && getState.after?.getOrNull(0) !== after) { - getState.after = ImmutableList.of(after) - sortBufferList() - } + return registerType(renderType, ImmutableList.of(after)) } fun registerType(renderType: RenderType, vararg after: RenderType) { - var getState = buffers[renderType] - - if (getState == null) { - getState = State(renderType, ImmutableList.copyOf(after), immutableAfter = true) - buffers[renderType] = getState - bufferList.add(getState) - sortBufferList() - } else if (!getState.immutableAfter && !equals(getState.after, after)) { - getState.after = ImmutableList.copyOf(after) - sortBufferList() - } + return registerType(renderType, ImmutableList.copyOf(after)) } - fun registerType(renderType: RenderType, after: ImmutableList) { + fun registerType(renderType: RenderType, after: List) { + val afterList = ImmutableList.copyOf(after) var getState = buffers[renderType] if (getState == null) { - getState = State(renderType, after, immutableAfter = true) + getState = State(renderType, afterList, immutableAfter = true) buffers[renderType] = getState bufferList.add(getState) sortBufferList() - } else if (!getState.immutableAfter && !equals(getState.after, after)) { - getState.after = after + } else if (!getState.immutableAfter && !equals(getState.after, afterList)) { + getState.after = afterList sortBufferList() } } fun endBatch() { - for (state in bufferList) { - if (state.dirty) { - state.dirty = false - state.type.end(state.builder, vertexSorting) - } - } + bufferList.forEach { it.finish() } } fun endBatch(type: RenderType) { - val state = buffers[type] ?: return - - if (state.dirty) { - state.dirty = false - type.end(state.builder, vertexSorting) - } + buffers[type]?.finish() } fun endBatchChain(type: RenderType) { - val state = buffers[type] ?: return - - if (state.dirty) { - state.dirty = false - type.end(state.builder, vertexSorting) - } - - for (ustate in state.dependants) { - endBatchChain(ustate) - } + buffers[type]?.finishChain() } - private fun endBatchChain(state: State) { - if (state.dirty) { - state.dirty = false - state.type.end(state.builder, vertexSorting) - } - - for (ustate in state.dependants) { - endBatchChain(ustate) - } + override fun close() { + bufferList.forEach { it.close() } } companion object {