instance.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. //go:build !js
  2. package wgpu
  3. /*
  4. #include <stdlib.h>
  5. #include "./lib/wgpu.h"
  6. extern void gowebgpu_request_adapter_callback_c(WGPURequestAdapterStatus status, WGPUAdapter adapter, char const *message, void *userdata);
  7. */
  8. import "C"
  9. import (
  10. "errors"
  11. "runtime/cgo"
  12. "unsafe"
  13. )
  14. type Instance struct {
  15. ref C.WGPUInstance
  16. }
  17. func CreateInstance(descriptor *InstanceDescriptor) *Instance {
  18. var desc C.WGPUInstanceDescriptor
  19. if descriptor != nil {
  20. instanceExtras := (*C.WGPUInstanceExtras)(C.malloc(C.size_t(unsafe.Sizeof(C.WGPUInstanceExtras{}))))
  21. defer C.free(unsafe.Pointer(instanceExtras))
  22. instanceExtras.chain.next = nil
  23. instanceExtras.chain.sType = C.WGPUSType_InstanceExtras
  24. instanceExtras.backends = C.WGPUInstanceBackendFlags(descriptor.Backends)
  25. instanceExtras.dx12ShaderCompiler = C.WGPUDx12Compiler(descriptor.Dx12ShaderCompiler)
  26. if descriptor.DxilPath != "" {
  27. dxilPath := C.CString(descriptor.DxilPath)
  28. defer C.free(unsafe.Pointer(dxilPath))
  29. instanceExtras.dxilPath = dxilPath
  30. }
  31. if descriptor.DxcPath != "" {
  32. dxcPath := C.CString(descriptor.DxcPath)
  33. defer C.free(unsafe.Pointer(dxcPath))
  34. instanceExtras.dxcPath = dxcPath
  35. }
  36. desc.nextInChain = (*C.WGPUChainedStruct)(unsafe.Pointer(instanceExtras))
  37. }
  38. ref := C.wgpuCreateInstance(&desc)
  39. if ref == nil {
  40. panic("Failed to acquire Instance")
  41. }
  42. return &Instance{ref}
  43. }
  44. type SurfaceDescriptorFromWindowsHWND struct {
  45. Hinstance unsafe.Pointer
  46. Hwnd unsafe.Pointer
  47. }
  48. type SurfaceDescriptorFromXcbWindow struct {
  49. Connection unsafe.Pointer
  50. Window uint32
  51. }
  52. type SurfaceDescriptorFromXlibWindow struct {
  53. Display unsafe.Pointer
  54. Window uint32
  55. }
  56. type SurfaceDescriptorFromMetalLayer struct {
  57. Layer unsafe.Pointer
  58. }
  59. type SurfaceDescriptorFromWaylandSurface struct {
  60. Display unsafe.Pointer
  61. Surface unsafe.Pointer
  62. }
  63. type SurfaceDescriptorFromAndroidNativeWindow struct {
  64. Window unsafe.Pointer
  65. }
  66. type SurfaceDescriptor struct {
  67. Label string
  68. WindowsHWND *SurfaceDescriptorFromWindowsHWND
  69. XcbWindow *SurfaceDescriptorFromXcbWindow
  70. XlibWindow *SurfaceDescriptorFromXlibWindow
  71. MetalLayer *SurfaceDescriptorFromMetalLayer
  72. WaylandSurface *SurfaceDescriptorFromWaylandSurface
  73. AndroidNativeWindow *SurfaceDescriptorFromAndroidNativeWindow
  74. }
  75. func (p *Instance) CreateSurface(descriptor *SurfaceDescriptor) *Surface {
  76. var desc C.WGPUSurfaceDescriptor
  77. if descriptor != nil {
  78. if descriptor.Label != "" {
  79. label := C.CString(descriptor.Label)
  80. defer C.free(unsafe.Pointer(label))
  81. desc.label = label
  82. }
  83. if descriptor.WindowsHWND != nil {
  84. windowsHWND := (*C.WGPUSurfaceDescriptorFromWindowsHWND)(C.malloc(C.size_t(unsafe.Sizeof(C.WGPUSurfaceDescriptorFromWindowsHWND{}))))
  85. defer C.free(unsafe.Pointer(windowsHWND))
  86. windowsHWND.chain.next = nil
  87. windowsHWND.chain.sType = C.WGPUSType_SurfaceDescriptorFromWindowsHWND
  88. windowsHWND.hinstance = descriptor.WindowsHWND.Hinstance
  89. windowsHWND.hwnd = descriptor.WindowsHWND.Hwnd
  90. desc.nextInChain = (*C.WGPUChainedStruct)(unsafe.Pointer(windowsHWND))
  91. }
  92. if descriptor.XcbWindow != nil {
  93. xcbWindow := (*C.WGPUSurfaceDescriptorFromXcbWindow)(C.malloc(C.size_t(unsafe.Sizeof(C.WGPUSurfaceDescriptorFromXcbWindow{}))))
  94. defer C.free(unsafe.Pointer(xcbWindow))
  95. xcbWindow.chain.next = nil
  96. xcbWindow.chain.sType = C.WGPUSType_SurfaceDescriptorFromXcbWindow
  97. xcbWindow.connection = descriptor.XcbWindow.Connection
  98. xcbWindow.window = C.uint32_t(descriptor.XcbWindow.Window)
  99. desc.nextInChain = (*C.WGPUChainedStruct)(unsafe.Pointer(xcbWindow))
  100. }
  101. if descriptor.XlibWindow != nil {
  102. xlibWindow := (*C.WGPUSurfaceDescriptorFromXlibWindow)(C.malloc(C.size_t(unsafe.Sizeof(C.WGPUSurfaceDescriptorFromXlibWindow{}))))
  103. defer C.free(unsafe.Pointer(xlibWindow))
  104. xlibWindow.chain.next = nil
  105. xlibWindow.chain.sType = C.WGPUSType_SurfaceDescriptorFromXlibWindow
  106. xlibWindow.display = descriptor.XlibWindow.Display
  107. xlibWindow.window = C.uint64_t(descriptor.XlibWindow.Window)
  108. desc.nextInChain = (*C.WGPUChainedStruct)(unsafe.Pointer(xlibWindow))
  109. }
  110. if descriptor.MetalLayer != nil {
  111. metalLayer := (*C.WGPUSurfaceDescriptorFromMetalLayer)(C.malloc(C.size_t(unsafe.Sizeof(C.WGPUSurfaceDescriptorFromMetalLayer{}))))
  112. defer C.free(unsafe.Pointer(metalLayer))
  113. metalLayer.chain.next = nil
  114. metalLayer.chain.sType = C.WGPUSType_SurfaceDescriptorFromMetalLayer
  115. metalLayer.layer = descriptor.MetalLayer.Layer
  116. desc.nextInChain = (*C.WGPUChainedStruct)(unsafe.Pointer(metalLayer))
  117. }
  118. if descriptor.WaylandSurface != nil {
  119. waylandSurface := (*C.WGPUSurfaceDescriptorFromWaylandSurface)(C.malloc(C.size_t(unsafe.Sizeof(C.WGPUSurfaceDescriptorFromWaylandSurface{}))))
  120. defer C.free(unsafe.Pointer(waylandSurface))
  121. waylandSurface.chain.next = nil
  122. waylandSurface.chain.sType = C.WGPUSType_SurfaceDescriptorFromWaylandSurface
  123. waylandSurface.display = descriptor.WaylandSurface.Display
  124. waylandSurface.surface = descriptor.WaylandSurface.Surface
  125. desc.nextInChain = (*C.WGPUChainedStruct)(unsafe.Pointer(waylandSurface))
  126. }
  127. if descriptor.AndroidNativeWindow != nil {
  128. androidNativeWindow := (*C.WGPUSurfaceDescriptorFromAndroidNativeWindow)(C.malloc(C.size_t(unsafe.Sizeof(C.WGPUSurfaceDescriptorFromAndroidNativeWindow{}))))
  129. defer C.free(unsafe.Pointer(androidNativeWindow))
  130. androidNativeWindow.chain.next = nil
  131. androidNativeWindow.chain.sType = C.WGPUSType_SurfaceDescriptorFromAndroidNativeWindow
  132. androidNativeWindow.window = descriptor.AndroidNativeWindow.Window
  133. desc.nextInChain = (*C.WGPUChainedStruct)(unsafe.Pointer(androidNativeWindow))
  134. }
  135. }
  136. ref := C.wgpuInstanceCreateSurface(p.ref, &desc)
  137. if ref == nil {
  138. panic("Failed to acquire Surface")
  139. }
  140. return &Surface{ref: ref}
  141. }
  142. type requestAdapterCb func(status RequestAdapterStatus, adapter *Adapter, message string)
  143. //export gowebgpu_request_adapter_callback_go
  144. func gowebgpu_request_adapter_callback_go(status C.WGPURequestAdapterStatus, adapter C.WGPUAdapter, message *C.char, userdata unsafe.Pointer) {
  145. handle := *(*cgo.Handle)(userdata)
  146. defer handle.Delete()
  147. cb, ok := handle.Value().(requestAdapterCb)
  148. if ok {
  149. cb(RequestAdapterStatus(status), &Adapter{ref: adapter}, C.GoString(message))
  150. }
  151. }
  152. func (p *Instance) RequestAdapter(options *RequestAdapterOptions) (*Adapter, error) {
  153. var opts *C.WGPURequestAdapterOptions
  154. if options != nil {
  155. opts = &C.WGPURequestAdapterOptions{}
  156. if options.CompatibleSurface != nil {
  157. opts.compatibleSurface = options.CompatibleSurface.ref
  158. }
  159. opts.powerPreference = C.WGPUPowerPreference(options.PowerPreference)
  160. opts.forceFallbackAdapter = cBool(options.ForceFallbackAdapter)
  161. opts.backendType = C.WGPUBackendType(options.BackendType)
  162. }
  163. var status RequestAdapterStatus
  164. var adapter *Adapter
  165. var cb requestAdapterCb = func(s RequestAdapterStatus, a *Adapter, _ string) {
  166. status = s
  167. adapter = a
  168. }
  169. handle := cgo.NewHandle(cb)
  170. C.wgpuInstanceRequestAdapter(p.ref, opts, C.WGPUInstanceRequestAdapterCallback(C.gowebgpu_request_adapter_callback_c), unsafe.Pointer(&handle))
  171. if status != RequestAdapterStatusSuccess {
  172. return nil, errors.New("failed to request adapter")
  173. }
  174. return adapter, nil
  175. }
  176. func (p *Instance) EnumerateAdapters(options *InstanceEnumerateAdapterOptons) []*Adapter {
  177. var opts *C.WGPUInstanceEnumerateAdapterOptions
  178. if options != nil {
  179. opts = &C.WGPUInstanceEnumerateAdapterOptions{
  180. backends: C.WGPUInstanceBackendFlags(options.Backends),
  181. }
  182. }
  183. size := C.wgpuInstanceEnumerateAdapters(p.ref, opts, nil)
  184. if size == 0 {
  185. return nil
  186. }
  187. adapterRefs := make([]C.WGPUAdapter, size)
  188. C.wgpuInstanceEnumerateAdapters(p.ref, opts, (*C.WGPUAdapter)(unsafe.Pointer(&adapterRefs[0])))
  189. adapters := make([]*Adapter, size)
  190. for i, ref := range adapterRefs {
  191. adapters[i] = &Adapter{ref}
  192. }
  193. return adapters
  194. }
  195. type RegistryReport struct {
  196. NumAllocated uint64
  197. NumKeptFromUser uint64
  198. NumReleasedFromUser uint64
  199. NumError uint64
  200. ElementSize uint64
  201. }
  202. type HubReport struct {
  203. Adapters RegistryReport
  204. Devices RegistryReport
  205. PipelineLayouts RegistryReport
  206. ShaderModules RegistryReport
  207. BindGroupLayouts RegistryReport
  208. BindGroups RegistryReport
  209. CommandBuffers RegistryReport
  210. RenderBundles RegistryReport
  211. RenderPipelines RegistryReport
  212. ComputePipelines RegistryReport
  213. QuerySets RegistryReport
  214. Buffers RegistryReport
  215. Textures RegistryReport
  216. TextureViews RegistryReport
  217. Samplers RegistryReport
  218. }
  219. type GlobalReport struct {
  220. Surfaces RegistryReport
  221. Vulkan *HubReport
  222. Metal *HubReport
  223. Dx12 *HubReport
  224. Dx11 *HubReport
  225. Gl *HubReport
  226. }
  227. func (p *Instance) GenerateReport() GlobalReport {
  228. var r C.WGPUGlobalReport
  229. C.wgpuGenerateReport(p.ref, &r)
  230. mapRegistryReport := func(creport C.WGPURegistryReport) RegistryReport {
  231. return RegistryReport{
  232. NumAllocated: uint64(creport.numAllocated),
  233. NumKeptFromUser: uint64(creport.numKeptFromUser),
  234. NumReleasedFromUser: uint64(creport.numReleasedFromUser),
  235. NumError: uint64(creport.numError),
  236. ElementSize: uint64(creport.elementSize),
  237. }
  238. }
  239. mapHubReport := func(creport C.WGPUHubReport) *HubReport {
  240. return &HubReport{
  241. Adapters: mapRegistryReport(creport.adapters),
  242. Devices: mapRegistryReport(creport.devices),
  243. PipelineLayouts: mapRegistryReport(creport.pipelineLayouts),
  244. ShaderModules: mapRegistryReport(creport.shaderModules),
  245. BindGroupLayouts: mapRegistryReport(creport.bindGroupLayouts),
  246. BindGroups: mapRegistryReport(creport.bindGroups),
  247. CommandBuffers: mapRegistryReport(creport.commandBuffers),
  248. RenderBundles: mapRegistryReport(creport.renderBundles),
  249. RenderPipelines: mapRegistryReport(creport.renderPipelines),
  250. ComputePipelines: mapRegistryReport(creport.computePipelines),
  251. QuerySets: mapRegistryReport(creport.querySets),
  252. Buffers: mapRegistryReport(creport.buffers),
  253. Textures: mapRegistryReport(creport.textures),
  254. TextureViews: mapRegistryReport(creport.textureViews),
  255. Samplers: mapRegistryReport(creport.samplers),
  256. }
  257. }
  258. report := GlobalReport{
  259. Surfaces: mapRegistryReport(r.surfaces),
  260. }
  261. switch r.backendType {
  262. case C.WGPUBackendType_Vulkan:
  263. report.Vulkan = mapHubReport(r.vulkan)
  264. case C.WGPUBackendType_Metal:
  265. report.Metal = mapHubReport(r.metal)
  266. case C.WGPUBackendType_D3D12:
  267. report.Dx12 = mapHubReport(r.dx12)
  268. // TODO: no longer present in C API
  269. // case C.WGPUBackendType_D3D11:
  270. // report.Dx11 = mapHubReport(r.dx11)
  271. case C.WGPUBackendType_OpenGL:
  272. report.Gl = mapHubReport(r.gl)
  273. }
  274. return report
  275. }
  276. func (p *Instance) Release() {
  277. C.wgpuInstanceRelease(p.ref)
  278. }