main.odin 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. package vendor_wgpu_example_triangle
  2. import "base:runtime"
  3. import "core:fmt"
  4. import "vendor:wgpu"
  5. State :: struct {
  6. ctx: runtime.Context,
  7. os: OS,
  8. instance: wgpu.Instance,
  9. surface: wgpu.Surface,
  10. adapter: wgpu.Adapter,
  11. device: wgpu.Device,
  12. config: wgpu.SurfaceConfiguration,
  13. queue: wgpu.Queue,
  14. module: wgpu.ShaderModule,
  15. pipeline_layout: wgpu.PipelineLayout,
  16. pipeline: wgpu.RenderPipeline,
  17. }
  18. @(private="file")
  19. state: State
  20. main :: proc() {
  21. state.ctx = context
  22. os_init(&state.os)
  23. state.instance = wgpu.CreateInstance(nil)
  24. if state.instance == nil {
  25. panic("WebGPU is not supported")
  26. }
  27. state.surface = os_get_surface(&state.os, state.instance)
  28. wgpu.InstanceRequestAdapter(state.instance, &{ compatibleSurface = state.surface }, on_adapter, nil)
  29. on_adapter :: proc "c" (status: wgpu.RequestAdapterStatus, adapter: wgpu.Adapter, message: cstring, userdata: rawptr) {
  30. context = state.ctx
  31. if status != .Success || adapter == nil {
  32. fmt.panicf("request adapter failure: [%v] %s", status, message)
  33. }
  34. state.adapter = adapter
  35. wgpu.AdapterRequestDevice(adapter, nil, on_device)
  36. }
  37. on_device :: proc "c" (status: wgpu.RequestDeviceStatus, device: wgpu.Device, message: cstring, userdata: rawptr) {
  38. context = state.ctx
  39. if status != .Success || device == nil {
  40. fmt.panicf("request device failure: [%v] %s", status, message)
  41. }
  42. state.device = device
  43. width, height := os_get_render_bounds(&state.os)
  44. state.config = wgpu.SurfaceConfiguration {
  45. device = state.device,
  46. usage = { .RenderAttachment },
  47. format = .BGRA8Unorm,
  48. width = width,
  49. height = height,
  50. presentMode = .Fifo,
  51. alphaMode = .Opaque,
  52. }
  53. wgpu.SurfaceConfigure(state.surface, &state.config)
  54. state.queue = wgpu.DeviceGetQueue(state.device)
  55. shader :: `
  56. @vertex
  57. fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4<f32> {
  58. let x = f32(i32(in_vertex_index) - 1);
  59. let y = f32(i32(in_vertex_index & 1u) * 2 - 1);
  60. return vec4<f32>(x, y, 0.0, 1.0);
  61. }
  62. @fragment
  63. fn fs_main() -> @location(0) vec4<f32> {
  64. return vec4<f32>(1.0, 0.0, 0.0, 1.0);
  65. }`
  66. state.module = wgpu.DeviceCreateShaderModule(state.device, &{
  67. nextInChain = &wgpu.ShaderModuleWGSLDescriptor{
  68. sType = .ShaderModuleWGSLDescriptor,
  69. code = shader,
  70. },
  71. })
  72. state.pipeline_layout = wgpu.DeviceCreatePipelineLayout(state.device, &{})
  73. state.pipeline = wgpu.DeviceCreateRenderPipeline(state.device, &{
  74. layout = state.pipeline_layout,
  75. vertex = {
  76. module = state.module,
  77. entryPoint = "vs_main",
  78. },
  79. fragment = &{
  80. module = state.module,
  81. entryPoint = "fs_main",
  82. targetCount = 1,
  83. targets = &wgpu.ColorTargetState{
  84. format = .BGRA8Unorm,
  85. writeMask = wgpu.ColorWriteMaskFlags_All,
  86. },
  87. },
  88. primitive = {
  89. topology = .TriangleList,
  90. },
  91. multisample = {
  92. count = 1,
  93. mask = 0xFFFFFFFF,
  94. },
  95. })
  96. os_run(&state.os)
  97. }
  98. }
  99. resize :: proc "c" () {
  100. context = state.ctx
  101. state.config.width, state.config.height = os_get_render_bounds(&state.os)
  102. wgpu.SurfaceConfigure(state.surface, &state.config)
  103. }
  104. frame :: proc "c" (dt: f32) {
  105. context = state.ctx
  106. surface_texture := wgpu.SurfaceGetCurrentTexture(state.surface)
  107. switch surface_texture.status {
  108. case .Success:
  109. // All good, could check for `surface_texture.suboptimal` here.
  110. case .Timeout, .Outdated, .Lost:
  111. // Skip this frame, and re-configure surface.
  112. if surface_texture.texture != nil {
  113. wgpu.TextureRelease(surface_texture.texture)
  114. }
  115. resize()
  116. return
  117. case .OutOfMemory, .DeviceLost:
  118. // Fatal error
  119. fmt.panicf("[triangle] get_current_texture status=%v", surface_texture.status)
  120. }
  121. defer wgpu.TextureRelease(surface_texture.texture)
  122. frame := wgpu.TextureCreateView(surface_texture.texture, nil)
  123. defer wgpu.TextureViewRelease(frame)
  124. command_encoder := wgpu.DeviceCreateCommandEncoder(state.device, nil)
  125. defer wgpu.CommandEncoderRelease(command_encoder)
  126. render_pass_encoder := wgpu.CommandEncoderBeginRenderPass(
  127. command_encoder, &{
  128. colorAttachmentCount = 1,
  129. colorAttachments = &wgpu.RenderPassColorAttachment{
  130. view = frame,
  131. loadOp = .Clear,
  132. storeOp = .Store,
  133. depthSlice = wgpu.DEPTH_SLICE_UNDEFINED,
  134. clearValue = { 0, 1, 0, 1 },
  135. },
  136. },
  137. )
  138. wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline)
  139. wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0)
  140. wgpu.RenderPassEncoderEnd(render_pass_encoder)
  141. wgpu.RenderPassEncoderRelease(render_pass_encoder)
  142. command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil)
  143. defer wgpu.CommandBufferRelease(command_buffer)
  144. wgpu.QueueSubmit(state.queue, { command_buffer })
  145. wgpu.SurfacePresent(state.surface)
  146. }
  147. finish :: proc() {
  148. wgpu.RenderPipelineRelease(state.pipeline)
  149. wgpu.PipelineLayoutRelease(state.pipeline_layout)
  150. wgpu.ShaderModuleRelease(state.module)
  151. wgpu.QueueRelease(state.queue)
  152. wgpu.DeviceRelease(state.device)
  153. wgpu.AdapterRelease(state.adapter)
  154. wgpu.SurfaceRelease(state.surface)
  155. wgpu.InstanceRelease(state.instance)
  156. }