由于生命周期限制,无法创建 wgpu 表面

问题描述 投票:0回答:1

我正在将一个项目更新到最新的 WGPU 版本,该版本向

wgpu::Surface<'window>
添加了一个生命周期参数,这导致我在窗口初始化时暴露的特征 winit 上出现问题
winit::application::ApplicationHandler

问题的较小版本如下:

use wgpu::{Dx12Compiler, Gles3MinorVersion, Instance, InstanceDescriptor, InstanceFlags, Surface};
use winit::{
    application::ApplicationHandler,
    event_loop::EventLoop,
    window::{Window, WindowAttributes},
};

struct Application<'a> {
    event_loop: EventLoop<()>,
    window: Option<Window>,
    surface: Option<Surface<'a>>,
}

impl<'a> ApplicationHandler for Application<'a> {
    fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
        if self.window.is_none() {
            self.window = Some(
                event_loop
                    .create_window(WindowAttributes::default())
                    .unwrap(),
            );
            let instance_descriptor = InstanceDescriptor {
                backends: wgpu::Backends::VULKAN,
                flags: InstanceFlags::default(),
                dx12_shader_compiler: Dx12Compiler::Fxc,
                gles_minor_version: Gles3MinorVersion::Automatic,
            };
            let instance = Instance::new(instance_descriptor);
            self.surface = Some(
                instance
                    .create_surface(self.window.as_ref().unwrap())
                    .unwrap(),
            );
        }
    }

    fn window_event(
        &mut self,
        event_loop: &winit::event_loop::ActiveEventLoop,
        window_id: winit::window::WindowId,
        event: winit::event::WindowEvent,
    ) {
    }
}

上面的代码产生

lifetime may not live long enough
引用
self.surface = Some(...)
,注意到
&mut self
的隐式生命周期不能保证与
'a

一样长

我无法用像

resumed<'b: 'a>(&'b mut self, ...)
这样的生命周期边界来增强恢复的特征方法,所以我找不到协调生命周期的方法。

我也尝试过这样构造类型

struct Inner<'a> {
    window: Window,
    surface: Option<Surface<'a>>
}

struct Outer<'a> {
    event_loop: EventLoop<()>,
    inner: Option<Inner<'a>>,
}

这让我合理化认为窗口的生命周期保证与表面的生命周期一样长,但这显然不会改变编译器错误,并且增加了循环引用的问题。

所以我的问题是:鉴于

ApplicationHandler::resumed
的签名和生命周期要求,我们如何创建 wgpu 表面?

rust wgpu-rs winit
1个回答
0
投票

您已经正确地观察到您有一种循环引用(“自引用结构”)。解决方法是使其成为非圆形:

         ┌────→ Surface ──┐
Application               ├─→ Window
         └────────────────┘ 

您可以通过使用

Arc
创建窗口的共享所有权来完成此操作。

struct Application {
    window: Option<Arc<Window>>,
    surface: Option<Surface<'static>>,
}

impl ApplicationHandler for Application {
    fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
        if self.window.is_none() {
            let window = Arc::new(
                event_loop
                    .create_window(WindowAttributes::default())
                    .unwrap(),
            );
            self.window = Some(window.clone()); // clone to share
            let instance = Instance::new(...);
            self.surface = Some(
                instance
                    .create_surface(window) // do not use as_ref
                    .unwrap(),
            );
        }
    }

当您将

Arc<Window>
而不是
&'a Window
传递给
create_surface()
时,返回的
Surface
没有任何生命周期限制,可以存储为
Surface<'static>

另请注意,虽然这不是您提出的问题的一部分,但您不得尝试将

EventLoop
存储在
Application
结构中。 一开始就被消耗了,你再也抓不住了。

© www.soinside.com 2019 - 2024. All rights reserved.