Skip to content

Instantly share code, notes, and snippets.

@smallshen
Created October 29, 2023 11:50
Show Gist options
  • Save smallshen/d6cd88b825e232ba39b6a78c8ae17a70 to your computer and use it in GitHub Desktop.
Save smallshen/d6cd88b825e232ba39b6a78c8ae17a70 to your computer and use it in GitHub Desktop.
custom jextract example
package io.mojang.webgpu
import webgpu.kotlin.*
import webgpu.webgpu_h.*
import java.lang.foreign.Arena
import java.lang.foreign.MemorySegment
private val shaderSrc = """
@vertex
fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4f {
var pos = array(
vec2f( 0.0, 0.5),
vec2f(-0.5, -0.5),
vec2f( 0.5, -0.5)
);
return vec4f(pos[in_vertex_index], 0.0, 1.0);
}
@fragment
fn fs_main() -> @location(0) vec4f {
return vec4f(1.0, 1.0, 0.0, 1.0);
}
""".trimIndent()
class TriangleExample : ApplicationWindow() {
var canStartRender = false
var shaderModule: MemorySegment = MemorySegment.NULL
var pipeline: MemorySegment = MemorySegment.NULL
fun initTriangleShaderModule() {
shaderModule = wgpuInstance.createShaderModule(shaderSrc)
}
fun initPipeline() {
val pipelineDesc = WGPURenderPipelineDescriptor(Arena.ofAuto())
pipelineDesc.nextInChain = MemorySegment.NULL
pipelineDesc.vertex.bufferCount = 0L
pipelineDesc.vertex.buffers = MemorySegment.NULL
pipelineDesc.vertex.module = shaderModule
pipelineDesc.vertex.entryPoint = Arena.ofAuto().allocateUtf8String("vs_main")
pipelineDesc.primitive.topology = WGPUPrimitiveTopology.WGPUPrimitiveTopology_TriangleList.v
pipelineDesc.primitive.stripIndexFormat = WGPUIndexFormat.WGPUIndexFormat_Undefined.v
pipelineDesc.primitive.frontFace = WGPUFrontFace.WGPUFrontFace_CCW.v
pipelineDesc.primitive.cullMode = WGPUCullMode.WGPUCullMode_None.v
val fragmentState = WGPUFragmentState(Arena.ofAuto())
pipelineDesc.fragment = fragmentState.native()
fragmentState.module = shaderModule
fragmentState.entryPoint = Arena.ofAuto().allocateUtf8String("fs_main")
fragmentState.constantCount = 0L
fragmentState.constants = MemorySegment.NULL
val blendState = WGPUBlendState(Arena.ofAuto())
blendState.color.srcFactor = WGPUBlendFactor.WGPUBlendFactor_SrcAlpha.v
blendState.color.dstFactor = WGPUBlendFactor.WGPUBlendFactor_OneMinusSrcAlpha.v
blendState.color.operation = WGPUBlendOperation.WGPUBlendOperation_Add.v
blendState.alpha.srcFactor = WGPUBlendFactor.WGPUBlendFactor_Zero.v
blendState.alpha.dstFactor = WGPUBlendFactor.WGPUBlendFactor_One.v
blendState.alpha.operation = WGPUBlendOperation.WGPUBlendOperation_Add.v
val colorTarget = WGPUColorTargetState(Arena.ofAuto())
colorTarget.nextInChain = MemorySegment.NULL
colorTarget.format = wgpuInstance.getSwapChainFormat()
colorTarget.blend = blendState.native()
colorTarget.writeMask = WGPUColorWriteMask.WGPUColorWriteMask_All.v
fragmentState.targetCount = 1L
fragmentState.targets = colorTarget.native()
pipelineDesc.depthStencil = MemorySegment.NULL
pipelineDesc.multisample.count = 1
pipelineDesc.multisample.mask = 0xFFFF
pipelineDesc.multisample.alphaToCoverageEnabled = 0
pipeline = wgpuDeviceCreateRenderPipeline(wgpuInstance.devicePtr, pipelineDesc.native())
assert(pipeline != MemorySegment.NULL)
wgpuShaderModuleRelease(shaderModule)
}
override fun frame(arena: Arena) {
if (!canStartRender) return
val nextTexture = wgpuSwapChainGetCurrentTextureView(wgpuInstance.swapChainPtr)
assert(nextTexture != MemorySegment.NULL) {
"Failed to acquire next swap chain texture"
}
val renderPassDesc = WGPURenderPassDescriptor(arena)
renderPassDesc.nextInChain = MemorySegment.NULL
val colorAttachment = WGPURenderPassColorAttachment(arena)
colorAttachment.view = nextTexture
colorAttachment.resolveTarget = MemorySegment.NULL
colorAttachment.loadOp = WGPULoadOp.WGPULoadOp_Clear.v
colorAttachment.storeOp = WGPUStoreOp.WGPUStoreOp_Store.v
colorAttachment.clearValue.r = 0.0
colorAttachment.clearValue.g = 0.0
colorAttachment.clearValue.b = 1.0
colorAttachment.clearValue.a = 1.0
renderPassDesc.colorAttachmentCount = 1
renderPassDesc.colorAttachments = colorAttachment.native()
renderPassDesc.depthStencilAttachment = MemorySegment.NULL
val encoder = wgpuDeviceCreateCommandEncoder(wgpuInstance.devicePtr, MemorySegment.NULL)
val pass = wgpuCommandEncoderBeginRenderPass(encoder, renderPassDesc.native())
wgpuRenderPassEncoderSetPipeline(pass, pipeline)
wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0)
wgpuRenderPassEncoderEnd(pass)
val command = wgpuCommandEncoderFinish(encoder, MemorySegment.NULL)
assert(command != MemorySegment.NULL)
wgpuQueueSubmit(wgpuInstance.queue, 1, command.ptr())
wgpuSwapChainPresent(wgpuInstance.swapChainPtr)
wgpuCommandBufferRelease(command)
wgpuCommandEncoderRelease(encoder)
wgpuTextureViewRelease(nextTexture)
wgpuRenderPassEncoderRelease(pass)
}
override fun close() {
wgpuRenderPipelineRelease(pipeline)
wgpuShaderModuleRelease(shaderModule)
super.close()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment