Skip to content
This repository has been archived by the owner on Jul 8, 2022. It is now read-only.

Commit

Permalink
Do not use gl_FragColor on newer versions of GLSL (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
soywiz committed Mar 18, 2020
1 parent dfec3e3 commit 820d94b
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 72 deletions.
15 changes: 13 additions & 2 deletions korgw/src/commonMain/kotlin/com/soywiz/kgl/KmlGlUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,26 @@ private fun KmlGl.createShader(type: Int, source: String): Int {
}

// TODO: Release resources on failure
/*
fun KmlGl.createProgram(vertex: String, fragment: String): KmlGlProgram {
println("************************************************")
val program = createProgram()
val hasLayout0 = fragment.contains(GlslGenerator.LAYOUT_LOCATION_0)
val rfragment = when {
//hasLayout0 -> fragment.replace(GlslGenerator.LAYOUT_LOCATION_0, "")
else -> fragment
}
val shaderVertex = createShader(VERTEX_SHADER, vertex)
val shaderFragment = createShader(FRAGMENT_SHADER, fragment)
val shaderFragment = createShader(FRAGMENT_SHADER, rfragment)
attachShader(program, shaderVertex)
attachShader(program, shaderFragment)
linkProgramAndCheck(program)
if (hasLayout0) {
bindAttribLocation(program, 0, GlslGenerator.FRAGCOLOR)
}
linkProgramAndCheck(program)
return KmlGlProgram(this, program, shaderVertex, shaderFragment)
}
*/

class KmlGlVertexLayout(val program: KmlGlProgram) {
data class Element(val index: Int, val size: Int, val type: Int, val pointer: Int, val normalized: Boolean)
Expand Down
28 changes: 20 additions & 8 deletions korgw/src/commonMain/kotlin/com/soywiz/korag/OpenglAG.kt
Original file line number Diff line number Diff line change
Expand Up @@ -439,16 +439,28 @@ abstract class AGOpengl : AG() {

//println("GL_SHADING_LANGUAGE_VERSION: $glslVersionInt : $glslVersionString")

fragmentShaderId = createShader(
gl.FRAGMENT_SHADER,
program.fragment.toNewGlslString(gles = gles, version = glSlVersion ?: gl.versionInt)
)
vertexShaderId = createShader(
gl.VERTEX_SHADER,
program.vertex.toNewGlslString(gles = gles, version = glSlVersion ?: gl.versionInt)
)
val guessedGlSlVersion = glSlVersion ?: gl.versionInt
val usedGlSlVersion = GlslGenerator.FORCE_GLSL_VERSION?.toIntOrNull() ?: when (guessedGlSlVersion) {
460 -> 460
in 300..450 -> 100
else -> guessedGlSlVersion
}

if (GlslGenerator.DEBUG_GLSL) {
println("GLSL version: requested=$glSlVersion, guessed=$guessedGlSlVersion, forced=${GlslGenerator.FORCE_GLSL_VERSION}. used=$usedGlSlVersion")
}

val fragResult = program.fragment.toNewGlslStringResult(gles = gles, version = usedGlSlVersion)
val vertResult = program.vertex.toNewGlslStringResult(gles = gles, version = usedGlSlVersion)

fragmentShaderId = createShader(gl.FRAGMENT_SHADER, fragResult.result)
vertexShaderId = createShader(gl.VERTEX_SHADER, vertResult.result)
gl.attachShader(id, fragmentShaderId)
gl.attachShader(id, vertexShaderId)
if (fragResult.generator.newGlSlVersion) {
//println("****************************")
//gl.bindAttribLocation(id, 0, fragResult.generator.gl_FragColor)
}
gl.linkProgram(id)
tempBuffer1.setInt(0, 0)
gl.getProgramiv(id, gl.LINK_STATUS, tempBuffer1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package com.soywiz.korag.shader.gl

import com.soywiz.korag.shader.*

fun Shader.toNewGlslString(gles: Boolean = true, version: Int = 100) =
fun Shader.toNewGlslString(gles: Boolean = true, version: Int = GlslGenerator.DEFAULT_VERSION) =
GlslGenerator(this.type, gles, version).generate(this.stm)

fun Shader.toNewGlslStringResult(gles: Boolean = true, version: Int = GlslGenerator.DEFAULT_VERSION) =
GlslGenerator(this.type, gles, version).generateResult(this.stm)

fun VertexShader.toGlSlString(gles: Boolean = true) = GlslGenerator(ShaderType.VERTEX, gles).generate(this.stm)
fun FragmentShader.toGlSlString(gles: Boolean = true) = GlslGenerator(ShaderType.FRAGMENT, gles).generate(this.stm)
fun FragmentShader.toGlSlString(gles: Boolean = true) = GlslGenerator(ShaderType.FRAGMENT, gles).generate(this.stm)
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,31 @@ import com.soywiz.korag.shader.*
import com.soywiz.korio.lang.*
import com.soywiz.korio.util.*

class GlslGenerator(val kind: ShaderType, @Suppress("unused") val gles: Boolean = true, val version: Int = 100) :
Program.Visitor<String>("") {
private val temps = hashSetOf<Temp>()
private val attributes = hashSetOf<Attribute>()
private val varyings = hashSetOf<Varying>()
private val uniforms = hashSetOf<Uniform>()
class GlslGenerator(
val kind: ShaderType,
@Suppress("unused") val gles: Boolean = true,
val version: Int = DEFAULT_VERSION
) : Program.Visitor<String>("") {
//val newGlSlVersion: Boolean = version > 120
val newGlSlVersion: Boolean = false

companion object {
val DEFAULT_VERSION = 100
val FRAGCOLOR = "fragColor"
val GL_FRAGCOLOR = "gl_FragColor"
val FORCE_GLSL_VERSION get() = Environment["FORCE_GLSL_VERSION"]
val DEBUG_GLSL get() = Environment["DEBUG_GLSL"] == "true"
}

val IN = if (newGlSlVersion) "in" else "attribute"
val OUT = if (newGlSlVersion) "out" else "varying"
val UNIFORM = "uniform"
val gl_FragColor = if (newGlSlVersion) FRAGCOLOR else GL_FRAGCOLOR

private val temps = LinkedHashSet<Temp>()
private val attributes = LinkedHashSet<Attribute>()
private val varyings = LinkedHashSet<Varying>()
private val uniforms = LinkedHashSet<Uniform>()
private var programIndenter = Indenter()

private fun errorType(type: VarType): Nothing = invalidOp("Don't know how to serialize type $type")
Expand Down Expand Up @@ -46,44 +65,68 @@ class GlslGenerator(val kind: ShaderType, @Suppress("unused") val gles: Boolean

val Variable.arrayDecl get() = if (arrayCount != 1) "[$arrayCount]" else ""

fun generate(root: Program.Stm): String {
temps.clear()
attributes.clear()
varyings.clear()
uniforms.clear()
programIndenter = Indenter()
visit(root)

if (kind == ShaderType.FRAGMENT && attributes.isNotEmpty()) {
throw RuntimeException("Can't use attributes in fragment shader")
}

return Indenter {
if (gles) {
line("#version $version")
line("#ifdef GL_ES")
indent {
line("precision mediump float;")
line("precision mediump int;")
line("precision lowp sampler2D;")
line("precision lowp samplerCube;")
}
line("#endif")
}

for (it in attributes) line("attribute ${typeToString(it.type)} ${it.name}${it.arrayDecl};")
for (it in uniforms) line("uniform ${typeToString(it.type)} ${it.name}${it.arrayDecl};")
for (it in varyings) line("varying ${typeToString(it.type)} ${it.name};")

line("void main()") {
for (temp in temps) {
line(typeToString(temp.type) + " " + temp.name + ";")
}
line(programIndenter)
}
}.toString()

}
data class Result(
val generator: GlslGenerator,
val result: String,
val attributes: List<Attribute>,
val uniforms: List<Uniform>,
val varyings: List<Varying>
)

fun generateResult(root: Program.Stm): Result {
temps.clear()
attributes.clear()
varyings.clear()
uniforms.clear()
programIndenter = Indenter()

if (kind == ShaderType.FRAGMENT && newGlSlVersion) {
varyings.add(Varying(gl_FragColor, VarType.Float4))
}
visit(root)

if (kind == ShaderType.FRAGMENT && attributes.isNotEmpty()) {
throw RuntimeException("Can't use attributes in fragment shader")
}

val result = Indenter {
if (gles) {
line("#version $version")
line("#ifdef GL_ES")
indent {
line("precision mediump float;")
line("precision mediump int;")
line("precision lowp sampler2D;")
line("precision lowp samplerCube;")
}
line("#endif")
}

for (it in attributes) line("$IN ${typeToString(it.type)} ${it.name}${it.arrayDecl};")
for (it in uniforms) line("$UNIFORM ${typeToString(it.type)} ${it.name}${it.arrayDecl};")
for (it in varyings) line("$OUT ${typeToString(it.type)} ${it.name};")

line("void main()") {
for (temp in temps) {
line(typeToString(temp.type) + " " + temp.name + ";")
}
line(programIndenter)
}
}.toString().also {
if (DEBUG_GLSL) {
println("GlSlGenerator.version: $version")
println("GlSlGenerator:\n$it")
}
}
return Result(
this, result,
attributes = attributes.toList(),
uniforms = uniforms.toList(),
varyings = varyings.toList()
)
}

fun generate(root: Program.Stm): String = generateResult(root).result

override fun visit(stms: Program.Stm.Stms) {
//programIndenter.line("") {
Expand Down Expand Up @@ -125,7 +168,7 @@ class GlslGenerator(val kind: ShaderType, @Suppress("unused") val gles: Boolean
return when (operand) {
is Output -> when (kind) {
ShaderType.VERTEX -> "gl_Position"
ShaderType.FRAGMENT -> "gl_FragColor"
ShaderType.FRAGMENT -> gl_FragColor
}
else -> operand.name
}
Expand Down
64 changes: 49 additions & 15 deletions korgw/src/commonTest/kotlin/com/soywiz/korag/shaders/ShadersTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,53 @@ class ShadersTest {
}

// @TODO: Optimizer phase!
assertEquals(
Indenter {
line("void main()") {
line("vec4 temp0;")
line("if (true)") {
line("temp0 = (1 * 2);")
}
line("else") {
line("temp0 = (3 * 4);")
}
}
}.toString(),
vs.toGlSlString(gles = false)
)
assertEqualsShader(vs) {
"void main()" {
+"vec4 temp0;"
"if (true)" {
+"temp0 = (1 * 2);"
}
"else" {
+"temp0 = (3 * 4);"
}
}
}
}
}

val fs = FragmentShader {
DefaultShaders.apply {
out setTo vec4(1.lit, 0.lit, 0.lit, 1.lit)
}
}

@Test
fun testGlslFragmentGenerationOld() {
assertEqualsShader(fs, version = 100) {
line("void main()") {
line("gl_FragColor = vec4(1, 0, 0, 1);")
}
}
}

@Test
fun testGlslFragmentGenerationNew() {
assertEqualsShader(fs, version = 330) {
line("void main()") {
line("gl_FragColor = vec4(1, 0, 0, 1);")
}
//+"layout(location = 0) out vec4 fragColor;"
//"void main()" {
// +"fragColor = vec4(1, 0, 0, 1);"
//}
}
}

fun assertEqualsShader(shader: Shader, version: Int = GlslGenerator.DEFAULT_VERSION, gles: Boolean = false, block: Indenter.() -> Unit) {
assertEquals(
Indenter {
block()
}.toString(),
shader.toNewGlslString(gles = gles, version = version)
)
}
}

0 comments on commit 820d94b

Please sign in to comment.