Softbuffer / winit generics problems with declaration

I am unable to read the declarations of winit and softbuffer in some cases. They are too abstract for my simple brain.
And that's why I don't know how to declare them.

struct AppHandler
{
    event_loop: winit::EventLoop<???>,
    window: winit::window::Window,
    context: softbuffer::Context<Window>,
    softbuffer_surface: softbuffer::Surface<???, ???>,
}

Furthermore I know that in the winit 'resumed' I can initialize things.
But I don't seem to get it working.
(one of the disadvantages of non-typed initialization syntax in my eyes).
The example in the documentation works but that is "non-declarative" and local.

let context (what type???) = softbuffer::Context::new(window.clone()).unwrap();
let surface (what type???) = softbuffer::Surface::new(&context, window.clone()).unwrap();

A bit of explanation and init-code very welcome. Thx!

The doc:

impl<D: HasDisplayHandle> Context<D> {
   pub fn new(display: D) -> Result<Self, SoftBufferError>
}

This returns a Result. When you unwrap a Result you get its first param, the Self in this case. Self is Context<D> from the impl line, and D is the type of the parameter you pass. So if you pass in an X, the unwrap returns Context<X>.

The other one is similar but has two parameters.

I saw that. Still fighting with a thousand questions. I will have to study first....

You should not put the EventLoop in your application data. Unless you're doing special things, you must give up ownership of the EventLoop when you start the actual event loop running, so it can't also be owned by your handler struct.

The type would be EventLoop<()> unless you are using custom events.

2 Likes

Ok thank you. I saw that and also noticed that the eventloop must be outside the handler. It would not compile.
It makes things a bit inconvenient setting up fields and game-context.

BTW:
Also I noticed deep down on windows the softbuffer uses a BitBlt (which in itself is fast and most of the times hardware accelerated) but needs one more extra CPU copy of pixeldata, which is quite some bytes on a big monitor.
Wouldn't StretchDIBits be more convenient? This does not need a pixels-handle, only a window handle.

// self.window: Option<Window>

let win: Window =  
event_loop.create_window(Window::default_attributes()).expect("win failed");
self.window = Some(win);

let ctx = softbuffer::Context::new(???);

Despair...
I don't see how to initialize ctx.
I don't know how to declare this context as a part of my app-struct.
I don't want my self.window to be an option. Is that possible? There is no default or empty possibility.

edit: and I also do not know how to declare the softbuffer::Surface or Buffer....

ctx needs to be something that implements HasDisplayHandle, and the winit::Window does that. However, you need to not give up ownership of the window, and the solution to that is to wrap it in Arc so that you can hand out clones of it freely, sharing the ownership.

use std::sync::Arc;
...

let win: Arc<Window> = Arc::new(
    event_loop.create_window(Window::default_attributes()).expect("win failed")
);
self.window = Some(win.clone());

let ctx = softbuffer::Context::new(win);

It looks like the type of the surface will be softbuffer::Surface<Arc<Window>, Arc<Window>>, but I'm not sure. (I have used softbuffer, but not recently.)

For something a little stricter, you could use OnceCell instead of Option, but fundamentally, there's always going to have to be a state of “no window yet”. Suggestion: think about it not as “the window is not initialized” but “your application currently has zero windows open”.

Ok. that makes a lot of sense. Thank you. I will try once again getting it compiled and have a complete red surface on-screen. :slight_smile:

(I still have big difficulties reading abstract generic declarations and also like to have the type declared always during a 'let' statement. It is like using 'var' in c# and trusting the type inference, so that it becomes unreadable for me).

ok now i have an initialized
softbuffer_surface: Option<softbuffer::Surface<Rc<Window>, Rc<Window>>>

which has the right size. winit runs and is visible. all well so far.

Now when writing this line:
let buf = *self.softbuffer_surface.unwrap().buffer_mut().unwrap();
I get the error:
the size for values of type [u32] cannot be known at compilation time. (oh why?)
the trait Sized is not implemented for [u32]
all local variables must have a statically known size
Again I cannot understand / read what on earth this buffer is.
The doc says it 'derefs' to a range of u32's.
Why don't we get back a &[u32} then?

Why don't we get back a &[u32} then?

Because that's not what the * dereference operator does; it gets you the [u32], not a reference to it. You're getting the same error you would get with this code:

let x = vec![1, 2, 3];
let y = *x;

Using a dereference operator there is attempting to copy out the contents of the Buffer into a variable, but you can't put a bare slice in a variable. To get a reference you need to ask for one:

let buffer: Buffer<'_, _, _> = self.softbuffer_surface.unwrap().buffer_mut();
let contents: &mut [u32] = &mut *buffer;

(The types are not necessary but I have included them for clarity about what is happening.)

Then you can loop over contents, or use copy_from_slice(), or however else you want to write into the buffer.

Ok, technically this works but only on a local var.
When the context is a field i cannot retrieve the pixels.

struct AppHandler
{
    window: Option<Arc<Window>>,
    softbuffer_context: Option<softbuffer::Context<Arc<Window>>>,
    softbuffer_surface: Option<softbuffer::Surface<Arc<Window>, Rc<Window>>>,
}

this seems impossible

impl AppHandler
{
    fn init_stuff(& mut self)
    {
        // init window, context, surface works ok.
    }

    fn get_pixels(&mut self) -> &mut [u32]
    {
        // impossible because of borrow checker?
        let buffer = self.softbuffer_surface.unwrap().buffer_mut().unwrap();
        let pixels: &mut [u32] = &mut *buffer;
        pixels
    }
}

if it is impossible, then how to structure the code??
I somewhere must be able to store the context.

FINALLY got it.

if let Some(ref mut os_ctx) = self.os
{
    let mut buffer = os_ctx.softbuffer_surface.buffer_mut().unwrap();
    let pixels: &mut [u32] = &mut *buffer;
    for i in 0..pixels.len()
    {
        pixels[i] = Rgba::RED.0;
    }

    _ = buffer.present();//.unwrap();
}