Kind of update dynamic buffer source, but question is, do we still need it

This commit is contained in:
DBotThePony 2024-08-25 18:33:24 +07:00
parent 2323854705
commit 567e03498e
Signed by: DBot
GPG Key ID: DCC23B5715498507

View File

@ -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<RenderType>?, types: Array<out RenderType>): Boolean {
if (types.isEmpty()) {
@ -63,7 +68,11 @@ private fun equals(existing: ImmutableList<RenderType>?, types: ImmutableList<Re
*
* Allows to batch OTM's geometry
*/
class DynamicBufferSource(val minimalInitialBufferSize: Int = 0, val maximalInitialBufferSize: Int = Int.MAX_VALUE, val vertexSorting: VertexSorting = VertexSorting.DISTANCE_TO_ORIGIN) : MultiBufferSource {
class DynamicBufferSource(
val minimalInitialBufferSize: Int = 0,
val maximalInitialBufferSize: Int = Int.MAX_VALUE,
val vertexSorting: VertexSorting = VertexSorting.DISTANCE_TO_ORIGIN
) : MultiBufferSource, Closeable {
init {
require(minimalInitialBufferSize >= 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<RenderType>? = 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<State>(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<State>().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<RenderType, State>()
private val bufferList = ArrayList<State>()
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<RenderType, ByteBufferBuilder>()
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<State>) {
@ -194,10 +237,6 @@ class DynamicBufferSource(val minimalInitialBufferSize: Int = 0, val maximalInit
}
}
private val buffers = Reference2ObjectOpenHashMap<RenderType, State>().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<RenderType>): 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<RenderType>) {
fun registerType(renderType: RenderType, after: List<RenderType>) {
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 {