diff options
Diffstat (limited to 'arch/sandbox/os/sdl.c')
-rw-r--r-- | arch/sandbox/os/sdl.c | 184 |
1 files changed, 119 insertions, 65 deletions
diff --git a/arch/sandbox/os/sdl.c b/arch/sandbox/os/sdl.c index 9a35279eb7..13178abfc0 100644 --- a/arch/sandbox/os/sdl.c +++ b/arch/sandbox/os/sdl.c @@ -1,103 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> - * - * GPL v2 + * Copyright (c) 2021 Ahmad Fatoum */ #include <stdio.h> +#include <stdbool.h> #include <SDL.h> -#include <time.h> -#include <signal.h> #include <mach/linux.h> -#include <unistd.h> -#include <pthread.h> -struct fb_bitfield { - uint32_t offset; /* beginning of bitfield */ - uint32_t length; /* length of bitfield */ - uint32_t msb_right; /* != 0 : Most significant bit is */ - /* right */ -}; +static void sdl_perror(const char *what) +{ + printf("SDL: Could not %s: %s.\n", what, SDL_GetError()); +} -static SDL_Surface *real_screen; -static void *buffer = NULL; -pthread_t th; +static struct sdl_fb_info info; +static SDL_atomic_t shutdown; +SDL_Window *window; -static void sdl_copy_buffer(SDL_Surface *screen) +static int scanout(void *ptr) { - if (SDL_MUSTLOCK(screen)) { - if (SDL_LockSurface(screen) < 0) - return; + SDL_Renderer *renderer; + SDL_Surface *surface; + SDL_Texture *texture; + void *buf = info.screen_base; + int ret = -1; + + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); + if (!renderer) { + sdl_perror("create renderer"); + return -1; } - memcpy(screen->pixels, buffer, screen->pitch * screen->h); + surface = SDL_CreateRGBSurface(0, info.xres, info.yres, info.bpp, + info.rmask, info.gmask, info.bmask, info.amask); + if (!surface) { + sdl_perror("create surface"); + goto destroy_renderer; + } - if(SDL_MUSTLOCK(screen)) - SDL_UnlockSurface(screen); -} + texture = SDL_CreateTextureFromSurface(renderer, surface); + if (!texture) { + sdl_perror("create texture"); + goto free_surface; + } -static void *threadStart(void *ptr) -{ - while (1) { - usleep(1000 * 100); + while (!SDL_AtomicGet(&shutdown)) { + SDL_Delay(100); - sdl_copy_buffer(real_screen); - SDL_Flip(real_screen); + SDL_UpdateTexture(texture, NULL, buf, surface->pitch); + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, texture, NULL, NULL); + SDL_RenderPresent(renderer); } - return 0; -} + ret = 0; -void sdl_start_timer(void) -{ - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_create(&th, &attr, threadStart, NULL); -} + SDL_DestroyTexture(texture); +free_surface: + SDL_FreeSurface(surface); +destroy_renderer: + SDL_DestroyRenderer(renderer); -void sdl_stop_timer(void) -{ - pthread_cancel(th); + return ret; } -void sdl_get_bitfield_rgba(struct fb_bitfield *r, struct fb_bitfield *g, - struct fb_bitfield *b, struct fb_bitfield *a) +static SDL_Thread *thread; + +void sdl_video_close(void) { - SDL_Surface *screen = real_screen; - - r->length = 8 - screen->format->Rloss; - r->offset = screen->format->Rshift; - g->length = 8 - screen->format->Gloss; - g->offset = screen->format->Gshift; - b->length = 8 - screen->format->Bloss; - b->offset = screen->format->Bshift; - a->length = 8 - screen->format->Aloss; - a->offset = screen->format->Ashift; + SDL_AtomicSet(&shutdown, true); /* implies full memory barrier */ + SDL_WaitThread(thread, NULL); + SDL_AtomicSet(&shutdown, false); + SDL_DestroyWindow(window); + SDL_QuitSubSystem(SDL_INIT_VIDEO); } -int sdl_open(int xres, int yres, int bpp, void* buf) +int sdl_video_open(const struct sdl_fb_info *_info) { - int flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL; + info = *_info; - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0) { - printf("Could not initialize SDL: %s.\n", SDL_GetError()); + if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { + sdl_perror("initialize SDL Video"); return -1; } - real_screen = SDL_SetVideoMode(xres, yres, bpp, flags); - if (!real_screen) { - sdl_close(); - fprintf(stderr, "Couldn't create renderer: %s\n", SDL_GetError()); + window = SDL_CreateWindow("barebox", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, + info.xres, info.yres, 0); + if (!window) { + sdl_perror("create window"); + goto quit_subsystem; + } + + /* All scanout needs to happen in the same thread, because not all + * graphic backends are thread-safe. The window is created in the main + * thread though to work around libEGL crashing with SDL_VIDEODRIVER=wayland + */ + + thread = SDL_CreateThread(scanout, "video-scanout", NULL); + if (!thread) { + sdl_perror("start scanout thread"); + goto destroy_window; + } + + return 0; + +destroy_window: + SDL_DestroyWindow(window); +quit_subsystem: + SDL_QuitSubSystem(SDL_INIT_VIDEO); + + return -1; +} + +static SDL_AudioDeviceID dev; + +int sdl_sound_init(unsigned sample_rate) +{ + SDL_AudioSpec audiospec = { + .freq = sample_rate, + .format = AUDIO_S16, + .channels = 1, + .samples = 2048, + }; + + if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { + sdl_perror("initialize SDL Audio"); return -1; } - buffer = buf; + dev = SDL_OpenAudioDevice(NULL, 0, &audiospec, NULL, 0); + if (!dev) { + sdl_perror("initialize open audio device"); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + return -1; + } + SDL_PauseAudioDevice(dev, 0); return 0; } -void sdl_close(void) +void sdl_sound_close(void) +{ + SDL_QuitSubSystem(SDL_INIT_AUDIO); +} + +int sdl_sound_play(const void *data, unsigned nsamples) +{ + /* core sound support handles all the queueing for us */ + SDL_ClearQueuedAudio(dev); + return SDL_QueueAudio(dev, data, nsamples * sizeof(uint16_t)); +} + +void sdl_sound_stop(void) { - sdl_stop_timer(); - SDL_Quit(); + SDL_ClearQueuedAudio(dev); } |