mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-15 02:15:34 -04:00
render pipeline tests
This commit is contained in:
parent
0cb1ab58f9
commit
ec08f86fed
@ -0,0 +1,216 @@
|
||||
package de.bixilon.minosoft.gui.rendering.renderer.renderer.pipeline.world
|
||||
|
||||
import de.bixilon.kotlinglm.vec2.Vec2i
|
||||
import de.bixilon.kutil.cast.CastUtil.unsafeCast
|
||||
import de.bixilon.kutil.exception.Broken
|
||||
import de.bixilon.kutil.reflection.ReflectionUtil.forceSet
|
||||
import de.bixilon.minosoft.data.registries.identified.Identified
|
||||
import de.bixilon.minosoft.data.registries.identified.Namespaces.minosoft
|
||||
import de.bixilon.minosoft.gui.rendering.RenderContext
|
||||
import de.bixilon.minosoft.gui.rendering.font.manager.FontManager
|
||||
import de.bixilon.minosoft.gui.rendering.font.types.dummy.DummyFontType
|
||||
import de.bixilon.minosoft.gui.rendering.framebuffer.FramebufferManager
|
||||
import de.bixilon.minosoft.gui.rendering.framebuffer.world.WorldFramebuffer
|
||||
import de.bixilon.minosoft.gui.rendering.gui.atlas.CodeTexturePart
|
||||
import de.bixilon.minosoft.gui.rendering.renderer.renderer.RendererManager
|
||||
import de.bixilon.minosoft.gui.rendering.renderer.renderer.pipeline.RendererPipeline
|
||||
import de.bixilon.minosoft.gui.rendering.renderer.renderer.world.LayerSettings
|
||||
import de.bixilon.minosoft.gui.rendering.renderer.renderer.world.WorldRenderer
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.PolygonModes
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.layer.OpaqueLayer
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.layer.RenderLayer
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.layer.TranslucentLayer
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.layer.TransparentLayer
|
||||
import de.bixilon.minosoft.gui.rendering.system.base.settings.RenderSettings
|
||||
import de.bixilon.minosoft.gui.rendering.system.dummy.DummyRenderSystem
|
||||
import de.bixilon.minosoft.gui.rendering.system.dummy.texture.DummyTexture
|
||||
import de.bixilon.minosoft.gui.rendering.system.dummy.texture.DummyTextureManager
|
||||
import de.bixilon.minosoft.test.IT
|
||||
import org.testng.Assert.assertEquals
|
||||
import org.testng.annotations.Test
|
||||
|
||||
@Test(groups = ["rendering"])
|
||||
class WorldRendererPipelineTest {
|
||||
private val elements = WorldRendererPipeline::class.java.getDeclaredField("elements").apply { isAccessible = true }
|
||||
val WorldRendererPipeline.elements: Array<PipelineElement> get() = this@WorldRendererPipelineTest.elements.get(this).unsafeCast()
|
||||
|
||||
private val pipeline = RendererManager::class.java.getDeclaredField("pipeline").apply { isAccessible = true }
|
||||
val RendererManager.pipeline: RendererPipeline get() = this@WorldRendererPipelineTest.pipeline.get(this).unsafeCast()
|
||||
|
||||
|
||||
fun construct() {
|
||||
manager()
|
||||
renderer()
|
||||
}
|
||||
|
||||
fun `register single layer`() {
|
||||
val manager = manager()
|
||||
val renderer = manager.register(renderer())
|
||||
|
||||
renderer.layers.register(OpaqueLayer, null, renderer::run)
|
||||
|
||||
manager.pipeline.world.rebuild()
|
||||
|
||||
val elements = manager.pipeline.world.elements
|
||||
assertEquals(elements.size, 1)
|
||||
assertEquals(elements[0].layer, OpaqueLayer)
|
||||
}
|
||||
|
||||
fun `register 2 but same layer, check insertion order`() {
|
||||
val manager = manager()
|
||||
val renderer = manager.register(renderer())
|
||||
|
||||
renderer.layers.register(OpaqueLayer, null, renderer::run)
|
||||
renderer.layers.register(layer("abc", OpaqueLayer.priority), null, renderer::run)
|
||||
|
||||
manager.pipeline.world.rebuild()
|
||||
|
||||
val elements = manager.pipeline.world.elements
|
||||
assertEquals(elements.size, 2)
|
||||
assertEquals(elements[0].layer, OpaqueLayer)
|
||||
assertEquals(elements[1].layer.priority, OpaqueLayer.priority)
|
||||
}
|
||||
|
||||
fun `register 2 but different layers priority, inserted correct order`() {
|
||||
val manager = manager()
|
||||
val renderer = manager.register(renderer())
|
||||
|
||||
renderer.layers.register(OpaqueLayer, null, renderer::run)
|
||||
renderer.layers.register(layer("abc", 10), null, renderer::run)
|
||||
|
||||
manager.pipeline.world.rebuild()
|
||||
|
||||
val elements = manager.pipeline.world.elements
|
||||
assertEquals(elements.size, 2)
|
||||
assertEquals(elements[0].layer, OpaqueLayer)
|
||||
assertEquals(elements[1].layer.priority, 10)
|
||||
}
|
||||
|
||||
fun `register 2 but different layers priority, wrong insertion order`() {
|
||||
val manager = manager()
|
||||
val renderer = manager.register(renderer())
|
||||
|
||||
renderer.layers.register(layer("abc", 10), null, renderer::run)
|
||||
renderer.layers.register(OpaqueLayer, null, renderer::run)
|
||||
|
||||
manager.pipeline.world.rebuild()
|
||||
|
||||
val elements = manager.pipeline.world.elements
|
||||
assertEquals(elements.size, 2)
|
||||
assertEquals(elements[0].layer, OpaqueLayer)
|
||||
assertEquals(elements[1].layer.priority, 10)
|
||||
}
|
||||
|
||||
fun `register 4 but different layers`() {
|
||||
val manager = manager()
|
||||
val renderer = manager.register(renderer())
|
||||
|
||||
renderer.layers.register(layer("a", 10), null, renderer::run)
|
||||
renderer.layers.register(OpaqueLayer, null, renderer::run)
|
||||
renderer.layers.register(layer("b", -10), null, renderer::run)
|
||||
renderer.layers.register(layer("c", -10), null, renderer::run)
|
||||
|
||||
manager.pipeline.world.rebuild()
|
||||
|
||||
val elements = manager.pipeline.world.elements
|
||||
assertEquals(elements.size, 4)
|
||||
assertEquals(elements[0].layer.unsafeCast<Identified>().identifier.path, "b")
|
||||
assertEquals(elements[1].layer.unsafeCast<Identified>().identifier.path, "c")
|
||||
assertEquals(elements[2].layer, OpaqueLayer)
|
||||
assertEquals(elements[3].layer.unsafeCast<Identified>().identifier.path, "a")
|
||||
}
|
||||
|
||||
fun `opaque transparent translucent`() {
|
||||
val manager = manager()
|
||||
val renderer = manager.register(renderer())
|
||||
|
||||
renderer.layers.register(TransparentLayer, null, renderer::run)
|
||||
renderer.layers.register(TranslucentLayer, null, renderer::run)
|
||||
renderer.layers.register(OpaqueLayer, null, renderer::run)
|
||||
|
||||
manager.pipeline.world.rebuild()
|
||||
|
||||
val elements = manager.pipeline.world.elements
|
||||
assertEquals(elements.size, 3)
|
||||
assertEquals(elements[0].layer, OpaqueLayer)
|
||||
assertEquals(elements[1].layer, TransparentLayer)
|
||||
assertEquals(elements[2].layer, TranslucentLayer)
|
||||
}
|
||||
|
||||
fun `different renderer`() {
|
||||
val manager = manager()
|
||||
|
||||
val first = manager.register(renderer())
|
||||
val second = manager.register(renderer())
|
||||
|
||||
first.layers.register(OpaqueLayer, null, first::run)
|
||||
second.layers.register(OpaqueLayer, null, second::run)
|
||||
second.layers.register(TranslucentLayer, null, second::run)
|
||||
|
||||
manager.pipeline.world.rebuild()
|
||||
|
||||
val elements = manager.pipeline.world.elements
|
||||
assertEquals(elements.size, 3)
|
||||
assertEquals(elements[0].layer, OpaqueLayer)
|
||||
assertEquals(elements[1].layer, OpaqueLayer)
|
||||
assertEquals(elements[2].layer, TranslucentLayer)
|
||||
}
|
||||
|
||||
fun `correct render draw order`() {
|
||||
val manager = manager()
|
||||
|
||||
val list: MutableList<String> = mutableListOf()
|
||||
|
||||
val first = manager.register(renderer())
|
||||
val second = manager.register(renderer())
|
||||
|
||||
first.layers.register(OpaqueLayer, null, { list += "a" })
|
||||
second.layers.register(OpaqueLayer, null, { list += "b" })
|
||||
second.layers.register(TranslucentLayer, null, { list += "c" })
|
||||
|
||||
manager.pipeline.world.rebuild()
|
||||
|
||||
manager.pipeline.world.draw()
|
||||
|
||||
assertEquals(list, listOf("a", "b", "c"))
|
||||
}
|
||||
|
||||
private fun context(): RenderContext {
|
||||
val context = IT.OBJENESIS.newInstance(RenderContext::class.java)
|
||||
context.font = FontManager(DummyFontType)
|
||||
context::system.forceSet(DummyRenderSystem(context))
|
||||
context::textures.forceSet(DummyTextureManager(context))
|
||||
|
||||
val framebuffer = IT.OBJENESIS.newInstance(FramebufferManager::class.java)
|
||||
framebuffer::world.forceSet(IT.OBJENESIS.newInstance(WorldFramebuffer::class.java).apply { this::polygonMode.forceSet(PolygonModes.FILL) })
|
||||
context::framebuffer.forceSet(framebuffer)
|
||||
|
||||
context.textures::whiteTexture.forceSet(CodeTexturePart(DummyTexture(), size = Vec2i(16, 16)))
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
|
||||
private fun manager(): RendererManager {
|
||||
val context = context()
|
||||
return RendererManager(context)
|
||||
}
|
||||
|
||||
private fun renderer() = object : WorldRenderer {
|
||||
override val context get() = Broken()
|
||||
override val framebuffer get() = null
|
||||
override val renderSystem get() = Broken()
|
||||
|
||||
override val layers = LayerSettings()
|
||||
override fun registerLayers() = Unit
|
||||
|
||||
|
||||
fun run(): Unit = TODO()
|
||||
}
|
||||
|
||||
private fun layer(name: String, priority: Int) = object : RenderLayer, Identified {
|
||||
override val identifier = minosoft(name)
|
||||
override val settings = RenderSettings.DEFAULT
|
||||
override val priority = priority
|
||||
}
|
||||
}
|
@ -31,17 +31,25 @@ import de.bixilon.minosoft.util.logging.LogMessageType
|
||||
class RendererManager(
|
||||
val context: RenderContext,
|
||||
) : Drawable, Iterable<Renderer> {
|
||||
private val list: MutableList<Renderer> = mutableListOf()
|
||||
private val renderers: MutableMap<RendererBuilder<*>, Renderer> = linkedMapOf()
|
||||
private val pipeline = RendererPipeline(this)
|
||||
private val connection = context.connection
|
||||
|
||||
|
||||
fun <T : Renderer> register(renderer: T): T {
|
||||
this.list += renderer
|
||||
|
||||
return renderer
|
||||
}
|
||||
|
||||
fun <T : Renderer> register(builder: RendererBuilder<T>): T? {
|
||||
val renderer = builder.build(connection, context) ?: return null
|
||||
val previous = renderers.put(builder, renderer)
|
||||
if (previous != null) {
|
||||
Log.log(LogMessageType.RENDERING, LogLevels.WARN) { "Renderer $previous ($builder) got replaced by $renderer!" }
|
||||
}
|
||||
list += renderer
|
||||
pipeline += renderer
|
||||
return renderer
|
||||
}
|
||||
@ -58,14 +66,14 @@ class RendererManager(
|
||||
val inner = if (latch == null) SimpleLatch(0) else ParentLatch(0, latch)
|
||||
|
||||
val worker = UnconditionalWorker()
|
||||
for (renderer in renderers.values) {
|
||||
for (renderer in list) {
|
||||
worker += { runnable.invoke(renderer, inner) }
|
||||
}
|
||||
worker.work(inner)
|
||||
}
|
||||
|
||||
fun init(latch: AbstractLatch) {
|
||||
for (renderer in renderers.values) {
|
||||
for (renderer in list) {
|
||||
if (renderer !is WorldRenderer) continue
|
||||
renderer.registerLayers()
|
||||
}
|
||||
@ -73,14 +81,14 @@ class RendererManager(
|
||||
|
||||
runAsync(latch, Renderer::preAsyncInit)
|
||||
|
||||
for (renderer in renderers.values) {
|
||||
for (renderer in list) {
|
||||
renderer.init(latch)
|
||||
}
|
||||
runAsync(latch, Renderer::asyncInit)
|
||||
}
|
||||
|
||||
fun postInit(latch: AbstractLatch) {
|
||||
for (renderer in renderers.values) {
|
||||
for (renderer in list) {
|
||||
renderer.postInit(latch)
|
||||
}
|
||||
|
||||
@ -88,19 +96,19 @@ class RendererManager(
|
||||
}
|
||||
|
||||
private fun prepare() {
|
||||
for (renderer in renderers.values) {
|
||||
for (renderer in list) {
|
||||
renderer.prePrepareDraw()
|
||||
}
|
||||
|
||||
val latch = SimpleLatch(0)
|
||||
val worker = UnconditionalWorker()
|
||||
for (renderer in renderers.values) {
|
||||
for (renderer in list) {
|
||||
if (renderer !is AsyncRenderer) continue
|
||||
worker += UnconditionalTask(priority = ThreadPool.HIGHER) { renderer.prepareDrawAsync() }
|
||||
}
|
||||
worker.work(latch)
|
||||
|
||||
for (renderer in renderers.values) {
|
||||
for (renderer in list) {
|
||||
renderer.postPrepareDraw()
|
||||
}
|
||||
}
|
||||
@ -111,6 +119,6 @@ class RendererManager(
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<Renderer> {
|
||||
return renderers.values.iterator()
|
||||
return list.iterator()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user