From 236652be3538805c45aa641e4ad0f6fba4e41148 Mon Sep 17 00:00:00 2001 From: oxmox Date: Sun, 19 Feb 2023 10:46:12 +0100 Subject: [PATCH] make dp_doom send out framebuffers via nng --- src/CMakeLists.txt | 1 + src/dp_doom/CMakeLists.txt | 9 +- .../linuxdoom-1.10/ib_sound/ib_sound_nng.c | 22 ++ .../linuxdoom-1.10/ib_video/ib_video_nng.c | 281 +++++++++++++++++- 4 files changed, 304 insertions(+), 9 deletions(-) create mode 100644 src/dp_doom/linuxdoom-1.10/ib_sound/ib_sound_nng.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 800e3fa..9d289ca 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,6 +25,7 @@ target_link_libraries(dp_common PUBLIC nng PUBLIC Threads::Threads ) +target_include_directories(dp_common INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) add_executable(doompanning doompanning.cc) target_compile_features(doompanning PRIVATE cxx_std_17) diff --git a/src/dp_doom/CMakeLists.txt b/src/dp_doom/CMakeLists.txt index 0bbb08c..2931612 100644 --- a/src/dp_doom/CMakeLists.txt +++ b/src/dp_doom/CMakeLists.txt @@ -213,13 +213,18 @@ elseif(BACKEND STREQUAL "SDL2") target_compile_definitions(dp_doom PRIVATE INCLUDE_SDL2_MAIN) elseif(BACKEND STREQUAL "nng") target_sources(dp_doom PRIVATE - "linuxdoom-1.10/ib_sound/sdl.c" + #"linuxdoom-1.10/ib_sound/sdl.c" + "linuxdoom-1.10/ib_sound/ib_sound_nng.c" "linuxdoom-1.10/ib_system/ib_system_nng.c" "linuxdoom-1.10/ib_video/ib_video_nng.c" ) find_package(SDL2 REQUIRED) - target_link_libraries(dp_doom PRIVATE SDL2::SDL2 m) + target_link_libraries(dp_doom + PRIVATE SDL2::SDL2 + PRIVATE m + PRIVATE dp_common + ) else() message(FATAL_ERROR "Invalid BACKEND") endif() diff --git a/src/dp_doom/linuxdoom-1.10/ib_sound/ib_sound_nng.c b/src/dp_doom/linuxdoom-1.10/ib_sound/ib_sound_nng.c new file mode 100644 index 0000000..12acd05 --- /dev/null +++ b/src/dp_doom/linuxdoom-1.10/ib_sound/ib_sound_nng.c @@ -0,0 +1,22 @@ +#include "../ib_sound.h" + +#include + +int IB_StartupSound(void (*initial_callback)(unsigned int output_sample_rate, void *user_data), void (*_audio_callback)(short* output_buffer, size_t frames_to_do, void *user_data), void *user_data) +{ + unsigned int freq = 48000; + initial_callback(freq, user_data); + return 1; +} + +void IB_ShutdownSound(void) +{ +} + +void IB_LockSound(void) +{ +} + +void IB_UnlockSound(void) +{ +} diff --git a/src/dp_doom/linuxdoom-1.10/ib_video/ib_video_nng.c b/src/dp_doom/linuxdoom-1.10/ib_video/ib_video_nng.c index 16f898b..4e5e7f7 100644 --- a/src/dp_doom/linuxdoom-1.10/ib_video/ib_video_nng.c +++ b/src/dp_doom/linuxdoom-1.10/ib_video/ib_video_nng.c @@ -33,22 +33,179 @@ #include "../v_video.h" #include "../m_argv.h" #include "../d_main.h" - #include "../doomdef.h" - #include "../ib_video.h" -#define BYTES_PER_PIXEL 3 +#include +#include +#include +#include +#include +#include -//uint8_t frameBuffer[SCREENWIDTH * SCREENHEIGHT * BYTES_PER_PIXEL]; +typedef struct DoomContext DoomContext; + +#define DEF_DOOM_STATE_FUNC(fn) int fn(DoomContext *ctx) + +typedef DEF_DOOM_STATE_FUNC(DoomStateFunc); + +struct DoomContext +{ + nng_socket pub; + nng_socket sub; + doomid_t id; + DP_DoomState state; + DoomStateFunc *f; +}; + +static int publish_state(DoomContext *ctx) +{ + nng_msg *msg = NULL; + int res = 0; + + if ((res = nng_msg_alloc(&msg, sizeof(MsgDoomState)))) + dp_nng_fatal("doom/nng_msg_alloc", res); + + MsgDoomState *dmsg = DP_NNG_BODY_AS(msg, MsgDoomState); + dmsg->head.msgType = DP_MT_DoomState; + dmsg->doomId = ctx->id; + dmsg->doomState = ctx->state; + + res = nng_sendmsg(ctx->pub, msg, 0); + + return res; +} + +DEF_DOOM_STATE_FUNC(do_doom_ready); +DEF_DOOM_STATE_FUNC(do_doom_running); + +DEF_DOOM_STATE_FUNC(do_doom_ready) +{ + assert(ctx->state == DP_DS_Ready); + + int res = 0; + + if ((res = publish_state(ctx))) + dp_nng_fatal("doom/publish_sate", res); + + nng_msg *msg = NULL; + + if ((res = dp_recv_new_msg_nonblock(ctx->sub, &msg))) + { + if (!dp_nng_is_timeout(res)) + dp_nng_fatal("doom/recvmsg", res); + + return 0; + } + + log_trace("do_doom_ready received message of size %zu", nng_msg_len(msg)); + + MessageBase *msgBase = DP_NNG_BODY_AS(msg, MessageBase); + + DP_DoomCommand cmd = DP_DC_Noop; + + if (msgBase->msgType == DP_MT_Command) + { + MsgCommand *msgCmd = DP_NNG_BODY_AS(msg, MsgCommand); + + if (msgCmd->doomId == ctx->id) + cmd = msgCmd->cmd; + } + else if (msgBase->msgType == DP_MT_McstCommand) + { + MsgMcstCommand *msgCmd = DP_NNG_BODY_AS(msg, MsgMcstCommand); + cmd = msgCmd->cmd; + } + + if (cmd == DP_DC_RunDoom) + { + ctx->state = DP_DS_Running; + ctx->f = do_doom_running; + + if ((res = publish_state(ctx))) + dp_nng_fatal("doom/publish_sate", res); + } + else if (cmd == DP_DC_Endoom) + { + ctx->state = DP_DS_Endoom; + + if ((res = publish_state(ctx))) + dp_nng_fatal("doom/publish_sate", res); + } + + nng_msg_free(msg); + return res; +} + +DEF_DOOM_STATE_FUNC(do_doom_running) +{ + + assert(ctx->state == DP_DS_Running); + + // Non-blocking receive of incoming messages. + // Check if we should quit. + // Handle incoming input. + // Let doom render a new frame. + // Publish the frame. + + int res = 0; + nng_msg *msg = NULL; + + if ((res = dp_recv_new_msg_nonblock(ctx->sub, &msg))) + { + if (!dp_nng_is_timeout(res)) + dp_nng_fatal("doom/recvmsg", res); + + return 0; + } + + log_trace("do_doom_running received message of size %zu", nng_msg_len(msg)); + + MessageBase *msgBase = DP_NNG_BODY_AS(msg, MessageBase); + + DP_DoomCommand cmd = DP_DC_Noop; + + if (msgBase->msgType == DP_MT_Command) + { + MsgCommand *msgCmd = DP_NNG_BODY_AS(msg, MsgCommand); + + if (msgCmd->doomId == ctx->id) + cmd = msgCmd->cmd; + } + else if (msgBase->msgType == DP_MT_McstCommand) + { + MsgMcstCommand *msgCmd = DP_NNG_BODY_AS(msg, MsgMcstCommand); + cmd = msgCmd->cmd; + } + + if (cmd == DP_DC_Endoom) + { + ctx->state = DP_DS_Endoom; + + if ((res = publish_state(ctx))) + dp_nng_fatal("doom/publish_sate", res); + } + + nng_msg_free(msg); + return res; +} + +static size_t g_frameBufferSize; static uint8_t *g_frameBuffer; static size_t g_pitch; +DoomContext g_doomContext; // // IB_StartTic // void IB_StartTic (void) { + /* TODO: post input events (could this be done in IB_FinishUpdate? try it) + case SDL_KEYDOWN: + event.type = ev_keydown; + event.data1 = xlatekey(sdl_event.key.keysym.sym); + D_PostEvent(&event); + */ } void IB_GetFramebuffer(unsigned char **pixels, size_t *pitch) @@ -59,6 +216,71 @@ void IB_GetFramebuffer(unsigned char **pixels, size_t *pitch) void IB_FinishUpdate (void) { + DoomContext *ctx = &g_doomContext; + + assert(ctx->state == DP_DS_Running); + + { + int res = 0; + nng_msg *msg = NULL; + + if ((res = dp_recv_new_msg_nonblock(ctx->sub, &msg))) + { + if (!dp_nng_is_timeout(res)) + dp_nng_fatal("doom/recvmsg", res); + + return; + } + + MessageBase *msgBase = DP_NNG_BODY_AS(msg, MessageBase); + + DP_DoomCommand cmd = DP_DC_Noop; + + if (msgBase->msgType == DP_MT_Command) + { + MsgCommand *msgCmd = DP_NNG_BODY_AS(msg, MsgCommand); + + if (msgCmd->doomId == ctx->id) + cmd = msgCmd->cmd; + } + else if (msgBase->msgType == DP_MT_McstCommand) + { + MsgMcstCommand *msgCmd = DP_NNG_BODY_AS(msg, MsgMcstCommand); + cmd = msgCmd->cmd; + } + + nng_msg_free(msg); + + if (cmd == DP_DC_Endoom) + { + ctx->state = DP_DS_Endoom; + + if ((res = publish_state(ctx))) + dp_nng_fatal("doom/publish_sate", res); + + I_Quit(); + return; + } + } + + { + int res = 0; + nng_msg *msg = NULL; + + if ((res = nng_msg_alloc(&msg, sizeof(MsgDoomFrame)))) + dp_nng_fatal("doom/nng_msg_alloc", res); + + MsgDoomFrame *dpmsg = DP_NNG_BODY_AS(msg, MsgDoomFrame); + dpmsg->head.msgType = DP_MT_DoomFrame; + dpmsg->doomId = ctx->id; + assert(g_frameBufferSize == DoomFrameSize); + memcpy(dpmsg->frame, g_frameBuffer, g_frameBufferSize); + + if ((res = nng_sendmsg(ctx->pub, msg, 0))) + dp_nng_fatal("ctrl/sendmsg", res); + + log_debug("doom(%d) published frame", ctx->id); + } } void IB_GetColor(unsigned char *bytes, unsigned char red, unsigned char green, unsigned char blue) @@ -78,15 +300,60 @@ static void I_Quit_Wrapper(int dummy) void IB_InitGraphics(const char *title, size_t screen_width, size_t screen_height, size_t *bytes_per_pixel) { (void) title; - g_frameBuffer = malloc(screen_width * screen_height * BYTES_PER_PIXEL); - g_pitch = screen_width * BYTES_PER_PIXEL; - *bytes_per_pixel = BYTES_PER_PIXEL; + g_frameBufferSize = screen_width * screen_height * DoomBytesPerPixel; + assert(g_frameBufferSize == DoomFrameSize); + g_frameBuffer = malloc(g_frameBufferSize); + g_pitch = screen_width * DoomBytesPerPixel; + *bytes_per_pixel = DoomBytesPerPixel; + + log_debug("IB_InitGraphics: w=%zu, h=%zu -> bytesPerPixel=%zu, frameBufferSize=%zu", + screen_width, screen_height, *bytes_per_pixel, g_frameBufferSize); signal(SIGINT, I_Quit_Wrapper); + +#ifndef NDEBUG + log_set_level(LOG_DEBUG); +#else + log_set_level(LOG_INFO); +#endif + + dp_nng_init_limits(1, 1, 1); + + g_doomContext.pub = make_doom_pub(DoomUrl); + g_doomContext.sub = make_doom_sub(CtrlUrl); + g_doomContext.id = getpid(); + g_doomContext.state = DP_DS_Ready; + g_doomContext.f = do_doom_ready; + + DoomContext *ctx = &g_doomContext; + + log_info("waiting for go from doompanning"); + + while (true) + { + DP_DoomState prevState = ctx->state; + ctx->f(ctx); + if (prevState != ctx->state) + { + log_info("transition %s -> %s", + doomstate_to_string(prevState), doomstate_to_string(ctx->state)); + } + + if (ctx->state != DP_DS_Endoom && ctx->state != DP_DS_Running) + usleep(10 * 1000); + else + break; + } + + if (ctx->state == DP_DS_Endoom) + I_Quit(); } void IB_ShutdownGraphics(void) { + nng_close(g_doomContext.pub); + nng_close(g_doomContext.sub); + free(g_frameBuffer); }