vulkan.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. // SPDX-License-Identifier: Unlicense OR MIT
  2. //go:build (linux || freebsd) && !novulkan
  3. // +build linux freebsd
  4. // +build !novulkan
  5. package app
  6. import (
  7. "errors"
  8. "unsafe"
  9. "gioui.org/gpu"
  10. "gioui.org/internal/vk"
  11. )
  12. type vkContext struct {
  13. physDev vk.PhysicalDevice
  14. inst vk.Instance
  15. dev vk.Device
  16. queueFam int
  17. queue vk.Queue
  18. acquireSem vk.Semaphore
  19. presentSem vk.Semaphore
  20. fence vk.Fence
  21. swchain vk.Swapchain
  22. imgs []vk.Image
  23. views []vk.ImageView
  24. fbos []vk.Framebuffer
  25. format vk.Format
  26. presentIdx int
  27. }
  28. func newVulkanContext(inst vk.Instance, surf vk.Surface) (*vkContext, error) {
  29. physDev, qFam, err := vk.ChoosePhysicalDevice(inst, surf)
  30. if err != nil {
  31. return nil, err
  32. }
  33. dev, err := vk.CreateDeviceAndQueue(physDev, qFam, "VK_KHR_swapchain")
  34. if err != nil {
  35. return nil, err
  36. }
  37. acquireSem, err := vk.CreateSemaphore(dev)
  38. if err != nil {
  39. vk.DestroyDevice(dev)
  40. return nil, err
  41. }
  42. presentSem, err := vk.CreateSemaphore(dev)
  43. if err != nil {
  44. vk.DestroySemaphore(dev, acquireSem)
  45. vk.DestroyDevice(dev)
  46. return nil, err
  47. }
  48. fence, err := vk.CreateFence(dev, vk.FENCE_CREATE_SIGNALED_BIT)
  49. if err != nil {
  50. vk.DestroySemaphore(dev, presentSem)
  51. vk.DestroySemaphore(dev, acquireSem)
  52. vk.DestroyDevice(dev)
  53. return nil, err
  54. }
  55. c := &vkContext{
  56. physDev: physDev,
  57. inst: inst,
  58. dev: dev,
  59. queueFam: qFam,
  60. queue: vk.GetDeviceQueue(dev, qFam, 0),
  61. acquireSem: acquireSem,
  62. presentSem: presentSem,
  63. fence: fence,
  64. }
  65. return c, nil
  66. }
  67. func (c *vkContext) RenderTarget() (gpu.RenderTarget, error) {
  68. vk.WaitForFences(c.dev, c.fence)
  69. vk.ResetFences(c.dev, c.fence)
  70. imgIdx, err := vk.AcquireNextImage(c.dev, c.swchain, c.acquireSem, 0)
  71. if err := mapSurfaceErr(err); err != nil {
  72. return nil, err
  73. }
  74. c.presentIdx = imgIdx
  75. return gpu.VulkanRenderTarget{
  76. WaitSem: uint64(c.acquireSem),
  77. SignalSem: uint64(c.presentSem),
  78. Fence: uint64(c.fence),
  79. Framebuffer: uint64(c.fbos[imgIdx]),
  80. Image: uint64(c.imgs[imgIdx]),
  81. }, nil
  82. }
  83. func (c *vkContext) api() gpu.API {
  84. return gpu.Vulkan{
  85. PhysDevice: unsafe.Pointer(c.physDev),
  86. Device: unsafe.Pointer(c.dev),
  87. Format: int(c.format),
  88. QueueFamily: c.queueFam,
  89. QueueIndex: 0,
  90. }
  91. }
  92. func mapErr(err error) error {
  93. var vkErr vk.Error
  94. if errors.As(err, &vkErr) && vkErr == vk.ERROR_DEVICE_LOST {
  95. return gpu.ErrDeviceLost
  96. }
  97. return err
  98. }
  99. func mapSurfaceErr(err error) error {
  100. var vkErr vk.Error
  101. if !errors.As(err, &vkErr) {
  102. return err
  103. }
  104. switch {
  105. case vkErr == vk.SUBOPTIMAL_KHR:
  106. // Android reports VK_SUBOPTIMAL_KHR when presenting to a rotated
  107. // swapchain (preTransform != currentTransform). However, we don't
  108. // support transforming the output ourselves, so we'll live with it.
  109. return nil
  110. case vkErr == vk.ERROR_OUT_OF_DATE_KHR:
  111. return errOutOfDate
  112. case vkErr == vk.ERROR_SURFACE_LOST_KHR:
  113. // Treating a lost surface as a lost device isn't accurate, but
  114. // probably not worth optimizing.
  115. return gpu.ErrDeviceLost
  116. }
  117. return mapErr(err)
  118. }
  119. func (c *vkContext) release() {
  120. vk.DeviceWaitIdle(c.dev)
  121. c.destroySwapchain()
  122. vk.DestroyFence(c.dev, c.fence)
  123. vk.DestroySemaphore(c.dev, c.acquireSem)
  124. vk.DestroySemaphore(c.dev, c.presentSem)
  125. vk.DestroyDevice(c.dev)
  126. *c = vkContext{}
  127. }
  128. func (c *vkContext) present() error {
  129. return mapSurfaceErr(vk.PresentQueue(c.queue, c.swchain, c.presentSem, c.presentIdx))
  130. }
  131. func (c *vkContext) destroyImageViews() {
  132. for _, f := range c.fbos {
  133. vk.DestroyFramebuffer(c.dev, f)
  134. }
  135. c.fbos = nil
  136. for _, view := range c.views {
  137. vk.DestroyImageView(c.dev, view)
  138. }
  139. c.views = nil
  140. }
  141. func (c *vkContext) destroySwapchain() {
  142. vk.DeviceWaitIdle(c.dev)
  143. c.destroyImageViews()
  144. if c.swchain != 0 {
  145. vk.DestroySwapchain(c.dev, c.swchain)
  146. c.swchain = 0
  147. }
  148. }
  149. func (c *vkContext) refresh(surf vk.Surface, width, height int) error {
  150. vk.DeviceWaitIdle(c.dev)
  151. c.destroyImageViews()
  152. // Check whether size is valid. That's needed on X11, where ConfigureNotify
  153. // is not always synchronized with the window extent.
  154. caps, err := vk.GetPhysicalDeviceSurfaceCapabilities(c.physDev, surf)
  155. if err != nil {
  156. return err
  157. }
  158. minExt, maxExt := vk.SurfaceCapabilitiesMinExtent(caps), vk.SurfaceCapabilitiesMaxExtent(caps)
  159. if width < minExt.X || maxExt.X < width || height < minExt.Y || maxExt.Y < height {
  160. return errOutOfDate
  161. }
  162. swchain, imgs, format, err := vk.CreateSwapchain(c.physDev, c.dev, surf, width, height, c.swchain)
  163. if c.swchain != 0 {
  164. vk.DestroySwapchain(c.dev, c.swchain)
  165. c.swchain = 0
  166. }
  167. if err := mapSurfaceErr(err); err != nil {
  168. return err
  169. }
  170. c.swchain = swchain
  171. c.imgs = imgs
  172. c.format = format
  173. pass, err := vk.CreateRenderPass(
  174. c.dev,
  175. format,
  176. vk.ATTACHMENT_LOAD_OP_CLEAR,
  177. vk.IMAGE_LAYOUT_UNDEFINED,
  178. vk.IMAGE_LAYOUT_PRESENT_SRC_KHR,
  179. nil,
  180. )
  181. if err := mapErr(err); err != nil {
  182. return err
  183. }
  184. defer vk.DestroyRenderPass(c.dev, pass)
  185. for _, img := range imgs {
  186. view, err := vk.CreateImageView(c.dev, img, format)
  187. if err := mapErr(err); err != nil {
  188. return err
  189. }
  190. c.views = append(c.views, view)
  191. fbo, err := vk.CreateFramebuffer(c.dev, pass, view, width, height)
  192. if err := mapErr(err); err != nil {
  193. return err
  194. }
  195. c.fbos = append(c.fbos, fbo)
  196. }
  197. return nil
  198. }