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(
|
class RendererManager(
|
||||||
val context: RenderContext,
|
val context: RenderContext,
|
||||||
) : Drawable, Iterable<Renderer> {
|
) : Drawable, Iterable<Renderer> {
|
||||||
|
private val list: MutableList<Renderer> = mutableListOf()
|
||||||
private val renderers: MutableMap<RendererBuilder<*>, Renderer> = linkedMapOf()
|
private val renderers: MutableMap<RendererBuilder<*>, Renderer> = linkedMapOf()
|
||||||
private val pipeline = RendererPipeline(this)
|
private val pipeline = RendererPipeline(this)
|
||||||
private val connection = context.connection
|
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? {
|
fun <T : Renderer> register(builder: RendererBuilder<T>): T? {
|
||||||
val renderer = builder.build(connection, context) ?: return null
|
val renderer = builder.build(connection, context) ?: return null
|
||||||
val previous = renderers.put(builder, renderer)
|
val previous = renderers.put(builder, renderer)
|
||||||
if (previous != null) {
|
if (previous != null) {
|
||||||
Log.log(LogMessageType.RENDERING, LogLevels.WARN) { "Renderer $previous ($builder) got replaced by $renderer!" }
|
Log.log(LogMessageType.RENDERING, LogLevels.WARN) { "Renderer $previous ($builder) got replaced by $renderer!" }
|
||||||
}
|
}
|
||||||
|
list += renderer
|
||||||
pipeline += renderer
|
pipeline += renderer
|
||||||
return renderer
|
return renderer
|
||||||
}
|
}
|
||||||
@ -58,14 +66,14 @@ class RendererManager(
|
|||||||
val inner = if (latch == null) SimpleLatch(0) else ParentLatch(0, latch)
|
val inner = if (latch == null) SimpleLatch(0) else ParentLatch(0, latch)
|
||||||
|
|
||||||
val worker = UnconditionalWorker()
|
val worker = UnconditionalWorker()
|
||||||
for (renderer in renderers.values) {
|
for (renderer in list) {
|
||||||
worker += { runnable.invoke(renderer, inner) }
|
worker += { runnable.invoke(renderer, inner) }
|
||||||
}
|
}
|
||||||
worker.work(inner)
|
worker.work(inner)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun init(latch: AbstractLatch) {
|
fun init(latch: AbstractLatch) {
|
||||||
for (renderer in renderers.values) {
|
for (renderer in list) {
|
||||||
if (renderer !is WorldRenderer) continue
|
if (renderer !is WorldRenderer) continue
|
||||||
renderer.registerLayers()
|
renderer.registerLayers()
|
||||||
}
|
}
|
||||||
@ -73,14 +81,14 @@ class RendererManager(
|
|||||||
|
|
||||||
runAsync(latch, Renderer::preAsyncInit)
|
runAsync(latch, Renderer::preAsyncInit)
|
||||||
|
|
||||||
for (renderer in renderers.values) {
|
for (renderer in list) {
|
||||||
renderer.init(latch)
|
renderer.init(latch)
|
||||||
}
|
}
|
||||||
runAsync(latch, Renderer::asyncInit)
|
runAsync(latch, Renderer::asyncInit)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun postInit(latch: AbstractLatch) {
|
fun postInit(latch: AbstractLatch) {
|
||||||
for (renderer in renderers.values) {
|
for (renderer in list) {
|
||||||
renderer.postInit(latch)
|
renderer.postInit(latch)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,19 +96,19 @@ class RendererManager(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun prepare() {
|
private fun prepare() {
|
||||||
for (renderer in renderers.values) {
|
for (renderer in list) {
|
||||||
renderer.prePrepareDraw()
|
renderer.prePrepareDraw()
|
||||||
}
|
}
|
||||||
|
|
||||||
val latch = SimpleLatch(0)
|
val latch = SimpleLatch(0)
|
||||||
val worker = UnconditionalWorker()
|
val worker = UnconditionalWorker()
|
||||||
for (renderer in renderers.values) {
|
for (renderer in list) {
|
||||||
if (renderer !is AsyncRenderer) continue
|
if (renderer !is AsyncRenderer) continue
|
||||||
worker += UnconditionalTask(priority = ThreadPool.HIGHER) { renderer.prepareDrawAsync() }
|
worker += UnconditionalTask(priority = ThreadPool.HIGHER) { renderer.prepareDrawAsync() }
|
||||||
}
|
}
|
||||||
worker.work(latch)
|
worker.work(latch)
|
||||||
|
|
||||||
for (renderer in renderers.values) {
|
for (renderer in list) {
|
||||||
renderer.postPrepareDraw()
|
renderer.postPrepareDraw()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -111,6 +119,6 @@ class RendererManager(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun iterator(): Iterator<Renderer> {
|
override fun iterator(): Iterator<Renderer> {
|
||||||
return renderers.values.iterator()
|
return list.iterator()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user