main
render_wayland.c
1/*
2 Copyright 2013 Michael Pavone
3 This file is part of BlastEm.
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
5*/
6#include <stdlib.h>
7#include <stdio.h>
8#include <string.h>
9#include <stdint.h>
10#include <errno.h>
11#include <math.h>
12#include <linux/input.h>
13#include <linux/kd.h>
14#include <alsa/asoundlib.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <sys/ioctl.h>
18#include <sys/mman.h>
19#include <poll.h>
20#include <fcntl.h>
21#include <unistd.h>
22#include <pthread.h>
23#include <dirent.h>
24#include <wayland-client.h>
25#include "xdg-shell-client-protocol.h"
26#include <sys/syscall.h>
27#include <time.h>
28#include "render.h"
29#include "blastem.h"
30#include "genesis.h"
31#include "bindings.h"
32#include "util.h"
33#include "paths.h"
34#include "ppm.h"
35#include "png.h"
36#include "config.h"
37#include "controller_info.h"
38
39#define MAX_EVENT_POLL_PER_FRAME 2
40
41static int main_width, main_height;
42static snd_pcm_uframes_t buffer_samples;
43static unsigned int output_channels, sample_rate;
44
45
46struct audio_source {
47 int16_t *front;
48 int16_t *back;
49 double dt;
50 uint64_t buffer_fraction;
51 uint64_t buffer_inc;
52 uint32_t buffer_pos;
53 uint32_t read_start;
54 uint32_t read_end;
55 uint32_t lowpass_alpha;
56 uint32_t mask;
57 float gain_mult;
58 int16_t last_left;
59 int16_t last_right;
60 uint8_t num_channels;
61 uint8_t front_populated;
62};
63
64static audio_source *audio_sources[8];
65static audio_source *inactive_audio_sources[8];
66static uint8_t num_audio_sources;
67static uint8_t num_inactive_audio_sources;
68
69typedef int32_t (*mix_func)(audio_source *audio, void *vstream, int len);
70
71static int32_t mix_s16(audio_source *audio, void *vstream, int len)
72{
73 int samples = len/(sizeof(int16_t)*output_channels);
74 int16_t *stream = vstream;
75 int16_t *end = stream + output_channels*samples;
76 int16_t *src = audio->front;
77 uint32_t i = audio->read_start;
78 uint32_t i_end = audio->read_end;
79 int16_t *cur = stream;
80 size_t first_add = output_channels > 1 ? 1 : 0, second_add = output_channels > 1 ? output_channels - 1 : 1;
81 if (audio->num_channels == 1) {
82 while (cur < end && i != i_end)
83 {
84 *cur += src[i];
85 cur += first_add;
86 *cur += src[i++];
87 cur += second_add;
88 i &= audio->mask;
89 }
90 } else {
91 while (cur < end && i != i_end)
92 {
93 *cur += src[i++];
94 cur += first_add;
95 *cur += src[i++];
96 cur += second_add;
97 i &= audio->mask;
98 }
99 }
100
101 if (cur != end) {
102 printf("Underflow of %d samples, read_start: %d, read_end: %d, mask: %X\n", (int)(end-cur)/2, audio->read_start, audio->read_end, audio->mask);
103 }
104 if (cur != end) {
105 //printf("Underflow of %d samples, read_start: %d, read_end: %d, mask: %X\n", (int)(end-cur)/2, audio->read_start, audio->read_end, audio->mask);
106 return (cur-end)/2;
107 } else {
108 return ((i_end - i) & audio->mask) / audio->num_channels;
109 }
110}
111
112static int32_t mix_f32(audio_source *audio, void *vstream, int len)
113{
114 int samples = len/(sizeof(float)*output_channels);
115 float *stream = vstream;
116 float *end = stream + output_channels*samples;
117 int16_t *src = audio->front;
118 uint32_t i = audio->read_start;
119 uint32_t i_end = audio->read_end;
120 float *cur = stream;
121 size_t first_add = output_channels > 1 ? 1 : 0, second_add = output_channels > 1 ? output_channels - 1 : 1;
122 if (audio->num_channels == 1) {
123 while (cur < end && i != i_end)
124 {
125 *cur += ((float)src[i]) / 0x7FFF;
126 cur += first_add;
127 *cur += ((float)src[i++]) / 0x7FFF;
128 cur += second_add;
129 i &= audio->mask;
130 }
131 } else {
132 while(cur < end && i != i_end)
133 {
134 *cur += ((float)src[i++]) / 0x7FFF;
135 cur += first_add;
136 *cur += ((float)src[i++]) / 0x7FFF;
137 cur += second_add;
138 i &= audio->mask;
139 }
140 }
141 if (cur != end) {
142 printf("Underflow of %d samples, read_start: %d, read_end: %d, mask: %X\n", (int)(end-cur)/2, audio->read_start, audio->read_end, audio->mask);
143 return (cur-end)/2;
144 } else {
145 return ((i_end - i) & audio->mask) / audio->num_channels;
146 }
147}
148
149static mix_func mix;
150
151static snd_pcm_t *audio_handle;
152static void render_close_audio()
153{
154 if (audio_handle) {
155 snd_pcm_close(audio_handle);
156 audio_handle = NULL;
157 }
158}
159
160static void destroy_wayland(void);
161
162#define BUFFER_INC_RES 0x40000000UL
163
164void render_audio_adjust_clock(audio_source *src, uint64_t master_clock, uint64_t sample_divider)
165{
166 src->buffer_inc = ((BUFFER_INC_RES * (uint64_t)sample_rate) / master_clock) * sample_divider;
167}
168
169audio_source *render_audio_source(uint64_t master_clock, uint64_t sample_divider, uint8_t channels)
170{
171 audio_source *ret = NULL;
172 uint32_t alloc_size = channels * buffer_samples;
173 if (num_audio_sources < 8) {
174 ret = malloc(sizeof(audio_source));
175 ret->back = malloc(alloc_size * sizeof(int16_t));
176 ret->front = malloc(alloc_size * sizeof(int16_t));
177 ret->front_populated = 0;
178 ret->num_channels = channels;
179 audio_sources[num_audio_sources++] = ret;
180 }
181 if (!ret) {
182 fatal_error("Too many audio sources!");
183 } else {
184 render_audio_adjust_clock(ret, master_clock, sample_divider);
185 double lowpass_cutoff = get_lowpass_cutoff(config);
186 double rc = (1.0 / lowpass_cutoff) / (2.0 * M_PI);
187 ret->dt = 1.0 / ((double)master_clock / (double)(sample_divider));
188 double alpha = ret->dt / (ret->dt + rc);
189 ret->lowpass_alpha = (int32_t)(((double)0x10000) * alpha);
190 ret->buffer_pos = 0;
191 ret->buffer_fraction = 0;
192 ret->gain_mult = 1.0f;
193 ret->last_left = ret->last_right = 0;
194 ret->read_start = 0;
195 ret->read_end = buffer_samples * channels;
196 ret->mask = 0xFFFFFFFF;
197 }
198 return ret;
199}
200
201static float db_to_mult(float gain)
202{
203 return powf(10.0f, gain / 20.0f);
204}
205
206void render_audio_source_gaindb(audio_source *src, float gain)
207{
208 src->gain_mult = db_to_mult(gain);
209}
210
211void render_pause_source(audio_source *src)
212{
213 for (uint8_t i = 0; i < num_audio_sources; i++)
214 {
215 if (audio_sources[i] == src) {
216 audio_sources[i] = audio_sources[--num_audio_sources];
217 break;
218 }
219 }
220 inactive_audio_sources[num_inactive_audio_sources++] = src;
221}
222
223void render_resume_source(audio_source *src)
224{
225 if (num_audio_sources < 8) {
226 audio_sources[num_audio_sources++] = src;
227 }
228 for (uint8_t i = 0; i < num_inactive_audio_sources; i++)
229 {
230 if (inactive_audio_sources[i] == src) {
231 inactive_audio_sources[i] = inactive_audio_sources[--num_inactive_audio_sources];
232 }
233 }
234}
235
236void render_free_source(audio_source *src)
237{
238 render_pause_source(src);
239
240 free(src->front);
241 free(src->back);
242 free(src);
243}
244static void do_audio_ready(audio_source *src)
245{
246 if (src->front_populated) {
247 fatal_error("Audio source filled up a buffer a second time before other sources finished their first\n");
248 }
249 int16_t *tmp = src->front;
250 src->front = src->back;
251 src->back = tmp;
252 src->front_populated = 1;
253 src->buffer_pos = 0;
254
255 for (uint8_t i = 0; i < num_audio_sources; i++)
256 {
257 if (!audio_sources[i]->front_populated) {
258 //at least one audio source is not ready yet.
259 return;
260 }
261 }
262
263 size_t bytes = (mix == mix_s16 ? sizeof(int16_t) : sizeof(float)) * output_channels * buffer_samples;
264 void *buffer = calloc(1, bytes);
265 for (uint8_t i = 0; i < num_audio_sources; i++)
266 {
267 mix(audio_sources[i], buffer, bytes);
268 audio_sources[i]->front_populated = 0;
269 }
270 int frames = snd_pcm_writei(audio_handle, buffer, buffer_samples);
271 if (frames < 0) {
272 frames = snd_pcm_recover(audio_handle, frames, 0);
273 }
274 if (frames < 0) {
275 fprintf(stderr, "Failed to write samples: %s\n", snd_strerror(frames));
276 }
277 free(buffer);
278}
279
280static int16_t lowpass_sample(audio_source *src, int16_t last, int16_t current)
281{
282 int32_t tmp = current * src->lowpass_alpha + last * (0x10000 - src->lowpass_alpha);
283 current = tmp >> 16;
284 return current;
285}
286
287static void interp_sample(audio_source *src, int16_t last, int16_t current)
288{
289 int64_t tmp = last * ((src->buffer_fraction << 16) / src->buffer_inc);
290 tmp += current * (0x10000 - ((src->buffer_fraction << 16) / src->buffer_inc));
291 src->back[src->buffer_pos++] = tmp >> 16;
292}
293
294void render_put_mono_sample(audio_source *src, int16_t value)
295{
296 value = lowpass_sample(src, src->last_left, value);
297 src->buffer_fraction += src->buffer_inc;
298 uint32_t base = 0;
299 while (src->buffer_fraction > BUFFER_INC_RES)
300 {
301 src->buffer_fraction -= BUFFER_INC_RES;
302 interp_sample(src, src->last_left, value);
303
304 if (((src->buffer_pos - base) & src->mask) >= buffer_samples) {
305 do_audio_ready(src);
306 }
307 src->buffer_pos &= src->mask;
308 }
309 src->last_left = value;
310}
311
312void render_put_stereo_sample(audio_source *src, int16_t left, int16_t right)
313{
314 left = lowpass_sample(src, src->last_left, left);
315 right = lowpass_sample(src, src->last_right, right);
316 src->buffer_fraction += src->buffer_inc;
317 uint32_t base = 0;
318 while (src->buffer_fraction > BUFFER_INC_RES)
319 {
320 src->buffer_fraction -= BUFFER_INC_RES;
321
322 interp_sample(src, src->last_left, left);
323 interp_sample(src, src->last_right, right);
324
325 if (((src->buffer_pos - base) & src->mask)/2 >= buffer_samples) {
326 do_audio_ready(src);
327 }
328 src->buffer_pos &= src->mask;
329 }
330 src->last_left = left;
331 src->last_right = right;
332}
333
334int render_width()
335{
336 return main_width;
337}
338
339int render_height()
340{
341 return main_height;
342}
343
344uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b)
345{
346 return 0xFF000000 | r << 16 | g << 8 | b;
347}
348
349#define MAX_VIDEO_BUFFER_LINES 590
350static uint32_t video_buffer[MAX_VIDEO_BUFFER_LINES * LINEBUF_SIZE * 2];
351
352static char * caption = NULL;
353static char * fps_caption = NULL;
354
355static void render_quit()
356{
357 render_close_audio();
358 destroy_wayland();
359}
360
361static float config_aspect()
362{
363 static float aspect = 0.0f;
364 if (aspect == 0.0f) {
365 char *config_aspect = tern_find_path_default(config, "video\0aspect\0", (tern_val){.ptrval = "4:3"}, TVAL_PTR).ptrval;
366 if (strcmp("stretch", config_aspect)) {
367 aspect = 4.0f/3.0f;
368 char *end;
369 float aspect_numerator = strtof(config_aspect, &end);
370 if (aspect_numerator > 0.0f && *end == ':') {
371 float aspect_denominator = strtof(end+1, &end);
372 if (aspect_denominator > 0.0f && !*end) {
373 aspect = aspect_numerator / aspect_denominator;
374 }
375 }
376 } else {
377 aspect = -1.0f;
378 }
379 }
380 return aspect;
381}
382
383static uint8_t scancode_map[128] = {
384 [KEY_A] = 0x1C,
385 [KEY_B] = 0x32,
386 [KEY_C] = 0x21,
387 [KEY_D] = 0x23,
388 [KEY_E] = 0x24,
389 [KEY_F] = 0x2B,
390 [KEY_G] = 0x34,
391 [KEY_H] = 0x33,
392 [KEY_I] = 0x43,
393 [KEY_J] = 0x3B,
394 [KEY_K] = 0x42,
395 [KEY_L] = 0x4B,
396 [KEY_M] = 0x3A,
397 [KEY_N] = 0x31,
398 [KEY_O] = 0x44,
399 [KEY_P] = 0x4D,
400 [KEY_Q] = 0x15,
401 [KEY_R] = 0x2D,
402 [KEY_S] = 0x1B,
403 [KEY_T] = 0x2C,
404 [KEY_U] = 0x3C,
405 [KEY_V] = 0x2A,
406 [KEY_W] = 0x1D,
407 [KEY_X] = 0x22,
408 [KEY_Y] = 0x35,
409 [KEY_Z] = 0x1A,
410 [KEY_1] = 0x16,
411 [KEY_2] = 0x1E,
412 [KEY_3] = 0x26,
413 [KEY_4] = 0x25,
414 [KEY_5] = 0x2E,
415 [KEY_6] = 0x36,
416 [KEY_7] = 0x3D,
417 [KEY_8] = 0x3E,
418 [KEY_9] = 0x46,
419 [KEY_0] = 0x45,
420 [KEY_ENTER] = 0x5A,
421 [KEY_ESC] = 0x76,
422 [KEY_SPACE] = 0x29,
423 [KEY_TAB] = 0x0D,
424 [KEY_BACKSPACE] = 0x66,
425 [KEY_MINUS] = 0x4E,
426 [KEY_EQUAL] = 0x55,
427 [KEY_LEFTBRACE] = 0x54,
428 [KEY_RIGHTBRACE] = 0x5B,
429 [KEY_BACKSLASH] = 0x5D,
430 [KEY_SEMICOLON] = 0x4C,
431 [KEY_APOSTROPHE] = 0x52,
432 [KEY_GRAVE] = 0x0E,
433 [KEY_COMMA] = 0x41,
434 [KEY_DOT] = 0x49,
435 [KEY_SLASH] = 0x4A,
436 [KEY_CAPSLOCK] = 0x58,
437 [KEY_F1] = 0x05,
438 [KEY_F2] = 0x06,
439 [KEY_F3] = 0x04,
440 [KEY_F4] = 0x0C,
441 [KEY_F5] = 0x03,
442 [KEY_F6] = 0x0B,
443 [KEY_F7] = 0x83,
444 [KEY_F8] = 0x0A,
445 [KEY_F9] = 0x01,
446 [KEY_F10] = 0x09,
447 [KEY_F11] = 0x78,
448 [KEY_F12] = 0x07,
449 [KEY_LEFTCTRL] = 0x14,
450 [KEY_LEFTSHIFT] = 0x12,
451 [KEY_LEFTALT] = 0x11,
452 [KEY_RIGHTCTRL] = 0x18,
453 [KEY_RIGHTSHIFT] = 0x59,
454 [KEY_RIGHTALT] = 0x17,
455 [KEY_INSERT] = 0x81,
456 [KEY_PAUSE] = 0x82,
457 [KEY_SYSRQ] = 0x84,
458 [KEY_SCROLLLOCK] = 0x7E,
459 [KEY_DELETE] = 0x85,
460 [KEY_LEFT] = 0x86,
461 [KEY_HOME] = 0x87,
462 [KEY_END] = 0x88,
463 [KEY_UP] = 0x89,
464 [KEY_DOWN] = 0x8A,
465 [KEY_PAGEUP] = 0x8B,
466 [KEY_PAGEDOWN] = 0x8C,
467 [KEY_RIGHT] = 0x8D,
468 [KEY_NUMLOCK] = 0x77,
469 [KEY_KPSLASH] = 0x80,
470 [KEY_KPASTERISK] = 0x7C,
471 [KEY_KPMINUS] = 0x7B,
472 [KEY_KPPLUS] = 0x79,
473 [KEY_KPENTER] = 0x19,
474 [KEY_KP1] = 0x69,
475 [KEY_KP2] = 0x72,
476 [KEY_KP3] = 0x7A,
477 [KEY_KP4] = 0x6B,
478 [KEY_KP5] = 0x73,
479 [KEY_KP6] = 0x74,
480 [KEY_KP7] = 0x6C,
481 [KEY_KP8] = 0x75,
482 [KEY_KP9] = 0x7D,
483 [KEY_KP0] = 0x70,
484 [KEY_KPDOT] = 0x71,
485};
486
487#include "special_keys_evdev.h"
488static uint8_t sym_map[128] = {
489 [KEY_A] = 'a',
490 [KEY_B] = 'b',
491 [KEY_C] = 'c',
492 [KEY_D] = 'd',
493 [KEY_E] = 'e',
494 [KEY_F] = 'f',
495 [KEY_G] = 'g',
496 [KEY_H] = 'h',
497 [KEY_I] = 'i',
498 [KEY_J] = 'j',
499 [KEY_K] = 'k',
500 [KEY_L] = 'l',
501 [KEY_M] = 'm',
502 [KEY_N] = 'n',
503 [KEY_O] = 'o',
504 [KEY_P] = 'p',
505 [KEY_Q] = 'q',
506 [KEY_R] = 'r',
507 [KEY_S] = 's',
508 [KEY_T] = 't',
509 [KEY_U] = 'u',
510 [KEY_V] = 'v',
511 [KEY_W] = 'w',
512 [KEY_X] = 'x',
513 [KEY_Y] = 'y',
514 [KEY_Z] = 'z',
515 [KEY_1] = '1',
516 [KEY_2] = '2',
517 [KEY_3] = '3',
518 [KEY_4] = '4',
519 [KEY_5] = '5',
520 [KEY_6] = '6',
521 [KEY_7] = '7',
522 [KEY_8] = '8',
523 [KEY_9] = '9',
524 [KEY_0] = '0',
525 [KEY_ENTER] = '\r',
526 [KEY_SPACE] = ' ',
527 [KEY_TAB] = '\t',
528 [KEY_BACKSPACE] = '\b',
529 [KEY_MINUS] = '-',
530 [KEY_EQUAL] = '=',
531 [KEY_LEFTBRACE] = '[',
532 [KEY_RIGHTBRACE] = ']',
533 [KEY_BACKSLASH] = '\\',
534 [KEY_SEMICOLON] = ';',
535 [KEY_APOSTROPHE] = '\'',
536 [KEY_GRAVE] = '`',
537 [KEY_COMMA] = ',',
538 [KEY_DOT] = '.',
539 [KEY_SLASH] = '/',
540 [KEY_ESC] = RENDERKEY_ESC,
541 [KEY_F1] = RENDERKEY_F1,
542 [KEY_F2] = RENDERKEY_F2,
543 [KEY_F3] = RENDERKEY_F3,
544 [KEY_F4] = RENDERKEY_F4,
545 [KEY_F5] = RENDERKEY_F5,
546 [KEY_F6] = RENDERKEY_F6,
547 [KEY_F7] = RENDERKEY_F7,
548 [KEY_F8] = RENDERKEY_F8,
549 [KEY_F9] = RENDERKEY_F9,
550 [KEY_F10] = RENDERKEY_F10,
551 [KEY_F11] = RENDERKEY_F11,
552 [KEY_F12] = RENDERKEY_F12,
553 [KEY_LEFTCTRL] = RENDERKEY_LCTRL,
554 [KEY_LEFTSHIFT] = RENDERKEY_LSHIFT,
555 [KEY_LEFTALT] = RENDERKEY_LALT,
556 [KEY_RIGHTCTRL] = RENDERKEY_RCTRL,
557 [KEY_RIGHTSHIFT] = RENDERKEY_RSHIFT,
558 [KEY_RIGHTALT] = RENDERKEY_RALT,
559 [KEY_DELETE] = RENDERKEY_DEL,
560 [KEY_LEFT] = RENDERKEY_LEFT,
561 [KEY_HOME] = RENDERKEY_HOME,
562 [KEY_END] = RENDERKEY_END,
563 [KEY_UP] = RENDERKEY_UP,
564 [KEY_DOWN] = RENDERKEY_DOWN,
565 [KEY_PAGEUP] = RENDERKEY_PAGEUP,
566 [KEY_PAGEDOWN] = RENDERKEY_PAGEDOWN,
567 [KEY_RIGHT] = RENDERKEY_RIGHT,
568 [KEY_KPSLASH] = 0x80,
569 [KEY_KPASTERISK] = 0x7C,
570 [KEY_KPMINUS] = 0x7B,
571 [KEY_KPPLUS] = 0x79,
572 [KEY_KPENTER] = 0x19,
573 [KEY_KP1] = 0x69,
574 [KEY_KP2] = 0x72,
575 [KEY_KP3] = 0x7A,
576 [KEY_KP4] = 0x6B,
577 [KEY_KP5] = 0x73,
578 [KEY_KP6] = 0x74,
579 [KEY_KP7] = 0x6C,
580 [KEY_KP8] = 0x75,
581 [KEY_KP9] = 0x7D,
582 [KEY_KP0] = 0x70,
583 [KEY_KPDOT] = 0x71,
584};
585
586char* render_joystick_type_id(int index)
587{
588 return strdup("");
589}
590
591static uint32_t overscan_top[NUM_VID_STD] = {2, 21};
592static uint32_t overscan_bot[NUM_VID_STD] = {1, 17};
593static uint32_t overscan_left[NUM_VID_STD] = {13, 13};
594static uint32_t overscan_right[NUM_VID_STD] = {14, 14};
595static vid_std video_standard = VID_NTSC;
596
597typedef enum {
598 DEV_NONE,
599 DEV_KEYBOARD,
600 DEV_MOUSE,
601 DEV_GAMEPAD
602} device_type;
603
604static int32_t mouse_x, mouse_y, mouse_accum_x, mouse_accum_y;
605static int32_t handle_event(device_type dtype, int device_index, struct input_event *event)
606{
607 switch (event->type) {
608 case EV_KEY:
609 //code is key, value is 1 for keydown, 0 for keyup
610 if (dtype == DEV_KEYBOARD && event->code < 128) {
611 //keyboard key that we might have a mapping for
612 if (event->value) {
613 handle_keydown(sym_map[event->code], scancode_map[event->code]);
614 } else {
615 handle_keyup(sym_map[event->code], scancode_map[event->code]);
616 }
617 } else if (dtype == DEV_MOUSE && event->code >= BTN_MOUSE && event->code < BTN_JOYSTICK) {
618 //mosue button
619 if (event->value) {
620 handle_mousedown(device_index, event->code - BTN_LEFT);
621 } else {
622 handle_mouseup(device_index, event->code - BTN_LEFT);
623 }
624 } else if (dtype == DEV_GAMEPAD && event->code >= BTN_GAMEPAD && event->code < BTN_DIGI) {
625 //gamepad button
626 if (event->value) {
627 handle_joydown(device_index, event->code - BTN_SOUTH);
628 } else {
629 handle_joyup(device_index, event->code - BTN_SOUTH);
630 }
631 }
632 break;
633 case EV_REL:
634 if (dtype == DEV_MOUSE) {
635 switch(event->code)
636 {
637 case REL_X:
638 mouse_accum_x += event->value;
639 break;
640 case REL_Y:
641 mouse_accum_y += event->value;
642 break;
643 }
644 }
645 break;
646 case EV_ABS:
647 //TODO: Handle joystick axis/hat motion, absolute mouse movement
648 break;
649 case EV_SYN:
650 if (dtype == DEV_MOUSE && (mouse_accum_x || mouse_accum_y)) {
651 mouse_x += mouse_accum_x;
652 mouse_y += mouse_accum_y;
653 if (mouse_x < 0) {
654 mouse_x = 0;
655 } else if (mouse_x >= main_width) {
656 mouse_x = main_width - 1;
657 }
658 if (mouse_y < 0) {
659 mouse_y = 0;
660 } else if (mouse_y >= main_height) {
661 mouse_y = main_height - 1;
662 }
663 handle_mouse_moved(device_index, mouse_x, mouse_y, mouse_accum_x, mouse_accum_y);
664 mouse_accum_x = mouse_accum_y = 0;
665 }
666 break;
667 }
668 return 0;
669}
670
671#define MAX_DEVICES 16
672static int device_fds[MAX_DEVICES];
673static device_type device_types[MAX_DEVICES];
674static int cur_devices;
675
676static void drain_events()
677{
678 struct input_event events[64];
679 int index_by_type[3] = {0,0,0};
680 for (int i = 0; i < cur_devices; i++)
681 {
682 int bytes = sizeof(events);
683 int device_index = index_by_type[device_types[i]-1]++;
684 while (bytes == sizeof(events))
685 {
686 bytes = read(device_fds[i], events, sizeof(events));
687 if (bytes > 0) {
688 int num_events = bytes / sizeof(events[0]);
689 for (int j = 0; j < num_events; j++)
690 {
691 handle_event(device_types[i], device_index, events + j);
692 }
693 } else if (bytes < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
694 perror("Failed to read evdev events");
695 }
696 }
697 }
698}
699
700static char *vid_std_names[NUM_VID_STD] = {"ntsc", "pal"};
701
702static void init_audio()
703{
704 char *device_name = tern_find_path_default(config, "audio\0alsa_device\0", (tern_val){.ptrval="default"}, TVAL_PTR).ptrval;
705 int res = snd_pcm_open(&audio_handle, device_name, SND_PCM_STREAM_PLAYBACK, 0);
706 if (res < 0) {
707 fatal_error("Failed to open ALSA device: %s\n", snd_strerror(res));
708 }
709
710 snd_pcm_hw_params_t *params;
711 snd_pcm_hw_params_alloca(¶ms);
712 res = snd_pcm_hw_params_any(audio_handle, params);
713 if (res < 0) {
714 fatal_error("No playback configurations available: %s\n", snd_strerror(res));
715 }
716 res = snd_pcm_hw_params_set_access(audio_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
717 if (res < 0) {
718 fatal_error("Failed to set access type: %s\n", snd_strerror(res));
719 }
720 res = snd_pcm_hw_params_set_format(audio_handle, params, SND_PCM_FORMAT_S16_LE);
721 if (res < 0) {
722 //failed to set, signed 16-bit integer, try floating point
723 res = snd_pcm_hw_params_set_format(audio_handle, params, SND_PCM_FORMAT_FLOAT_LE);
724 if (res < 0) {
725 fatal_error("Failed to set an acceptable format: %s\n", snd_strerror(res));
726 }
727 mix = mix_f32;
728 } else {
729 mix = mix_s16;
730 }
731
732 char * rate_str = tern_find_path(config, "audio\0rate\0", TVAL_PTR).ptrval;
733 sample_rate = rate_str ? atoi(rate_str) : 0;
734 if (!sample_rate) {
735 sample_rate = 48000;
736 }
737 snd_pcm_hw_params_set_rate_near(audio_handle, params, &sample_rate, NULL);
738 output_channels = 2;
739 snd_pcm_hw_params_set_channels_near(audio_handle, params, &output_channels);
740
741 char * samples_str = tern_find_path(config, "audio\0buffer\0", TVAL_PTR).ptrval;
742 buffer_samples = samples_str ? atoi(samples_str) : 0;
743 if (!buffer_samples) {
744 buffer_samples = 512;
745 }
746 snd_pcm_hw_params_set_period_size_near(audio_handle, params, &buffer_samples, NULL);
747
748 int dir = 1;
749 unsigned int periods = 2;
750 snd_pcm_hw_params_set_periods_near(audio_handle, params, &periods, &dir);
751
752 res = snd_pcm_hw_params(audio_handle, params);
753 if (res < 0) {
754 fatal_error("Failed to set ALSA hardware params: %s\n", snd_strerror(res));
755 }
756
757 printf("Initialized audio at frequency %d with a %d sample buffer, ", (int)sample_rate, (int)buffer_samples);
758 if (mix == mix_s16) {
759 puts("signed 16-bit int format");
760 } else {
761 puts("32-bit float format");
762 }
763}
764
765struct wayland_buffer {
766 struct wl_buffer *buffer;
767 uint32_t *pixels;
768 uint8_t busy;
769};
770
771static struct wl_display *wl_display_handle;
772static struct wl_compositor *wl_compositor_handle;
773static struct wl_shm *wl_shm_handle;
774static struct wl_seat *wl_seat_handle;
775static struct wl_keyboard *wl_keyboard_handle;
776static struct wl_pointer *wl_pointer_handle;
777static struct xdg_wm_base *xdg_wm_base_handle;
778static struct wl_surface *wl_surface_handle;
779static struct xdg_surface *xdg_surface_handle;
780static struct xdg_toplevel *xdg_toplevel_handle;
781static struct wl_callback *frame_callback;
782static struct wayland_buffer wl_buffers[2];
783static uint8_t wl_cur_buffer;
784static uint8_t wl_configured;
785static uint8_t frame_pending;
786static uint32_t wl_stride;
787static int32_t wl_pointer_x, wl_pointer_y;
788static uint32_t *copy_buffer;
789static uint32_t last_width, last_width_scale, last_height, last_height_scale;
790static uint32_t max_multiple;
791
792static void wl_buffer_release(void *data, struct wl_buffer *buffer)
793{
794 ((struct wayland_buffer *)data)->busy = 0;
795}
796
797static const struct wl_buffer_listener wl_buffer_listener = {
798 .release = wl_buffer_release
799};
800
801static void dispatch_wayland_pending(uint32_t timeout)
802{
803 if (!wl_display_handle) {
804 return;
805 }
806 while (wl_display_prepare_read(wl_display_handle) != 0)
807 {
808 wl_display_dispatch_pending(wl_display_handle);
809 }
810 wl_display_flush(wl_display_handle);
811 struct pollfd pfd = {
812 .fd = wl_display_get_fd(wl_display_handle),
813 .events = POLLIN
814 };
815 if (poll(&pfd, 1, timeout) > 0 && (pfd.revents & POLLIN)) {
816 wl_display_read_events(wl_display_handle);
817 } else {
818 wl_display_cancel_read(wl_display_handle);
819 }
820 wl_display_dispatch_pending(wl_display_handle);
821}
822
823static void frame_done(void *data, struct wl_callback *callback, uint32_t time)
824{
825 wl_callback_destroy(callback);
826 if (callback == frame_callback) {
827 frame_callback = NULL;
828 frame_pending = 0;
829 }
830}
831
832static const struct wl_callback_listener frame_listener = {
833 .done = frame_done
834};
835
836static int create_shm_file(size_t size)
837{
838#ifdef SYS_memfd_create
839 int fd = syscall(SYS_memfd_create, "blastem-wayland", 0);
840 if (fd >= 0) {
841 if (ftruncate(fd, size) == 0) {
842 return fd;
843 }
844 close(fd);
845 }
846#endif
847 char template[] = "/blastem-wayland-XXXXXX";
848 const char *runtime_dir = getenv("XDG_RUNTIME_DIR");
849 if (!runtime_dir) {
850 return -1;
851 }
852 char *name = alloc_concat(runtime_dir, template);
853 fd = mkstemp(name);
854 if (fd >= 0) {
855 int flags = fcntl(fd, F_GETFD);
856 if (flags >= 0) {
857 fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
858 }
859 unlink(name);
860 if (ftruncate(fd, size) == 0) {
861 free(name);
862 return fd;
863 }
864 close(fd);
865 }
866 free(name);
867 return -1;
868}
869
870static void create_wayland_buffer(struct wayland_buffer *buf);
871static void destroy_wayland_buffer(struct wayland_buffer *buf);
872
873static void xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
874{
875 xdg_wm_base_pong(xdg_wm_base, serial);
876}
877
878static const struct xdg_wm_base_listener xdg_wm_base_listener = {
879 .ping = xdg_wm_base_ping
880};
881
882static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial)
883{
884 xdg_surface_ack_configure(xdg_surface, serial);
885 wl_configured = 1;
886}
887
888static const struct xdg_surface_listener xdg_surface_listener = {
889 .configure = xdg_surface_configure
890};
891
892static void xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states)
893{
894 if (width > 0 && height > 0 && (width != main_width || height != main_height)) {
895 destroy_wayland_buffer(&wl_buffers[0]);
896 destroy_wayland_buffer(&wl_buffers[1]);
897 main_width = width;
898 main_height = height;
899 wl_stride = main_width * sizeof(uint32_t);
900 create_wayland_buffer(&wl_buffers[0]);
901 create_wayland_buffer(&wl_buffers[1]);
902 }
903}
904
905static void xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
906{
907 if (current_system) {
908 current_system->request_exit(current_system);
909 } else {
910 exit(0);
911 }
912}
913
914static const struct xdg_toplevel_listener xdg_toplevel_listener = {
915 .configure = xdg_toplevel_configure,
916 .close = xdg_toplevel_close
917};
918
919static void wl_keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size)
920{
921 close(fd);
922}
923
924static void wl_keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
925{
926}
927
928static void wl_keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface)
929{
930}
931
932static void wl_keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
933{
934 if (key >= 128) {
935 return;
936 }
937 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
938 handle_keydown(sym_map[key], scancode_map[key]);
939 } else {
940 handle_keyup(sym_map[key], scancode_map[key]);
941 }
942}
943
944static void wl_keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
945{
946}
947
948static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay)
949{
950}
951
952static const struct wl_keyboard_listener wl_keyboard_listener = {
953 .keymap = wl_keyboard_keymap,
954 .enter = wl_keyboard_enter,
955 .leave = wl_keyboard_leave,
956 .key = wl_keyboard_key,
957 .modifiers = wl_keyboard_modifiers,
958 .repeat_info = wl_keyboard_repeat_info
959};
960
961static void wl_pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y)
962{
963 wl_pointer_x = wl_fixed_to_int(surface_x);
964 wl_pointer_y = wl_fixed_to_int(surface_y);
965 handle_mouse_moved(0, wl_pointer_x, wl_pointer_y, 0, 0);
966}
967
968static void wl_pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface)
969{
970}
971
972static void wl_pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
973{
974 int32_t x = wl_fixed_to_int(surface_x);
975 int32_t y = wl_fixed_to_int(surface_y);
976 handle_mouse_moved(0, x, y, x - wl_pointer_x, y - wl_pointer_y);
977 wl_pointer_x = x;
978 wl_pointer_y = y;
979}
980
981static void wl_pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
982{
983 if (button < BTN_MOUSE || button >= BTN_JOYSTICK) {
984 return;
985 }
986 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
987 handle_mousedown(0, button - BTN_LEFT);
988 } else {
989 handle_mouseup(0, button - BTN_LEFT);
990 }
991}
992
993static void wl_pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value)
994{
995}
996
997static const struct wl_pointer_listener wl_pointer_listener = {
998 .enter = wl_pointer_enter,
999 .leave = wl_pointer_leave,
1000 .motion = wl_pointer_motion,
1001 .button = wl_pointer_button,
1002 .axis = wl_pointer_axis
1003};
1004
1005static void seat_capabilities(void *data, struct wl_seat *seat, uint32_t capabilities)
1006{
1007 if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && !wl_keyboard_handle) {
1008 wl_keyboard_handle = wl_seat_get_keyboard(seat);
1009 wl_keyboard_add_listener(wl_keyboard_handle, &wl_keyboard_listener, NULL);
1010 } else if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) && wl_keyboard_handle) {
1011 wl_keyboard_destroy(wl_keyboard_handle);
1012 wl_keyboard_handle = NULL;
1013 }
1014 if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !wl_pointer_handle) {
1015 wl_pointer_handle = wl_seat_get_pointer(seat);
1016 wl_pointer_add_listener(wl_pointer_handle, &wl_pointer_listener, NULL);
1017 } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && wl_pointer_handle) {
1018 wl_pointer_destroy(wl_pointer_handle);
1019 wl_pointer_handle = NULL;
1020 }
1021}
1022
1023static void seat_name(void *data, struct wl_seat *seat, const char *name)
1024{
1025}
1026
1027static const struct wl_seat_listener wl_seat_listener = {
1028 .capabilities = seat_capabilities,
1029 .name = seat_name
1030};
1031
1032static void registry_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version)
1033{
1034 if (!strcmp(interface, wl_compositor_interface.name)) {
1035 wl_compositor_handle = wl_registry_bind(registry, name, &wl_compositor_interface, version < 4 ? version : 4);
1036 } else if (!strcmp(interface, wl_shm_interface.name)) {
1037 wl_shm_handle = wl_registry_bind(registry, name, &wl_shm_interface, 1);
1038 } else if (!strcmp(interface, wl_seat_interface.name)) {
1039 wl_seat_handle = wl_registry_bind(registry, name, &wl_seat_interface, 1);
1040 wl_seat_add_listener(wl_seat_handle, &wl_seat_listener, NULL);
1041 } else if (!strcmp(interface, xdg_wm_base_interface.name)) {
1042 xdg_wm_base_handle = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
1043 xdg_wm_base_add_listener(xdg_wm_base_handle, &xdg_wm_base_listener, NULL);
1044 }
1045}
1046
1047static void registry_global_remove(void *data, struct wl_registry *registry, uint32_t name)
1048{
1049}
1050
1051static const struct wl_registry_listener registry_listener = {
1052 .global = registry_global,
1053 .global_remove = registry_global_remove
1054};
1055
1056static void create_wayland_buffer(struct wayland_buffer *buf)
1057{
1058 size_t size = wl_stride * main_height;
1059 int fd = create_shm_file(size);
1060 if (fd < 0) {
1061 fatal_error("Failed to create Wayland shared memory file\n");
1062 }
1063 buf->pixels = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1064 if (buf->pixels == MAP_FAILED) {
1065 close(fd);
1066 fatal_error("Failed to mmap Wayland shared memory buffer\n");
1067 }
1068 struct wl_shm_pool *pool = wl_shm_create_pool(wl_shm_handle, fd, size);
1069 buf->buffer = wl_shm_pool_create_buffer(pool, 0, main_width, main_height, wl_stride, WL_SHM_FORMAT_XRGB8888);
1070 wl_buffer_add_listener(buf->buffer, &wl_buffer_listener, buf);
1071 wl_shm_pool_destroy(pool);
1072 close(fd);
1073}
1074
1075static void destroy_wayland_buffer(struct wayland_buffer *buf)
1076{
1077 size_t size = wl_stride * main_height;
1078 if (buf->buffer) {
1079 wl_buffer_destroy(buf->buffer);
1080 buf->buffer = NULL;
1081 }
1082 if (buf->pixels) {
1083 munmap(buf->pixels, size);
1084 buf->pixels = NULL;
1085 }
1086 buf->busy = 0;
1087}
1088
1089static void destroy_wayland(void)
1090{
1091 destroy_wayland_buffer(&wl_buffers[0]);
1092 destroy_wayland_buffer(&wl_buffers[1]);
1093 if (xdg_toplevel_handle) {
1094 xdg_toplevel_destroy(xdg_toplevel_handle);
1095 xdg_toplevel_handle = NULL;
1096 }
1097 if (xdg_surface_handle) {
1098 xdg_surface_destroy(xdg_surface_handle);
1099 xdg_surface_handle = NULL;
1100 }
1101 if (frame_callback) {
1102 wl_callback_destroy(frame_callback);
1103 frame_callback = NULL;
1104 frame_pending = 0;
1105 }
1106 if (wl_surface_handle) {
1107 wl_surface_destroy(wl_surface_handle);
1108 wl_surface_handle = NULL;
1109 }
1110 if (wl_keyboard_handle) {
1111 wl_keyboard_destroy(wl_keyboard_handle);
1112 wl_keyboard_handle = NULL;
1113 }
1114 if (wl_pointer_handle) {
1115 wl_pointer_destroy(wl_pointer_handle);
1116 wl_pointer_handle = NULL;
1117 }
1118 if (wl_seat_handle) {
1119 wl_seat_destroy(wl_seat_handle);
1120 wl_seat_handle = NULL;
1121 }
1122 if (xdg_wm_base_handle) {
1123 xdg_wm_base_destroy(xdg_wm_base_handle);
1124 xdg_wm_base_handle = NULL;
1125 }
1126 if (wl_shm_handle) {
1127 wl_shm_destroy(wl_shm_handle);
1128 wl_shm_handle = NULL;
1129 }
1130 if (wl_compositor_handle) {
1131 wl_compositor_destroy(wl_compositor_handle);
1132 wl_compositor_handle = NULL;
1133 }
1134 if (wl_display_handle) {
1135 wl_display_disconnect(wl_display_handle);
1136 wl_display_handle = NULL;
1137 }
1138 wl_configured = 0;
1139}
1140
1141static uint32_t mix_pixel(uint32_t last, uint32_t cur, float ratio)
1142{
1143 float a,b,c,d;
1144 a = (last & 255) * ratio;
1145 b = (last >> 8 & 255) * ratio;
1146 c = (last >> 16 & 255) * ratio;
1147 d = (last >> 24 & 255) * ratio;
1148 ratio = 1.0f - ratio;
1149 a += (cur & 255) * ratio;
1150 b += (cur >> 8 & 255) * ratio;
1151 c += (cur >> 16 & 255) * ratio;
1152 d += (cur >> 24 & 255) * ratio;
1153 return ((int)d) << 24 | ((int)c) << 16 | ((int)b) << 8 | ((int)a);
1154}
1155static void do_buffer_copy(void)
1156{
1157 while (frame_pending && wl_display_handle)
1158 {
1159 wl_display_dispatch(wl_display_handle);
1160 }
1161 struct wayland_buffer *target = &wl_buffers[wl_cur_buffer];
1162 if (target->busy) {
1163 target = &wl_buffers[wl_cur_buffer ^ 1];
1164 while (target->busy && wl_display_handle)
1165 {
1166 wl_display_dispatch(wl_display_handle);
1167 }
1168 }
1169 wl_cur_buffer = target == &wl_buffers[0] ? 1 : 0;
1170 uint32_t *pixels = target->pixels;
1171 uint32_t width_multiple = main_width / last_width_scale;
1172 uint32_t height_multiple = main_height / last_height_scale;
1173 uint32_t multiple = width_multiple < height_multiple ? width_multiple : height_multiple;
1174 if (max_multiple && multiple > max_multiple) {
1175 multiple = max_multiple;
1176 }
1177 height_multiple = last_height_scale * multiple / last_height;
1178 uint32_t *cur_line = pixels + (main_width - last_width_scale * multiple)/2;
1179 cur_line += wl_stride * (main_height - last_height_scale * multiple) / (2 * sizeof(uint32_t));
1180 uint32_t *src_line = copy_buffer;
1181 memset(pixels, 0, wl_stride * main_height);
1182 if (height_multiple * last_height == multiple * last_height_scale) {
1183 if (last_width == last_width_scale) {
1184 for (uint32_t y = 0; y < last_height; y++)
1185 {
1186 for (uint32_t i = 0; i < height_multiple; i++)
1187 {
1188 uint32_t *cur = cur_line;
1189 uint32_t *src = src_line;
1190 for (uint32_t x = 0; x < last_width ; x++)
1191 {
1192 uint32_t pixel = *(src++);
1193 for (uint32_t j = 0; j < multiple; j++)
1194 {
1195 *(cur++) = pixel;
1196 }
1197 }
1198
1199 cur_line += wl_stride / sizeof(uint32_t);
1200 }
1201 src_line += LINEBUF_SIZE;
1202 }
1203 } else {
1204 float scale_multiple = ((float)(last_width_scale * multiple)) / (float)last_width;
1205 float remaining = 0.0f;
1206 uint32_t last_pixel = 0;
1207 for (uint32_t y = 0; y < last_height; y++)
1208 {
1209 for (uint32_t i = 0; i < height_multiple; i++)
1210 {
1211 uint32_t *cur = cur_line;
1212 uint32_t *src = src_line;
1213 for (uint32_t x = 0; x < last_width ; x++)
1214 {
1215 uint32_t pixel = *(src++);
1216 float count = scale_multiple;
1217 if (remaining > 0.0f) {
1218 *(cur++) = mix_pixel(last_pixel, pixel, remaining);
1219 count -= 1.0f - remaining;
1220 }
1221 for (; count >= 1; count -= 1.0f)
1222 {
1223 *(cur++) = pixel;
1224 }
1225 remaining = count;
1226 last_pixel = pixel;
1227 }
1228
1229 cur_line += wl_stride / sizeof(uint32_t);
1230 }
1231 src_line += LINEBUF_SIZE;
1232 }
1233 }
1234 } else {
1235 float height_scale = ((float)(last_height_scale * multiple)) / (float)last_height;
1236 float height_remaining = 0.0f;
1237 uint32_t *last_line;
1238 if (last_width == last_width_scale) {
1239 for (uint32_t y = 0; y < last_height; y++)
1240 {
1241 float hcount = height_scale;
1242 if (height_remaining > 0.0f) {
1243 uint32_t *cur = cur_line;
1244 uint32_t *src = src_line;
1245 uint32_t *last = last_line;
1246 for (uint32_t x = 0; x < last_width ; x++)
1247 {
1248 uint32_t mixed = mix_pixel(*(last++), *(src++), height_remaining);
1249 for (uint32_t j = 0; j < multiple; j++)
1250 {
1251 *(cur++) = mixed;
1252 }
1253 }
1254 hcount -= 1.0f - height_remaining;
1255 cur_line += wl_stride / sizeof(uint32_t);
1256 }
1257 for(; hcount >= 1; hcount -= 1.0f)
1258 {
1259 uint32_t *cur = cur_line;
1260 uint32_t *src = src_line;
1261 for (uint32_t x = 0; x < last_width ; x++)
1262 {
1263 uint32_t pixel = *(src++);
1264 for (uint32_t j = 0; j < multiple; j++)
1265 {
1266 *(cur++) = pixel;
1267 }
1268 }
1269
1270 cur_line += wl_stride / sizeof(uint32_t);
1271 }
1272 height_remaining = hcount;
1273 last_line = src_line;
1274 src_line += LINEBUF_SIZE;
1275 }
1276 } else {
1277 float scale_multiple = ((float)(last_width_scale * multiple)) / (float)last_width;
1278 float remaining = 0.0f;
1279 uint32_t last_pixel = 0;
1280 for (uint32_t y = 0; y < last_height; y++)
1281 {
1282 float hcount = height_scale;
1283 if (height_remaining > 0.0f) {
1284 uint32_t *cur = cur_line;
1285 uint32_t *src = src_line;
1286 uint32_t *last = last_line;
1287
1288 for (uint32_t x = 0; x < last_width; x++)
1289 {
1290 uint32_t pixel = mix_pixel(*(last++), *(src++), height_remaining);
1291 float count = scale_multiple;
1292 if (remaining > 0.0f) {
1293 *(cur++) = mix_pixel(last_pixel, pixel, remaining);
1294 count -= 1.0f - remaining;
1295 }
1296 for (; count >= 1.0f; count -= 1.0f)
1297 {
1298 *(cur++) = pixel;
1299 }
1300 remaining = count;
1301 last_pixel = pixel;
1302 }
1303 hcount -= 1.0f - height_remaining;
1304 cur_line += wl_stride / sizeof(uint32_t);
1305 }
1306
1307 for (; hcount >= 1.0f; hcount -= 1.0f)
1308 {
1309 uint32_t *cur = cur_line;
1310 uint32_t *src = src_line;
1311 for (uint32_t x = 0; x < last_width ; x++)
1312 {
1313 uint32_t pixel = *(src++);
1314 float count = scale_multiple;
1315 if (remaining > 0.0f) {
1316 *(cur++) = mix_pixel(last_pixel, pixel, remaining);
1317 count -= 1.0f - remaining;
1318 }
1319 for (; count >= 1; count -= 1.0f)
1320 {
1321 *(cur++) = pixel;
1322 }
1323 remaining = count;
1324 last_pixel = pixel;
1325 }
1326
1327 cur_line += wl_stride / sizeof(uint32_t);
1328 }
1329 height_remaining = hcount;
1330 last_line = src_line;
1331 src_line += LINEBUF_SIZE;
1332 }
1333 }
1334 }
1335 wl_surface_attach(wl_surface_handle, target->buffer, 0, 0);
1336 wl_surface_damage(wl_surface_handle, 0, 0, main_width, main_height);
1337 frame_callback = wl_surface_frame(wl_surface_handle);
1338 wl_callback_add_listener(frame_callback, &frame_listener, NULL);
1339 frame_pending = 1;
1340 wl_surface_commit(wl_surface_handle);
1341 target->busy = 1;
1342 wl_display_flush(wl_display_handle);
1343}
1344
1345void window_setup(void)
1346{
1347 tern_val def = {.ptrval = "audio"};
1348 tern_node *video = tern_find_node(config, "video");
1349 if (video)
1350 {
1351 for (int i = 0; i < NUM_VID_STD; i++)
1352 {
1353 tern_node *std_settings = tern_find_node(video, vid_std_names[i]);
1354 if (std_settings) {
1355 char *val = tern_find_path_default(std_settings, "overscan\0top\0", (tern_val){.ptrval = NULL}, TVAL_PTR).ptrval;
1356 if (val) {
1357 overscan_top[i] = atoi(val);
1358 }
1359 val = tern_find_path_default(std_settings, "overscan\0bottom\0", (tern_val){.ptrval = NULL}, TVAL_PTR).ptrval;
1360 if (val) {
1361 overscan_bot[i] = atoi(val);
1362 }
1363 val = tern_find_path_default(std_settings, "overscan\0left\0", (tern_val){.ptrval = NULL}, TVAL_PTR).ptrval;
1364 if (val) {
1365 overscan_left[i] = atoi(val);
1366 }
1367 val = tern_find_path_default(std_settings, "overscan\0right\0", (tern_val){.ptrval = NULL}, TVAL_PTR).ptrval;
1368 if (val) {
1369 overscan_right[i] = atoi(val);
1370 }
1371 }
1372 }
1373 }
1374 wl_display_handle = wl_display_connect(NULL);
1375 if (!wl_display_handle) {
1376 fatal_error("Failed to connect to Wayland display\n");
1377 }
1378 struct wl_registry *registry = wl_display_get_registry(wl_display_handle);
1379 wl_registry_add_listener(registry, ®istry_listener, NULL);
1380 wl_display_roundtrip(wl_display_handle);
1381 if (!wl_compositor_handle || !wl_shm_handle || !xdg_wm_base_handle) {
1382 fatal_error("Wayland compositor is missing wl_compositor, wl_shm or xdg_wm_base support\n");
1383 }
1384 wl_display_roundtrip(wl_display_handle);
1385 wl_surface_handle = wl_compositor_create_surface(wl_compositor_handle);
1386 xdg_surface_handle = xdg_wm_base_get_xdg_surface(xdg_wm_base_handle, wl_surface_handle);
1387 xdg_surface_add_listener(xdg_surface_handle, &xdg_surface_listener, NULL);
1388 xdg_toplevel_handle = xdg_surface_get_toplevel(xdg_surface_handle);
1389 xdg_toplevel_add_listener(xdg_toplevel_handle, &xdg_toplevel_listener, NULL);
1390 if (caption) {
1391 xdg_toplevel_set_title(xdg_toplevel_handle, caption);
1392 }
1393 wl_surface_commit(wl_surface_handle);
1394 while (!wl_configured && wl_display_dispatch(wl_display_handle) != -1)
1395 {
1396 }
1397 wl_stride = main_width * sizeof(uint32_t);
1398 create_wayland_buffer(&wl_buffers[0]);
1399 create_wayland_buffer(&wl_buffers[1]);
1400 printf("Wayland shm window: %d x %d\n", main_width, main_height);
1401
1402 def.ptrval = "0";
1403 max_multiple = atoi(tern_find_path_default(config, "video\0wayland\0max_multiple\0", def, TVAL_PTR).ptrval);
1404
1405}
1406
1407void restore_tty(void)
1408{
1409 ioctl(STDIN_FILENO, KDSETMODE, KD_TEXT);
1410 for (int i = 0; i < cur_devices; i++)
1411 {
1412 if (device_types[i] == DEV_KEYBOARD) {
1413 ioctl(device_fds[i], EVIOCGRAB, 0);
1414 }
1415 }
1416}
1417
1418static void init_evdev(void)
1419{
1420 tern_val def = {.ptrval = "off"};
1421 if (strcmp(tern_find_path_default(config, "video\0wayland\0evdev\0", def, TVAL_PTR).ptrval, "on")) {
1422 return;
1423 }
1424 DIR *d = opendir("/dev/input");
1425 if (!d) {
1426 warning("Failed to open /dev/input for reading: %s\n", strerror(errno));
1427 return;
1428 }
1429 struct dirent* entry;
1430 int joystick_counter = 0;
1431 while ((entry = readdir(d)) && cur_devices < MAX_DEVICES)
1432 {
1433 if (!strncmp("event", entry->d_name, strlen("event"))) {
1434 char *filename = alloc_concat("/dev/input/", entry->d_name);
1435 int fd = open(filename, O_RDONLY);
1436 if (fd == -1) {
1437 int errnum = errno;
1438 warning("Failed to open evdev device %s for reading: %s\n", filename, strerror(errnum));
1439 free(filename);
1440 continue;
1441 }
1442
1443 unsigned long bits;
1444 if (-1 == ioctl(fd, EVIOCGBIT(0, sizeof(bits)), &bits)) {
1445 int errnum = errno;
1446 warning("Failed get capability bits from evdev device %s: %s\n", filename, strerror(errnum));
1447 free(filename);
1448 close(fd);
1449 continue;
1450 }
1451 if (!(1 & bits >> EV_KEY)) {
1452 free(filename);
1453 close(fd);
1454 continue;
1455 }
1456 unsigned long button_bits[(BTN_THUMBR+8*sizeof(long))/(8*sizeof(long))];
1457 int res = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(button_bits)), button_bits);
1458 if (-1 == res) {
1459 int errnum = errno;
1460 warning("Failed get capability bits from evdev device %s: %s\n", filename, strerror(errnum));
1461 free(filename);
1462 close(fd);
1463 continue;
1464 }
1465 int to_check[] = {KEY_ENTER, BTN_MOUSE, BTN_GAMEPAD};
1466 device_type dtype = DEV_NONE;
1467 for (int i = 0; i < 3; i++)
1468 {
1469 if (1 & button_bits[to_check[i]/(8*sizeof(button_bits[0]))] >> to_check[i]%(8*sizeof(button_bits[0]))) {
1470 dtype = i + 1;
1471 }
1472 }
1473 if (dtype == DEV_NONE) {
1474 close(fd);
1475 } else {
1476 device_fds[cur_devices] = fd;
1477 device_types[cur_devices] = dtype;
1478 char name[1024];
1479 char *names[] = {"Keyboard", "Mouse", "Gamepad"};
1480 ioctl(fd, EVIOCGNAME(sizeof(name)), name);
1481 printf("%s is a %s\n%s\n", filename, names[dtype - 1], name);
1482
1483 if (dtype == DEV_GAMEPAD) {
1484 handle_joy_added(joystick_counter++);
1485 } else if (dtype == DEV_KEYBOARD && isatty(STDIN_FILENO)) {
1486 ioctl(fd, EVIOCGRAB, 1);
1487 }
1488
1489 fcntl(fd, F_SETFL, O_NONBLOCK);
1490 cur_devices++;
1491 }
1492 free(filename);
1493 }
1494 }
1495 closedir(d);
1496}
1497
1498void render_init(int width, int height, char * title)
1499{
1500 if (height <= 0) {
1501 float aspect = config_aspect() > 0.0f ? config_aspect() : 4.0f/3.0f;
1502 height = ((float)width / aspect) + 0.5f;
1503 }
1504 printf("width: %d, height: %d\n", width, height);
1505 main_width = width;
1506 main_height = height;
1507
1508 caption = title;
1509
1510 if (isatty(STDIN_FILENO)) {
1511 ioctl(STDIN_FILENO, KDSETMODE, KD_GRAPHICS);
1512 atexit(restore_tty);
1513 }
1514
1515 window_setup();
1516
1517 init_audio();
1518
1519 render_set_video_standard(VID_NTSC);
1520 init_evdev();
1521
1522 atexit(render_quit);
1523}
1524static void update_source(audio_source *src, double rc, uint8_t sync_changed)
1525{
1526 double alpha = src->dt / (src->dt + rc);
1527 int32_t lowpass_alpha = (int32_t)(((double)0x10000) * alpha);
1528 src->lowpass_alpha = lowpass_alpha;
1529}
1530
1531void render_config_updated(void)
1532{
1533
1534 destroy_wayland();
1535 drain_events();
1536
1537 window_setup();
1538
1539 render_close_audio();
1540 init_audio();
1541 render_set_video_standard(video_standard);
1542
1543 double lowpass_cutoff = get_lowpass_cutoff(config);
1544 double rc = (1.0 / lowpass_cutoff) / (2.0 * M_PI);
1545 for (uint8_t i = 0; i < num_audio_sources; i++)
1546 {
1547 update_source(audio_sources[i], rc, 0);
1548 }
1549 for (uint8_t i = 0; i < num_inactive_audio_sources; i++)
1550 {
1551 update_source(inactive_audio_sources[i], rc, 0);
1552 }
1553 drain_events();
1554}
1555
1556void render_set_video_standard(vid_std std)
1557{
1558 video_standard = std;
1559}
1560
1561void render_update_caption(char *title)
1562{
1563 caption = title;
1564 if (xdg_toplevel_handle) {
1565 xdg_toplevel_set_title(xdg_toplevel_handle, title);
1566 }
1567 free(fps_caption);
1568 fps_caption = NULL;
1569}
1570
1571static char *screenshot_path;
1572void render_save_screenshot(char *path)
1573{
1574 if (screenshot_path) {
1575 free(screenshot_path);
1576 }
1577 screenshot_path = path;
1578}
1579
1580uint8_t render_create_window(char *caption, uint32_t width, uint32_t height, window_close_handler close_handler)
1581{
1582 //no op
1583 return 0;
1584}
1585
1586void render_destroy_window(uint8_t which)
1587{
1588 //no op
1589}
1590
1591static uint8_t last_video_buffer;
1592static uint32_t video_buffer_offset;
1593uint32_t *render_get_video_buffer(uint8_t which, int *pitch)
1594{
1595 if (last_video_buffer != which) {
1596 *pitch = LINEBUF_SIZE * sizeof(uint32_t) * 2;
1597 return video_buffer + video_buffer_offset + (which == VIDEO_BUFFER_EVEN ? LINEBUF_SIZE : 0);
1598 }
1599 *pitch = LINEBUF_SIZE * sizeof(uint32_t);
1600 return video_buffer + video_buffer_offset;
1601}
1602
1603uint8_t events_processed;
1604#define FPS_INTERVAL 1000
1605
1606void render_video_buffer_updated(uint8_t which, int width)
1607{
1608 uint32_t height = which <= VIDEO_BUFFER_EVEN
1609 ? (video_standard == VID_NTSC ? 243 : 294) - (overscan_top[video_standard] + overscan_bot[video_standard])
1610 : 240;
1611 width -= overscan_left[video_standard] + overscan_right[video_standard];
1612 last_width = width;
1613 last_width_scale = LINEBUF_SIZE - (overscan_left[video_standard] + overscan_right[video_standard]);
1614 last_height = last_height_scale = height;
1615 copy_buffer = video_buffer + video_buffer_offset + overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard];
1616 if (which != last_video_buffer) {
1617 last_height *= 2;
1618 copy_buffer += LINEBUF_SIZE * overscan_top[video_standard];
1619 uint32_t *src = video_buffer + (video_buffer_offset ? 0 : LINEBUF_SIZE * MAX_VIDEO_BUFFER_LINES) + overscan_left[video_standard] + LINEBUF_SIZE * overscan_top[video_standard] + LINEBUF_SIZE * overscan_top[video_standard];
1620 uint32_t *dst = copy_buffer;
1621 if (which == VIDEO_BUFFER_ODD) {
1622 src += LINEBUF_SIZE;
1623 dst += LINEBUF_SIZE;
1624 }
1625 for (int i = 0; i < height; i++)
1626 {
1627 memcpy(dst, src, width * sizeof(uint32_t));
1628 src += LINEBUF_SIZE * 2;
1629 dst += LINEBUF_SIZE * 2;
1630 }
1631 video_buffer_offset = video_buffer_offset ? 0 : LINEBUF_SIZE * MAX_VIDEO_BUFFER_LINES;
1632 }
1633 do_buffer_copy();
1634 last_video_buffer = which;
1635 if (!events_processed) {
1636 process_events();
1637 }
1638 events_processed = 0;
1639}
1640
1641uint32_t render_emulated_width()
1642{
1643 return last_width - overscan_left[video_standard] - overscan_right[video_standard];
1644}
1645
1646uint32_t render_emulated_height()
1647{
1648 return (video_standard == VID_NTSC ? 243 : 294) - overscan_top[video_standard] - overscan_bot[video_standard];
1649}
1650
1651uint32_t render_overscan_left()
1652{
1653 return overscan_left[video_standard];
1654}
1655
1656uint32_t render_overscan_top()
1657{
1658 return overscan_top[video_standard];
1659}
1660
1661void render_wait_quit(vdp_context * context)
1662{
1663 for(;;)
1664 {
1665 drain_events();
1666 sleep(1);
1667 }
1668}
1669
1670int render_lookup_button(char *name)
1671{
1672 static tern_node *button_lookup;
1673 if (!button_lookup) {
1674 //xbox names
1675 button_lookup = tern_insert_int(button_lookup, "a", BTN_SOUTH);
1676 button_lookup = tern_insert_int(button_lookup, "b", BTN_EAST);
1677 button_lookup = tern_insert_int(button_lookup, "x", BTN_WEST);
1678 button_lookup = tern_insert_int(button_lookup, "y", BTN_NORTH);
1679 button_lookup = tern_insert_int(button_lookup, "back", BTN_SELECT);
1680 button_lookup = tern_insert_int(button_lookup, "start", BTN_START);
1681 button_lookup = tern_insert_int(button_lookup, "guid", BTN_MODE);
1682 button_lookup = tern_insert_int(button_lookup, "leftshoulder", BTN_TL);
1683 button_lookup = tern_insert_int(button_lookup, "rightshoulder", BTN_TR);
1684 button_lookup = tern_insert_int(button_lookup, "leftstick", BTN_THUMBL);
1685 button_lookup = tern_insert_int(button_lookup, "rightstick", BTN_THUMBR);
1686 //ps names
1687 button_lookup = tern_insert_int(button_lookup, "cross", BTN_SOUTH);
1688 button_lookup = tern_insert_int(button_lookup, "circle", BTN_EAST);
1689 button_lookup = tern_insert_int(button_lookup, "square", BTN_WEST);
1690 button_lookup = tern_insert_int(button_lookup, "triangle", BTN_NORTH);
1691 button_lookup = tern_insert_int(button_lookup, "share", BTN_SELECT);
1692 button_lookup = tern_insert_int(button_lookup, "select", BTN_SELECT);
1693 button_lookup = tern_insert_int(button_lookup, "options", BTN_START);
1694 button_lookup = tern_insert_int(button_lookup, "l1", BTN_TL);
1695 button_lookup = tern_insert_int(button_lookup, "r1", BTN_TR);
1696 button_lookup = tern_insert_int(button_lookup, "l3", BTN_THUMBL);
1697 button_lookup = tern_insert_int(button_lookup, "r3", BTN_THUMBR);
1698 }
1699 return (int)tern_find_int(button_lookup, name, KEY_CNT);
1700}
1701
1702int render_lookup_axis(char *name)
1703{
1704 static tern_node *axis_lookup;
1705 if (!axis_lookup) {
1706 //xbox names
1707 axis_lookup = tern_insert_int(axis_lookup, "leftx", ABS_X);
1708 axis_lookup = tern_insert_int(axis_lookup, "lefty", ABS_Y);
1709 axis_lookup = tern_insert_int(axis_lookup, "lefttrigger", ABS_Z);
1710 axis_lookup = tern_insert_int(axis_lookup, "rightx", ABS_RX);
1711 axis_lookup = tern_insert_int(axis_lookup, "righty", ABS_RY);
1712 axis_lookup = tern_insert_int(axis_lookup, "righttrigger", ABS_RZ);
1713 //ps names
1714 axis_lookup = tern_insert_int(axis_lookup, "l2", ABS_Z);
1715 axis_lookup = tern_insert_int(axis_lookup, "r2", ABS_RZ);
1716 }
1717 return (int)tern_find_int(axis_lookup, name, ABS_CNT);
1718}
1719
1720int32_t render_translate_input_name(int32_t controller, char *name, uint8_t is_axis)
1721{
1722 if (is_axis) {
1723 int axis = render_lookup_axis(name);
1724 if (axis == ABS_CNT) {
1725 return RENDER_INVALID_NAME;
1726 }
1727 return RENDER_AXIS_BIT | axis;
1728 } else {
1729 int button = render_lookup_button(name);
1730 if (button != KEY_CNT) {
1731 return button;
1732 }
1733 if (!strcmp("dpup", name)) {
1734 return RENDER_DPAD_BIT | 1;
1735 }
1736 if (!strcmp("dpdown", name)) {
1737 return RENDER_DPAD_BIT | 4;
1738 }
1739 if (!strcmp("dpdleft", name)) {
1740 return RENDER_DPAD_BIT | 8;
1741 }
1742 if (!strcmp("dpright", name)) {
1743 return RENDER_DPAD_BIT | 2;
1744 }
1745 return RENDER_INVALID_NAME;
1746 }
1747}
1748
1749int32_t render_dpad_part(int32_t input)
1750{
1751 return input >> 4 & 0xFFFFFF;
1752}
1753
1754uint8_t render_direction_part(int32_t input)
1755{
1756 return input & 0xF;
1757}
1758
1759int32_t render_axis_part(int32_t input)
1760{
1761 return input & 0xFFFFFFF;
1762}
1763
1764void process_events()
1765{
1766 if (events_processed > MAX_EVENT_POLL_PER_FRAME) {
1767 return;
1768 }
1769 if (wl_display_handle) {
1770 dispatch_wayland_pending(0);
1771 }
1772 drain_events();
1773 events_processed++;
1774}
1775
1776uint32_t render_audio_buffer()
1777{
1778 return buffer_samples;
1779}
1780
1781uint32_t render_sample_rate()
1782{
1783 return sample_rate;
1784}
1785
1786void render_errorbox(char *title, char *message)
1787{
1788
1789}
1790
1791void render_warnbox(char *title, char *message)
1792{
1793
1794}
1795
1796void render_infobox(char *title, char *message)
1797{
1798
1799}
1800
1801uint8_t render_get_active_video_buffer(void)
1802{
1803 return VIDEO_BUFFER_ODD;
1804}