Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some WebGPU AG work #2259

Merged
merged 4 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ if (isJava8or9) {
dependencies {
implementation(libs.kover)
implementation(libs.dokka)
//implementation(libs.jsplainobjects)
implementation(libs.proguard.gradle)
implementation(libs.gson)
implementation(libs.gradle.publish.plugin)
Expand Down
2 changes: 2 additions & 0 deletions buildSrc/src/main/kotlin/korlibs/root/RootKorlibsPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ object RootKorlibsPlugin {

fun Project.init() {
plugins.apply(DokkaPlugin::class.java)
//plugins.apply("js-plain-objects")

allprojects {
tasks.withType(AbstractDokkaTask::class.java).configureEach {
Expand Down Expand Up @@ -238,6 +239,7 @@ object RootKorlibsPlugin {

// AppData\Local\Android\Sdk\tools\bin>sdkmanager --licenses
plugins.apply("kotlin-multiplatform")
//plugins.apply(JsPlainObjectsKotlinGradleSubplugin::class.java)

//initAndroidProject()
if (hasAndroid) {
Expand Down
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", v
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" }
#jsplainobjects = { module = "org.jetbrains.kotlin:js-plain-objects", version.ref = "kotlin" }
kover = { module = "org.jetbrains.kotlinx:kover", version.ref = "kover" }
kover-intellij-agent = { module = "org.jetbrains.intellij.deps:intellij-coverage-agent", version.ref = "kover-agent" }
jcodec-core = { module = "org.jcodec:jcodec", version.ref = "jcodec" }
Expand Down
1,076 changes: 769 additions & 307 deletions korge-core/src@js/io/ygdrasil/wgpu/internal/js/WebGPUTypes.kt

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion korge-core/src@js/korlibs/render/DefaultGameWindowJs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,13 @@ private external interface JsGamepadEvent {

class NodeJsGameWindow : JsGameWindow()

actual fun CreateDefaultGameWindow(config: GameWindowCreationConfig): GameWindow = if (Platform.isJsNodeJs) NodeJsGameWindow() else BrowserCanvasJsGameWindow()
class DenoJsGameWindow : JsGameWindow()

actual fun CreateDefaultGameWindow(config: GameWindowCreationConfig): GameWindow = when {
Platform.isJsDenoJs -> DenoJsGameWindow()
Platform.isJsNodeJs -> NodeJsGameWindow()
else -> BrowserCanvasJsGameWindow()
}

/*
public external open class TouchEvent(type: String, eventInitDict: MouseEventInit = definedExternally) : UIEvent {
Expand Down
178 changes: 177 additions & 1 deletion korge-core/src@js/korlibs/webgpu/WebGPUAG.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,182 @@
package korlibs.webgpu

import io.ygdrasil.wgpu.internal.js.*
import korlibs.graphics.*
import korlibs.image.color.*
import korlibs.js.*
import korlibs.math.geom.*
import kotlinx.coroutines.*

class WebGPUAG : AG() {
private external val navigator: NavigatorGPU

class WebGPUAG(val device: GPUDevice) : AG() {
val dimensions = SizeInt(320, 240)

fun test() {
navigator.onLine
}

val shaderModule = device.createShaderModule(GPUShaderModuleDescriptor(
code = """
@vertex
fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4<f32> {
let x = f32(i32(in_vertex_index) - 1);
let y = f32(i32(in_vertex_index & 1u) * 2 - 1);
return vec4<f32>(x, y, 0.0, 1.0);
}

@fragment
fn fs_main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
""".trimIndent()
))

val pipelineLayout = device.createPipelineLayout(GPUPipelineLayoutDescriptor(
bindGroupLayouts = arrayOf(),
))

val renderPipeline = device.createRenderPipeline(
GPURenderPipelineDescriptor(
layout = pipelineLayout,
vertex = GPUVertexState(
module = shaderModule,
entryPoint = "vs_main",
),
fragment = GPUFragmentState(
module = shaderModule,
entryPoint = "fs_main",
targets = arrayOf(
GPUColorTargetState(
format = GPUTextureFormat.RGBA8UNORM_SRGB,
),
),
),
)
)

val captureInfo = createCapture(
device,
dimensions.width,
dimensions.height,
)
val texture = captureInfo.texture
val outputBuffer = captureInfo.outputBuffer

companion object {
suspend operator fun invoke(): WebGPUAG {
val adapter: GPUAdapter = navigator.gpu.requestAdapter().await()
?: error("No WebGPU adapter found")
return WebGPUAG(adapter.requestDevice().await())
}
}


override fun clear(
frameBuffer: AGFrameBufferBase,
frameBufferInfo: AGFrameBufferInfo,
color: RGBA,
depth: Float,
stencil: Int,
clearColor: Boolean,
clearDepth: Boolean,
clearStencil: Boolean,
scissor: AGScissor
) {
val encoder = device.createCommandEncoder();
val renderPass = encoder.beginRenderPass(
GPURenderPassDescriptor(
colorAttachments = arrayOf(
GPURenderPassColorAttachment(
view = texture.createView(),
storeOp = GPUStoreOP.STORE,
loadOp = GPULoadOP.CLEAR,
clearValue = arrayOf(0, 1, 0, 1),
),
),
)
//GPURenderPassDescriptor()
);
renderPass.setPipeline(renderPipeline);
renderPass.draw(3, 1);
renderPass.end();
copyToBuffer(encoder, texture, outputBuffer, dimensions);
device.queue.submit(arrayOf(encoder.finish()));
}

override fun readToMemory(frameBuffer: AGFrameBufferBase, frameBufferInfo: AGFrameBufferInfo, x: Int, y: Int, width: Int, height: Int, data: Any, kind: AGReadKind) {

}

private fun copyToBuffer(
encoder: GPUCommandEncoder,
texture: GPUTexture,
outputBuffer: GPUBuffer,
dimensions: SizeInt,
) {
val padded = getRowPadding(dimensions.width).padded;

encoder.copyTextureToBuffer(
GPUImageCopyTexture(texture = texture,),
GPUImageCopyBuffer(buffer = outputBuffer, bytesPerRow = padded),
GPUExtent3DDictStrict(width = dimensions.width, height = dimensions.height),
);
}

data class CreateCapture(val texture: GPUTexture, val outputBuffer: GPUBuffer)

private fun createCapture(
device: GPUDevice,
width: Int,
height: Int,
): CreateCapture {
val padded = getRowPadding(width).padded;
val outputBuffer = device.createBuffer(GPUBufferDescriptor(
label = "Capture",
size = padded * height,
usage = (GPUBufferUsage.MAP_READ or GPUBufferUsage.COPY_DST
)))
val texture = device.createTexture(
GPUTextureDescriptor(
label = "Capture",
size = GPUExtent3DDictStrict(width = width, height = height),
format = GPUTextureFormat.RGBA8UNORM_SRGB,
usage = (GPUTextureUsage.RENDER_ATTACHMENT or GPUTextureUsage.COPY_SRC),
)
)

return CreateCapture(texture, outputBuffer)
}


/** Return value for {@linkcode getRowPadding}. */
data class Padding(
/** The number of bytes per row without padding calculated. */
val unpadded: Int,
/** The number of bytes per row with padding calculated. */
val padded: Int,
)
/** Buffer-Texture copies must have [`bytes_per_row`] aligned to this number. */
val COPY_BYTES_PER_ROW_ALIGNMENT = 256;
/** Number of bytes per pixel. */
val BYTES_PER_PIXEL = 4;


private fun getRowPadding(width: Int): Padding {
// It is a WebGPU requirement that
// GPUImageCopyBuffer.layout.bytesPerRow % COPY_BYTES_PER_ROW_ALIGNMENT == 0
// So we calculate paddedBytesPerRow by rounding unpaddedBytesPerRow
// up to the next multiple of COPY_BYTES_PER_ROW_ALIGNMENT.

val unpaddedBytesPerRow = width * BYTES_PER_PIXEL;
val paddedBytesPerRowPadding = (COPY_BYTES_PER_ROW_ALIGNMENT -
(unpaddedBytesPerRow % COPY_BYTES_PER_ROW_ALIGNMENT)) %
COPY_BYTES_PER_ROW_ALIGNMENT;
val paddedBytesPerRow = unpaddedBytesPerRow + paddedBytesPerRowPadding;

return Padding(
unpadded = unpaddedBytesPerRow,
padded = paddedBytesPerRow,
)
}
}
Loading