fix(window): the destructor cancels the frame callback; a window without a display or swapchain
wl_surface_frame_done re-armed the frame callback through its local and left the member stale, so the destructor could not cancel it and a done already queued would dispatch into the freed window; the member now names the live callback and the destructor destroys it. The destructor also flushed a null display for a window created without Device::Initialize (tests do that) and freed never-created command buffers (a default-constructed Window after Initialize); both guarded. And wp_scale was one inline static for every window, which the destructor destroyed on behalf of all of them: it is a member now, like the viewport.
This commit is contained in:
parent
cc04d4e121
commit
c8b5739e1a
2 changed files with 12 additions and 10 deletions
|
|
@ -521,7 +521,7 @@ Window::~Window() {
|
|||
// Nothing may still run against the semaphores, fences or images below.
|
||||
if (Device::device != VK_NULL_HANDLE) vkDeviceWaitIdle(Device::device);
|
||||
if (Device::device != VK_NULL_HANDLE) {
|
||||
vkFreeCommandBuffers(Device::device, Device::commandPool, numFrames, drawCmdBuffers);
|
||||
if (drawCmdBuffers[0] != VK_NULL_HANDLE) vkFreeCommandBuffers(Device::device, Device::commandPool, numFrames, drawCmdBuffers);
|
||||
for (std::uint8_t i = 0; i < numFrames; i++) {
|
||||
if (renderFinishedSemaphores[i]) vkDestroySemaphore(Device::device, renderFinishedSemaphores[i], nullptr);
|
||||
if (waitFences[i]) vkDestroyFence(Device::device, waitFences[i], nullptr);
|
||||
|
|
@ -537,9 +537,10 @@ Window::~Window() {
|
|||
|
||||
#ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND
|
||||
SetDefaultCursor();
|
||||
// `cb` is not destroyed here: wl_surface_frame_done frees the callback it
|
||||
// was called with and re-arms through its own local, so the member may
|
||||
// already name a freed one.
|
||||
// A pending frame callback would still dispatch into this window;
|
||||
// destroying the proxy makes libwayland drop its event.
|
||||
if (cb) wl_callback_destroy(cb);
|
||||
cb = nullptr;
|
||||
if (wpViewport) wp_viewport_destroy(wpViewport);
|
||||
if (wp_scale) {
|
||||
wp_fractional_scale_v1_destroy(wp_scale);
|
||||
|
|
@ -554,7 +555,7 @@ Window::~Window() {
|
|||
xdgToplevel = nullptr;
|
||||
xdgSurface = nullptr;
|
||||
surface = nullptr;
|
||||
wl_display_flush(Device::display);
|
||||
if (Device::display) wl_display_flush(Device::display);
|
||||
std::erase(Device::windows, this);
|
||||
if (Device::focusedWindow == this) Device::focusedWindow = nullptr;
|
||||
if (Device::keyboardWindow == this) Device::keyboardWindow = nullptr;
|
||||
|
|
@ -1299,12 +1300,13 @@ void Window::wl_surface_frame_done(void* data, struct wl_callback *cb, uint32_t
|
|||
wl_callback_destroy(cb);
|
||||
Window* window = reinterpret_cast<Window*>(data);
|
||||
|
||||
// The member names the live callback, so the destructor can cancel it.
|
||||
if(window->updating) {
|
||||
cb = wl_surface_frame(window->surface);
|
||||
wl_callback_add_listener(cb, &Window::wl_callback_listener, window);
|
||||
window->cb = wl_surface_frame(window->surface);
|
||||
wl_callback_add_listener(window->cb, &Window::wl_callback_listener, window);
|
||||
window->Update();
|
||||
} else {
|
||||
cb = nullptr;
|
||||
window->cb = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue