From ef7ef598fc337b6580b37502a6784c5bfae65fbb Mon Sep 17 00:00:00 2001 From: Chen Meng Date: Sat, 1 Nov 2025 19:56:53 +0800 Subject: [PATCH 1/6] G2RenderingInfo hasn't finished yet --- .../sakura/graphics/buffer/G2Buffer.kt | 19 ++++++- .../sakura/graphics/buffer/G2CommandList.kt | 10 ++++ .../sakura/graphics/buffer/G2Format.kt | 5 ++ .../graphics/buffer/G2GraphicsPipeline.kt | 17 ++++++ .../sakura/graphics/buffer/G2Image.kt | 4 ++ .../sakura/graphics/buffer/G2RenderingInfo.kt | 20 +++++++ .../sakura/graphics/buffer/G2RingBuffer.kt | 42 +++++++++++++++ .../sakura/graphics/buffer/G2ShaderSet.kt | 4 ++ .../exception/sakura/graphics/gl/GlBuffer.kt | 52 +++++++++++++++---- .../sakura/graphics/gl/GlCommandList.kt | 48 +++++++++++++++++ .../sakura/graphics/gl/GlGraphicsPipeline.kt | 23 ++++++++ 11 files changed, 234 insertions(+), 10 deletions(-) create mode 100644 src/main/kotlin/team/exception/sakura/graphics/buffer/G2Format.kt create mode 100644 src/main/kotlin/team/exception/sakura/graphics/buffer/G2GraphicsPipeline.kt create mode 100644 src/main/kotlin/team/exception/sakura/graphics/buffer/G2Image.kt create mode 100644 src/main/kotlin/team/exception/sakura/graphics/buffer/G2RenderingInfo.kt create mode 100644 src/main/kotlin/team/exception/sakura/graphics/buffer/G2RingBuffer.kt create mode 100644 src/main/kotlin/team/exception/sakura/graphics/buffer/G2ShaderSet.kt create mode 100644 src/main/kotlin/team/exception/sakura/graphics/gl/GlGraphicsPipeline.kt diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Buffer.kt b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Buffer.kt index ff6d935..1b78572 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Buffer.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Buffer.kt @@ -3,8 +3,8 @@ package team.exception.sakura.graphics.buffer import java.nio.ByteBuffer abstract class G2Buffer( + open val device: G2Device, val size: Long, - val access: Access, ) { /** @@ -14,6 +14,23 @@ abstract class G2Buffer( */ abstract fun getMappedBuffer(): ByteBuffer + /** + * Refresh modified data in the buffer. + * @throws IllegalStateException if the buffer hasn't been mapped. + */ + abstract fun refresh() + + /** + * Remap the buffer. + * @throws IllegalStateException if the buffer hasn't been mapped. + */ + abstract fun remap() + + /** + * Destroy & unmap the buffer. + */ + abstract fun destroy() + enum class Access { WRITE, READ, diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2CommandList.kt b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2CommandList.kt index eebf54a..4f576f7 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2CommandList.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2CommandList.kt @@ -2,6 +2,16 @@ package team.exception.sakura.graphics.buffer abstract class G2CommandList { + abstract fun bindGraphicsPipeline(pipeline: G2GraphicsPipeline) + + abstract fun draw(vertexCount: Int, instanceCount: Int, firstVertex: Int, firstInstance: Int) + + abstract fun drawIndexed(indexCount: Int, instanceCount: Int, firstIndex: Int, vertexOffset: Int, firstInstance: Int) + + abstract fun beginRendering(renderingInfo: G2RenderingInfo) + + abstract fun endRendering() + abstract fun summit() abstract fun clear() diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Format.kt b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Format.kt new file mode 100644 index 0000000..67ecb45 --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Format.kt @@ -0,0 +1,5 @@ +package team.exception.sakura.graphics.buffer + +enum class G2Format { + A8R8G8B8, +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2GraphicsPipeline.kt b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2GraphicsPipeline.kt new file mode 100644 index 0000000..a1fab31 --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2GraphicsPipeline.kt @@ -0,0 +1,17 @@ +package team.exception.sakura.graphics.buffer + +abstract class G2GraphicsPipeline( + val primitive: Primitive, + val shaderSet: G2ShaderSet +) { + + enum class Primitive { + TRIANGLES, + TRIANGLE_FAN, + TRIANGLE_STRIP, + LINES, + LINE_STRIP, + POINTS + } + +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Image.kt b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Image.kt new file mode 100644 index 0000000..24da681 --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Image.kt @@ -0,0 +1,4 @@ +package team.exception.sakura.graphics.buffer + +abstract class G2Image { +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2RenderingInfo.kt b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2RenderingInfo.kt new file mode 100644 index 0000000..d322178 --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2RenderingInfo.kt @@ -0,0 +1,20 @@ +package team.exception.sakura.graphics.buffer + +abstract class G2RenderingInfo { + + abstract val colorAttachment: Attachment? + + abstract val depthAttachment: Attachment? + + abstract val stencilAttachment: Attachment? + + abstract val width: Int + + abstract val height: Int + + data class Attachment( + val image: G2Image, + val format: G2Format, + ) + +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2RingBuffer.kt b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2RingBuffer.kt new file mode 100644 index 0000000..65c915c --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2RingBuffer.kt @@ -0,0 +1,42 @@ +package team.exception.sakura.graphics.buffer + +import java.nio.ByteBuffer + +class G2RingBuffer( + device: G2Device, + val size: Long, +) { + + private val buffer = device.createBuffer(size) + private var offset = 0L + + /** + * Put data into the buffer. + * @param size of the data to be put. + * @param invoke the function if there is enough space in the buffer. + * @throws IllegalArgumentException if the size is too large. + */ + fun alloc(size: Long, func: (ByteBuffer) -> Unit) { + // Check if the size is too large. + if (size > this.size) throw IllegalArgumentException("size is too large") + + // Check if there is enough space in the buffer. + val end = (offset + size) % size + if (end < offset) { + offset = 0 + } + + func(buffer.getMappedBuffer().apply { + position(offset.toInt()) + }) + } + + /** + * Release the buffer. + */ + fun destroy() { + buffer.destroy() + } + + +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2ShaderSet.kt b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2ShaderSet.kt new file mode 100644 index 0000000..76880a2 --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2ShaderSet.kt @@ -0,0 +1,4 @@ +package team.exception.sakura.graphics.buffer + +class G2ShaderSet { +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlBuffer.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlBuffer.kt index 80304b7..ef835e8 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlBuffer.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlBuffer.kt @@ -1,14 +1,15 @@ package team.exception.sakura.graphics.gl +import com.mojang.blaze3d.opengl.GlStateManager import org.lwjgl.opengl.GL41.* import team.exception.sakura.graphics.buffer.G2Buffer import java.nio.ByteBuffer class GlBuffer( - device: GlDevice, + override val device: GlDevice, size: Long, - access: Access, -): G2Buffer(size, access) { + val access: Access, +): G2Buffer(device, size) { private val id: Int = glGenBuffers() private var mappedBuf: ByteBuffer? = null @@ -18,11 +19,11 @@ class GlBuffer( val cmdList = device.getTempCommandList() cmdList.add { - glBindBuffer(GL_ARRAY_BUFFER, id) + GlStateManager._glBindBuffer(GL_ARRAY_BUFFER, id) glBufferData(GL_ARRAY_BUFFER, size, GL_STATIC_DRAW) - mappedBuf = glMapBuffer(GL_ARRAY_BUFFER, getGlByG2Access(access)) - glBindBuffer(GL_ARRAY_BUFFER, 0) + mappedBuf = glMapBufferRange(GL_ARRAY_BUFFER, + 0, size, getGlByG2Access(access)) } cmdList.summitAndClear() @@ -35,11 +36,44 @@ class GlBuffer( return mappedBuf!! } + override fun refresh() { + // TODO: Refresh modified data + } + + override fun remap() { + val cmdList = device.getTempCommandList() + + cmdList.add { + GlStateManager._glBindBuffer(GL_ARRAY_BUFFER, id) + if (mappedBuf == null) { + throw IllegalStateException("Buffer hasn't been mapped") + } + glUnmapBuffer(GL_ARRAY_BUFFER) + mappedBuf = glMapBufferRange(GL_ARRAY_BUFFER, 0, + size, getGlByG2Access(access)) + } + cmdList.summitAndClear() + } + + override fun destroy() { + val cmdList = device.getTempCommandList() + + cmdList.add { + GlStateManager._glBindBuffer(GL_ARRAY_BUFFER, id) + glUnmapBuffer(GL_ARRAY_BUFFER) + mappedBuf = null + glDeleteBuffers(id) + } + cmdList.summitAndClear() + } + companion object { + const val DEFAULT_ACCESS_BITS = GL_MAP_FLUSH_EXPLICIT_BIT + fun getGlByG2Access(access: Access): Int = when (access) { - Access.READ -> GL_READ_ONLY - Access.WRITE -> GL_WRITE_ONLY - Access.READ_WRITE -> GL_READ_WRITE + Access.READ -> GL_MAP_READ_BIT and DEFAULT_ACCESS_BITS + Access.WRITE -> GL_MAP_WRITE_BIT and DEFAULT_ACCESS_BITS + Access.READ_WRITE -> GL_MAP_READ_BIT and GL_MAP_WRITE_BIT and DEFAULT_ACCESS_BITS } } diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt index 556cfda..d608423 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt @@ -1,15 +1,63 @@ package team.exception.sakura.graphics.gl import team.exception.sakura.graphics.buffer.G2CommandList +import team.exception.sakura.graphics.buffer.G2GraphicsPipeline +import team.exception.sakura.graphics.buffer.G2RenderingInfo +import org.lwjgl.opengl.GL41.* +import team.exception.sakura.graphics.gl.GlGraphicsPipeline.Companion.toGlPrimitive +import java.util.Stack class GlCommandList: G2CommandList() { private val commands: MutableList = mutableListOf() + private var graphicsPipeline: GlGraphicsPipeline? = null + private val renderingInfoStack: Stack = Stack() internal fun add(command: () -> Unit) { commands.add(GlCommand(command)) } + override fun bindGraphicsPipeline(pipeline: G2GraphicsPipeline) { + graphicsPipeline = pipeline as GlGraphicsPipeline + } + + override fun draw( + vertexCount: Int, + instanceCount: Int, + firstVertex: Int, + firstInstance: Int + ) { + graphicsPipeline?.let { pipeline -> add { + glDrawArrays( + pipeline.primitive.toGlPrimitive(), + firstVertex, vertexCount + ) + } } + } + + override fun drawIndexed( + indexCount: Int, + instanceCount: Int, + firstIndex: Int, + vertexOffset: Int, + firstInstance: Int + ) { + graphicsPipeline?.let { pipeline -> add { + glDrawElements( + pipeline.primitive.toGlPrimitive(), + indexCount, GL_UNSIGNED_INT, (firstIndex * 4).toLong() + ) + } } + } + + override fun beginRendering(renderingInfo: G2RenderingInfo) { + renderingInfoStack.push(renderingInfo) + } + + override fun endRendering() { + renderingInfoStack.pop() + } + override fun summit() { commands.forEach { it.func() } } diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlGraphicsPipeline.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlGraphicsPipeline.kt new file mode 100644 index 0000000..da89764 --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlGraphicsPipeline.kt @@ -0,0 +1,23 @@ +package team.exception.sakura.graphics.gl + +import org.lwjgl.opengl.GL41.* +import team.exception.sakura.graphics.buffer.G2GraphicsPipeline +import team.exception.sakura.graphics.buffer.G2ShaderSet + +class GlGraphicsPipeline( + primitive: Primitive, + shaderSet: G2ShaderSet +): G2GraphicsPipeline(primitive, shaderSet) { + + companion object { + fun Primitive.toGlPrimitive(): Int = when (this) { + Primitive.TRIANGLES -> GL_TRIANGLES + Primitive.TRIANGLE_FAN -> GL_TRIANGLE_FAN + Primitive.TRIANGLE_STRIP -> GL_TRIANGLE_STRIP + Primitive.LINES -> GL_LINES + Primitive.LINE_STRIP -> GL_LINE_STRIP + Primitive.POINTS -> GL_POINTS + } + } + +} \ No newline at end of file From 89d56cdc7e381a3f1c4b32373369f84347406ddd Mon Sep 17 00:00:00 2001 From: Chen Meng Date: Sat, 1 Nov 2025 22:58:03 +0800 Subject: [PATCH 2/6] idk whether it can work or not --- .../sakura/graphics/G2RenderSystem.kt | 2 +- .../sakura/graphics/buffer/G2Format.kt | 5 - .../sakura/graphics/buffer/G2Image.kt | 4 - .../sakura/graphics/buffer/G2ShaderSet.kt | 4 - .../graphics/{buffer => geek2}/G2Buffer.kt | 2 +- .../{buffer => geek2}/G2CommandList.kt | 26 +++- .../graphics/{buffer => geek2}/G2Device.kt | 2 +- .../sakura/graphics/geek2/G2Format.kt | 5 + .../{buffer => geek2}/G2GraphicsPipeline.kt | 2 +- .../sakura/graphics/geek2/G2Image.kt | 5 + .../sakura/graphics/geek2/G2ImageView.kt | 7 ++ .../{buffer => geek2}/G2RenderingInfo.kt | 4 +- .../{buffer => geek2}/G2RingBuffer.kt | 2 +- .../sakura/graphics/geek2/G2Shader.kt | 8 ++ .../sakura/graphics/geek2/G2ShaderSet.kt | 7 ++ .../sakura/graphics/geek2/G2VertexInput.kt | 23 ++++ .../exception/sakura/graphics/gl/GlBuffer.kt | 2 +- .../sakura/graphics/gl/GlCommandList.kt | 6 +- .../exception/sakura/graphics/gl/GlDevice.kt | 4 +- .../graphics/gl/GlFrameBufferManager.kt | 115 ++++++++++++++++++ .../sakura/graphics/gl/GlGraphicsPipeline.kt | 4 +- .../exception/sakura/graphics/gl/GlImage.kt | 9 ++ .../sakura/graphics/gl/GlImageView.kt | 8 ++ 23 files changed, 227 insertions(+), 29 deletions(-) delete mode 100644 src/main/kotlin/team/exception/sakura/graphics/buffer/G2Format.kt delete mode 100644 src/main/kotlin/team/exception/sakura/graphics/buffer/G2Image.kt delete mode 100644 src/main/kotlin/team/exception/sakura/graphics/buffer/G2ShaderSet.kt rename src/main/kotlin/team/exception/sakura/graphics/{buffer => geek2}/G2Buffer.kt (94%) rename src/main/kotlin/team/exception/sakura/graphics/{buffer => geek2}/G2CommandList.kt (51%) rename src/main/kotlin/team/exception/sakura/graphics/{buffer => geek2}/G2Device.kt (85%) create mode 100644 src/main/kotlin/team/exception/sakura/graphics/geek2/G2Format.kt rename src/main/kotlin/team/exception/sakura/graphics/{buffer => geek2}/G2GraphicsPipeline.kt (84%) create mode 100644 src/main/kotlin/team/exception/sakura/graphics/geek2/G2Image.kt create mode 100644 src/main/kotlin/team/exception/sakura/graphics/geek2/G2ImageView.kt rename src/main/kotlin/team/exception/sakura/graphics/{buffer => geek2}/G2RenderingInfo.kt (79%) rename src/main/kotlin/team/exception/sakura/graphics/{buffer => geek2}/G2RingBuffer.kt (95%) create mode 100644 src/main/kotlin/team/exception/sakura/graphics/geek2/G2Shader.kt create mode 100644 src/main/kotlin/team/exception/sakura/graphics/geek2/G2ShaderSet.kt create mode 100644 src/main/kotlin/team/exception/sakura/graphics/geek2/G2VertexInput.kt create mode 100644 src/main/kotlin/team/exception/sakura/graphics/gl/GlFrameBufferManager.kt create mode 100644 src/main/kotlin/team/exception/sakura/graphics/gl/GlImage.kt create mode 100644 src/main/kotlin/team/exception/sakura/graphics/gl/GlImageView.kt diff --git a/src/main/kotlin/team/exception/sakura/graphics/G2RenderSystem.kt b/src/main/kotlin/team/exception/sakura/graphics/G2RenderSystem.kt index 8bd7d13..d803090 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/G2RenderSystem.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/G2RenderSystem.kt @@ -1,6 +1,6 @@ package team.exception.sakura.graphics -import team.exception.sakura.graphics.buffer.G2Device +import team.exception.sakura.graphics.geek2.G2Device import team.exception.sakura.graphics.gl.GlDevice object G2RenderSystem { diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Format.kt b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Format.kt deleted file mode 100644 index 67ecb45..0000000 --- a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Format.kt +++ /dev/null @@ -1,5 +0,0 @@ -package team.exception.sakura.graphics.buffer - -enum class G2Format { - A8R8G8B8, -} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Image.kt b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Image.kt deleted file mode 100644 index 24da681..0000000 --- a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Image.kt +++ /dev/null @@ -1,4 +0,0 @@ -package team.exception.sakura.graphics.buffer - -abstract class G2Image { -} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2ShaderSet.kt b/src/main/kotlin/team/exception/sakura/graphics/buffer/G2ShaderSet.kt deleted file mode 100644 index 76880a2..0000000 --- a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2ShaderSet.kt +++ /dev/null @@ -1,4 +0,0 @@ -package team.exception.sakura.graphics.buffer - -class G2ShaderSet { -} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Buffer.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Buffer.kt similarity index 94% rename from src/main/kotlin/team/exception/sakura/graphics/buffer/G2Buffer.kt rename to src/main/kotlin/team/exception/sakura/graphics/geek2/G2Buffer.kt index 1b78572..940f968 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Buffer.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Buffer.kt @@ -1,4 +1,4 @@ -package team.exception.sakura.graphics.buffer +package team.exception.sakura.graphics.geek2 import java.nio.ByteBuffer diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2CommandList.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2CommandList.kt similarity index 51% rename from src/main/kotlin/team/exception/sakura/graphics/buffer/G2CommandList.kt rename to src/main/kotlin/team/exception/sakura/graphics/geek2/G2CommandList.kt index 4f576f7..3586aef 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2CommandList.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2CommandList.kt @@ -1,21 +1,45 @@ -package team.exception.sakura.graphics.buffer +package team.exception.sakura.graphics.geek2 abstract class G2CommandList { + /** + * Binds the graphics pipeline to the command list. + */ abstract fun bindGraphicsPipeline(pipeline: G2GraphicsPipeline) + /** + * Draw array + */ abstract fun draw(vertexCount: Int, instanceCount: Int, firstVertex: Int, firstInstance: Int) + /** + * Draw indexed + */ abstract fun drawIndexed(indexCount: Int, instanceCount: Int, firstIndex: Int, vertexOffset: Int, firstInstance: Int) + /** + * Begin rendering (Dynamic rendering in vulkan) + */ abstract fun beginRendering(renderingInfo: G2RenderingInfo) + /** + * End rendering (Dynamic rendering in vulkan) + */ abstract fun endRendering() + /** + * Summit the command list + */ abstract fun summit() + /** + * Clear the command list + */ abstract fun clear() + /** + * Summit and clear the command list + */ abstract fun summitAndClear() } \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Device.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Device.kt similarity index 85% rename from src/main/kotlin/team/exception/sakura/graphics/buffer/G2Device.kt rename to src/main/kotlin/team/exception/sakura/graphics/geek2/G2Device.kt index d58d4c4..f7c239d 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2Device.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Device.kt @@ -1,4 +1,4 @@ -package team.exception.sakura.graphics.buffer +package team.exception.sakura.graphics.geek2 abstract class G2Device { diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Format.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Format.kt new file mode 100644 index 0000000..8ac5b4c --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Format.kt @@ -0,0 +1,5 @@ +package team.exception.sakura.graphics.geek2 + +enum class G2Format { + A8R8G8B8, +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2GraphicsPipeline.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2GraphicsPipeline.kt similarity index 84% rename from src/main/kotlin/team/exception/sakura/graphics/buffer/G2GraphicsPipeline.kt rename to src/main/kotlin/team/exception/sakura/graphics/geek2/G2GraphicsPipeline.kt index a1fab31..044035b 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2GraphicsPipeline.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2GraphicsPipeline.kt @@ -1,4 +1,4 @@ -package team.exception.sakura.graphics.buffer +package team.exception.sakura.graphics.geek2 abstract class G2GraphicsPipeline( val primitive: Primitive, diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Image.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Image.kt new file mode 100644 index 0000000..b5eef1e --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Image.kt @@ -0,0 +1,5 @@ +package team.exception.sakura.graphics.geek2 + +abstract class G2Image { + +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2ImageView.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2ImageView.kt new file mode 100644 index 0000000..21a43b0 --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2ImageView.kt @@ -0,0 +1,7 @@ +package team.exception.sakura.graphics.geek2 + +abstract class G2ImageView( + open val image: G2Image, +) { + +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2RenderingInfo.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2RenderingInfo.kt similarity index 79% rename from src/main/kotlin/team/exception/sakura/graphics/buffer/G2RenderingInfo.kt rename to src/main/kotlin/team/exception/sakura/graphics/geek2/G2RenderingInfo.kt index d322178..10aa5d7 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2RenderingInfo.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2RenderingInfo.kt @@ -1,4 +1,4 @@ -package team.exception.sakura.graphics.buffer +package team.exception.sakura.graphics.geek2 abstract class G2RenderingInfo { @@ -13,7 +13,7 @@ abstract class G2RenderingInfo { abstract val height: Int data class Attachment( - val image: G2Image, + val image: G2ImageView, val format: G2Format, ) diff --git a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2RingBuffer.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2RingBuffer.kt similarity index 95% rename from src/main/kotlin/team/exception/sakura/graphics/buffer/G2RingBuffer.kt rename to src/main/kotlin/team/exception/sakura/graphics/geek2/G2RingBuffer.kt index 65c915c..d84baf1 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/buffer/G2RingBuffer.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2RingBuffer.kt @@ -1,4 +1,4 @@ -package team.exception.sakura.graphics.buffer +package team.exception.sakura.graphics.geek2 import java.nio.ByteBuffer diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Shader.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Shader.kt new file mode 100644 index 0000000..cee98b0 --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Shader.kt @@ -0,0 +1,8 @@ +package team.exception.sakura.graphics.geek2 + +class G2Shader( + val source: String, + val entryPoint: String, + val vertexInput: G2VertexInput? = null, +) { +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2ShaderSet.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2ShaderSet.kt new file mode 100644 index 0000000..282c97e --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2ShaderSet.kt @@ -0,0 +1,7 @@ +package team.exception.sakura.graphics.geek2 + +data class G2ShaderSet( + var vertexShader: G2Shader? = null, + var fragmentShader: G2Shader? = null, + var geometryShader: G2Shader? = null, +) \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2VertexInput.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2VertexInput.kt new file mode 100644 index 0000000..d2b58ce --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2VertexInput.kt @@ -0,0 +1,23 @@ +package team.exception.sakura.graphics.geek2 + +abstract class G2VertexInput { + + abstract fun int(index: Int) + + abstract fun float(index: Int) + + abstract fun vec2(index: Int) + + abstract fun vec3(index: Int) + + abstract fun vec4(index: Int) + + abstract fun mat2(index: Int) + + abstract fun mat3(index: Int) + + abstract fun mat4(index: Int) + + abstract fun sampler2D(index: Int) + +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlBuffer.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlBuffer.kt index ef835e8..df7e3df 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlBuffer.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlBuffer.kt @@ -2,7 +2,7 @@ package team.exception.sakura.graphics.gl import com.mojang.blaze3d.opengl.GlStateManager import org.lwjgl.opengl.GL41.* -import team.exception.sakura.graphics.buffer.G2Buffer +import team.exception.sakura.graphics.geek2.G2Buffer import java.nio.ByteBuffer class GlBuffer( diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt index d608423..19edef4 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt @@ -1,8 +1,8 @@ package team.exception.sakura.graphics.gl -import team.exception.sakura.graphics.buffer.G2CommandList -import team.exception.sakura.graphics.buffer.G2GraphicsPipeline -import team.exception.sakura.graphics.buffer.G2RenderingInfo +import team.exception.sakura.graphics.geek2.G2CommandList +import team.exception.sakura.graphics.geek2.G2GraphicsPipeline +import team.exception.sakura.graphics.geek2.G2RenderingInfo import org.lwjgl.opengl.GL41.* import team.exception.sakura.graphics.gl.GlGraphicsPipeline.Companion.toGlPrimitive import java.util.Stack diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlDevice.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlDevice.kt index e3b4f8a..d13bdb3 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlDevice.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlDevice.kt @@ -1,7 +1,7 @@ package team.exception.sakura.graphics.gl -import team.exception.sakura.graphics.buffer.G2Buffer -import team.exception.sakura.graphics.buffer.G2Device +import team.exception.sakura.graphics.geek2.G2Buffer +import team.exception.sakura.graphics.geek2.G2Device class GlDevice: G2Device() { diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlFrameBufferManager.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlFrameBufferManager.kt new file mode 100644 index 0000000..a7aa5a1 --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlFrameBufferManager.kt @@ -0,0 +1,115 @@ +package team.exception.sakura.graphics.gl + +import com.mojang.blaze3d.opengl.GlStateManager +import com.mojang.blaze3d.opengl.GlTexture +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.opengl.GlDevice as MojGlDevice +import net.minecraft.client.Minecraft +import team.exception.sakura.graphics.G2RenderSystem +import org.lwjgl.opengl.GL41.* +import team.exception.sakura.graphics.geek2.G2RenderingInfo + + +object GlFrameBufferManager { + + val mcFboId = (Minecraft.getInstance().mainRenderTarget.colorTexture as GlTexture) + .getFbo((RenderSystem.getDevice() as MojGlDevice).directStateAccess(), + Minecraft.getInstance().mainRenderTarget.depthTexture) + + // FrameBuffer -> OpenGl FBO ID + private val frameBuffers = mutableMapOf() + + /** + * Get a FrameBuffer by attachments. + * If attachments are null, return the Minecraft FrameBuffer. + * @return OpenGl FBO ID + */ + fun getFrameBufferByAttachments( + colorAttachment: GlImageView?, + depthAttachment: GlImageView?, + ): Int { + if (colorAttachment == null || depthAttachment == null) { + return mcFboId + } + val frameBuffer = FrameBuffer(colorAttachment, depthAttachment) + return frameBuffers.getOrPut(frameBuffer) { + val fboId = createFrameBuffer(colorAttachment, depthAttachment) + frameBuffers[frameBuffer] = fboId + fboId + } + } + + fun getFrameBufferByAttachments( + colorAttachment: G2RenderingInfo.Attachment?, + depthAttachment: G2RenderingInfo.Attachment?, + ): Int = getFrameBufferByAttachments( + colorAttachment?.image as GlImageView?, + depthAttachment?.image as GlImageView?, + ) + + /** + * Create a FrameBuffer with attachments. + * @param colorAttachment the color attachment of the FrameBuffer, null if not needed + * @param depthAttachment the depth attachment of the FrameBuffer, null if not needed + * @throws IllegalStateException if FrameBuffer creation failed + * @return OpenGl FBO ID + */ + private fun createFrameBuffer( + colorAttachment: GlImageView?, + depthAttachment: GlImageView?, + ): Int { + + val device = G2RenderSystem.device as GlDevice + + val fboId = glGenFramebuffers() + val cmdList = device.getTempCommandList() + + cmdList.add { + val prevFboId = glGetInteger(GL_FRAMEBUFFER_BINDING) + GlStateManager._glBindFramebuffer(GL_FRAMEBUFFER, fboId) + colorAttachment?.let { + glBindTexture(GL_TEXTURE_2D, it.image.glId) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, it.image.glId, 0) + } + depthAttachment?.let { + glBindTexture(GL_TEXTURE_2D, it.image.glId) + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, it.image.glId, 0) + } + val status = glCheckFramebufferStatus(GL_FRAMEBUFFER) + if (status != GL_FRAMEBUFFER_COMPLETE) { + throw IllegalStateException("FrameBuffer creation failed: $status") + } + GlStateManager._glBindFramebuffer(GL_FRAMEBUFFER, prevFboId) + } + cmdList.summitAndClear() + + return fboId + + } + + class FrameBuffer( + val colorImage: GlImageView? = null, + val depthImage: GlImageView? = null, + ) { + override fun hashCode(): Int { + val colorHash = colorImage?.image?.glId ?: 0 + val depthHash = depthImage?.image?.glId ?: 0 + return colorHash + depthHash + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as FrameBuffer + + if (colorImage?.image?.glId != other.colorImage?.image?.glId) return false + if (depthImage?.image?.glId != other.depthImage?.image?.glId) return false + + return true + } + } + +} diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlGraphicsPipeline.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlGraphicsPipeline.kt index da89764..1da024f 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlGraphicsPipeline.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlGraphicsPipeline.kt @@ -1,8 +1,8 @@ package team.exception.sakura.graphics.gl import org.lwjgl.opengl.GL41.* -import team.exception.sakura.graphics.buffer.G2GraphicsPipeline -import team.exception.sakura.graphics.buffer.G2ShaderSet +import team.exception.sakura.graphics.geek2.G2GraphicsPipeline +import team.exception.sakura.graphics.geek2.G2ShaderSet class GlGraphicsPipeline( primitive: Primitive, diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlImage.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlImage.kt new file mode 100644 index 0000000..57e4f7a --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlImage.kt @@ -0,0 +1,9 @@ +package team.exception.sakura.graphics.gl + +import team.exception.sakura.graphics.geek2.G2Image + +class GlImage: G2Image() { + + val glId: Int = 0 + +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlImageView.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlImageView.kt new file mode 100644 index 0000000..4e161e1 --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlImageView.kt @@ -0,0 +1,8 @@ +package team.exception.sakura.graphics.gl + +import team.exception.sakura.graphics.geek2.G2ImageView + +class GlImageView( + override val image: GlImage +): G2ImageView(image) { +} \ No newline at end of file From 71f7617ced0c5de48a640e79494967c48ea1365b Mon Sep 17 00:00:00 2001 From: Chen Meng Date: Sun, 2 Nov 2025 12:01:43 +0800 Subject: [PATCH 3/6] XD --- .../sakura/graphics/G2RenderSystem.kt | 26 ++++ .../sakura/graphics/geek2/G2Buffer.kt | 2 +- .../sakura/graphics/geek2/G2CommandList.kt | 10 ++ .../sakura/graphics/geek2/G2Device.kt | 17 ++- .../sakura/graphics/geek2/G2RingBuffer.kt | 127 ++++++++++++++---- .../sakura/graphics/geek2/G2Shader.kt | 28 +++- .../sakura/graphics/geek2/G2ShaderSet.kt | 9 +- .../exception/sakura/graphics/gl/GlBuffer.kt | 23 ++-- .../sakura/graphics/gl/GlCommandList.kt | 11 ++ .../exception/sakura/graphics/gl/GlDevice.kt | 15 ++- .../graphics/gl/GlFrameBufferManager.kt | 4 +- .../exception/sakura/graphics/gl/GlShader.kt | 67 +++++++++ .../sakura/utils/extension/ByteBufferUtils.kt | 13 ++ .../sakura/utils/extension/StringUtils.kt | 7 + 14 files changed, 310 insertions(+), 49 deletions(-) create mode 100644 src/main/kotlin/team/exception/sakura/graphics/gl/GlShader.kt create mode 100644 src/main/kotlin/team/exception/sakura/utils/extension/ByteBufferUtils.kt create mode 100644 src/main/kotlin/team/exception/sakura/utils/extension/StringUtils.kt diff --git a/src/main/kotlin/team/exception/sakura/graphics/G2RenderSystem.kt b/src/main/kotlin/team/exception/sakura/graphics/G2RenderSystem.kt index d803090..40c2d84 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/G2RenderSystem.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/G2RenderSystem.kt @@ -1,5 +1,6 @@ package team.exception.sakura.graphics +import org.lwjgl.opengl.GL41.* import team.exception.sakura.graphics.geek2.G2Device import team.exception.sakura.graphics.gl.GlDevice @@ -7,6 +8,23 @@ object G2RenderSystem { val backend: Backends = Backends.OPENGL + val gpuType: GpuTypes = pickGpuType() + + private fun pickGpuType(): GpuTypes { + when (backend) { + Backends.OPENGL -> { + val glVendor = glGetString(GL_VENDOR) ?: return GpuTypes.OTHER + return when { + glVendor.contains("Intel") -> GpuTypes.INTEL + glVendor.contains("AMD") -> GpuTypes.AMD + glVendor.contains("NVIDIA") -> GpuTypes.NVIDIA + glVendor.contains("Apple") -> GpuTypes.APPLE + else -> GpuTypes.OTHER + } + } + } + } + val device: G2Device = when (backend) { Backends.OPENGL -> GlDevice() } @@ -15,4 +33,12 @@ object G2RenderSystem { OPENGL, } + enum class GpuTypes { + INTEL, + AMD, + NVIDIA, + APPLE, + OTHER, + } + } \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Buffer.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Buffer.kt index 940f968..93a9f2d 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Buffer.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Buffer.kt @@ -18,7 +18,7 @@ abstract class G2Buffer( * Refresh modified data in the buffer. * @throws IllegalStateException if the buffer hasn't been mapped. */ - abstract fun refresh() + abstract fun refresh(modifiedRange: LongRange) /** * Remap the buffer. diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2CommandList.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2CommandList.kt index 3586aef..ed5f05a 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2CommandList.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2CommandList.kt @@ -42,4 +42,14 @@ abstract class G2CommandList { */ abstract fun summitAndClear() + /** + * Destroy the command list + */ + abstract fun destroy() + + /** + * Summit and destroy the command list + */ + abstract fun summitAndDestroy() + } \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Device.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Device.kt index f7c239d..5f3f61f 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Device.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Device.kt @@ -1,14 +1,27 @@ package team.exception.sakura.graphics.geek2 +import java.nio.ByteBuffer + abstract class G2Device { + /** + * Create a new command list. + * + * Note: You should destroy the command list after use. + * @return A new command list. + */ abstract fun createCommandList(): G2CommandList - abstract fun getTempCommandList(): G2CommandList - abstract fun createBuffer( size: Long, access: G2Buffer.Access = G2Buffer.Access.READ_WRITE ): G2Buffer + abstract fun createShader( + source: ByteBuffer, + sourceType: G2Shader.SourceType, + shaderType: G2Shader.ShaderType, + entryPoint: String + ): G2Shader + } \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2RingBuffer.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2RingBuffer.kt index d84baf1..36531c4 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2RingBuffer.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2RingBuffer.kt @@ -2,41 +2,120 @@ package team.exception.sakura.graphics.geek2 import java.nio.ByteBuffer +/** + * A GPU-backed ring buffer implementation built on top of {@link G2Buffer}. + *

+ * The ring buffer provides a continuously mapped memory region that supports + * sequential writes with automatic wrapping when the end of the buffer is reached. + * This is typically used for streaming data such as dynamic vertex or uniform buffers. + *

+ * + *

Note: This implementation does not perform GPU/CPU synchronization (no fences). + * It assumes that overwriting old data is safe when the user reuses the buffer.

+ */ class G2RingBuffer( - device: G2Device, - val size: Long, -) { + override val device: G2Device, + val capacity: Long +) : G2Buffer(device, capacity) { - private val buffer = device.createBuffer(size) - private var offset = 0L + private val buffer = device.createBuffer(capacity) + private var head = 0L + private var tail = 0L + private var used = 0L + + private val mapped: ByteBuffer by lazy { + buffer.getMappedBuffer() + } /** - * Put data into the buffer. - * @param size of the data to be put. - * @param invoke the function if there is enough space in the buffer. - * @throws IllegalArgumentException if the size is too large. + * Allocates a continuous region of the ring buffer and provides access to it. + *

+ * If the remaining space from the current head to the end of the buffer is + * insufficient, the head wraps back to the beginning. + *

+ * + * @param size The number of bytes to allocate. + * @param func A callback that receives a {@link ByteBuffer} view of the allocated region + * and the byte offset of the start of that region. + * @throws IllegalArgumentException if {@code size} exceeds the total capacity. */ - fun alloc(size: Long, func: (ByteBuffer) -> Unit) { - // Check if the size is too large. - if (size > this.size) throw IllegalArgumentException("size is too large") - - // Check if there is enough space in the buffer. - val end = (offset + size) % size - if (end < offset) { - offset = 0 + fun use(size: Long, func: (ByteBuffer, offset: Long) -> Unit) { + require(size <= capacity) { "Requested size ($size) exceeds buffer capacity ($capacity)" } + + // Wrap around if there is not enough remaining space + if (remaining() < size) { + head = 0 + used = tail } - func(buffer.getMappedBuffer().apply { - position(offset.toInt()) - }) + val currentOffset = head + val bufferView = mapped.duplicate().apply { + position(currentOffset.toInt()) + limit((currentOffset + size).toInt()) + } + + func(bufferView, currentOffset) + + head = (head + size) % capacity + used += size } /** - * Release the buffer. + * Returns the remaining free space before wrapping occurs. + * + * @return The number of free bytes in the ring buffer. */ - fun destroy() { - buffer.destroy() + private fun remaining(): Long { + return if (head >= tail) { + capacity - (head - tail) + } else { + tail - head + } + } + + /** + * Flushes (synchronizes) a specified range of the buffer to the GPU. + * + * @param modifiedRange The byte range that has been modified. + * @throws IllegalStateException if the buffer has not been mapped. + */ + override fun refresh(modifiedRange: LongRange) { + buffer.refresh(modifiedRange) + } + + /** + * Flushes the last written region to the GPU. + * + * @param size The size of the most recently written region. + */ + fun refreshLast(size: Long) { + val start = (head - size + capacity) % capacity + refresh(start until start + size) } + /** + * Remaps the buffer memory. + *

+ * This can be used after a device reset or when the underlying + * buffer has been reallocated. + *

+ */ + override fun remap() { + buffer.remap() + } -} \ No newline at end of file + /** + * Returns the mapped {@link ByteBuffer} for direct access. + * + * @return The mapped buffer. + * @throws IllegalStateException if the buffer has not been mapped. + */ + override fun getMappedBuffer(): ByteBuffer = mapped + + /** + * Destroys the underlying buffer and releases its resources. + */ + override fun destroy() { + buffer.destroy() + } +} diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Shader.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Shader.kt index cee98b0..b60b09c 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Shader.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Shader.kt @@ -1,8 +1,28 @@ package team.exception.sakura.graphics.geek2 -class G2Shader( - val source: String, - val entryPoint: String, - val vertexInput: G2VertexInput? = null, +import java.nio.ByteBuffer + +/** + * Warn: This class can only be created by G2Device. + */ +abstract class G2Shader( + open val device: G2Device, + val source: ByteBuffer, + val sourceType: SourceType, + val shaderType: ShaderType, + val entryPoint: String = "main", ) { + + abstract fun compile() + + enum class SourceType { + SPIR_V, + GLSL, + } + + enum class ShaderType { + VERTEX, + FRAGMENT, + } + } \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2ShaderSet.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2ShaderSet.kt index 282c97e..d070bd8 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2ShaderSet.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2ShaderSet.kt @@ -1,7 +1,8 @@ package team.exception.sakura.graphics.geek2 data class G2ShaderSet( - var vertexShader: G2Shader? = null, - var fragmentShader: G2Shader? = null, - var geometryShader: G2Shader? = null, -) \ No newline at end of file + val shaders: List, + val vertexInput: G2VertexInput? = null, +) { + +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlBuffer.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlBuffer.kt index df7e3df..232c4ff 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlBuffer.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlBuffer.kt @@ -16,7 +16,7 @@ class GlBuffer( init { - val cmdList = device.getTempCommandList() + val cmdList = device.createCommandList() cmdList.add { GlStateManager._glBindBuffer(GL_ARRAY_BUFFER, id) @@ -25,7 +25,7 @@ class GlBuffer( mappedBuf = glMapBufferRange(GL_ARRAY_BUFFER, 0, size, getGlByG2Access(access)) } - cmdList.summitAndClear() + cmdList.summitAndDestroy() } @@ -36,12 +36,19 @@ class GlBuffer( return mappedBuf!! } - override fun refresh() { - // TODO: Refresh modified data + override fun refresh(modifiedRange: LongRange) { + val cmdList = device.createCommandList() + + cmdList.add { + GlStateManager._glBindBuffer(GL_ARRAY_BUFFER, id) + glFlushMappedBufferRange(GL_ARRAY_BUFFER, modifiedRange.first, + modifiedRange.last - modifiedRange.first) + } + cmdList.summitAndDestroy() } override fun remap() { - val cmdList = device.getTempCommandList() + val cmdList = device.createCommandList() cmdList.add { GlStateManager._glBindBuffer(GL_ARRAY_BUFFER, id) @@ -52,11 +59,11 @@ class GlBuffer( mappedBuf = glMapBufferRange(GL_ARRAY_BUFFER, 0, size, getGlByG2Access(access)) } - cmdList.summitAndClear() + cmdList.summitAndDestroy() } override fun destroy() { - val cmdList = device.getTempCommandList() + val cmdList = device.createCommandList() cmdList.add { GlStateManager._glBindBuffer(GL_ARRAY_BUFFER, id) @@ -64,7 +71,7 @@ class GlBuffer( mappedBuf = null glDeleteBuffers(id) } - cmdList.summitAndClear() + cmdList.summitAndDestroy() } companion object { diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt index 19edef4..06e028e 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt @@ -71,6 +71,17 @@ class GlCommandList: G2CommandList() { clear() } + override fun destroy() { + if (commands.isNotEmpty()) { + commands.clear() + } + } + + override fun summitAndDestroy() { + summit() + destroy() + } + class GlCommand(val func: () -> Unit) } \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlDevice.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlDevice.kt index d13bdb3..5b60b0b 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlDevice.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlDevice.kt @@ -2,18 +2,25 @@ package team.exception.sakura.graphics.gl import team.exception.sakura.graphics.geek2.G2Buffer import team.exception.sakura.graphics.geek2.G2Device +import team.exception.sakura.graphics.geek2.G2Shader +import java.nio.ByteBuffer class GlDevice: G2Device() { - private val tmpCommandList = createCommandList() - override fun createCommandList(): GlCommandList = GlCommandList() - override fun getTempCommandList(): GlCommandList = tmpCommandList - override fun createBuffer( size: Long, access: G2Buffer.Access ): G2Buffer = GlBuffer(this, size, access) + override fun createShader( + source: ByteBuffer, + sourceType: G2Shader.SourceType, + shaderType: G2Shader.ShaderType, + entryPoint: String + ): G2Shader = GlShader(this, source, sourceType, shaderType, entryPoint).apply { + compile() + } + } \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlFrameBufferManager.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlFrameBufferManager.kt index a7aa5a1..4ebe847 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlFrameBufferManager.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlFrameBufferManager.kt @@ -62,7 +62,7 @@ object GlFrameBufferManager { val device = G2RenderSystem.device as GlDevice val fboId = glGenFramebuffers() - val cmdList = device.getTempCommandList() + val cmdList = device.createCommandList() cmdList.add { val prevFboId = glGetInteger(GL_FRAMEBUFFER_BINDING) @@ -83,7 +83,7 @@ object GlFrameBufferManager { } GlStateManager._glBindFramebuffer(GL_FRAMEBUFFER, prevFboId) } - cmdList.summitAndClear() + cmdList.summitAndDestroy() return fboId diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlShader.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlShader.kt new file mode 100644 index 0000000..5e82b4b --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlShader.kt @@ -0,0 +1,67 @@ +package team.exception.sakura.graphics.gl + +import team.exception.sakura.graphics.geek2.G2Shader +import org.lwjgl.opengl.GL41.* +import org.lwjgl.opengl.GL46.GL_SHADER_BINARY_FORMAT_SPIR_V +import org.lwjgl.opengl.GL46.glSpecializeShader +import team.exception.sakura.graphics.G2RenderSystem +import team.exception.sakura.utils.extension.ByteBufferUtils.readAsString +import team.exception.sakura.utils.extension.StringUtils.asCharSequence +import java.nio.ByteBuffer + +/** + * SPIR-V is not supported in OpenGL 4.1 (macOS) + */ +class GlShader( + override val device: GlDevice, + source: ByteBuffer, + sourceType: SourceType, + shaderType: ShaderType, + entryPoint: String = "main", +): G2Shader(device, source, sourceType, shaderType, entryPoint) { + + init { + if (sourceType == SourceType.SPIR_V && + G2RenderSystem.gpuType == G2RenderSystem.GpuTypes.APPLE) { + throw Exception("SPIR-V is not supported in OpenGL 4.1 (macOS)") + } + } + + private val shaderId: Int = glCreateShader(shaderType.toGlShaderType()) + + override fun compile() { + val cmdList = device.createCommandList() + + cmdList.add { + when (sourceType) { + SourceType.SPIR_V -> { + glShaderBinary( + intArrayOf(shaderId), + GL_SHADER_BINARY_FORMAT_SPIR_V, + source + ) + glSpecializeShader( + shaderId, entryPoint.asCharSequence(), + null as IntArray?, null as IntArray? + ) + } + SourceType.GLSL -> glShaderSource(shaderId, source.readAsString()) + } + glCompileShader(shaderId) + } + cmdList.summitAndDestroy() + + val compileStatus = glGetShaderi(shaderId, GL_COMPILE_STATUS) + if (compileStatus == GL_FALSE) { + val infoLog = glGetShaderInfoLog(shaderId) + throw Exception("Shader compilation failed: $infoLog") + } + } + + companion object { + fun ShaderType.toGlShaderType() = when (this) { + ShaderType.VERTEX -> GL_VERTEX_SHADER + ShaderType.FRAGMENT -> GL_FRAGMENT_SHADER + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/utils/extension/ByteBufferUtils.kt b/src/main/kotlin/team/exception/sakura/utils/extension/ByteBufferUtils.kt new file mode 100644 index 0000000..1136e2c --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/utils/extension/ByteBufferUtils.kt @@ -0,0 +1,13 @@ +package team.exception.sakura.utils.extension + +import java.nio.ByteBuffer + +object ByteBufferUtils { + + fun ByteBuffer.readAsString(): String { + val bytes = ByteArray(remaining()) + get(bytes) + return String(bytes) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/utils/extension/StringUtils.kt b/src/main/kotlin/team/exception/sakura/utils/extension/StringUtils.kt new file mode 100644 index 0000000..6495edf --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/utils/extension/StringUtils.kt @@ -0,0 +1,7 @@ +package team.exception.sakura.utils.extension + +object StringUtils { + + fun String.asCharSequence(): CharSequence = this + +} \ No newline at end of file From 952978c3cdff786045b45cb1afcaa153d5e332d6 Mon Sep 17 00:00:00 2001 From: Chen Meng Date: Sun, 2 Nov 2025 13:44:30 +0800 Subject: [PATCH 4/6] Maybe finished --- .../kotlin/team/exception/sakura/Sakura.kt | 3 + .../sakura/graphics/geek2/G2Device.kt | 2 + .../graphics/geek2/G2GraphicsPipeline.kt | 81 +++++++++++++++- .../sakura/graphics/geek2/G2Shader.kt | 3 +- .../sakura/graphics/geek2/G2ShaderSet.kt | 11 ++- .../sakura/graphics/geek2/G2VertexInput.kt | 2 +- .../sakura/graphics/gl/GlCommandList.kt | 7 +- .../exception/sakura/graphics/gl/GlDevice.kt | 9 +- .../graphics/gl/GlFrameBufferManager.kt | 8 +- .../sakura/graphics/gl/GlGraphicsPipeline.kt | 97 +++++++++++++++++-- .../sakura/graphics/gl/GlImageView.kt | 3 +- .../exception/sakura/graphics/gl/GlShader.kt | 10 +- .../sakura/graphics/gl/GlShaderSet.kt | 29 ++++++ .../sakura/graphics/gl/GlVertexInput.kt | 86 ++++++++++++++++ 14 files changed, 326 insertions(+), 25 deletions(-) create mode 100644 src/main/kotlin/team/exception/sakura/graphics/gl/GlShaderSet.kt create mode 100644 src/main/kotlin/team/exception/sakura/graphics/gl/GlVertexInput.kt diff --git a/src/main/kotlin/team/exception/sakura/Sakura.kt b/src/main/kotlin/team/exception/sakura/Sakura.kt index 9311ff5..88ad119 100644 --- a/src/main/kotlin/team/exception/sakura/Sakura.kt +++ b/src/main/kotlin/team/exception/sakura/Sakura.kt @@ -33,4 +33,7 @@ object Sakura { LOGGER.info("Toggled module ${event.module.name}" + if (event.enabled) " ON" else " OFF") } + @SubscribeEvent + fun onRenderSystemStart(event: ) + } \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Device.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Device.kt index 5f3f61f..5115bd6 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Device.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Device.kt @@ -24,4 +24,6 @@ abstract class G2Device { entryPoint: String ): G2Shader + abstract fun createShaderSet(shaders: List): G2ShaderSet + } \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2GraphicsPipeline.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2GraphicsPipeline.kt index 044035b..c429de6 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2GraphicsPipeline.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2GraphicsPipeline.kt @@ -2,9 +2,28 @@ package team.exception.sakura.graphics.geek2 abstract class G2GraphicsPipeline( val primitive: Primitive, - val shaderSet: G2ShaderSet + open val shaderSet: G2ShaderSet, + val pipelineStates: PipelineStates, + val vertexInput: G2VertexInput? = null, ) { + data class PipelineStates( + var depthTest: Boolean = false, + var depthWrite: Boolean = true, + var depthFunc: DepthFunc = DepthFunc.LESS, + var cullEnable: Boolean = false, + var cullMode: CullMode = CullMode.BACK, + var frontFace: FrontFace = FrontFace.COUNTER_CLOCKWISE, + var fillMode: FillMode = FillMode.FILL, + var blendEnable: Boolean = false, + var blendEquation: BlendEquation = BlendEquation.ADD, + var srcColorBlend: BlendFunc = BlendFunc.SRC_ALPHA, + var dstColorBlend: BlendFunc = BlendFunc.ONE_MINUS_SRC_ALPHA, + var srcAlphaBlend: BlendFunc = BlendFunc.ONE, + var dstAlphaBlend: BlendFunc = BlendFunc.ZERO, + var colorWriteMask: ColorMask = ColorMask.ALL + ) + enum class Primitive { TRIANGLES, TRIANGLE_FAN, @@ -14,4 +33,62 @@ abstract class G2GraphicsPipeline( POINTS } -} \ No newline at end of file + enum class CullMode { + NONE, + FRONT, + BACK, + FRONT_AND_BACK + } + + enum class FillMode { + FILL, + LINE, + POINT + } + + enum class FrontFace { + CLOCKWISE, + COUNTER_CLOCKWISE + } + + enum class DepthFunc { + NEVER, + LESS, + EQUAL, + LEQUAL, + GREATER, + NOTEQUAL, + GEQUAL, + ALWAYS + } + + enum class BlendEquation { + ADD, + SUBTRACT, + REVERSE_SUBTRACT, + MIN, + MAX + } + + enum class BlendFunc { + ZERO, + ONE, + SRC_COLOR, + ONE_MINUS_SRC_COLOR, + DST_COLOR, + ONE_MINUS_DST_COLOR, + SRC_ALPHA, + ONE_MINUS_SRC_ALPHA, + DST_ALPHA, + ONE_MINUS_DST_ALPHA, + } + + enum class ColorMask { + NONE, + RED, + GREEN, + BLUE, + ALPHA, + ALL + } +} diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Shader.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Shader.kt index b60b09c..4c6616d 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Shader.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2Shader.kt @@ -9,12 +9,13 @@ abstract class G2Shader( open val device: G2Device, val source: ByteBuffer, val sourceType: SourceType, - val shaderType: ShaderType, val entryPoint: String = "main", ) { abstract fun compile() + abstract fun destroy() + enum class SourceType { SPIR_V, GLSL, diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2ShaderSet.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2ShaderSet.kt index d070bd8..2d24403 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2ShaderSet.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2ShaderSet.kt @@ -1,8 +1,13 @@ package team.exception.sakura.graphics.geek2 -data class G2ShaderSet( - val shaders: List, - val vertexInput: G2VertexInput? = null, +/** + * Note: This class can only be created by G2Device. + */ +abstract class G2ShaderSet( + open val device: G2Device, + open val shaders: List, ) { + abstract fun attachShaders() + } \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2VertexInput.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2VertexInput.kt index d2b58ce..765676f 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2VertexInput.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2VertexInput.kt @@ -18,6 +18,6 @@ abstract class G2VertexInput { abstract fun mat4(index: Int) - abstract fun sampler2D(index: Int) + abstract fun destroy() } \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt index 06e028e..fbecfc8 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt @@ -4,7 +4,7 @@ import team.exception.sakura.graphics.geek2.G2CommandList import team.exception.sakura.graphics.geek2.G2GraphicsPipeline import team.exception.sakura.graphics.geek2.G2RenderingInfo import org.lwjgl.opengl.GL41.* -import team.exception.sakura.graphics.gl.GlGraphicsPipeline.Companion.toGlPrimitive +import team.exception.sakura.graphics.gl.GlGraphicsPipeline.Companion.toGL import java.util.Stack class GlCommandList: G2CommandList() { @@ -19,6 +19,7 @@ class GlCommandList: G2CommandList() { override fun bindGraphicsPipeline(pipeline: G2GraphicsPipeline) { graphicsPipeline = pipeline as GlGraphicsPipeline + graphicsPipeline?.bind() } override fun draw( @@ -29,7 +30,7 @@ class GlCommandList: G2CommandList() { ) { graphicsPipeline?.let { pipeline -> add { glDrawArrays( - pipeline.primitive.toGlPrimitive(), + pipeline.primitive.toGL(), firstVertex, vertexCount ) } } @@ -44,7 +45,7 @@ class GlCommandList: G2CommandList() { ) { graphicsPipeline?.let { pipeline -> add { glDrawElements( - pipeline.primitive.toGlPrimitive(), + pipeline.primitive.toGL(), indexCount, GL_UNSIGNED_INT, (firstIndex * 4).toLong() ) } } diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlDevice.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlDevice.kt index 5b60b0b..8513820 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlDevice.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlDevice.kt @@ -3,6 +3,7 @@ package team.exception.sakura.graphics.gl import team.exception.sakura.graphics.geek2.G2Buffer import team.exception.sakura.graphics.geek2.G2Device import team.exception.sakura.graphics.geek2.G2Shader +import team.exception.sakura.graphics.geek2.G2ShaderSet import java.nio.ByteBuffer class GlDevice: G2Device() { @@ -12,15 +13,19 @@ class GlDevice: G2Device() { override fun createBuffer( size: Long, access: G2Buffer.Access - ): G2Buffer = GlBuffer(this, size, access) + ): GlBuffer = GlBuffer(this, size, access) override fun createShader( source: ByteBuffer, sourceType: G2Shader.SourceType, shaderType: G2Shader.ShaderType, entryPoint: String - ): G2Shader = GlShader(this, source, sourceType, shaderType, entryPoint).apply { + ): GlShader = GlShader(this, source, sourceType, shaderType, entryPoint).apply { compile() } + override fun createShaderSet(shaders: List): GlShaderSet = GlShaderSet( + this, shaders.map { it as GlShader } + ).apply { attachShaders() } + } \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlFrameBufferManager.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlFrameBufferManager.kt index 4ebe847..ea116da 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlFrameBufferManager.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlFrameBufferManager.kt @@ -64,6 +64,8 @@ object GlFrameBufferManager { val fboId = glGenFramebuffers() val cmdList = device.createCommandList() + var successFlag = false + cmdList.add { val prevFboId = glGetInteger(GL_FRAMEBUFFER_BINDING) GlStateManager._glBindFramebuffer(GL_FRAMEBUFFER, fboId) @@ -79,12 +81,16 @@ object GlFrameBufferManager { } val status = glCheckFramebufferStatus(GL_FRAMEBUFFER) if (status != GL_FRAMEBUFFER_COMPLETE) { - throw IllegalStateException("FrameBuffer creation failed: $status") + successFlag = true } GlStateManager._glBindFramebuffer(GL_FRAMEBUFFER, prevFboId) } cmdList.summitAndDestroy() + if (successFlag) { + throw IllegalStateException("FrameBuffer creation failed") + } + return fboId } diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlGraphicsPipeline.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlGraphicsPipeline.kt index 1da024f..33a1a1a 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlGraphicsPipeline.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlGraphicsPipeline.kt @@ -1,16 +1,53 @@ package team.exception.sakura.graphics.gl -import org.lwjgl.opengl.GL41.* +import com.mojang.blaze3d.opengl.GlStateManager +import org.lwjgl.opengl.GL11.* import team.exception.sakura.graphics.geek2.G2GraphicsPipeline -import team.exception.sakura.graphics.geek2.G2ShaderSet class GlGraphicsPipeline( primitive: Primitive, - shaderSet: G2ShaderSet -): G2GraphicsPipeline(primitive, shaderSet) { + override val shaderSet: GlShaderSet, + pipelineStates: PipelineStates, + vertexInput: GlVertexInput? = null, +) : G2GraphicsPipeline(primitive, shaderSet, pipelineStates, vertexInput) { + + fun bind() { + val states = pipelineStates + + if (states.depthTest) GlStateManager._enableDepthTest() else GlStateManager._disableDepthTest() + GlStateManager._depthMask(states.depthWrite) + GlStateManager._depthFunc(states.depthFunc.toGl()) + + if (states.cullEnable) { + GlStateManager._enableCull() + glCullFace(states.cullMode.toGl()) + } else GlStateManager._disableCull() + + glFrontFace(states.frontFace.toGl()) + GlStateManager._polygonMode(GL_FRONT_AND_BACK, states.fillMode.toGl()) + + if (states.blendEnable) { + GlStateManager._enableBlend() + GlStateManager._blendFuncSeparate( + states.srcColorBlend.toGl(), + states.dstColorBlend.toGl(), + states.srcAlphaBlend.toGl(), + states.dstAlphaBlend.toGl() + ) + } else GlStateManager._disableBlend() + + GlStateManager._colorMask( + states.colorWriteMask.red(), + states.colorWriteMask.green(), + states.colorWriteMask.blue(), + states.colorWriteMask.alpha() + ) + + GlStateManager._glUseProgram(shaderSet.programId) + } companion object { - fun Primitive.toGlPrimitive(): Int = when (this) { + fun Primitive.toGL(): Int = when (this) { Primitive.TRIANGLES -> GL_TRIANGLES Primitive.TRIANGLE_FAN -> GL_TRIANGLE_FAN Primitive.TRIANGLE_STRIP -> GL_TRIANGLE_STRIP @@ -18,6 +55,52 @@ class GlGraphicsPipeline( Primitive.LINE_STRIP -> GL_LINE_STRIP Primitive.POINTS -> GL_POINTS } - } -} \ No newline at end of file + fun DepthFunc.toGl() = when (this) { + DepthFunc.NEVER -> GL_NEVER + DepthFunc.LESS -> GL_LESS + DepthFunc.EQUAL -> GL_EQUAL + DepthFunc.LEQUAL -> GL_LEQUAL + DepthFunc.GREATER -> GL_GREATER + DepthFunc.NOTEQUAL -> GL_NOTEQUAL + DepthFunc.GEQUAL -> GL_GEQUAL + DepthFunc.ALWAYS -> GL_ALWAYS + } + + fun CullMode.toGl() = when (this) { + CullMode.FRONT -> GL_FRONT + CullMode.BACK -> GL_BACK + CullMode.FRONT_AND_BACK -> GL_FRONT_AND_BACK + CullMode.NONE -> 0 + } + + fun FrontFace.toGl() = when (this) { + FrontFace.CLOCKWISE -> GL_CW + FrontFace.COUNTER_CLOCKWISE -> GL_CCW + } + + fun FillMode.toGl() = when (this) { + FillMode.FILL -> GL_FILL + FillMode.LINE -> GL_LINE + FillMode.POINT -> GL_POINT + } + + fun BlendFunc.toGl() = when (this) { + BlendFunc.ZERO -> GL_ZERO + BlendFunc.ONE -> GL_ONE + BlendFunc.SRC_COLOR -> GL_SRC_COLOR + BlendFunc.ONE_MINUS_SRC_COLOR -> GL_ONE_MINUS_SRC_COLOR + BlendFunc.DST_COLOR -> GL_DST_COLOR + BlendFunc.ONE_MINUS_DST_COLOR -> GL_ONE_MINUS_DST_COLOR + BlendFunc.SRC_ALPHA -> GL_SRC_ALPHA + BlendFunc.ONE_MINUS_SRC_ALPHA -> GL_ONE_MINUS_SRC_ALPHA + BlendFunc.DST_ALPHA -> GL_DST_ALPHA + BlendFunc.ONE_MINUS_DST_ALPHA -> GL_ONE_MINUS_DST_ALPHA + } + + fun ColorMask.red() = this == ColorMask.RED || this == ColorMask.ALL + fun ColorMask.green() = this == ColorMask.GREEN || this == ColorMask.ALL + fun ColorMask.blue() = this == ColorMask.BLUE || this == ColorMask.ALL + fun ColorMask.alpha() = this == ColorMask.ALPHA || this == ColorMask.ALL + } +} diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlImageView.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlImageView.kt index 4e161e1..5ac00d1 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlImageView.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlImageView.kt @@ -4,5 +4,4 @@ import team.exception.sakura.graphics.geek2.G2ImageView class GlImageView( override val image: GlImage -): G2ImageView(image) { -} \ No newline at end of file +): G2ImageView(image) \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlShader.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlShader.kt index 5e82b4b..f4a25b4 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlShader.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlShader.kt @@ -18,7 +18,7 @@ class GlShader( sourceType: SourceType, shaderType: ShaderType, entryPoint: String = "main", -): G2Shader(device, source, sourceType, shaderType, entryPoint) { +): G2Shader(device, source, sourceType, entryPoint) { init { if (sourceType == SourceType.SPIR_V && @@ -27,7 +27,7 @@ class GlShader( } } - private val shaderId: Int = glCreateShader(shaderType.toGlShaderType()) + val shaderId: Int = glCreateShader(shaderType.toGl()) override fun compile() { val cmdList = device.createCommandList() @@ -58,8 +58,12 @@ class GlShader( } } + override fun destroy() { + glDeleteShader(shaderId) + } + companion object { - fun ShaderType.toGlShaderType() = when (this) { + fun ShaderType.toGl() = when (this) { ShaderType.VERTEX -> GL_VERTEX_SHADER ShaderType.FRAGMENT -> GL_FRAGMENT_SHADER } diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlShaderSet.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlShaderSet.kt new file mode 100644 index 0000000..3ca9958 --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlShaderSet.kt @@ -0,0 +1,29 @@ +package team.exception.sakura.graphics.gl + +import org.lwjgl.opengl.GL41.* +import team.exception.sakura.graphics.geek2.G2ShaderSet + +class GlShaderSet( + override val device: GlDevice, + override val shaders: List, +): G2ShaderSet(device, shaders) { + + val programId: Int = glCreateProgram() + + override fun attachShaders() { + val cmdList = device.createCommandList() + + cmdList.add { + shaders.forEach { shader -> + glAttachShader(programId, shader.shaderId) + } + glLinkProgram(programId) + } + cmdList.summitAndDestroy() + + if (glGetProgrami(programId, GL_LINK_STATUS) == 0) { + throw Exception("Error linking program: " + glGetProgramInfoLog(programId)) + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlVertexInput.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlVertexInput.kt new file mode 100644 index 0000000..9b3da42 --- /dev/null +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlVertexInput.kt @@ -0,0 +1,86 @@ +package team.exception.sakura.graphics.gl + +import org.lwjgl.opengl.GL33.* +import team.exception.sakura.graphics.geek2.G2VertexInput + +class GlVertexInput: G2VertexInput() { + + private val vaoId: Int = glGenVertexArrays() + + private var offset = 0L + + var stride: Int = 0 + + fun bind() { + glBindVertexArray(vaoId) + } + + fun unbind() { + glBindVertexArray(0) + } + + override fun int(index: Int) { + glEnableVertexAttribArray(index) + glVertexAttribIPointer(index, 1, GL_INT, stride, offset) + offset += Int.SIZE_BYTES + } + + override fun float(index: Int) { + glEnableVertexAttribArray(index) + glVertexAttribPointer(index, 1, GL_FLOAT, false, stride, offset) + offset += Float.SIZE_BYTES + } + + override fun vec2(index: Int) { + glEnableVertexAttribArray(index) + glVertexAttribPointer(index, 2, GL_FLOAT, false, stride, offset) + offset += 2 * Float.SIZE_BYTES + } + + override fun vec3(index: Int) { + glEnableVertexAttribArray(index) + glVertexAttribPointer(index, 3, GL_FLOAT, false, stride, offset) + offset += 3 * Float.SIZE_BYTES + } + + override fun vec4(index: Int) { + glEnableVertexAttribArray(index) + glVertexAttribPointer(index, 4, GL_FLOAT, false, stride, offset) + offset += 4 * Float.SIZE_BYTES + } + + override fun mat2(index: Int) { + for (i in 0 until 2) { + glEnableVertexAttribArray(index + i) + glVertexAttribPointer(index + i, 2, GL_FLOAT, false, stride, offset + i * 2 * Float.SIZE_BYTES) + glVertexAttribDivisor(index + i, 1) + } + offset += 4 * Float.SIZE_BYTES + } + + override fun mat3(index: Int) { + for (i in 0 until 3) { + glEnableVertexAttribArray(index + i) + glVertexAttribPointer(index + i, 3, GL_FLOAT, false, stride, offset + i * 3 * Float.SIZE_BYTES) + glVertexAttribDivisor(index + i, 1) + } + offset += 9 * Float.SIZE_BYTES + } + + /** + * Enables a mat4 attribute (4 columns of vec4). + * Each column is treated as a separate attribute. + */ + override fun mat4(index: Int) { + for (i in 0 until 4) { + glEnableVertexAttribArray(index + i) + glVertexAttribPointer(index + i, 4, GL_FLOAT, false, stride, offset + i * 4 * Float.SIZE_BYTES) + glVertexAttribDivisor(index + i, 1) + } + offset += 16 * Float.SIZE_BYTES + } + + override fun destroy() { + glDeleteVertexArrays(vaoId) + } +} From 99c0032d3db5e4d3fddb45674d33326d12cb1cd1 Mon Sep 17 00:00:00 2001 From: Chen Meng Date: Sun, 2 Nov 2025 13:45:56 +0800 Subject: [PATCH 5/6] removed some code --- src/main/kotlin/team/exception/sakura/Sakura.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/kotlin/team/exception/sakura/Sakura.kt b/src/main/kotlin/team/exception/sakura/Sakura.kt index 88ad119..9311ff5 100644 --- a/src/main/kotlin/team/exception/sakura/Sakura.kt +++ b/src/main/kotlin/team/exception/sakura/Sakura.kt @@ -33,7 +33,4 @@ object Sakura { LOGGER.info("Toggled module ${event.module.name}" + if (event.enabled) " ON" else " OFF") } - @SubscribeEvent - fun onRenderSystemStart(event: ) - } \ No newline at end of file From 85af799e0af3ce4438e2ba1dc5c8cf82224b3e70 Mon Sep 17 00:00:00 2001 From: Chen Meng Date: Sun, 2 Nov 2025 13:49:42 +0800 Subject: [PATCH 6/6] Rendering info binding --- .../exception/sakura/graphics/geek2/G2RenderingInfo.kt | 2 -- .../team/exception/sakura/graphics/gl/GlCommandList.kt | 10 ++++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2RenderingInfo.kt b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2RenderingInfo.kt index 10aa5d7..59a7a75 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/geek2/G2RenderingInfo.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/geek2/G2RenderingInfo.kt @@ -6,8 +6,6 @@ abstract class G2RenderingInfo { abstract val depthAttachment: Attachment? - abstract val stencilAttachment: Attachment? - abstract val width: Int abstract val height: Int diff --git a/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt b/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt index fbecfc8..d6195e6 100644 --- a/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt +++ b/src/main/kotlin/team/exception/sakura/graphics/gl/GlCommandList.kt @@ -53,10 +53,12 @@ class GlCommandList: G2CommandList() { override fun beginRendering(renderingInfo: G2RenderingInfo) { renderingInfoStack.push(renderingInfo) + refreshRenderingInfo(renderingInfo) } override fun endRendering() { renderingInfoStack.pop() + refreshRenderingInfo(renderingInfoStack.peek()) } override fun summit() { @@ -83,6 +85,14 @@ class GlCommandList: G2CommandList() { destroy() } + private fun refreshRenderingInfo(renderingInfo: G2RenderingInfo) { + val frameBuffer = GlFrameBufferManager.getFrameBufferByAttachments( + renderingInfo.colorAttachment, + renderingInfo.depthAttachment, + ) + glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer) + } + class GlCommand(val func: () -> Unit) } \ No newline at end of file