mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 18:05:35 +00:00
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:
@@ -22,6 +22,10 @@ type size struct {
|
|||||||
Height unit.Value
|
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.
|
// Config describes a Window configuration.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// Size is the window dimensions (Width, Height).
|
// Size is the window dimensions (Width, Height).
|
||||||
|
|||||||
+17
-1
@@ -104,7 +104,13 @@ func mapErr(err error) error {
|
|||||||
// swapchain (preTransform != currentTransform). However, we don't
|
// swapchain (preTransform != currentTransform). However, we don't
|
||||||
// support transforming the output ourselves, so we'll live with it.
|
// support transforming the output ourselves, so we'll live with it.
|
||||||
return nil
|
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 gpu.ErrDeviceLost
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@@ -149,6 +155,16 @@ func (c *vkContext) refresh(surf vk.Surface, width, height int) error {
|
|||||||
vk.DeviceWaitIdle(c.dev)
|
vk.DeviceWaitIdle(c.dev)
|
||||||
|
|
||||||
c.destroyImageViews()
|
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)
|
swchain, imgs, format, err := vk.CreateSwapchain(c.physDev, c.dev, surf, width, height, c.swchain)
|
||||||
if c.swchain != 0 {
|
if c.swchain != 0 {
|
||||||
vk.DestroySwapchain(c.dev, c.swchain)
|
vk.DestroySwapchain(c.dev, c.swchain)
|
||||||
|
|||||||
@@ -57,7 +57,9 @@ func (c *wlVkContext) API() gpu.API {
|
|||||||
|
|
||||||
func (c *wlVkContext) Release() {
|
func (c *wlVkContext) Release() {
|
||||||
c.ctx.release()
|
c.ctx.release()
|
||||||
|
if c.surf != 0 {
|
||||||
vk.DestroySurface(c.inst, c.surf)
|
vk.DestroySurface(c.inst, c.surf)
|
||||||
|
}
|
||||||
vk.DestroyInstance(c.inst)
|
vk.DestroyInstance(c.inst)
|
||||||
*c = wlVkContext{}
|
*c = wlVkContext{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,6 +152,11 @@ func (w *Window) validateAndProcess(frameStart time.Time, size image.Point, sync
|
|||||||
err = w.ctx.Refresh()
|
err = w.ctx.Refresh()
|
||||||
})
|
})
|
||||||
if err != nil {
|
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()
|
w.destroyGPU()
|
||||||
if errors.Is(err, gpu.ErrDeviceLost) {
|
if errors.Is(err, gpu.ErrDeviceLost) {
|
||||||
continue
|
continue
|
||||||
@@ -174,6 +179,11 @@ func (w *Window) validateAndProcess(frameStart time.Time, size image.Point, sync
|
|||||||
}
|
}
|
||||||
if w.gpu != nil {
|
if w.gpu != nil {
|
||||||
if err := w.render(frame, size); err != nil {
|
if err := w.render(frame, size); err != nil {
|
||||||
|
if errors.Is(err, errOutOfDate) {
|
||||||
|
// GPU surface needs refreshing.
|
||||||
|
sync = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
w.destroyGPU()
|
w.destroyGPU()
|
||||||
if errors.Is(err, gpu.ErrDeviceLost) {
|
if errors.Is(err, gpu.ErrDeviceLost) {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -1110,7 +1110,7 @@ func formatFor(format driver.TextureFormat) vk.Format {
|
|||||||
|
|
||||||
func mapErr(err error) error {
|
func mapErr(err error) error {
|
||||||
var vkErr vk.Error
|
var vkErr vk.Error
|
||||||
if errors.As(err, &vkErr) && vkErr.IsDeviceLost() {
|
if errors.As(err, &vkErr) && vkErr == vk.ERROR_DEVICE_LOST {
|
||||||
return driver.ErrDeviceLost
|
return driver.ErrDeviceLost
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
|||||||
+20
-11
@@ -380,6 +380,7 @@ import "C"
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"math"
|
"math"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -442,6 +443,7 @@ type (
|
|||||||
WriteDescriptorSet = C.VkWriteDescriptorSet
|
WriteDescriptorSet = C.VkWriteDescriptorSet
|
||||||
|
|
||||||
Surface = C.VkSurfaceKHR
|
Surface = C.VkSurfaceKHR
|
||||||
|
SurfaceCapabilities = C.VkSurfaceCapabilitiesKHR
|
||||||
|
|
||||||
Swapchain = C.VkSwapchainKHR
|
Swapchain = C.VkSwapchainKHR
|
||||||
)
|
)
|
||||||
@@ -939,11 +941,19 @@ func GetDeviceQueue(d Device, queueFamily, queueIndex int) Queue {
|
|||||||
return queue
|
return queue
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateSwapchain(pd PhysicalDevice, d Device, surf Surface, width, height int, old Swapchain) (Swapchain, []Image, Format, error) {
|
func GetPhysicalDeviceSurfaceCapabilities(pd PhysicalDevice, surf Surface) (SurfaceCapabilities, error) {
|
||||||
var caps C.VkSurfaceCapabilitiesKHR
|
var caps C.VkSurfaceCapabilitiesKHR
|
||||||
err := vkErr(C.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(funcs.vkGetPhysicalDeviceSurfaceCapabilitiesKHR, pd, surf, &caps))
|
err := vkErr(C.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(funcs.vkGetPhysicalDeviceSurfaceCapabilitiesKHR, pd, surf, &caps))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nilSwapchain, nil, 0, fmt.Errorf("vulkan: vkGetPhysicalDeviceSurfaceCapabilitiesKHR: %w", err)
|
return SurfaceCapabilities{}, fmt.Errorf("vulkan: vkGetPhysicalDeviceSurfaceCapabilitiesKHR: %w", err)
|
||||||
|
}
|
||||||
|
return caps, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateSwapchain(pd PhysicalDevice, d Device, surf Surface, width, height int, old Swapchain) (Swapchain, []Image, Format, error) {
|
||||||
|
caps, err := GetPhysicalDeviceSurfaceCapabilities(pd, surf)
|
||||||
|
if err != nil {
|
||||||
|
return nilSwapchain, nil, 0, err
|
||||||
}
|
}
|
||||||
mode, modeOK, err := choosePresentMode(pd, surf)
|
mode, modeOK, err := choosePresentMode(pd, surf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1846,6 +1856,14 @@ func (p QueueFamilyProperties) Flags() QueueFlags {
|
|||||||
return p.queueFlags
|
return p.queueFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c SurfaceCapabilities) MinExtent() image.Point {
|
||||||
|
return image.Pt(int(c.minImageExtent.width), int(c.minImageExtent.height))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c SurfaceCapabilities) MaxExtent() image.Point {
|
||||||
|
return image.Pt(int(c.maxImageExtent.width), int(c.maxImageExtent.height))
|
||||||
|
}
|
||||||
|
|
||||||
func BuildViewport(x, y, width, height float32) Viewport {
|
func BuildViewport(x, y, width, height float32) Viewport {
|
||||||
return C.VkViewport{
|
return C.VkViewport{
|
||||||
x: C.float(x),
|
x: C.float(x),
|
||||||
@@ -2048,12 +2066,3 @@ func vkErr(res C.VkResult) error {
|
|||||||
func (e Error) Error() string {
|
func (e Error) Error() string {
|
||||||
return fmt.Sprintf("error %d", e)
|
return fmt.Sprintf("error %d", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Error) IsDeviceLost() bool {
|
|
||||||
switch e {
|
|
||||||
case ERROR_OUT_OF_DATE_KHR, ERROR_SURFACE_LOST_KHR, ERROR_DEVICE_LOST:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user