Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Surface configuration Validation Error #5823

Open
StepingForward opened this issue Jun 16, 2024 · 6 comments
Open

Surface configuration Validation Error #5823

StepingForward opened this issue Jun 16, 2024 · 6 comments

Comments

@StepingForward
Copy link

StepingForward commented Jun 16, 2024

Description
I am using glfw and wgpu(following this tutorial: https://www.youtube.com/watch?v=DGPrn5qCI_c), for some reason when I run the code I get a validation error:

Error in Surface::configure: Validation Error

Caused by:
    Invalid surface

The code:

use glfw::{
    fail_on_errors, 
    Action, 
    Context, 
    Key,
    Window
};
use wgpu::core::command;

struct State <'s>{
    instance: wgpu::Instance,
    surface: wgpu::Surface<'s>,
    device: wgpu::Device,
    queue: wgpu::Queue,
    config: wgpu::SurfaceConfiguration,
    size: (i32, i32),
    window: &'s mut Window,
}

impl<'s> State<'s>{
    async fn new(window: &'s mut Window) -> Self{
        let size = window.get_size();

        let instance_descriptor = wgpu::InstanceDescriptor{
            backends: wgpu::Backends::PRIMARY, ..Default::default()
        };

        let instance = wgpu::Instance::new(instance_descriptor);

        //Unsafe surface... spooky :0 No.1
        let target = unsafe {
            wgpu::SurfaceTargetUnsafe::from_window(&window)
        }.unwrap();
        let surface = unsafe {
            instance.create_surface_unsafe(target)
        }.unwrap();

        let adapter_descriptor = wgpu::RequestAdapterOptionsBase {
            power_preference: wgpu::PowerPreference::default(),
            compatible_surface: Some(&surface),
            force_fallback_adapter: false,
        };
        let adapter = instance.request_adapter(&adapter_descriptor).await.unwrap();

        let device_descriptor = wgpu::DeviceDescriptor {
            required_features: wgpu::Features::empty(),
            required_limits: wgpu::Limits::default(),
            label: Some("Device"),
        };
        let (device, queue) = adapter.request_device(&device_descriptor, None).await.unwrap();

        let surface_capabilities = surface.get_capabilities(&adapter);
        let surface_format = surface_capabilities.formats.iter()
            .find(|f| f.is_srgb())
            .copied()
            .unwrap_or(surface_capabilities.formats[0]);

        let config = wgpu::SurfaceConfiguration {
            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
            format: surface_format,
            width: size.0 as u32,
            height: size.1 as u32,
            present_mode: surface_capabilities.present_modes[0],
            alpha_mode: surface_capabilities.alpha_modes[0],
            view_formats: vec![],
            desired_maximum_frame_latency: 2,
        };
        surface.configure(&device, &config);

        Self {
            instance,
            surface,
            device,
            queue,
            config,
            size,
            window
        }
    }

    fn render(&mut self) -> Result<(), wgpu::SurfaceError>{
        let drawable = self.surface.get_current_texture()?;
        let image_view_descriptor = wgpu::TextureViewDescriptor::default();
        let image_view = drawable.texture.create_view(&image_view_descriptor);

        let command_encoder_descriptor = wgpu::CommandEncoderDescriptor{
            label: Some("Render Encoder"),
        };
        let mut command_encoder = self.device.create_command_encoder(&command_encoder_descriptor);

        let color_attachment = wgpu::RenderPassColorAttachment {
            view: &image_view,
            resolve_target: None,
            ops: wgpu::Operations{
                load: wgpu::LoadOp::Clear(wgpu::Color{
                    r: 0.25,
                    g: 0.0,
                    b: 0.5,
                    a: 0.0,
                }),
                store: wgpu::StoreOp::Store,
            }
        };

        {
            let _render_pass = command_encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
                label: Some("Render Pass"),
                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
                    view: &image_view,
                    resolve_target: None,
                    ops: wgpu::Operations {
                        load: wgpu::LoadOp::Clear(wgpu::Color {
                            r: 0.1,
                            g: 0.2,
                            b: 0.3,
                            a: 1.0,
                        }),
                        store: wgpu::StoreOp::Store,
                    },
                })],
                depth_stencil_attachment: None,
                occlusion_query_set: None,
                timestamp_writes: None,
            });
        }

        self.queue.submit(std::iter::once(command_encoder.finish()));

        drawable.present();
        Ok(())
    }

    fn resize(&mut self, new_size: (i32, i32)) {
        if new_size.0 > 0 && new_size.1 > 0 {
            self.size = new_size;
            self.config.width = new_size.0 as u32;
            self.config.height = new_size.1 as u32;
            self.surface.configure(&self.device, &self.config)
        }
    }

    fn update_surface(&mut self) {
        //Unsafe surface... spooky :0 No.2
        let target = unsafe {
            wgpu::SurfaceTargetUnsafe::from_window(&self.window)
        }.unwrap();
        self.surface = unsafe {
            self.instance.create_surface_unsafe(target)
        }.unwrap();
    }
}

async fn run() {
    let mut glfw = glfw::init(fail_on_errors!())
        .unwrap();
    let (mut window, events) = 
        glfw.create_window(
            800, 600, "It's SNA time.", 
            glfw::WindowMode::Windowed).unwrap();
    
    let mut state = State::new(&mut window).await;
    state.window.set_all_polling(true);

    state.window.make_current();

    glfw.set_swap_interval(glfw::SwapInterval::Sync(1));

    while !state.window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            match event {
                glfw::WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
                    state.window.set_should_close(true)
                }

                _ => {}
            }
        }

        match state.render() {
            Ok(_) => {},
            Err(e) => eprintln!("{:?}", e),
        }
        state.window.swap_buffers();
    }
}

fn main(){
    pollster::block_on(run());
}

Platform
Windows 10, Vulkan Instance Version: 1.3.255

@StepingForward StepingForward changed the title Validation Error Surface configuration Validation Error Jun 16, 2024
@Vecvec
Copy link
Contributor

Vecvec commented Jun 16, 2024

have you tried

    glfw.window_hint(WindowHint::ClientApi(ClientApiHint::NoApi));

just before creating the windows. This fixed some issues on some platforms.

@StepingForward
Copy link
Author

I put it right before creating the window, but it returns a new error:

GLFW Error: Cannot make current with a window that has no OpenGL or OpenGL ES context

@Vecvec
Copy link
Contributor

Vecvec commented Jun 17, 2024

That's probably todo with

state.window.make_current();

only some calls can be done without an api (typically because the other api can do this). For example:

window.swap_buffers();

does basically the same thing as

surface_texture.present();

though on the internal API (in this case OpenGL).

Also this conversation should probably be moved to glfw-rs as this is mostly a glfw issue.

Questions I have:

  • Why use Surface Target Unsafe? Couldn't you use a Arc<Window> or use the window.render_context() function?
  • Why glfw.set_swap_interval(glfw::SwapInterval::Sync(1));? Wgpu has it's own presentation mode.
  • Why both state.window.swap_buffers(); and drawable.present(); don't these do the same thing?
    Sorry if these seem like a lot of suggestions, I'm just trying to work out the code.

@Vecvec
Copy link
Contributor

Vecvec commented Jun 18, 2024

Copying the code onto my machine and making this the run function

        let mut glfw = glfw::init(fail_on_errors!())
            .unwrap();
        glfw.window_hint(WindowHint::ClientApi(ClientApiHint::NoApi));
        let (mut window, events) =
            glfw.create_window(
                800, 600, "It's SNA time.",
                glfw::WindowMode::Windowed).unwrap();

        let mut state = State::new(&mut window).await;
        //state.window.set_all_polling(true);

        //state.window.make_current();

        //glfw.set_swap_interval(glfw::SwapInterval::Sync(1));

        while !state.window.should_close() {
            glfw.poll_events();
            for (_, event) in glfw::flush_messages(&events) {
                match event {
                    glfw::WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
                        state.window.set_should_close(true)
                    }

                    _ => {}
                }
            }

            match state.render() {
                Ok(_) => {},
                Err(e) => eprintln!("{:?}", e),
            }
            //state.window.swap_buffers();
        }

seems to fix the issue (commented out code is both not required and unsupported). This is definitely a GLFW documentation issue. I'm working on a pull request to fix the docs.

@StepingForward
Copy link
Author

OMG, it works now! Thank you so much!!!

@Vecvec
Copy link
Contributor

Vecvec commented Jun 18, 2024

Thank you! By the way, there is a safe way of creating a surface:

instance.create_surface(window.render_context()).unwrap();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants