Немножечко низкоуровневых оптимизаций рендера

This commit is contained in:
DBotThePony 2023-02-21 13:43:49 +07:00
parent 2a7a62e6ed
commit 1f50315ed5
Signed by: DBot
GPG Key ID: DCC23B5715498507
3 changed files with 95 additions and 66 deletions
src/main/kotlin/ru/dbotthepony/kstarbound/client

View File

@ -200,54 +200,39 @@ class GLStateTracker(val locator: ISBFileLocator) {
var VBO: VertexBufferObject? = null
set(value) {
ensureSameThread()
if (field === value) return
isMe(value?.state)
field = value
if (value == null) {
glBindBuffer(GL_ARRAY_BUFFER, 0)
checkForGLError()
return
if (field !== value) {
isMe(value?.state)
require(value?.isArray != false) { "Provided buffer object is not of Array type" }
glBindBuffer(GL_ARRAY_BUFFER, value?.pointer ?: 0)
checkForGLError("Setting Vertex Buffer Object")
field = value
}
if (!value.isArray) throw IllegalArgumentException("Provided buffer object is not of Array type")
glBindBuffer(GL_ARRAY_BUFFER, value.pointer)
checkForGLError()
}
var EBO: VertexBufferObject? = null
set(value) {
ensureSameThread()
if (field === value) return
isMe(value?.state)
field = value
if (value == null) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
checkForGLError()
return
if (field !== value) {
isMe(value?.state)
require(value?.isElementArray != false) { "Provided buffer object is not of Array type" }
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, value?.pointer ?: 0)
checkForGLError("Setting Element Buffer Object")
field = value
}
if (!value.isElementArray) throw IllegalArgumentException("Provided buffer object is not of Array type")
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, value.pointer)
checkForGLError()
}
var VAO: VertexArrayObject? = null
set(value) {
ensureSameThread()
if (field === value) return
isMe(value?.state)
field = value
if (value == null) {
glBindVertexArray(0)
checkForGLError()
return
if (field !== value) {
isMe(value?.state)
glBindVertexArray(value?.pointer ?: 0)
checkForGLError("Setting Vertex Array Object")
field = value
}
glBindVertexArray(value.pointer)
checkForGLError()
}
var readFramebuffer: GLFrameBuffer? = null
@ -301,17 +286,28 @@ class GLStateTracker(val locator: ISBFileLocator) {
}
var program: GLShaderProgram? = null
private set
set(value) {
ensureSameThread()
if (value !== field) {
isMe(value?.state)
glUseProgram(value?.pointer ?: 0)
checkForGLError("Setting shader program")
field = value
}
}
var activeTexture = 0
set(value) {
ensureSameThread()
if (field == value) return
require(value >= 0) { "Invalid texture block $value" }
require(value < 80) { "Too big texture block index $value, OpenGL 4.6 guarantee only 80!" }
field = value
glActiveTexture(GL_TEXTURE0 + value)
checkForGLError()
if (field != value) {
require(value >= 0) { "Invalid texture block $value" }
require(value < 80) { "Too big texture block index $value, OpenGL 4.6 guarantee only 80!" }
glActiveTexture(GL_TEXTURE0 + value)
checkForGLError()
field = value
}
}
var texture2D: GLTexture2D? by TexturesTracker(80)
@ -439,18 +435,6 @@ class GLStateTracker(val locator: ISBFileLocator) {
return obj
}
fun use(obj: GLShaderProgram): GLShaderProgram {
ensureSameThread()
if (obj === program)
return obj
program = obj
glUseProgram(obj.pointer)
checkForGLError()
return obj
}
val shaderVertexTexture: TexturedProgram
val shaderVertexTextureColor: TexturedColoredProgram

View File

@ -57,7 +57,10 @@ open class GLShaderProgram(val state: GLStateTracker, shaders: Iterable<GLStateT
glGetError()
}
fun use() = state.use(this)
fun use(): GLShaderProgram {
state.program = this
return this
}
private val locations = Object2ObjectArrayMap<String, Uniform<*>>()
private val uniformsExist = Object2BooleanArrayMap<String>()
@ -129,35 +132,51 @@ open class GLShaderProgram(val state: GLStateTracker, shaders: Iterable<GLStateT
}
inner class F2Uniform(name: String) : Uniform<IStruct2f>(name) {
private var v0 = 0f
private var v1 = 0f
override var value: IStruct2f = Vector2f.ZERO
set(value) {
state.ensureSameThread()
if (field != value) {
glProgramUniform2f(pointer, location, value.component1(), value.component2())
val (v0, v1) = value
if (this.v0 != v0 || this.v1 != v1) {
glProgramUniform2f(pointer, location, v0, v1)
checkForGLError()
field = if (value is Vector2f) value else Vector2f(value)
this.v0 = v0
this.v1 = v1
}
}
}
inner class F3Uniform(name: String) : Uniform<IStruct3f>(name) {
private var v0 = 0f
private var v1 = 0f
private var v2 = 0f
override var value: IStruct3f = Vector3f.ZERO
set(value) {
state.ensureSameThread()
if (field != value) {
glProgramUniform3f(pointer, location, value.component1(), value.component2(), value.component3())
val (v0, v1, v2) = value
if (this.v0 != v0 || this.v1 != v1 || this.v2 != v2) {
glProgramUniform3f(pointer, location, v0, v1, v2)
checkForGLError()
field = if (value is Vector3f) value else Vector3f(value)
this.v0 = v0
this.v1 = v1
this.v2 = v2
}
}
}
private val buff3x3: FloatBuffer by lazy(LazyThreadSafetyMode.NONE) { ByteBuffer.allocateDirect(4 * 3 * 3).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer() }
private val buff4x4: FloatBuffer by lazy(LazyThreadSafetyMode.NONE) { ByteBuffer.allocateDirect(4 * 4 * 4).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer() }
private val buff3x3: FloatBuffer = ByteBuffer.allocateDirect(4 * 3 * 3).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer()
private val buff4x4: FloatBuffer = ByteBuffer.allocateDirect(4 * 4 * 4).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer()
inner class F3x3Uniform(name: String) : Uniform<IMatrix3f<*>>(name) {
override var value: IMatrix3f<*> = Matrix3f.ZERO
@ -177,32 +196,48 @@ open class GLShaderProgram(val state: GLStateTracker, shaders: Iterable<GLStateT
}
inner class F4x4Uniform(name: String) : Uniform<IMatrix4f<*>>(name) {
private val _value = ByteBuffer.allocate(4 * 4 * 4).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer()
override var value: IMatrix4f<*> = Matrix4f.ZERO
set(value) {
state.ensureSameThread()
if (field != value) {
buff4x4.position(0)
value.write(buff4x4)
buff4x4.position(0)
buff4x4.position(0)
value.write(buff4x4)
buff4x4.position(0)
_value.position(0)
if (buff4x4 != _value) {
glProgramUniformMatrix4fv(pointer, location, false, buff4x4)
checkForGLError()
buff4x4.position(0)
_value.put(buff4x4)
field = value.toMatrix4f()
}
}
}
inner class F4Uniform(name: String) : Uniform<IStruct4f>(name) {
private var v0 = 0f
private var v1 = 0f
private var v2 = 0f
private var v3 = 0f
override var value: IStruct4f = Vector4f.ZERO
set(value) {
state.ensureSameThread()
if (field != value) {
glProgramUniform4f(pointer, location, value.component1(), value.component2(), value.component3(), value.component4())
val (v0, v1, v2, v3) = value
if (this.v0 != v0 || this.v1 != v1 || this.v2 != v2 || this.v3 != v3) {
glProgramUniform4f(pointer, location, v0, v1, v2, v3)
checkForGLError()
field = if (value is Vector4f) value else Vector4f(value)
this.v0 = v0
this.v1 = v1
this.v2 = v2
this.v3 = v3
}
}
}

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.kstarbound.client.render
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.ints.Int2ObjectFunction
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import ru.dbotthepony.kvector.matrix.Matrix4fStack
/**
@ -9,6 +10,7 @@ import ru.dbotthepony.kvector.matrix.Matrix4fStack
*/
class LayeredRenderer {
private val layers = Int2ObjectAVLTreeMap<ArrayList<(Matrix4fStack) -> Unit>>()
private val layersHash = Int2ObjectOpenHashMap<ArrayList<(Matrix4fStack) -> Unit>>()
/**
* Сортировка [layer] происходит от дальнего (БОЛЬШЕ!) к ближнему (МЕНЬШЕ!)
@ -17,7 +19,15 @@ class LayeredRenderer {
* `8 -> 6 -> 4 -> 1 -> -4 -> -7`
*/
fun add(layer: Int, renderer: (Matrix4fStack) -> Unit) {
layers.computeIfAbsent(-layer, Int2ObjectFunction { ArrayList() }).add(renderer)
var list = layersHash[layer]
if (list == null) {
list = ArrayList()
layers[-layer] = list
layersHash[layer] = list
}
list.add(renderer)
}
fun render(stack: Matrix4fStack) {