diff --git a/repos/libports/lib/mk/sdlmain.mk b/repos/libports/lib/mk/sdlmain.mk
new file mode 100644
index 0000000000..bf344e42b1
--- /dev/null
+++ b/repos/libports/lib/mk/sdlmain.mk
@@ -0,0 +1,5 @@
+SRC_CC = sdl_main.cc
+
+LIBS += libc
+
+vpath sdl_main.cc $(REP_DIR)/src/lib/sdl
diff --git a/repos/libports/run/avplay.run b/repos/libports/run/avplay.run
index e96fbbe69d..e7d59b2c38 100644
--- a/repos/libports/run/avplay.run
+++ b/repos/libports/run/avplay.run
@@ -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
}
diff --git a/repos/libports/run/sdl.run b/repos/libports/run/sdl.run
index 7597f64f88..874e239326 100644
--- a/repos/libports/run/sdl.run
+++ b/repos/libports/run/sdl.run
@@ -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
diff --git a/repos/libports/src/app/avplay/target.mk b/repos/libports/src/app/avplay/target.mk
index 62cf1f6875..8dcca5363b 100644
--- a/repos/libports/src/app/avplay/target.mk
+++ b/repos/libports/src/app/avplay/target.mk
@@ -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
diff --git a/repos/libports/src/lib/sdl/SDL_genode_internal.h b/repos/libports/src/lib/sdl/SDL_genode_internal.h
new file mode 100644
index 0000000000..bec66bb2dc
--- /dev/null
+++ b/repos/libports/src/lib/sdl/SDL_genode_internal.h
@@ -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_ */
diff --git a/repos/libports/src/lib/sdl/audio/SDL_genodeaudio.cc b/repos/libports/src/lib/sdl/audio/SDL_genodeaudio.cc
index 6e86e774c8..699668c1dc 100644
--- a/repos/libports/src/lib/sdl/audio/SDL_genodeaudio.cc
+++ b/repos/libports/src/lib/sdl/audio/SDL_genodeaudio.cc
@@ -14,6 +14,7 @@
* under the terms of the GNU Affero General Public License version 3.
*/
+/* Genode includes */
#include
#include
#include
@@ -21,6 +22,13 @@
#include
#include
+/* local includes */
+#include
+
+
+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 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 _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;
Constructible 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 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] =
diff --git a/repos/libports/src/lib/sdl/sdl_main.cc b/repos/libports/src/lib/sdl/sdl_main.cc
new file mode 100644
index 0000000000..53a03cf116
--- /dev/null
+++ b/repos/libports/src/lib/sdl/sdl_main.cc
@@ -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
+#include
+
+/* libc includes */
+#include /* 'malloc' and 'exit' */
+#include
+
+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);
+ }
+}
diff --git a/repos/libports/src/lib/sdl/video/SDL_genode_fb_events.cc b/repos/libports/src/lib/sdl/video/SDL_genode_fb_events.cc
index 97bdd851a6..bbe8d58a0e 100644
--- a/repos/libports/src/lib/sdl/video/SDL_genode_fb_events.cc
+++ b/repos/libports/src/lib/sdl/video/SDL_genode_fb_events.cc
@@ -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
#include
#include
#include
+/* local includes */
+#include
+
+
+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
@@ -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;
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 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
#include
+/* local includes */
+#include
+
+
+extern Genode::Env *global_env();
+
+extern Genode::Lock event_lock;
+extern Video video_events;
+
+
extern "C" {
#include
@@ -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 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 _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 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"
diff --git a/repos/libports/src/test/sdl/target.mk b/repos/libports/src/test/sdl/target.mk
index a14e11b268..fc7f75f89d 100644
--- a/repos/libports/src/test/sdl/target.mk
+++ b/repos/libports/src/test/sdl/target.mk
@@ -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
diff --git a/repos/ports/run/dosbox.run b/repos/ports/run/dosbox.run
index 6816ada6bb..bfef30d366 100644
--- a/repos/ports/run/dosbox.run
+++ b/repos/ports/run/dosbox.run
@@ -88,7 +88,7 @@ append config {
-
+
@@ -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
diff --git a/repos/ports/src/app/dosbox/target.mk b/repos/ports/src/app/dosbox/target.mk
index 875bfd6641..bcdfc2a7a2 100644
--- a/repos/ports/src/app/dosbox/target.mk
+++ b/repos/ports/src/app/dosbox/target.mk
@@ -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