neovide 0.16.2

Neovide: No Nonsense Neovim Gui
use std::{
    sync::mpsc::{Sender, channel},
    thread::{JoinHandle, spawn},
};

use windows::Win32::Foundation::HANDLE;
use windows::Win32::System::Threading::WaitForSingleObjectEx;

use winit::event_loop::EventLoopProxy;

use crate::{
    profiling::tracy_zone,
    window::{EventPayload, UserEvent},
};

enum Message {
    RequestRedraw,
    Quit,
}

struct SwapChainHandle {
    handle: HANDLE,
}

unsafe impl Send for SwapChainHandle {}
unsafe impl Sync for SwapChainHandle {}

pub struct VSyncWinSwapChain {
    vsync_thread: Option<JoinHandle<()>>,
    sender: Sender<Message>,
}

impl VSyncWinSwapChain {
    pub fn new(proxy: EventLoopProxy<EventPayload>, swap_chain_waitable: HANDLE) -> Self {
        let handle = SwapChainHandle { handle: swap_chain_waitable };
        let (sender, receiver) = channel();
        let vsync_thread = spawn(move || {
            // Removing this asignment causes a build failure complaining that
            // `*mut c_void` cannot be sent between threads safely.
            #[allow(clippy::redundant_locals)]
            let handle = handle;
            while let Ok(Message::RequestRedraw) = receiver.recv() {
                tracy_zone!("wait for vblank");
                unsafe {
                    WaitForSingleObjectEx(handle.handle, 1000, true);
                }
                proxy.send_event(EventPayload::all(UserEvent::RedrawRequested)).ok();
            }
        });
        Self { vsync_thread: Some(vsync_thread), sender }
    }

    pub fn wait_for_vsync(&mut self) {}

    pub fn request_redraw(&mut self) {
        self.sender.send(Message::RequestRedraw).ok();
    }
}

impl Drop for VSyncWinSwapChain {
    fn drop(&mut self) {
        self.sender.send(Message::Quit).ok();
        self.vsync_thread.take().unwrap().join().unwrap();
    }
}