app,internal/vk: [Vulkan] skip frame with stale window dimensions

While here, add a missing nil check.

Updates gio#280

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2021-09-30 17:21:52 +02:00
parent 9e8fe5305b
commit 6c1f9c19f5
6 changed files with 56 additions and 15 deletions
+4
View File
@@ -22,6 +22,10 @@ type size struct {
Height unit.Value
}
// errOutOfDate is reported when the GPU surface dimensions or properties no
// longer match the window.
var errOutOfDate = errors.New("app: GPU surface out of date")
// Config describes a Window configuration.
type Config struct {
// Size is the window dimensions (Width, Height).
+17 -1
View File
@@ -104,7 +104,13 @@ func mapErr(err error) error {
// swapchain (preTransform != currentTransform). However, we don't
// support transforming the output ourselves, so we'll live with it.
return nil
case vkErr.IsDeviceLost():
case vkErr == vk.ERROR_OUT_OF_DATE_KHR:
return errOutOfDate
case vkErr == vk.ERROR_SURFACE_LOST_KHR:
// Treating a lost surface as a lost device isn't accurate, but
// porbably not worth optimizing.
return gpu.ErrDeviceLost
case vkErr == vk.ERROR_DEVICE_LOST:
return gpu.ErrDeviceLost
}
return err
@@ -149,6 +155,16 @@ func (c *vkContext) refresh(surf vk.Surface, width, height int) error {
vk.DeviceWaitIdle(c.dev)
c.destroyImageViews()
// Check whether size is valid. That's needed on X11, where ConfigureNotify
// is not always synchronized with the window extent.
caps, err := vk.GetPhysicalDeviceSurfaceCapabilities(c.physDev, surf)
if err != nil {
return err
}
minExt, maxExt := caps.MinExtent(), caps.MaxExtent()
if width < minExt.X || maxExt.X < width || height < minExt.Y || maxExt.Y < height {
return errOutOfDate
}
swchain, imgs, format, err := vk.CreateSwapchain(c.physDev, c.dev, surf, width, height, c.swchain)
if c.swchain != 0 {
vk.DestroySwapchain(c.dev, c.swchain)
+3 -1
View File
@@ -57,7 +57,9 @@ func (c *wlVkContext) API() gpu.API {
func (c *wlVkContext) Release() {
c.ctx.release()
vk.DestroySurface(c.inst, c.surf)
if c.surf != 0 {
vk.DestroySurface(c.inst, c.surf)
}
vk.DestroyInstance(c.inst)
*c = wlVkContext{}
}
+10
View File
@@ -152,6 +152,11 @@ func (w *Window) validateAndProcess(frameStart time.Time, size image.Point, sync
err = w.ctx.Refresh()
})
if err != nil {
if errors.Is(err, errOutOfDate) {
// Surface couldn't be created for transient reasons. Skip
// this frame and wait for the next.
return nil
}
w.destroyGPU()
if errors.Is(err, gpu.ErrDeviceLost) {
continue
@@ -174,6 +179,11 @@ func (w *Window) validateAndProcess(frameStart time.Time, size image.Point, sync
}
if w.gpu != nil {
if err := w.render(frame, size); err != nil {
if errors.Is(err, errOutOfDate) {
// GPU surface needs refreshing.
sync = true
continue
}
w.destroyGPU()
if errors.Is(err, gpu.ErrDeviceLost) {
continue