Skip to content

Commit

Permalink
spinning cube with web gpu
Browse files Browse the repository at this point in the history
  • Loading branch information
fabmax committed Jan 7, 2024
1 parent 78a9d4c commit a90a63e
Show file tree
Hide file tree
Showing 16 changed files with 763 additions and 425 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,7 @@ class KslFragmentStage(program: KslProgram) : KslShaderStage(program, KslShaderS
fun KslScopeBuilder.colorOutput(rgb: KslVectorExpression<KslFloat3, KslFloat1>, a: KslScalarExpression<KslFloat1> = 1f.const, location: Int = 0) {
check (parentStage is KslFragmentStage) { "colorOutput is only available in fragment stage" }
val outColor = parentStage.colorOutput(location)
outColor.value.rgb set rgb
outColor.value.a set a
outColor.value set float4Value(rgb, a)
}

fun KslScopeBuilder.colorOutput(value: KslVectorExpression<KslFloat4, KslFloat1>, location: Int = 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class WgslGenerator : KslGenerator() {
// src.generateFunctions(fragmentStage)

src.appendLine("@fragment")
src.appendLine("fn fragmentMain(input: FragmentInput) -> FragmentOutput {")
src.appendLine("fn fragmentMain(fragmentInput: FragmentInput) -> FragmentOutput {")

src.appendLine(" var fragmentOutput: FragmentOutput;")
fragmentOutput.generateExplodedMembers(src)
Expand Down Expand Up @@ -563,12 +563,12 @@ class WgslGenerator : KslGenerator() {
return when (stateName) {
KslVertexStage.NAME_IN_VERTEX_INDEX -> "vertexInput.vertexIndex" // vertex_index
KslVertexStage.NAME_IN_INSTANCE_INDEX -> "vertexInput.instanceIndex" // instance_index
KslVertexStage.NAME_OUT_POSITION -> "vertexOutput.position" // position
KslVertexStage.NAME_OUT_POINT_SIZE -> "vertexOutput.pointSize" // <unsupported>
KslVertexStage.NAME_OUT_POSITION -> "position" // position
KslVertexStage.NAME_OUT_POINT_SIZE -> "pointSize" // <unsupported>

KslFragmentStage.NAME_IN_FRAG_POSITION -> "fragmentInput.position" // position
KslFragmentStage.NAME_IN_IS_FRONT_FACING -> "fragmentInput.isFrontFacing" // front_facing
KslFragmentStage.NAME_OUT_DEPTH -> "fragmentOutput.fragDepth" // frag_depth
KslFragmentStage.NAME_OUT_DEPTH -> "fragDepth" // frag_depth
// not-implemented: sample_index
// not-implemented: sample_mask

Expand Down Expand Up @@ -627,7 +627,11 @@ class WgslGenerator : KslGenerator() {
}
}

class WgslGeneratorOutput : GeneratedSourceOutput() {
class WgslGeneratorOutput(
val vertexEntryPoint: String = "vertexMain",
val fragmentEntryPoint: String = "fragmentMain",
val computeEntryPoint: String = "computeMain"
) : GeneratedSourceOutput() {
companion object {
fun shaderOutput(vertexSrc: String, fragmentSrc: String) = WgslGeneratorOutput().apply {
stages[KslShaderStageType.VertexShader] = vertexSrc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ interface WgslStructHelper {

data class WgslStructMember(val structName: String, val name: String, val type: String, val annotation: String = "") {
fun generateStructMember(builder: StringBuilder) {
builder.appendLine(" ${annotation}${name}: ${type};")
builder.appendLine(" ${annotation}${name}: ${type},")
}

fun createExplodedMember(builder: StringBuilder) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package de.fabmax.kool

import de.fabmax.kool.math.Vec2i
import de.fabmax.kool.platform.Lwjgl3Context
import de.fabmax.kool.util.MsdfFontInfo
import de.fabmax.kool.util.MsdfMeta
import kotlinx.serialization.json.Json
Expand Down Expand Up @@ -30,7 +29,7 @@ data class KoolConfigJvm(
val storageDir: String = "./.storage",
val httpCacheDir: String = "./.httpCache",

val renderBackend: Lwjgl3Context.Backend = Lwjgl3Context.Backend.OPEN_GL,
val renderBackend: Backend = Backend.OPEN_GL,
val windowTitle: String = "Kool App",
val windowSize: Vec2i = Vec2i(1600, 900),
val isFullscreen: Boolean = false,
Expand Down Expand Up @@ -61,4 +60,9 @@ data class KoolConfigJvm(
}
}
}

enum class Backend(val displayName: String) {
VULKAN("Vulkan"),
OPEN_GL("OpenGL")
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.fabmax.kool.platform

import de.fabmax.kool.KoolConfigJvm
import de.fabmax.kool.KoolContext
import de.fabmax.kool.KoolSystem
import de.fabmax.kool.configJvm
Expand Down Expand Up @@ -75,7 +76,7 @@ class Lwjgl3Context : KoolContext() {
}

init {
backend = if (KoolSystem.configJvm.renderBackend == Backend.VULKAN) {
backend = if (KoolSystem.configJvm.renderBackend == KoolConfigJvm.Backend.VULKAN) {
VkRenderBackend(this)
} else {
RenderBackendGlImpl(this)
Expand Down Expand Up @@ -160,10 +161,5 @@ class Lwjgl3Context : KoolContext() {
}

override fun getSysInfos(): List<String> = SysInfo.lines

enum class Backend(val displayName: String) {
VULKAN("Vulkan"),
OPEN_GL("OpenGL")
}
}

6 changes: 6 additions & 0 deletions kool-core/src/jsMain/kotlin/de/fabmax/kool/KoolConfigJs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ data class KoolConfigJs(
override val defaultFont: MsdfFontInfo = DEFAULT_MSDF_FONT_INFO,

val canvasName: String = "glCanvas",
val renderBackend: Backend = Backend.WEB_GL2,
val isGlobalKeyEventGrabbing: Boolean = true,
val isJsCanvasToWindowFitting: Boolean = true,
val loaderTasks: List<suspend () -> Unit> = emptyList(),
Expand All @@ -32,4 +33,9 @@ data class KoolConfigJs(
MsdfFontInfo(meta, "fonts/font-roboto-regular.png")
}
}

enum class Backend(val displayName: String) {
WEB_GL2("WebGL2"),
WEB_GPU("WebGPU")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import de.fabmax.kool.pipeline.backend.RenderBackend
import de.fabmax.kool.pipeline.backend.RenderBackendJs
import de.fabmax.kool.pipeline.backend.stats.BackendStats
import de.fabmax.kool.platform.JsContext
import de.fabmax.kool.scene.Scene
import de.fabmax.kool.util.LongHash
import de.fabmax.kool.util.logE
import de.fabmax.kool.util.logI
Expand All @@ -26,9 +25,17 @@ class RenderBackendWebGpu(val ctx: KoolContext, val canvas: HTMLCanvasElement) :
override val canBlitRenderPasses: Boolean = false
override val isOnscreenInfiniteDepthCapable: Boolean = false // actually it can...

private lateinit var adapter: GPUAdapter
private lateinit var device: GPUDevice
private lateinit var gpuContext: GPUCanvasContext
lateinit var adapter: GPUAdapter
private set
lateinit var device: GPUDevice
private set
lateinit var gpuContext: GPUCanvasContext
private set
private var _canvasFormat: GPUTextureFormat? = null
val canvasFormat: GPUTextureFormat
get() = _canvasFormat!!

private val sceneRenderer = WgpuRenderPass(this)

init {
check(!js("!navigator.gpu") as Boolean) {
Expand All @@ -48,7 +55,7 @@ class RenderBackendWebGpu(val ctx: KoolContext, val canvas: HTMLCanvasElement) :
device = adapter.requestDevice().await()

gpuContext = canvas.getContext("webgpu") as GPUCanvasContext
val canvasFormat = navigator.gpu.getPreferredCanvasFormat()
_canvasFormat = navigator.gpu.getPreferredCanvasFormat()
gpuContext.configure(GPUCanvasConfiguration(device, canvasFormat))
logI { "WebGPU context created" }

Expand All @@ -74,40 +81,37 @@ class RenderBackendWebGpu(val ctx: KoolContext, val canvas: HTMLCanvasElement) :
// captureFramebuffer(scene)
// }
// doOffscreenPasses(scene, ctx)
doForegroundPass(scene)
sceneRenderer.doForegroundPass(scene)
}
}
}

fun doForegroundPass(scene: Scene) {
val clearColor = scene.mainRenderPass.clearColor ?: return

val encoder = device.createCommandEncoder()
val pass = encoder.beginRenderPass(GPURenderPassDescriptor(arrayOf(
GPURenderPassColorAttachment(
view = gpuContext.getCurrentTexture().createView(),
clearValue = GPUColorDict(clearColor.r.toDouble(), clearColor.g.toDouble(), clearColor.b.toDouble(), clearColor.a.toDouble()),
loadOp = GPULoadOp.clear,
storeOp = GPUStoreOp.store
)
)))

pass.end()
device.queue.submit(arrayOf(encoder.finish()))
}

override fun cleanup(ctx: KoolContext) {
// do nothing for now
}

override fun generateKslShader(shader: KslShader, pipeline: Pipeline): ShaderCode {
logE { "Not yet implemented: WebGpuShaderCode()" }
return WebGpuShaderCode()
val output = WgslGenerator().generateProgram(shader.program, pipeline)
if (shader.program.dumpCode) {
output.dump()
}
return WebGpuShaderCode(
vertexSrc = output.vertexSrc,
vertexEntryPoint = output.vertexEntryPoint,
fragmentSrc = output.fragmentSrc,
fragmentEntryPoint = output.fragmentEntryPoint
)
}

override fun generateKslComputeShader(shader: KslComputeShader, pipeline: ComputePipeline): ComputeShaderCode {
logE { "Not yet implemented: WebGpuComputeShaderCode()" }
return WebGpuComputeShaderCode()
val output = WgslGenerator().generateComputeProgram(shader.program, pipeline)
if (shader.program.dumpCode) {
output.dump()
}
return WebGpuComputeShaderCode(
computeSrc = output.computeSrc,
computeEntryPoint = output.computeEntryPoint
)
}

override fun createOffscreenPass2d(parentPass: OffscreenRenderPass2d): OffscreenPass2dImpl {
Expand Down Expand Up @@ -146,11 +150,20 @@ class RenderBackendWebGpu(val ctx: KoolContext, val canvas: HTMLCanvasElement) :
}
}

class WebGpuShaderCode: ShaderCode {
override val hash: LongHash = LongHash()
data class WebGpuShaderCode(
val vertexSrc: String,
val vertexEntryPoint: String,
val fragmentSrc: String,
val fragmentEntryPoint: String
): ShaderCode {
override val hash = LongHash().apply {
this += vertexSrc.hashCode().toLong() shl 32 or fragmentSrc.hashCode().toLong()
}
}

class WebGpuComputeShaderCode: ComputeShaderCode {
override val hash: LongHash = LongHash()
data class WebGpuComputeShaderCode(val computeSrc: String, val computeEntryPoint: String): ComputeShaderCode {
override val hash = LongHash().apply {
this += computeSrc
}
}
}
Loading

0 comments on commit a90a63e

Please sign in to comment.