diff --git a/cmd/main.go b/cmd/main.go index db4f18c..4123dfd 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -164,7 +164,6 @@ func main() { GraphicsFamily: gfx, Extensions: []string{"VK_KHR_swapchain"}, }) - fmt.Println("vkQueue=", vkQueue) if err != nil { panic(err) } @@ -208,92 +207,119 @@ func main() { if err != nil { panic(err.Error()) } - fmt.Println(vkCommands) - defer vkDevice.WaitIdle() - // Vulkan Surface Capabilities - caps, err := vkPhysDevice.SurfaceCapabilities(vkSurf) - if err != nil { - panic(err.Error()) - } - //compute swapchain extent - var w, h int32 = WIN_WIDTH, WIN_HEIGHT - if !sdlGetWindowSizeInPixels(windowHandler, &w, &h) { - log.Fatalf("SDL_GetWindowSizeInPixels: %s", sdlError()) - } - if w < int32(caps.MinImageExtent.Width) { - w = int32(caps.MinImageExtent.Width) - } - if h < int32(caps.MinImageExtent.Height) { - h = int32(caps.MinImageExtent.Height) - } - if w > int32(caps.MaxImageExtent.Width) { - w = int32(caps.MaxImageExtent.Width) - } - if h > int32(caps.MaxImageExtent.Height) { - h = int32(caps.MaxImageExtent.Height) - } - vkExtent := vk.Extent2D{Width: uint32(w), Height: uint32(h)} - // Vulkan swapchain (pool of presentable images, that OS and GPU share) - vkSwapchain, err := vkDevice.CreateSwapchain(vk.SwapchainConfig{ - Surface: vkSurf, - MinImageCount: caps.MinImageCount, - Format: vkFormat, - ColorSpace: vkColorSpace, - Extent: vkExtent, - PresentMode: vkPresentMode, - PreTransform: caps.CurrentTransform, - }) - if err != nil { - panic(err.Error()) - } - defer vkDevice.DestroySwapchain(vkSwapchain) - swapImages, err := vkDevice.SwapchainImages(vkSwapchain) - if err != nil { - panic(err.Error()) - } - // one image view per swapchain. Image = raw GPU memory with a format - swapViews := make([]vk.ImageView, len(swapImages)) - for i, img := range swapImages { - v, err := vkDevice.CreateImageView(img, vkFormat, vk.AspectColor) - if err != nil { - panic(err.Error()) - } - swapViews[i] = v - } - defer func() { - for _, v := range swapViews { - vkDevice.DestroyImageView(v) - } - }() - // depth image + view - depthImg, err := vkDevice.CreateImage2D( - vkPhysDevice, vk.FormatD32Sfloat, vkExtent, vk.ImageUsageDepthStencilAttachment) - if err != nil { - panic(err.Error()) - } - defer vkDevice.DestroyImage(depthImg) - - depthView, err := vkDevice.CreateImageView(depthImg.Image, vk.FormatD32Sfloat, vk.AspectDepth) - if err != nil { - panic(err.Error()) - } - defer vkDevice.DestroyImageView(depthView) - - // frame buffer i.e. binding between RenderPass and actual ImageViews - fbs := make([]vk.Framebuffer, len(swapViews)) - for i, cv := range swapViews { - fb, err := vkDevice.CreateFramebuffer(vkRenderPass, []vk.ImageView{cv, depthView}, vkExtent) - if err != nil { - panic(err.Error()) - } - fbs[i] = fb - } - defer func() { + var ( + vkExtent vk.Extent2D + vkSwapchain vk.SwapchainKHR + swapImages []vk.Image + swapViews []vk.ImageView + depthImg vk.AllocImage + depthView vk.ImageView + fbs []vk.Framebuffer + ) + destroySwapChain := func() { for _, fb := range fbs { vkDevice.DestroyFramebuffer(fb) } - }() + vkDevice.DestroyImageView(depthView) + vkDevice.DestroyImage(depthImg) + for _, v := range swapViews { + vkDevice.DestroyImageView(v) + } + vkDevice.DestroySwapchain(vkSwapchain) + fbs = nil + swapViews = nil + swapImages = nil + depthView = 0 + depthImg = vk.AllocImage{} + vkSwapchain = 0 + vkExtent = vk.Extent2D{} + } + createSwapChain := func() (err error) { + defer func() { + if err != nil { + destroySwapChain() + } + }() + caps, err := vkPhysDevice.SurfaceCapabilities(vkSurf) + if err != nil { + return err + } + //compute swapchain extent + var w, h int32 = WIN_WIDTH, WIN_HEIGHT + if !sdlGetWindowSizeInPixels(windowHandler, &w, &h) { + return fmt.Errorf("SDL_GetWindowSizeInPixels: %s", sdlError()) + } + if w < int32(caps.MinImageExtent.Width) { + w = int32(caps.MinImageExtent.Width) + } + if h < int32(caps.MinImageExtent.Height) { + h = int32(caps.MinImageExtent.Height) + } + if w > int32(caps.MaxImageExtent.Width) { + w = int32(caps.MaxImageExtent.Width) + } + if h > int32(caps.MaxImageExtent.Height) { + h = int32(caps.MaxImageExtent.Height) + } + vkExtent = vk.Extent2D{Width: uint32(w), Height: uint32(h)} + + vkSwapchain, err = vkDevice.CreateSwapchain(vk.SwapchainConfig{ + Surface: vkSurf, + MinImageCount: caps.MinImageCount, + Format: vkFormat, + ColorSpace: vkColorSpace, + Extent: vkExtent, + PresentMode: vkPresentMode, + PreTransform: caps.CurrentTransform, + }) + if err != nil { + return err + } + swapImages, err = vkDevice.SwapchainImages(vkSwapchain) + if err != nil { + return err + } + swapViews = make([]vk.ImageView, len(swapImages)) + for i, img := range swapImages { + v, err := vkDevice.CreateImageView(img, vkFormat, vk.AspectColor) + if err != nil { + return err + } + swapViews[i] = v + } + depthImg, err = vkDevice.CreateImage2D( + vkPhysDevice, vk.FormatD32Sfloat, vkExtent, vk.ImageUsageDepthStencilAttachment) + if err != nil { + return err + } + depthView, err = vkDevice.CreateImageView(depthImg.Image, vk.FormatD32Sfloat, vk.AspectDepth) + if err != nil { + return err + } + fbs = make([]vk.Framebuffer, len(swapViews)) + for i, cv := range swapViews { + fb, err := vkDevice.CreateFramebuffer(vkRenderPass, []vk.ImageView{cv, depthView}, vkExtent) + if err != nil { + return err + } + fbs[i] = fb + } + return nil + } + recreateSwapChain := func() error { + if err := vkDevice.WaitIdle(); err != nil { + return err + } + destroySwapChain() + return createSwapChain() + } + + if err := createSwapChain(); err != nil { + panic(err) + } + defer destroySwapChain() + // syncs // Semaphores sync GPU work to GPU work (you never wait on these from the CPU). You need two: // - imageAvailable — AcquireNextImage signals it when a swapchain image is ready to render into. @@ -322,6 +348,7 @@ func main() { panic(err.Error()) } defer vkDevice.DestroyFence(inFlight) + defer vkDevice.WaitIdle() // Core Loop running := true @@ -338,6 +365,12 @@ func main() { } // Acquire the next swapchain image imageIndex, r := vkDevice.AcquireNextImage(vkSwapchain, imageAvailable, ^uint64(0)) + if r == vk.ErrorOutOfDateKHR || r == vk.SuboptimalKHR { + if err := recreateSwapChain(); err != nil { + panic(err) + } + continue + } if !r.Ok() { panic(fmt.Errorf("acquire: %v", r)) } @@ -383,14 +416,13 @@ func main() { // Present. Wait on renderFinished r = vkQueue.Present(vkSwapchain, imageIndex, renderFinished) if r == vk.ErrorOutOfDateKHR || r == vk.SuboptimalKHR { - break + if err := recreateSwapChain(); err != nil { + panic(err) + } + continue } if !r.Ok() { panic(fmt.Errorf("present: %v", r)) } - // Make sure GPU is idle before any deferred destruction runs - if err := vkDevice.WaitIdle(); err != nil { - panic(err) - } } } diff --git a/main b/main index 084c072..d16ca95 100755 Binary files a/main and b/main differ