Questions about an efficient SHM game loop

2024-05-08 Thread Philip Bizimis
I am currently working on a small Wayland Snake game to
learn about Wayland and game development. I am using SHM
double buffers for rendering.

My main game loop has two parts that run at different speeds so
that I can have a constant game speed independent of variable
FPS (based on https://dewitters.com/dewitters-gameloop):
```
game_loop() {
while(1) {
// wl_display_dispatch
while(at least X times a sec) {
update();
}
render();
}
```
In my case, there could be several game updates before a frame
is rendered. But there could also be hundreds of frames between
game updates if the hardware is good enough.

Currently, the game works fine if I use wl_display_dispatch.
However, I feel like for optimal performance a blocking call does not
make sense. Also, I would think that I would only want to process
events that I need for the updating in the update loop, and not only
once in the main loop. So my plan is to have something like:
```
game_loop() {
while(1) {

while(at least X times a sec) {
// receive all input changes
update(); // update game state based on
   // LEFT RIGHT UP DOWN
}
// render where the snake is currently
render();
}
```
My render function at the moment looks like:
```
void render(...) {
  struct buffer *free_buffer = find_free_buffer(...);
  // set to available with a buffer_release callback

  if (free_buffer != NULL) {
fill_frame(free_buffer->shm_data, state);
render_frame(state->wl_surface, free_buffer);
  }
}
```
My update function does not interact with Wayland except using the
last pressed key as the direction of the snake.

I have attempted the following approaches without success:
```
game_loop() {
while(1) {
   wl_display_dispatch_pending(d);
while(at least X times a sec) {
update();
}
render();
wl_display_flush(d);
}
```
```
  struct pollfd pollfds[] = {
  {
  .fd = wl_display_get_fd(state->wl_display),
  .events = POLLIN,
  },
  };

  while (1) {
if (pollfds[0].revents & POLLIN) { // never true
wl_display_dispatch();
...
```
Both compiled but did not produce any client window.
I would greatly appreciate your help. I have spent a lot of hours
on this and seem to have hit a wall. In case you would like to take
a look at the whole code: github.com/pbizimis/snake

Thank you so much and have a great day,
Philip


Re: Questions about an efficient SHM game loop

2024-05-08 Thread Pekka Paalanen
On Wed, 8 May 2024 13:49:51 +0200
Philip Bizimis  wrote:

> I am currently working on a small Wayland Snake game to
> learn about Wayland and game development. I am using SHM
> double buffers for rendering.
> 
> My main game loop has two parts that run at different speeds so
> that I can have a constant game speed independent of variable
> FPS (based on https://dewitters.com/dewitters-gameloop):
> ```
> game_loop() {
> while(1) {
> // wl_display_dispatch
> while(at least X times a sec) {
> update();
> }
> render();
> }
> ```
> In my case, there could be several game updates before a frame
> is rendered. But there could also be hundreds of frames between
> game updates if the hardware is good enough.
> 
> Currently, the game works fine if I use wl_display_dispatch.
> However, I feel like for optimal performance a blocking call does not
> make sense. Also, I would think that I would only want to process
> events that I need for the updating in the update loop, and not only
> once in the main loop.

Hi Philip,

do I understand correctly that your game event loop architecture is not
tied to any ready-made library, and it is all yours to write any way
you like? That is sweet.

I should probably start with a disclaimer that there are many opinions
on how a game main loop should be architected, and my opinion is
probably one of the less popular among game developers. However, it
does suit both single-threaded and multi-threaded programs.

I would suggest a fully event driven main loop. You would advance your
game simulation by a timer. You would record input events as they come,
and then handle them when you advance the simulation. You would render
only when the display server is ready for a new frame.

The event loop would have these event sources:
- Wayland display fd, for dispatching incoming events.
  - input events
  - wl_surface.frame callbacks
  - wl_buffer.release events
- A timer, to advance the simulation at a steady rate.
- A trigger to render a new frame.

When you dispatch input events, you record what happened. Maybe you
just want to keep track of what was the last key pressed, so that the
next simulation update knows to change the snake direction. Or maybe
you want to record the timestamp of when that press happened, so your
simulation can handle keys more precisely than just at a simulation
cycle granularity.

In order to render a new frame, several conditions must be fulfilled:

- You have something new to show, that is, the simulation has advanced
  since the last time.

- The display server is ready to use a new frame; wl_surface.frame
  callback from the previous frame has returned, *if* there was a
  previous frame. (1)

- You have a free wl_buffer to render into. If you wait for
  wl_surface.frame, you practically always do if you have enough
  wl_buffers to choose from, but this is how to wait for one to be
  freed by the display server if necessary.

When all these conditions are fulfilled, you trigger rendering a new
frame. If you use an event loop library, they may offer facilities to
run code before the event loop goes to sleep again. That's the point
where I would render.

I would recommend finding an event loop library you like, rather than
writing it yourself. It will be much easier to make things more
fancy later. They also have readily solved problems like how to watch
for an fd and a timer at the same time. OTOH, it's not too hard to
write something that works on Linux with poll() or epoll and timeouts
or timerfd.

Integrating the Wayland fd with an event loop does take some care, so
that everything runs smoothly. The documentation of
wl_display_prepare_read_queue() attempts to explain how to do it:
https://wayland.freedesktop.org/docs/html/apb.html#Client-classwl__display_1a40039c1169b153269a3dc0796a54ddb0

The main parts are:

- When preparing to sleep/poll, first make sure all incoming events
  have been handled, and all outgoing requests are actually flushed out.

- Sleep in poll.

- When anything causes a wake-up, you have to either
  wl_display_read_events() for the Wayland fd being readable, or
  wl_display_cancel_read() for any other wake-up reason.

- Dispatch incoming events.

It may seem complicated, but it also makes the Wayland display handling
thread-safe. Your program might not create threads, but libraries
might, so it's good to be safe just in case.

(1) When you create the window, you naturally have no wl_surface.frame
callback to wait for. It's ok to render a new frame any time you like
after the xdg_toplevel setup sequence. The wait for the frame callback
is just to throttle the rendering so that no rendered frame gets
discarded without displaying. Discarded frames are wasted work.

I think that should get you a nice foundation. It should be relatively
straightforward to extend later with fancier features, like more precise
timing of rendered frames vs. real-time simulation, network support, or
threads. The ma

2024 X.Org Developers Conference - October 9-11, Montréal, Canada

2024-05-08 Thread Mark Filion
Hello!

We're delighted to announce that the 2024 X.Org Developers Conference
(XDC) will be taking place on October 9 to 11 in Montréal, Canada, co-
located with the GStreamer Conference & Hackfest 2024 which will be
running from October 7 to 10. Join us for a freedesktop week in
Montréal!

XDC is the event for developers working on all things Open graphics
(Linux kernel, Mesa, DRM, Wayland, X11, etc.).

New this year: XDC 2024 will feature two full days of talks followed by
a day dedicated to workshops, meetings & hacking.

XDC 2024 website: https://indico.freedesktop.org/event/6/

The in-person venue is the Concordia University Conference Centre,
located within the John Molson School of Business.

Concordia University Conference Centre
1450 Guy St., Montreal, Quebec, Canada, H3H 0A1
https://goo.gl/maps/9nDyTvKtf7X1JuJc9

As usual, XDC will be free of charge and open to the general public.

Registration & Call for Proposals will be opening soon, stay tuned!

Best regards,

Mark Filion, on behalf of X.org



Re: How to support wl_touch input? (when developing clients)

2024-05-08 Thread Peter Hutterer
On Wed, May 08, 2024 at 11:19:56AM +1000, Peter Hutterer wrote:
> On Tue, May 07, 2024 at 09:27:36PM +1000, Campbell Barton wrote:
> > Hi, what are some ways to test "wl_touch" events?
> > 
> > - Is it possible to make track-pads use the wl_touch interface?
> 
> generally - no. most general-purpose compositors use libinput which
> converts the touch points on touchpads into pointer movement and thus
> compositors forward those as wl_pointer events.
> 
> > - Is there a way to emulate touch input using a mouse?
> > - If specific hardware is needed, any suggestions?
> 
> A few options:
> 
> you can emulate any device with uinput (or uhid if you want to also
> test the kernel). the simplest way is to get a recording from a device
> with libinput record and then replay that locally with libinput replay.
> that requires that you find a touchscreen and execute the sequence
> though. I have one, so here's a gist I recorded:
> https://gist.github.com/whot/8000f803836db1425a7a1e920c10cf85
> 
> Alternatively, you can create a uinput device that attaches to your
> touchpad, sets INPUT_PROP_DIRECT and otherwise forwards event 1:1.
> https://python-libevdev.readthedocs.io/en/latest/examples.html
> should help with that.
> 
> finally, you can put a quirk with
> AttrInputProp=+INPUT_PROP_DIRECT;-INPUT_PROP_BUTTONPAD
> that should make libinput treat your device like a touchscreen (though
> you'll also need a udev rule to remove ID_INPUT_TOUCHPAD and instead set
> ID_INPUT_TOUCHSCREEN, or hack that into libinput's evdev.c).
> https://wayland.freedesktop.org/libinput/doc/latest/device-quirks.html
> 
> I'd personally go with the record/replay approach, it's the simplest one and
> you can re-play that exact same sequence until whatever bug you're
> seeing is fixed. docs on record/replay are here:
> https://wayland.freedesktop.org/libinput/doc/latest/tools.html

Follow-up:

Another one I wrote (apparently):
https://gitlab.freedesktop.org/whot/touchmouse
I don't remember much about this (last commit 3 years ago) but it still
works. This may be the easiest one for quick testing if no specific
event sequences are required.

There's also this repo here which is useful to emulate a Wacom tablet:
https://github.com/whot/wacom-recordings
That one uses hid-replay but uses the same principle.

Cheers,
  Peter

> > For context, recently a user reported a bug where touch events aren't
> > supported (wl_touch), see: https://wayland-book.com/seat/touch.html
> > 
> > While it seems fairly straightforward to support, I don't think I have any
> > hardware that uses this interface & buying a Wacom touch-screen just to add
> > support for wl_touch seems excessive (I already have a touch-pad &
> > wacom-tablet, even though both support "touch" it it seems neither active
> > the wl_touch API).
> > 
> > Any suggestions for how to test that wl_touch support is working for
> > application/toolkit developers?
> > 
> > 
> >