comparison render_sdl.c @ 2693:46dba737b931

WIP Nuklear UI in VDP debug windows
author Michael Pavone <pavone@retrodev.com>
date Thu, 19 Jun 2025 19:59:05 -0700
parents 05915f01046d
children 84771c6e31c5
comparison
equal deleted inserted replaced
2692:effbb52ab3f0 2693:46dba737b931
32 32
33 #define MAX_EVENT_POLL_PER_FRAME 2 33 #define MAX_EVENT_POLL_PER_FRAME 2
34 34
35 35
36 typedef struct { 36 typedef struct {
37 SDL_Window *win; 37 SDL_Window *win;
38 SDL_Renderer *renderer; 38 SDL_Renderer *renderer;
39 SDL_Texture *sdl_texture; 39 SDL_Texture *sdl_texture;
40 SDL_Texture **static_images; 40 SDL_Texture **static_images;
41 window_close_handler on_close; 41 window_close_handler on_close;
42 ui_render_fun on_render;
43 event_handler on_event;
42 uint32_t width; 44 uint32_t width;
43 uint32_t height; 45 uint32_t height;
44 uint8_t num_static; 46 uint8_t num_static;
45 #ifndef DISABLE_OPENGL 47 #ifndef DISABLE_OPENGL
46 SDL_GLContext *gl_context; 48 SDL_GLContext *gl_context;
47 pixel_t *texture_buf; 49 pixel_t *texture_buf;
50 uint32_t orig_tex_width;
51 uint32_t orig_tex_height;
48 uint32_t tex_width; 52 uint32_t tex_width;
49 uint32_t tex_height; 53 uint32_t tex_height;
50 GLuint gl_texture[2]; 54 GLuint gl_texture[2];
51 GLuint *gl_static_images; 55 GLuint *gl_static_images;
52 GLuint vshader; 56 GLuint vshader;
823 { 827 {
824 drag_drop_handler = handler; 828 drag_drop_handler = handler;
825 } 829 }
826 830
827 static event_handler custom_event_handler; 831 static event_handler custom_event_handler;
828 void render_set_event_handler(event_handler handler) 832 void render_set_event_handler(uint8_t which, event_handler handler)
829 { 833 {
830 custom_event_handler = handler; 834 if (which < FRAMEBUFFER_USER_START) {
835 custom_event_handler = handler;
836 } else {
837 extras[which - FRAMEBUFFER_USER_START].on_event = handler;
838 }
831 } 839 }
832 840
833 int render_find_joystick_index(SDL_JoystickID instanceID) 841 int render_find_joystick_index(SDL_JoystickID instanceID)
834 { 842 {
835 for (int i = 0; i < MAX_JOYSTICKS; i++) { 843 for (int i = 0; i < MAX_JOYSTICKS; i++) {
950 return ui * ui_scale_y + 0.5f; 958 return ui * ui_scale_y + 0.5f;
951 } 959 }
952 960
953 static int32_t handle_event(SDL_Event *event) 961 static int32_t handle_event(SDL_Event *event)
954 { 962 {
955 if (custom_event_handler) { 963 SDL_Window *event_win = NULL;
956 custom_event_handler(event);
957 }
958 switch (event->type) { 964 switch (event->type) {
959 case SDL_KEYDOWN: 965 case SDL_KEYDOWN:
960 handle_keydown(event->key.keysym.sym, scancode_map[event->key.keysym.scancode]); 966 event_win = SDL_GetWindowFromID(event->key.windowID);
967 if (event_win == main_window) {
968 handle_keydown(event->key.keysym.sym, scancode_map[event->key.keysym.scancode]);
969 }
961 break; 970 break;
962 case SDL_KEYUP: 971 case SDL_KEYUP:
963 handle_keyup(event->key.keysym.sym, scancode_map[event->key.keysym.scancode]); 972 event_win = SDL_GetWindowFromID(event->key.windowID);
973 if (event_win == main_window) {
974 handle_keyup(event->key.keysym.sym, scancode_map[event->key.keysym.scancode]);
975 }
964 break; 976 break;
965 case SDL_JOYBUTTONDOWN: 977 case SDL_JOYBUTTONDOWN:
978 event_win = main_window;
966 handle_joydown(render_find_joystick_index(event->jbutton.which), event->jbutton.button); 979 handle_joydown(render_find_joystick_index(event->jbutton.which), event->jbutton.button);
967 break; 980 break;
968 case SDL_JOYBUTTONUP: 981 case SDL_JOYBUTTONUP:
982 event_win = main_window;
969 handle_joyup(lock_joystick_index(render_find_joystick_index(event->jbutton.which), -1), event->jbutton.button); 983 handle_joyup(lock_joystick_index(render_find_joystick_index(event->jbutton.which), -1), event->jbutton.button);
970 break; 984 break;
971 case SDL_JOYHATMOTION: 985 case SDL_JOYHATMOTION:
986 event_win = main_window;
972 handle_joy_dpad(lock_joystick_index(render_find_joystick_index(event->jhat.which), -1), event->jhat.hat, event->jhat.value); 987 handle_joy_dpad(lock_joystick_index(render_find_joystick_index(event->jhat.which), -1), event->jhat.hat, event->jhat.value);
973 break; 988 break;
974 case SDL_JOYAXISMOTION: 989 case SDL_JOYAXISMOTION:
990 event_win = main_window;
975 handle_joy_axis(lock_joystick_index(render_find_joystick_index(event->jaxis.which), -1), event->jaxis.axis, event->jaxis.value); 991 handle_joy_axis(lock_joystick_index(render_find_joystick_index(event->jaxis.which), -1), event->jaxis.axis, event->jaxis.value);
976 break; 992 break;
977 case SDL_JOYDEVICEADDED: { 993 case SDL_JOYDEVICEADDED: {
978 int index = lowest_unused_joystick_index(); 994 int index = lowest_unused_joystick_index();
979 if (index >= 0) { 995 if (index >= 0) {
1011 debug_message("Failed to find removed joystick with instance ID: %d\n", index); 1027 debug_message("Failed to find removed joystick with instance ID: %d\n", index);
1012 } 1028 }
1013 break; 1029 break;
1014 } 1030 }
1015 case SDL_MOUSEMOTION: 1031 case SDL_MOUSEMOTION:
1032 event_win = SDL_GetWindowFromID(event->motion.windowID);
1016 handle_mouse_moved(event->motion.which, event->motion.x * ui_scale_x + 0.5f, event->motion.y * ui_scale_y + 0.5f + overscan_top[video_standard], event->motion.xrel, event->motion.yrel); 1033 handle_mouse_moved(event->motion.which, event->motion.x * ui_scale_x + 0.5f, event->motion.y * ui_scale_y + 0.5f + overscan_top[video_standard], event->motion.xrel, event->motion.yrel);
1017 break; 1034 break;
1018 case SDL_MOUSEBUTTONDOWN: 1035 case SDL_MOUSEBUTTONDOWN:
1036 event_win = SDL_GetWindowFromID(event->button.windowID);
1019 handle_mousedown(event->button.which, event->button.button); 1037 handle_mousedown(event->button.which, event->button.button);
1020 break; 1038 break;
1021 case SDL_MOUSEBUTTONUP: 1039 case SDL_MOUSEBUTTONUP:
1040 event_win = SDL_GetWindowFromID(event->button.windowID);
1022 handle_mouseup(event->button.which, event->button.button); 1041 handle_mouseup(event->button.which, event->button.button);
1042 break;
1043 case SDL_MOUSEWHEEL:
1044 event_win = SDL_GetWindowFromID(event->wheel.windowID);
1045 break;
1046 case SDL_FINGERMOTION:
1047 case SDL_FINGERDOWN:
1048 case SDL_FINGERUP:
1049 event_win = SDL_GetWindowFromID(event->tfinger.windowID);
1023 break; 1050 break;
1024 case SDL_WINDOWEVENT: 1051 case SDL_WINDOWEVENT:
1025 switch (event->window.event) 1052 switch (event->window.event)
1026 { 1053 {
1027 case SDL_WINDOWEVENT_SIZE_CHANGED: 1054 case SDL_WINDOWEVENT_SIZE_CHANGED:
1028 if (!main_window) { 1055 if (!main_window || SDL_GetWindowFromID(event->window.windowID) != main_window) {
1029 break; 1056 break;
1030 } 1057 }
1031 need_ui_fb_resize = 1; 1058 need_ui_fb_resize = 1;
1032 #ifndef DISABLE_OPENGL 1059 #ifndef DISABLE_OPENGL
1033 if (render_gl) { 1060 if (render_gl) {
1074 } 1101 }
1075 } 1102 }
1076 break; 1103 break;
1077 } 1104 }
1078 break; 1105 break;
1106 case SDL_TEXTEDITING:
1107 event_win = SDL_GetWindowFromID(event->edit.windowID);
1108 break;
1109 #if SDL_VERSION_ATLEAST(2, 0, 22)
1110 case SDL_TEXTEDITING_EXT:
1111 event_win = SDL_GetWindowFromID(event->editExt.windowID);
1112 break;
1113 #endif
1114 case SDL_TEXTINPUT:
1115 event_win = SDL_GetWindowFromID(event->text.windowID);
1116 break;
1079 case SDL_DROPFILE: 1117 case SDL_DROPFILE:
1080 if (drag_drop_handler) { 1118 if (drag_drop_handler) {
1081 drag_drop_handler(strdup(event->drop.file)); 1119 drag_drop_handler(strdup(event->drop.file));
1082 } 1120 }
1083 SDL_free(event->drop.file); 1121 SDL_free(event->drop.file);
1084 break; 1122 break;
1085 case SDL_QUIT: 1123 case SDL_QUIT:
1086 puts(""); 1124 puts("");
1087 exit(0); 1125 exit(0);
1126 }
1127 if (event_win) {
1128 if (event_win == main_window) {
1129 if (custom_event_handler) {
1130 custom_event_handler(FRAMEBUFFER_UI, event);
1131 }
1132 } else {
1133 for (uint8_t i = 0; i < num_extras; i++)
1134 {
1135 if (extras[i].win == event_win) {
1136 if (extras[i].on_event) {
1137 extras[i].on_event(i + FRAMEBUFFER_USER_START, event);
1138 }
1139 break;
1140 }
1141 }
1142 }
1088 } 1143 }
1089 return 0; 1144 return 0;
1090 } 1145 }
1091 1146
1092 static void drain_events() 1147 static void drain_events()
1544 if (!was_paused) { 1599 if (!was_paused) {
1545 SDL_PauseAudio(0); 1600 SDL_PauseAudio(0);
1546 } 1601 }
1547 } 1602 }
1548 1603
1549 SDL_Window *render_get_window(void) 1604 SDL_Window *render_get_window(uint8_t which)
1550 { 1605 {
1606 SDL_Window *ret = which < FRAMEBUFFER_USER_START ? main_window : extras[which - FRAMEBUFFER_USER_START].win;
1551 #ifndef DISABLE_OPENGL 1607 #ifndef DISABLE_OPENGL
1552 if (render_gl) { 1608 if (render_gl) {
1553 SDL_GL_MakeCurrent(main_window, main_context); 1609 SDL_GL_MakeCurrent(ret, which < FRAMEBUFFER_USER_START ? main_context : extras[which - FRAMEBUFFER_USER_START].gl_context);
1554 } 1610 }
1555 #endif 1611 #endif
1556 return main_window; 1612 return ret;
1557 } 1613 }
1558 1614
1559 uint32_t render_audio_syncs_per_sec(void) 1615 uint32_t render_audio_syncs_per_sec(void)
1560 { 1616 {
1561 //sync samples with audio thread approximately every 8 lines when doing sync to video 1617 //sync samples with audio thread approximately every 8 lines when doing sync to video
1660 { 1716 {
1661 fprintf(stderr, "GL Message: %d, %d, %d - %s\n", source, type, severity, message); 1717 fprintf(stderr, "GL Message: %d, %d, %d - %s\n", source, type, severity, message);
1662 } 1718 }
1663 #endif 1719 #endif
1664 1720
1665 uint8_t render_create_window(char *caption, uint32_t width, uint32_t height, window_close_handler close_handler) 1721 uint8_t render_create_window_tex(char *caption, uint32_t width, uint32_t height, uint32_t tex_width, uint32_t tex_height, window_close_handler close_handler)
1666 { 1722 {
1667 uint8_t win_idx = 0xFF; 1723 uint8_t win_idx = 0xFF;
1668 for (int i = 0; i < num_extras; i++) 1724 for (int i = 0; i < num_extras; i++)
1669 { 1725 {
1670 if (!extras[i].win) { 1726 if (!extras[i].win) {
1716 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 1772 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1717 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 1773 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1718 if (i) { 1774 if (i) {
1719 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 1, 1, 0, SRC_FORMAT, SRC_TYPE, extras[win_idx].color); 1775 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, 1, 1, 0, SRC_FORMAT, SRC_TYPE, extras[win_idx].color);
1720 } else { 1776 } else {
1721 extras[win_idx].tex_width = width; 1777 extras[win_idx].tex_width = extras[win_idx].orig_tex_width = tex_width;
1722 extras[win_idx].tex_height = height; 1778 extras[win_idx].tex_height = extras[win_idx].orig_tex_height = tex_height;
1723 char *npot_textures = tern_find_path_default(config, "video\0npot_textures\0", (tern_val){.ptrval = "off"}, TVAL_PTR).ptrval; 1779 char *npot_textures = tern_find_path_default(config, "video\0npot_textures\0", (tern_val){.ptrval = "off"}, TVAL_PTR).ptrval;
1724 if (strcmp(npot_textures, "on")) { 1780 if (strcmp(npot_textures, "on")) {
1725 extras[win_idx].tex_width = nearest_pow2(width); 1781 extras[win_idx].tex_width = nearest_pow2(tex_width);
1726 extras[win_idx].tex_height = nearest_pow2(height); 1782 extras[win_idx].tex_height = nearest_pow2(tex_height);
1727 } 1783 }
1728 extras[win_idx].texture_buf = calloc(PITCH_PIXEL_T(extras[win_idx].tex_width) * extras[win_idx].tex_height, sizeof(pixel_t)); 1784 extras[win_idx].texture_buf = calloc(PITCH_PIXEL_T(extras[win_idx].tex_width) * extras[win_idx].tex_height, sizeof(pixel_t));
1729 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, extras[win_idx].tex_width, extras[win_idx].tex_height, 0, SRC_FORMAT, SRC_TYPE, extras[win_idx].texture_buf); 1785 glTexImage2D(GL_TEXTURE_2D, 0, INTERNAL_FORMAT, extras[win_idx].tex_width, extras[win_idx].tex_height, 0, SRC_FORMAT, SRC_TYPE, extras[win_idx].texture_buf);
1730 } 1786 }
1731 } 1787 }
1760 #endif 1816 #endif
1761 extras[win_idx].renderer = SDL_CreateRenderer(extras[win_idx].win, -1, SDL_RENDERER_ACCELERATED); 1817 extras[win_idx].renderer = SDL_CreateRenderer(extras[win_idx].win, -1, SDL_RENDERER_ACCELERATED);
1762 if (!extras[win_idx].renderer) { 1818 if (!extras[win_idx].renderer) {
1763 goto fail_renderer; 1819 goto fail_renderer;
1764 } 1820 }
1765 extras[win_idx].sdl_texture = SDL_CreateTexture(extras[win_idx].renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height); 1821 extras[win_idx].sdl_texture = SDL_CreateTexture(extras[win_idx].renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, tex_width, tex_height);
1766 if (!extras[win_idx].sdl_texture) { 1822 if (!extras[win_idx].sdl_texture) {
1767 goto fail_texture; 1823 goto fail_texture;
1768 } 1824 }
1769 #ifndef DISABLE_OPENGL 1825 #ifndef DISABLE_OPENGL
1770 } 1826 }
1777 fail_renderer: 1833 fail_renderer:
1778 SDL_DestroyWindow(extras[win_idx].win); 1834 SDL_DestroyWindow(extras[win_idx].win);
1779 fail_window: 1835 fail_window:
1780 return 0; 1836 return 0;
1781 } 1837 }
1838
1839 uint8_t render_create_window(char *caption, uint32_t width, uint32_t height, window_close_handler close_handler)
1840 {
1841 return render_create_window_tex(caption, width, height, width, height, close_handler);
1842 }
1843
1844 #ifndef DISABLE_OPENGL
1845 uint32_t render_get_window_texture(uint8_t which)
1846 {
1847 return extras[which - FRAMEBUFFER_USER_START].gl_texture[0];
1848 }
1849 #endif
1782 1850
1783 void render_destroy_window(uint8_t which) 1851 void render_destroy_window(uint8_t which)
1784 { 1852 {
1785 uint8_t win_idx = which - FRAMEBUFFER_USER_START; 1853 uint8_t win_idx = which - FRAMEBUFFER_USER_START;
1786 if (extras[win_idx].renderer) { 1854 if (extras[win_idx].renderer) {
2031 if (render_gl && which <= FRAMEBUFFER_EVEN) { 2099 if (render_gl && which <= FRAMEBUFFER_EVEN) {
2032 *pitch = PITCH_BYTES(LINEBUF_SIZE); 2100 *pitch = PITCH_BYTES(LINEBUF_SIZE);
2033 return texture_buf; 2101 return texture_buf;
2034 } else if (render_gl && which >= FRAMEBUFFER_USER_START) { 2102 } else if (render_gl && which >= FRAMEBUFFER_USER_START) {
2035 uint8_t win_idx = which - FRAMEBUFFER_USER_START; 2103 uint8_t win_idx = which - FRAMEBUFFER_USER_START;
2036 *pitch = PITCH_BYTES(extras[win_idx].width); 2104 *pitch = PITCH_BYTES(extras[win_idx].tex_width);
2037 return extras[win_idx].texture_buf; 2105 return extras[win_idx].texture_buf;
2038 } else { 2106 } else {
2039 #endif 2107 #endif
2040 if (which == FRAMEBUFFER_UI && !sdl_textures[which]) { 2108 if (which == FRAMEBUFFER_UI && !sdl_textures[which]) {
2041 sdl_textures[which] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, main_width, main_height); 2109 sdl_textures[which] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, main_width, main_height);
2161 #endif 2229 #endif
2162 } else if (render_gl && which >= FRAMEBUFFER_USER_START) { 2230 } else if (render_gl && which >= FRAMEBUFFER_USER_START) {
2163 uint8_t win_idx = which - FRAMEBUFFER_USER_START; 2231 uint8_t win_idx = which - FRAMEBUFFER_USER_START;
2164 SDL_GL_MakeCurrent(extras[win_idx].win, extras[win_idx].gl_context); 2232 SDL_GL_MakeCurrent(extras[win_idx].win, extras[win_idx].gl_context);
2165 glBindTexture(GL_TEXTURE_2D, extras[win_idx].gl_texture[0]); 2233 glBindTexture(GL_TEXTURE_2D, extras[win_idx].gl_texture[0]);
2166 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, extras[win_idx].width, extras[win_idx].height, SRC_FORMAT, SRC_TYPE, buffer); 2234 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, extras[win_idx].orig_tex_width, extras[win_idx].orig_tex_height, SRC_FORMAT, SRC_TYPE, buffer);
2167 } else { 2235 } else {
2168 #endif 2236 #endif
2169 uint32_t shot_height = height; 2237 uint32_t shot_height = height;
2170 //TODO: Support SYNC_AUDIO_THREAD/SYNC_EXTERNAL for render API framebuffers 2238 //TODO: Support SYNC_AUDIO_THREAD/SYNC_EXTERNAL for render API framebuffers
2171 if (which <= FRAMEBUFFER_EVEN && last_field != which) { 2239 if (which <= FRAMEBUFFER_EVEN && last_field != which) {
2228 } 2296 }
2229 #ifndef DISABLE_OPENGL 2297 #ifndef DISABLE_OPENGL
2230 else { 2298 else {
2231 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 2299 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
2232 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 2300 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2233 2301 if (extras[win_idx].on_render) {
2234 glBindBuffer(GL_ARRAY_BUFFER, extras[win_idx].gl_buffers[0]); 2302 extras[win_idx].on_render();
2235 extra_draw_quad( 2303 } else {
2236 extras + win_idx, 2304 glBindBuffer(GL_ARRAY_BUFFER, extras[win_idx].gl_buffers[0]);
2237 extras[win_idx].gl_texture[0], 2305 extra_draw_quad(
2238 (float)extras[win_idx].width / (float)extras[win_idx].tex_width, 2306 extras + win_idx,
2239 (float)extras[win_idx].height / (float)extras[win_idx].tex_height 2307 extras[win_idx].gl_texture[0],
2240 ); 2308 (float)extras[win_idx].orig_tex_width / (float)extras[win_idx].tex_width,
2309 (float)extras[win_idx].orig_tex_height / (float)extras[win_idx].tex_height
2310 );
2311 }
2241 2312
2242 SDL_GL_SwapWindow(extras[win_idx].win); 2313 SDL_GL_SwapWindow(extras[win_idx].win);
2243 } 2314 }
2244 #endif 2315 #endif
2245 } 2316 }
2333 frame frame_queue[4]; 2404 frame frame_queue[4];
2334 int frame_queue_len, frame_queue_read, frame_queue_write; 2405 int frame_queue_len, frame_queue_read, frame_queue_write;
2335 2406
2336 void render_framebuffer_updated(uint8_t which, int width) 2407 void render_framebuffer_updated(uint8_t which, int width)
2337 { 2408 {
2338 if (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL) { 2409 if (which < FRAMEBUFFER_USER_START && (sync_src == SYNC_AUDIO_THREAD || sync_src == SYNC_EXTERNAL)) {
2339 SDL_LockMutex(frame_mutex); 2410 SDL_LockMutex(frame_mutex);
2340 while (frame_queue_len == 4) { 2411 while (frame_queue_len == 4) {
2341 SDL_CondSignal(frame_ready); 2412 SDL_CondSignal(frame_ready);
2342 SDL_UnlockMutex(frame_mutex); 2413 SDL_UnlockMutex(frame_mutex);
2343 SDL_Delay(1); 2414 SDL_Delay(1);
2415 2486
2416 SDL_UnlockMutex(frame_mutex); 2487 SDL_UnlockMutex(frame_mutex);
2417 } 2488 }
2418 2489
2419 static ui_render_fun render_ui; 2490 static ui_render_fun render_ui;
2420 void render_set_ui_render_fun(ui_render_fun fun) 2491 void render_set_ui_render_fun(uint8_t which, ui_render_fun fun)
2421 { 2492 {
2422 render_ui = fun; 2493 if (which < FRAMEBUFFER_USER_START) {
2494 render_ui = fun;
2495 } else {
2496 extras[which - FRAMEBUFFER_USER_START].on_render = fun;
2497 }
2423 } 2498 }
2424 2499
2425 static ui_render_fun frame_presented; 2500 static ui_render_fun frame_presented;
2426 void render_set_frame_presented_fun(ui_render_fun fun) 2501 void render_set_frame_presented_fun(ui_render_fun fun)
2427 { 2502 {