sdl: remove deprecated API usage

In addition framebuffer resizing is now also supported.

Fixes #2583.
This commit is contained in:
Josef Söntgen 2017-11-17 13:03:22 +01:00 committed by Christian Helmuth
parent 86c1f65dfe
commit 6ca8f4c174
12 changed files with 372 additions and 93 deletions

View File

@ -0,0 +1,5 @@
SRC_CC = sdl_main.cc
LIBS += libc
vpath sdl_main.cc $(REP_DIR)/src/lib/sdl

View File

@ -115,7 +115,7 @@ append boot_modules {
core init timer } [audio_drv_binary] { avplay
ld.lib.so libc.lib.so libm.lib.so pthread.lib.so zlib.lib.so sdl.lib.so
avfilter.lib.so avutil.lib.so avcodec.lib.so avformat.lib.so swscale.lib.so
avresample.lib.so posix.lib.so
avresample.lib.so
mediafile
}

View File

@ -85,7 +85,7 @@ set boot_modules {
core init
timer
test-sdl
ld.lib.so libc.lib.so libm.lib.so sdl.lib.so pthread.lib.so posix.lib.so
ld.lib.so libc.lib.so libm.lib.so sdl.lib.so pthread.lib.so
}
# platform-specific modules

View File

@ -3,7 +3,7 @@ include $(REP_DIR)/lib/import/import-av.inc
TARGET = avplay
SRC_C = avplay.c cmdutils.c libc_dummies.c
LIBS += avfilter avformat avcodec avutil avresample swscale
LIBS += sdl posix
LIBS += sdl sdlmain libc libm
CC_WARN += -Wno-parentheses -Wno-switch -Wno-uninitialized \
-Wno-format-zero-length -Wno-pointer-sign

View File

@ -0,0 +1,24 @@
/*
* \brief Genode-specific data structures
* \author Josef Soentgen
* \date 2017-11-21
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SDL_GENODE_INTERNAL_H_
#define _SDL_GENODE_INTERNAL_H_
struct Video
{
bool resize_pending;
int width;
int height;
};
#endif /* _SDL_GENODE_INTERNAL_H_ */

View File

@ -14,6 +14,7 @@
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/allocator_avl.h>
#include <base/attached_rom_dataspace.h>
#include <base/log.h>
@ -21,6 +22,13 @@
#include <audio_out_session/connection.h>
#include <util/reconstructible.h>
/* local includes */
#include <SDL_genode_internal.h>
extern Genode::Env *global_env();
extern Genode::Lock event_lock;
enum {
AUDIO_CHANNELS = 2,
@ -34,7 +42,6 @@ using Genode::Hex;
using Genode::Constructible;
static const char *channel_names[] = { "front left", "front right" };
static float volume = 1.0;
static Signal_context config_signal_context;
extern "C" {
@ -54,48 +61,55 @@ extern "C" {
/* The tag name used by Genode audio */
#define GENODEAUD_DRIVER_NAME "genode"
struct Volume_config
{
Genode::Env &_env;
Genode::Attached_rom_dataspace _config_rom { _env, "config" };
float volume { 1.0f };
void _handle_config_update()
{
_config_rom.update();
if (!_config_rom.valid()) { return; }
Genode::Lock_guard<Genode::Lock> guard(event_lock);
Genode::Xml_node config = _config_rom.xml();
try {
unsigned int config_volume;
config.sub_node("sdl_audio_volume").attribute("value")
.value(&config_volume);
volume = (float)config_volume / 100;
} catch (...) { }
Genode::log("Change SDL audio volume to ", volume * 100);
}
Genode::Signal_handler<Volume_config> _config_handler {
_env.ep(), *this, &Volume_config::_handle_config_update };
Volume_config(Genode::Env &env) : _env(env)
{
_config_rom.sigh(_config_handler);
_handle_config_update();
}
};
struct SDL_PrivateAudioData {
Uint8 *mixbuf;
Uint32 mixlen;
Constructible<Volume_config> volume_config;
Constructible<Audio_out::Connection> audio[AUDIO_CHANNELS];
Audio_out::Packet *packet[AUDIO_CHANNELS];
};
/*
* The first 'Signal_receiver' object in a process creates a signal receiver
* thread. Currently this must not happen before the main program has started
* or else the thread's stack area would get overmapped on Genode/Linux when
* the main program calls 'main_thread_bootstrap()' from '_main()'.
*/
static Signal_receiver *signal_receiver()
{
static Signal_receiver _signal_receiver;
return &_signal_receiver;
}
static void read_config(Genode::Signal_context_capability sigh =
Genode::Signal_context_capability())
{
/* read volume from config file */
try {
unsigned int config_volume;
Genode::Attached_rom_dataspace config("config");
if (sigh.valid()) config.sigh(sigh);
else config.update();
config.xml().sub_node("sdl_audio_volume")
.attribute("value").value(&config_volume);
volume = (float)config_volume / 100;
}
catch (Genode::Xml_node::Nonexistent_sub_node) { }
catch (Genode::Xml_node::Nonexistent_attribute) { }
}
/* Audio driver functions */
static int GENODEAUD_OpenAudio(_THIS, SDL_AudioSpec *spec);
static void GENODEAUD_WaitAudio(_THIS);
@ -153,7 +167,7 @@ static SDL_AudioDevice *GENODEAUD_CreateDevice(int devindex)
/* connect to 'Audio_out' service */
for (int channel = 0; channel < AUDIO_CHANNELS; channel++) {
try {
_this->hidden->audio[channel].construct(
_this->hidden->audio[channel].construct(*global_env(),
channel_names[channel], false, channel == 0 ? true : false);
_this->hidden->audio[channel]->start();
}
@ -167,7 +181,7 @@ static SDL_AudioDevice *GENODEAUD_CreateDevice(int devindex)
}
}
read_config(signal_receiver()->manage(&config_signal_context));
_this->hidden->volume_config.construct(*global_env());
return _this;
}
@ -200,6 +214,8 @@ static void GENODEAUD_WaitAudio(_THIS)
static void GENODEAUD_PlayAudio(_THIS)
{
Genode::Lock_guard<Genode::Lock> guard(event_lock);
Audio_out::Connection *c[AUDIO_CHANNELS];
Audio_out::Packet *p[AUDIO_CHANNELS];
for (int channel = 0; channel < AUDIO_CHANNELS; channel++) {
@ -214,6 +230,8 @@ static void GENODEAUD_PlayAudio(_THIS)
init = true;
}
float const volume = _this->hidden->volume_config->volume;
/*
* Get new packet for left channel and use it to synchronize
* the right channel
@ -222,11 +240,6 @@ static void GENODEAUD_PlayAudio(_THIS)
unsigned ppos = c[0]->stream()->packet_position(p[0]);
p[1] = c[1]->stream()->get(ppos);
if (signal_receiver()->pending()) {
signal_receiver()->wait_for_signal();
read_config();
}
for (int sample = 0; sample < Audio_out::PERIOD; sample++)
for (int channel = 0; channel < AUDIO_CHANNELS; channel++)
p[channel]->content()[sample] =

View File

@ -0,0 +1,132 @@
/*
* \brief Entry point for SDL applications with a main() function
* \author Josef Soentgen
* \date 2017-11-21
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/sleep.h>
#include <libc/component.h>
/* libc includes */
#include <stdlib.h> /* 'malloc' and 'exit' */
#include <pthread.h>
extern char **genode_argv;
extern int genode_argc;
extern char **genode_envp;
/* initial environment for the FreeBSD libc implementation */
extern char **environ;
/* provided by the application */
extern "C" int main(int argc, char *argv[], char *envp[]);
/* provided by our SDL backend */
extern void sdl_init_genode(Genode::Env &env);
static void* sdl_main(void *)
{
exit(main(genode_argc, genode_argv, genode_envp));
return nullptr;
}
void Libc::Component::construct(Libc::Env &env)
{
using Genode::Xml_node;
using Genode::Xml_attribute;
env.config([&] (Xml_node const &node) {
int argc = 0;
int envc = 0;
char **argv;
char **envp;
/* count the number of arguments and environment variables */
node.for_each_sub_node([&] (Xml_node const &node) {
/* check if the 'value' attribute exists */
if (node.has_type("arg") && node.has_attribute("value"))
++argc;
else
if (node.has_type("env") && node.has_attribute("key") && node.has_attribute("value"))
++envc;
});
if (argc == 0 && envc == 0)
return; /* from lambda */
/* arguments and environment are a contiguous array (but don't count on it) */
argv = (char**)malloc((argc + envc + 1) * sizeof(char*));
envp = &argv[argc];
/* read the arguments */
int arg_i = 0;
int env_i = 0;
node.for_each_sub_node([&] (Xml_node const &node) {
/* insert an argument */
if (node.has_type("arg")) try {
Xml_attribute attr = node.attribute("value");
Genode::size_t const arg_len = attr.value_size()+1;
char *arg = argv[arg_i] = (char*)malloc(arg_len);
attr.value(arg, arg_len);
++arg_i;
} catch (Xml_node::Nonexistent_sub_node) { }
else
/* insert an environment variable */
if (node.has_type("env")) try {
Xml_attribute key_attr = node.attribute("key");
Xml_attribute val_attr = node.attribute("value");
Genode::size_t const pair_len =
key_attr.value_size() +
val_attr.value_size() + 1;
char *env = envp[env_i] = (char*)malloc(pair_len);
Genode::size_t off = 0;
key_attr.value(&env[off], key_attr.value_size()+1);
off = key_attr.value_size();
env[off++] = '=';
val_attr.value(&env[off], val_attr.value_size()+1);
++env_i;
} catch (Xml_node::Nonexistent_sub_node) { }
});
envp[env_i] = NULL;
/* register command-line arguments at Genode's startup code */
genode_argc = argc;
genode_argv = argv;
genode_envp = environ = envp;
});
/* pass env to SDL backend */
sdl_init_genode(env);
pthread_attr_t attr;
pthread_t main_thread;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 768 * 1024);
if (pthread_create(&main_thread, &attr, sdl_main, nullptr)) {
Genode::error("failed to create SDL main thread");
exit(1);
}
}

View File

@ -28,11 +28,41 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/* Genode includes */
#include <base/log.h>
#include <input_session/connection.h>
#include <input/event.h>
#include <input/keycodes.h>
/* local includes */
#include <SDL_genode_internal.h>
Genode::Lock event_lock;
Video video_events;
static Genode::Env *_global_env = nullptr;
Genode::Env *global_env()
{
if (!_global_env) {
Genode::error("sdl_init_genode() not called, aborting");
throw Genode::Exception();
}
return _global_env;
}
void sdl_init_genode(Genode::Env &env)
{
_global_env = &env;
}
extern "C" {
#include <SDL/SDL.h>
@ -40,7 +70,8 @@ extern "C" {
#include "SDL_sysevents.h"
#include "SDL_genode_fb_events.h"
static Input::Connection *input = 0;
static Genode::Constructible<Input::Connection> input;
static const int KEYNUM_MAX = 512;
static SDLKey keymap[KEYNUM_MAX];
static int buttonmap[KEYNUM_MAX];
@ -58,8 +89,17 @@ extern "C" {
void Genode_Fb_PumpEvents(SDL_VideoDevice *t)
{
Genode::Lock_guard<Genode::Lock> guard(event_lock);
if (video_events.resize_pending) {
video_events.resize_pending = false;
SDL_PrivateResize(video_events.width, video_events.height);
}
if (!input->pending())
return;
input->for_each_event([&] (Input::Event const &curr) {
SDL_keysym ksym;
switch(curr.type())
@ -104,14 +144,15 @@ extern "C" {
void Genode_Fb_InitOSKeymap(SDL_VideoDevice *t)
{
using namespace Input;
input = new(Genode::env()->heap()) Connection();
if(!input->cap().valid())
{
try {
input.construct(*_global_env);
} catch (...) {
Genode::error("no input driver available!");
return;
}
using namespace Input;
/* Prepare button mappings */
for (int i=0; i<KEYNUM_MAX; i++)
{

View File

@ -34,6 +34,16 @@
#include <base/env.h>
#include <framebuffer_session/connection.h>
/* local includes */
#include <SDL_genode_internal.h>
extern Genode::Env *global_env();
extern Genode::Lock event_lock;
extern Video video_events;
extern "C" {
#include <dlfcn.h>
@ -47,10 +57,52 @@ extern "C" {
#include "SDL_genode_fb_events.h"
#include "SDL_genode_fb_video.h"
static Framebuffer::Connection *framebuffer = 0;
static SDL_Rect df_mode;
struct Sdl_framebuffer
{
Genode::Env &_env;
Framebuffer::Mode _mode;
Framebuffer::Connection _fb { _env, _mode };
void _handle_mode_change()
{
Genode::Lock_guard<Genode::Lock> guard(event_lock);
Framebuffer::Mode mode = _fb.mode();
df_mode.w = mode.width();
df_mode.h = mode.height();
video_events.resize_pending = true;
video_events.width = mode.width();
video_events.height = mode.height();
}
Genode::Signal_handler<Sdl_framebuffer> _mode_handler {
_env.ep(), *this, &Sdl_framebuffer::_handle_mode_change };
Sdl_framebuffer(Genode::Env &env) : _env(env) {
_fb.mode_sigh(_mode_handler); }
bool valid() const { return _fb.cap().valid(); }
/************************************
** Framebuffer::Session Interface **
************************************/
Genode::Dataspace_capability dataspace() { return _fb.dataspace(); }
Framebuffer::Mode mode() const { return _fb.mode(); }
void refresh(int x, int y, int w, int h) {
_fb.refresh(x, y, w, h); }
};
static Genode::Constructible<Sdl_framebuffer> framebuffer;
static Framebuffer::Mode scr_mode;
static SDL_Rect *modes[2];
static SDL_Rect df_mode;
#if defined(SDL_VIDEO_OPENGL)
@ -216,11 +268,11 @@ extern "C" {
static int Genode_Fb_Available(void)
{
if (framebuffer == nullptr) {
framebuffer = new (Genode::env()->heap()) Framebuffer::Connection();
if (!framebuffer.constructed()) {
framebuffer.construct(*global_env());
}
if (!framebuffer->cap().valid()) {
if (!framebuffer->valid()) {
Genode::error("could not obtain framebuffer session");
return 0;
}
@ -231,12 +283,9 @@ extern "C" {
static void Genode_Fb_DeleteDevice(SDL_VideoDevice *device)
{
Genode::log("free framebuffer session object");
if(framebuffer != nullptr) {
Genode::destroy(Genode::env()->heap(), framebuffer);
if (framebuffer.constructed()) {
framebuffer.destruct();
}
framebuffer = nullptr;
}
@ -310,9 +359,8 @@ extern "C" {
*/
int Genode_Fb_VideoInit(SDL_VideoDevice *t, SDL_PixelFormat *vformat)
{
if (framebuffer == 0)
{
Genode::error("framebuffer isn't initialized");
if (!framebuffer.constructed()) {
Genode::error("framebuffer not initialized");
return -1;
}
@ -345,17 +393,30 @@ extern "C" {
df_mode.h = scr_mode.height();
modes[1] = 0;
/* Map the buffer */
Genode::Dataspace_capability fb_ds_cap = framebuffer->dataspace();
if (!fb_ds_cap.valid()) {
Genode::error("could not request dataspace for frame buffer");
return -1;
}
t->hidden->buffer = Genode::env()->rm_session()->attach(fb_ds_cap);
t->hidden->buffer = 0;
return 0;
}
/**
*Note: If we are terminated, this could be called in the middle of
* another SDL video routine -- notably UpdateRects.
*/
void Genode_Fb_VideoQuit(SDL_VideoDevice *t)
{
Genode::log("Quit video device ...");
if (t->screen->pixels) {
t->screen->pixels = nullptr;
}
if (t->hidden->buffer) {
global_env()->rm().detach(t->hidden->buffer);
t->hidden->buffer = nullptr;
}
}
/**
* List the available video modes for the given pixel format,
* sorted from largest to smallest.
@ -383,13 +444,32 @@ extern "C" {
int width, int height,
int bpp, Uint32 flags)
{
Genode::log("Set video mode to: "
"width=", width, " " "height=", height, " " "bpp=", bpp);
/* for now we do not support this */
if (t->hidden->buffer && flags & SDL_OPENGL) {
Genode::error("resizing a OpenGL window not possible");
return nullptr;
}
/* Map the buffer */
Genode::Dataspace_capability fb_ds_cap = framebuffer->dataspace();
if (!fb_ds_cap.valid()) {
Genode::error("could not request dataspace for frame buffer");
return nullptr;
}
if (t->hidden->buffer) {
global_env()->rm().detach(t->hidden->buffer);
}
t->hidden->buffer = global_env()->rm().attach(fb_ds_cap);
if (!t->hidden->buffer) {
Genode::error("no buffer for requested mode");
return nullptr;
}
Genode::log("Set video mode to: ", width, "x", height, "@", bpp);
SDL_memset(t->hidden->buffer, 0, width * height * (bpp / 8));
if (!SDL_ReallocFormat(current, bpp, 0, 0, 0, 0) ) {
@ -481,21 +561,6 @@ extern "C" {
}
/**
*Note: If we are terminated, this could be called in the middle of
* another SDL video routine -- notably UpdateRects.
*/
void Genode_Fb_VideoQuit(SDL_VideoDevice *t)
{
Genode::log("Quit video device ...");
if (t->screen->pixels != 0)
{
SDL_free(t->screen->pixels);
t->screen->pixels = 0;
}
}
int Genode_Fb_GL_MakeCurrent(SDL_VideoDevice *t)
{
Genode::warning(__func__, ": not yet implemented");
@ -523,5 +588,4 @@ extern "C" {
{
return !__mesa ? nullptr : dlsym(__mesa, proc);
}
} //extern "C"

View File

@ -1,3 +1,3 @@
TARGET = test-sdl
LIBS = sdl posix
SRC_CC = main.cc
TARGET := test-sdl
LIBS := libc sdl sdlmain
SRC_CC := main.cc

View File

@ -88,7 +88,7 @@ append config {
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="dosbox">
<start name="dosbox" caps="200">
<resource name="RAM" quantum="128M"/>
<config>
<sdl_audio_volume value="100"/>
@ -121,7 +121,7 @@ if {![file exists bin/dosbox.tar]} {
append boot_modules {
core init timer } [audio_drv_binary] {
ld.lib.so
libc.lib.so posix.lib.so
libc.lib.so
libm.lib.so lwip.lib.so libpng.lib.so
stdcxx.lib.so sdl.lib.so sdl_net.lib.so pthread.lib.so zlib.lib.so
dosbox dosbox.tar

View File

@ -55,5 +55,5 @@ CC_WARN += -Wno-unused-variable -Wno-unused-function -Wno-switch -Wno-unused-val
-Wno-sign-compare -Wno-narrowing -Wno-missing-braces -Wno-array-bounds \
-Wno-parentheses
LIBS += posix libpng sdl sdl_net stdcxx zlib
LIBS += libpng libc sdl sdlmain sdl_net stdcxx zlib
LIBS += libc_lwip_nic_dhcp