Невозможно создать поверхность wgpu из-за ограничения срока службы

Я обновляю проект до новейшей версии 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?

Полное сообщение об ошибке

error: lifetime may not live long enough
  --> src\main.rs:68:13
   |
53 | impl<'a> ApplicationHandler for Application<'a> {
   |      -- lifetime `'a` defined here
54 |     fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
   |                - let's call the lifetime of this reference `'1`
...
68 |             self.surface = Some(
   |             ^^^^^^^^^^^^ assignment requires that `'1` must outlive `'a`
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
0
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы правильно заметили, что у вас есть своего рода циклическая ссылка («самоссылающаяся структура»). Исправление состоит в том, чтобы сделать его некруглым:

         ┌────→ 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 структуре. ‼Оно расходуется, когда начинаешь и ты уже не можешь его удержать.

Спасибо, Кевин, это сработало! Что касается цикла событий, я ценю дополнение; ранее я сохранял его в опции и принимал() перед его запуском, но создание его перед запуском имеет больше смысла

loaner9 10.07.2024 16:52

Другие вопросы по теме