diff --git a/CMakeLists.txt b/CMakeLists.txt index d609224783019..945ba02402420 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -241,7 +241,7 @@ if(USE_GCC OR USE_CLANG OR USE_INTELCC OR USE_QCC) endif() # Default option knobs -if(UNIX OR MINGW OR MSYS OR (USE_CLANG AND NOT WINDOWS) OR VITA OR PSP OR PS2 OR N3DS OR SDL_CPU_ARM64EC) +if(UNIX OR MINGW OR MSYS OR (USE_CLANG AND NOT WINDOWS) OR VITA OR PSP OR PS2 OR N3DS OR SDL_CPU_ARM64EC OR DOS) set(OPT_DEF_LIBC ON) endif() if(WINDOWS OR MACOS OR IOS OR TVOS OR VISIONOS OR WATCHOS) @@ -358,11 +358,20 @@ if(EMSCRIPTEN) set(SDL_CPUINFO_ENABLED_BY_DEFAULT OFF) endif() -if(VITA OR PSP OR PS2 OR N3DS) +if(VITA OR PSP OR PS2 OR N3DS OR DOS) set(SDL_SHARED_ENABLED_BY_DEFAULT OFF) set(SDL_LOADSO_ENABLED_BY_DEFAULT OFF) endif() +if(DOS) + set(SDL_THREADS_ENABLED_BY_DEFAULT OFF) + set(SDL_SSE OFF) + set(SDL_SSE2 OFF) + set(SDL_SSE3 OFF) + set(SDL_MMX OFF) + set(SDL_3DNOW OFF) +endif() + set(SDL_X11_XRANDR_DEFAULT ON) if(SOLARIS) set(SDL_X11_XRANDR_DEFAULT OFF) @@ -412,7 +421,7 @@ set_option(SDL2_DISABLE_UNINSTALL "Disable uninstallation of SDL2" OFF) option_string(SDL_ASSERTIONS "Enable internal sanity checks (auto/disabled/release/enabled/paranoid)" "auto") #set_option(SDL_DEPENDENCY_TRACKING "Use gcc -MMD -MT dependency tracking" ON) set_option(SDL_ASSEMBLY "Enable assembly routines" ${OPT_DEF_ASM}) -dep_option(SDL_SSEMATH "Allow GCC to use SSE floating point math" ON "SDL_ASSEMBLY;SDL_CPU_X86 OR SDL_CPU_X64" OFF) +dep_option(SDL_SSEMATH "Allow GCC to use SSE floating point math" ON "SDL_ASSEMBLY;SDL_CPU_X86 OR SDL_CPU_X64;NOT DOS" OFF) dep_option(SDL_SSE "Use SSE assembly routines" ON "SDL_ASSEMBLY;SDL_CPU_X86 OR SDL_CPU_X64" OFF) dep_option(SDL_SSE2 "Use SSE2 assembly routines" ON "SDL_ASSEMBLY;SDL_CPU_X86 OR SDL_CPU_X64" OFF) dep_option(SDL_SSE3 "Use SSE3 assembly routines" ON "SDL_ASSEMBLY;SDL_CPU_X86 OR SDL_CPU_X64" OFF) @@ -525,6 +534,10 @@ if(VITA) set_option(VIDEO_VITA_PVR "Build with PSVita PVR gles/gles2 support" OFF) endif() +if(DOS) + set_option(SDL_DOS_UCLOCK "Whether to use uclock() for performance counter on DOS" TRUE) +endif() + # General source files file(GLOB SOURCE_FILES ${SDL2_SOURCE_DIR}/src/*.c @@ -2873,6 +2886,28 @@ elseif(OS2) CheckHIDAPI() endif() +elseif(DOS) + file(GLOB DOS_CORE_SOURCES ${SDL2_SOURCE_DIR}/src/core/dos/*.c) + list(APPEND SOURCE_FILES ${DOS_CORE_SOURCES}) + + if(SDL_TIMERS) + if(SDL_DOS_UCLOCK) + set(HAVE_UCLOCK TRUE) + endif() + + set(SDL_TIMER_DOS 1) + file(GLOB DOS_TIMER_SOURCES ${SDL2_SOURCE_DIR}/src/timer/dos/*.c) + list(APPEND SOURCE_FILES ${DOS_TIMER_SOURCES}) + set(HAVE_SDL_TIMERS TRUE) + endif() + + if(SDL_VIDEO) + set(SDL_VIDEO_DRIVER_SVGA 1) + file(GLOB SVGA_VIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/svga/*.c) + list(APPEND SOURCE_FILES ${SVGA_VIDEO_SOURCES}) + set(HAVE_SDL_VIDEO TRUE) + endif() + elseif(N3DS) file(GLOB N3DS_MAIN_SOURCES ${SDL2_SOURCE_DIR}/src/main/n3ds/*.c) set(SDLMAIN_SOURCES ${SDLMAIN_SOURCES} ${N3DS_MAIN_SOURCES}) @@ -3028,7 +3063,7 @@ endif() # We always need to have threads and timers around if(NOT HAVE_SDL_THREADS) # The emscripten platform has been carefully vetted to work without threads - if (EMSCRIPTEN) + if (EMSCRIPTEN OR DOS) set(SDL_THREADS_DISABLED 1) file(GLOB THREADS_SOURCES ${SDL2_SOURCE_DIR}/src/thread/generic/*.c) list(APPEND SOURCE_FILES ${THREADS_SOURCES}) diff --git a/configure b/configure index 4ecefec717a82..88b9e88de32db 100755 --- a/configure +++ b/configure @@ -952,6 +952,7 @@ enable_wasapi enable_hidapi_joystick enable_hidapi_libusb enable_clock_gettime +enable_uclock enable_rpath enable_backgrounding_signal enable_foregrounding_signal @@ -1671,9 +1672,9 @@ Optional Features: --enable-assembly Enable assembly routines [default=yes] --enable-ssemath Allow GCC to use SSE floating point math [default=maybe] - --enable-mmx use MMX assembly routines [default=yes] - --enable-3dnow use 3DNow! assembly routines [default=no] - --enable-sse use SSE assembly routines [default=yes] + --enable-mmx use MMX assembly routines [default=maybe] + --enable-3dnow use 3DNow! assembly routines [default=maybe] + --enable-sse use SSE assembly routines [default=maybe] --enable-sse2 use SSE2 assembly routines [default=maybe] --enable-sse3 use SSE3 assembly routines [default=maybe] --enable-altivec use Altivec assembly routines [default=yes] @@ -1779,6 +1780,8 @@ Optional Features: --enable-clock_gettime use clock_gettime() instead of gettimeofday() on UNIX [default=yes] --enable-rpath use an rpath when linking SDL [default=yes] + --enable-uclock use uclock() for performance counter on DOS + [default=yes] --enable-backgrounding-signal number to use for magic backgrounding signal or 'no' [default=no] @@ -19358,6 +19361,25 @@ printf "%s\n" "#define HAVE_MPROTECT 1" >>confdefs.h fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + case "$host" in + *-*-msdosdjgpp*) + { $as_echo "$as_me:${as_lineno-$LINENO}: skipping unfinished fseeko64 in DJGPP" >&5 +$as_echo "$as_me: skipping unfinished fseeko64 in DJGPP" >&6;} + ;; + *) + for ac_func in fseeko64 +do : + ac_fn_c_check_func "$LINENO" "fseeko64" "ac_cv_func_fseeko64" +if test "x$ac_cv_func_fseeko64" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FSEEKO64 1 +_ACEOF + +fi +done + + ;; + esac fi ac_fn_c_check_func "$LINENO" "malloc" "ac_cv_func_malloc" @@ -19743,12 +19765,6 @@ if test "x$ac_cv_func_fseeko" = xyes then : printf "%s\n" "#define HAVE_FSEEKO 1" >>confdefs.h -fi -ac_fn_c_check_func "$LINENO" "fseeko64" "ac_cv_func_fseeko64" -if test "x$ac_cv_func_fseeko64" = xyes -then : - printf "%s\n" "#define HAVE_FSEEKO64 1" >>confdefs.h - fi ac_fn_c_check_func "$LINENO" "sigaction" "ac_cv_func_sigaction" if test "x$ac_cv_func_sigaction" = xyes @@ -20647,7 +20663,7 @@ if test ${enable_mmx+y} then : enableval=$enable_mmx; else $as_nop - enable_mmx=yes + enable_mmx=$default_ssemath fi if test x$enable_mmx = xyes; then @@ -20703,7 +20719,7 @@ if test ${enable_3dnow+y} then : enableval=$enable_3dnow; else $as_nop - enable_3dnow=no + enable_3dnow=$default_ssemath fi if test x$enable_3dnow = xyes; then @@ -20754,7 +20770,7 @@ if test ${enable_sse+y} then : enableval=$enable_sse; else $as_nop - enable_sse=yes + enable_sse=$default_ssemath fi if test x$enable_sse = xyes; then @@ -25984,6 +26000,18 @@ printf "%s\n" "#define SDL_AUDIO_DRIVER_QSA 1" >>confdefs.h fi } +CheckSVGAVideo() +{ + if test x$enable_video = xyes; then + +$as_echo "#define SDL_VIDEO_DRIVER_SVGA 1" >>confdefs.h + + SOURCES="$SOURCES $srcdir/src/video/svga/*.c" + have_video=yes + SUMMARY_video="${SUMMARY_video} svga" + fi +} + # Check whether --enable-video-opengl was given. if test ${enable_video_opengl+y} then : @@ -28553,6 +28581,30 @@ printf "%s\n" "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h fi } +CheckUCLOCK() +{ + # Check whether --enable-uclock was given. +if test "${enable_uclock+set}" = set; then : + enableval=$enable_uclock; +else + enable_uclock=yes +fi + + if test x$enable_uclock = xyes; then + for ac_func in uclock +do : + ac_fn_c_check_func "$LINENO" "uclock" "ac_cv_func_uclock" +if test "x$ac_cv_func_uclock" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_UCLOCK 1 +_ACEOF + +fi +done + + fi +} + CheckLinuxVersion() { ac_fn_c_check_header_compile "$LINENO" "linux/version.h" "ac_cv_header_linux_version_h" "$ac_includes_default" @@ -29762,6 +29814,29 @@ printf "%s\n" "#define SDL_JOYSTICK_OS2 1" >>confdefs.h have_joystick=yes fi ;; + *-*-msdosdjgpp*) + ARCH=dos + CheckVisibilityHidden + CheckDeclarationAfterStatement + CheckDummyVideo + CheckDiskAudio + CheckDummyAudio + CheckSVGAVideo + CheckDLOPEN + CheckUCLOCK + + # Set up files for the timer library + if test x$enable_timers = xyes; then + +$as_echo "#define SDL_TIMER_DOS 1" >>confdefs.h + + SOURCES="$SOURCES $srcdir/src/timer/dos/*.c" + have_timers=yes + fi + + # Set up files for shared DOS utilities and event handling + SOURCES="$SOURCES $srcdir/src/core/dos/*.c" + ;; *) as_fn_error $? " *** Unsupported host: Please add to configure.ac diff --git a/configure.ac b/configure.ac index cd58faa21acda..3f7b64c767300 100644 --- a/configure.ac +++ b/configure.ac @@ -359,7 +359,17 @@ dnl Checks for library functions. AC_DEFINE(HAVE_MPROTECT, 1, [ ]) ],[]), ) - AC_CHECK_FUNCS(malloc calloc realloc free getenv setenv putenv unsetenv bsearch qsort abs bcopy memset memcmp memcpy memmove wcslen wcslcpy wcslcat _wcsdup wcsdup wcsstr wcscmp wcsncmp wcscasecmp _wcsicmp wcsncasecmp _wcsnicmp strlen strlcpy strlcat _strrev _strupr _strlwr index rindex strchr strrchr strstr strtok_r itoa _ltoa _uitoa _ultoa strtod strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp strcasestr vsscanf vsnprintf fopen64 fseeko fseeko64 sigaction sigtimedwait setjmp nanosleep sysconf sysctlbyname getauxval elf_aux_info poll memfd_create posix_fallocate _Exit) + + case "$host" in + *-*-msdosdjgpp*) + AC_MSG_NOTICE(skipping unfinished fseeko64 in DJGPP) + ;; + *) + AC_CHECK_FUNCS(fseeko64) + ;; + esac + + AC_CHECK_FUNCS(malloc calloc realloc free getenv setenv putenv unsetenv bsearch qsort abs bcopy memset memcmp memcpy memmove wcslen wcslcpy wcslcat _wcsdup wcsdup wcsstr wcscmp wcsncmp wcscasecmp _wcsicmp wcsncasecmp _wcsnicmp strlen strlcpy strlcat _strrev _strupr _strlwr index rindex strchr strrchr strstr strtok_r itoa _ltoa _uitoa _ultoa strtod strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp strcasestr vsscanf vsnprintf fopen64 fseeko sigaction sigtimedwait setjmp nanosleep sysconf sysctlbyname getauxval elf_aux_info poll memfd_create posix_fallocate _Exit) AC_CHECK_LIB(m, pow, [LIBS="$LIBS -lm"; EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lm"]) AC_CHECK_FUNCS(acos acosf asin asinf atan atanf atan2 atan2f ceil ceilf copysign copysignf cos cosf exp expf fabs fabsf floor floorf trunc truncf fmod fmodf log logf log10 log10f lround lroundf pow powf round roundf scalbn scalbnf sin sinf sqrt sqrtf tan tanf) @@ -664,8 +674,8 @@ if test x$enable_assembly = xyes; then dnl Check for various instruction support AC_ARG_ENABLE(mmx, -[AS_HELP_STRING([--enable-mmx], [use MMX assembly routines [default=yes]])], - , enable_mmx=yes) +[AS_HELP_STRING([--enable-mmx], [use MMX assembly routines [[default=maybe]]])], + , enable_mmx=$default_ssemath) if test x$enable_mmx = xyes; then save_CFLAGS="$CFLAGS" have_gcc_mmx=no @@ -698,8 +708,8 @@ dnl Check for various instruction support fi AC_ARG_ENABLE(3dnow, -[AS_HELP_STRING([--enable-3dnow], [use 3DNow! assembly routines [default=no]])], - , enable_3dnow=no) +[AS_HELP_STRING([--enable-3dnow], [use 3DNow! assembly routines [[default=maybe]]])], + , enable_3dnow=$default_ssemath) if test x$enable_3dnow = xyes; then save_CFLAGS="$CFLAGS" have_gcc_3dnow=no @@ -727,8 +737,8 @@ dnl Check for various instruction support fi AC_ARG_ENABLE(sse, -[AS_HELP_STRING([--enable-sse], [use SSE assembly routines [default=yes]])], - , enable_sse=yes) +[AS_HELP_STRING([--enable-sse], [use SSE assembly routines [[default=maybe]]])], + , enable_sse=$default_ssemath) if test x$enable_sse = xyes; then save_CFLAGS="$CFLAGS" have_gcc_sse=no @@ -2508,6 +2518,17 @@ CheckQNXAudio() fi } +dnl Set up the SVGA video driver if enabled +CheckSVGAVideo() +{ + if test x$enable_video = xyes; then + AC_DEFINE(SDL_VIDEO_DRIVER_SVGA, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/video/svga/*.c" + have_video=yes + SUMMARY_video="${SUMMARY_video} svga" + fi +} + dnl Check to see if OpenGL support is desired AC_ARG_ENABLE(video-opengl, [AS_HELP_STRING([--enable-video-opengl], [include OpenGL support [default=yes]])], @@ -3694,6 +3715,17 @@ CheckClockGettime() fi } +dnl Check for uclock() +CheckUCLOCK() +{ + AC_ARG_ENABLE(uclock, +AS_HELP_STRING([--enable-uclock], [use uclock() for performance counter on DOS [[default=yes]]]), + , enable_uclock=yes) + if test x$enable_uclock = xyes; then + AC_CHECK_FUNCS(uclock) + fi +} + dnl Check for a valid linux/version.h CheckLinuxVersion() { @@ -4673,6 +4705,27 @@ dnl BeOS support removed after SDL 2.0.1. Haiku still works. --ryan. have_joystick=yes fi ;; + *-*-msdosdjgpp*) + ARCH=dos + CheckVisibilityHidden + CheckDeclarationAfterStatement + CheckDummyVideo + CheckDiskAudio + CheckDummyAudio + CheckSVGAVideo + CheckDLOPEN + CheckUCLOCK + + # Set up files for the timer library + if test x$enable_timers = xyes; then + AC_DEFINE(SDL_TIMER_DOS, 1, [ ]) + SOURCES="$SOURCES $srcdir/src/timer/dos/*.c" + have_timers=yes + fi + + # Set up files for shared DOS utilities and event handling + SOURCES="$SOURCES $srcdir/src/core/dos/*.c" + ;; *) AC_MSG_ERROR([ *** Unsupported host: Please add to configure.ac diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake index 64b8413c8cdc7..934141280c8fa 100644 --- a/include/SDL_config.h.cmake +++ b/include/SDL_config.h.cmake @@ -229,6 +229,7 @@ #cmakedefine HAVE_INOTIFY 1 #cmakedefine HAVE_LIBUSB 1 #cmakedefine HAVE_O_CLOEXEC 1 +#cmakedefine HAVE_UCLOCK /* Apple platforms might be building universal binaries, where Intel builds can use immintrin.h but other architectures can't. */ @@ -398,6 +399,7 @@ #cmakedefine SDL_TIMER_UNIX @SDL_TIMER_UNIX@ #cmakedefine SDL_TIMER_WINDOWS @SDL_TIMER_WINDOWS@ #cmakedefine SDL_TIMER_OS2 @SDL_TIMER_OS2@ +#cmakedefine SDL_TIMER_DOS @SDL_TIMER_DOS@ #cmakedefine SDL_TIMER_VITA @SDL_TIMER_VITA@ #cmakedefine SDL_TIMER_PSP @SDL_TIMER_PSP@ #cmakedefine SDL_TIMER_PS2 @SDL_TIMER_PS2@ @@ -420,6 +422,7 @@ #cmakedefine SDL_VIDEO_DRIVER_VIVANTE @SDL_VIDEO_DRIVER_VIVANTE@ #cmakedefine SDL_VIDEO_DRIVER_VIVANTE_VDK @SDL_VIDEO_DRIVER_VIVANTE_VDK@ #cmakedefine SDL_VIDEO_DRIVER_OS2 @SDL_VIDEO_DRIVER_OS2@ +#cmakedefine SDL_VIDEO_DRIVER_SVGA @SDL_VIDEO_DRIVER_SVGA@ #cmakedefine SDL_VIDEO_DRIVER_QNX @SDL_VIDEO_DRIVER_QNX@ #cmakedefine SDL_VIDEO_DRIVER_RISCOS @SDL_VIDEO_DRIVER_RISCOS@ #cmakedefine SDL_VIDEO_DRIVER_PSP @SDL_VIDEO_DRIVER_PSP@ diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in index 35281d158d869..e5a877892a2d5 100644 --- a/include/SDL_config.h.in +++ b/include/SDL_config.h.in @@ -202,6 +202,7 @@ #undef HAVE_SYSCONF #undef HAVE_SYSCTLBYNAME #undef HAVE_CLOCK_GETTIME +#undef HAVE_UCLOCK #undef HAVE_GETPAGESIZE #undef HAVE_MPROTECT #undef HAVE_ICONV @@ -370,6 +371,7 @@ #undef SDL_TIMER_UNIX #undef SDL_TIMER_WINDOWS #undef SDL_TIMER_OS2 +#undef SDL_TIMER_DOS /* Enable various video drivers */ #undef SDL_VIDEO_DRIVER_HAIKU @@ -416,6 +418,7 @@ #undef SDL_VIDEO_DRIVER_OS2 #undef SDL_VIDEO_DRIVER_QNX #undef SDL_VIDEO_DRIVER_RISCOS +#undef SDL_VIDEO_DRIVER_SVGA #undef SDL_VIDEO_RENDER_D3D #undef SDL_VIDEO_RENDER_D3D11 diff --git a/src/SDL_log.c b/src/SDL_log.c index 47f5b7251eac8..8dc612c29e8e3 100644 --- a/src/SDL_log.c +++ b/src/SDL_log.c @@ -555,7 +555,7 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority SDL_NSLog(SDL_priority_prefixes[priority], message); return; } -#elif defined(__PSP__) || defined(__PS2__) +#elif defined(__PSP__) || defined(__PS2__) || defined(__MSDOS__) { FILE *pFile; pFile = fopen("SDL_Log.txt", "a"); diff --git a/src/core/dos/SDL_dos.c b/src/core/dos/SDL_dos.c new file mode 100644 index 0000000000000..52c685b7acc27 --- /dev/null +++ b/src/core/dos/SDL_dos.c @@ -0,0 +1,465 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + Copyright (C) 2020 Jay Petacat + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "../../SDL_internal.h" + +#ifdef __MSDOS__ + +#include +#include + +#include "../../events/SDL_events_c.h" + +#define KEYBOARD_INTERRUPT 0x09 + +#define PS2_DATA 0x60 +#define PS2_STATUS 0x64 + +static const SDL_Scancode bios_to_sdl_scancode[128] = { + 0, /* 0 0x00 */ + SDL_SCANCODE_ESCAPE, /* 1 0x01 */ + SDL_SCANCODE_1, /* 2 0x02 */ + SDL_SCANCODE_2, /* 3 0x03 */ + SDL_SCANCODE_3, /* 4 0x04 */ + SDL_SCANCODE_4, /* 5 0x05 */ + SDL_SCANCODE_5, /* 6 0x06 */ + SDL_SCANCODE_6, /* 7 0x07 */ + SDL_SCANCODE_7, /* 8 0x08 */ + SDL_SCANCODE_8, /* 9 0x09 */ + SDL_SCANCODE_9, /* 10 0x0a */ + SDL_SCANCODE_0, /* 11 0x0b */ + SDL_SCANCODE_MINUS, /* 12 0x0c */ + SDL_SCANCODE_EQUALS, /* 13 0x0d */ + SDL_SCANCODE_BACKSPACE, /* 14 0x0e */ + SDL_SCANCODE_TAB, /* 15 0x0f */ + SDL_SCANCODE_Q, /* 16 0x10 */ + SDL_SCANCODE_W, /* 17 0x11 */ + SDL_SCANCODE_E, /* 18 0x12 */ + SDL_SCANCODE_R, /* 19 0x13 */ + SDL_SCANCODE_T, /* 20 0x14 */ + SDL_SCANCODE_Y, /* 21 0x15 */ + SDL_SCANCODE_U, /* 22 0x16 */ + SDL_SCANCODE_I, /* 23 0x17 */ + SDL_SCANCODE_O, /* 24 0x18 */ + SDL_SCANCODE_P, /* 25 0x19 */ + SDL_SCANCODE_LEFTBRACKET, /* 26 0x1a */ + SDL_SCANCODE_RIGHTBRACKET, /* 27 0x1b */ + SDL_SCANCODE_RETURN, /* 28 0x1c */ + SDL_SCANCODE_LCTRL, /* 29 0x1d */ + SDL_SCANCODE_A, /* 30 0x1e */ + SDL_SCANCODE_S, /* 31 0x1f */ + SDL_SCANCODE_D, /* 32 0x20 */ + SDL_SCANCODE_F, /* 33 0x21 */ + SDL_SCANCODE_G, /* 34 0x22 */ + SDL_SCANCODE_H, /* 35 0x23 */ + SDL_SCANCODE_J, /* 36 0x24 */ + SDL_SCANCODE_K, /* 37 0x25 */ + SDL_SCANCODE_L, /* 38 0x26 */ + SDL_SCANCODE_SEMICOLON, /* 39 0x27 */ + SDL_SCANCODE_APOSTROPHE, /* 40 0x28 */ + SDL_SCANCODE_GRAVE, /* 41 0x29 */ + SDL_SCANCODE_LSHIFT, /* 42 0x2a */ + SDL_SCANCODE_BACKSLASH, /* 43 0x2b */ + SDL_SCANCODE_Z, /* 44 0x2c */ + SDL_SCANCODE_X, /* 45 0x2d */ + SDL_SCANCODE_C, /* 46 0x2e */ + SDL_SCANCODE_V, /* 47 0x2f */ + SDL_SCANCODE_B, /* 48 0x30 */ + SDL_SCANCODE_N, /* 49 0x31 */ + SDL_SCANCODE_M, /* 50 0x32 */ + SDL_SCANCODE_COMMA, /* 51 0x33 */ + SDL_SCANCODE_PERIOD, /* 52 0x34 */ + SDL_SCANCODE_SLASH, /* 53 0x35 */ + SDL_SCANCODE_RSHIFT, /* 54 0x36 */ + SDL_SCANCODE_KP_MULTIPLY, /* 55 0x37 */ + SDL_SCANCODE_LALT, /* 56 0x38 */ + SDL_SCANCODE_SPACE, /* 57 0x39 */ + SDL_SCANCODE_CAPSLOCK, /* 58 0x3a */ + SDL_SCANCODE_F1, /* 59 0x3b */ + SDL_SCANCODE_F2, /* 60 0x3c */ + SDL_SCANCODE_F3, /* 61 0x3d */ + SDL_SCANCODE_F4, /* 62 0x3e */ + SDL_SCANCODE_F5, /* 63 0x3f */ + SDL_SCANCODE_F6, /* 64 0x40 */ + SDL_SCANCODE_F7, /* 65 0x41 */ + SDL_SCANCODE_F8, /* 66 0x42 */ + SDL_SCANCODE_F9, /* 67 0x43 */ + SDL_SCANCODE_F10, /* 68 0x44 */ + SDL_SCANCODE_NUMLOCKCLEAR, /* 69 0x45 */ + SDL_SCANCODE_SCROLLLOCK, /* 70 0x46 */ + SDL_SCANCODE_KP_7, /* 71 0x47 */ + SDL_SCANCODE_KP_8, /* 72 0x48 */ + SDL_SCANCODE_KP_9, /* 73 0x49 */ + SDL_SCANCODE_KP_MINUS, /* 74 0x4a */ + SDL_SCANCODE_KP_4, /* 75 0x4b */ + SDL_SCANCODE_KP_5, /* 76 0x4c */ + SDL_SCANCODE_KP_6, /* 77 0x4d */ + SDL_SCANCODE_KP_PLUS, /* 78 0x4e */ + SDL_SCANCODE_KP_1, /* 79 0x4f */ + SDL_SCANCODE_KP_2, /* 80 0x50 */ + SDL_SCANCODE_KP_3, /* 81 0x51 */ + SDL_SCANCODE_KP_0, /* 82 0x52 */ + SDL_SCANCODE_KP_PERIOD, /* 83 0x53 */ + SDL_SCANCODE_SYSREQ, /* 84 0x54 */ + 0, /* 85 0x55 */ + SDL_SCANCODE_LGUI, /* 86 0x56 */ + SDL_SCANCODE_F11, /* 87 0x57 */ + SDL_SCANCODE_F12, /* 88 0x58 */ +}; + +/* Keys that are first indicated by 0xE0 */ +static const SDL_Scancode extended_key_to_sdl_scancode[128] = { + 0, /* 0 0x00 */ + 0, /* 1 0x01 */ + 0, /* 2 0x02 */ + 0, /* 3 0x03 */ + 0, /* 4 0x04 */ + 0, /* 5 0x05 */ + 0, /* 6 0x06 */ + 0, /* 7 0x07 */ + 0, /* 8 0x08 */ + 0, /* 9 0x09 */ + 0, /* 10 0x0a */ + 0, /* 11 0x0b */ + 0, /* 12 0x0c */ + 0, /* 13 0x0d */ + 0, /* 14 0x0e */ + 0, /* 15 0x0f */ + 0, /* 16 0x10 */ + 0, /* 17 0x11 */ + 0, /* 18 0x12 */ + 0, /* 19 0x13 */ + 0, /* 20 0x14 */ + 0, /* 21 0x15 */ + 0, /* 22 0x16 */ + 0, /* 23 0x17 */ + 0, /* 24 0x18 */ + 0, /* 25 0x19 */ + 0, /* 26 0x1a */ + 0, /* 27 0x1b */ + SDL_SCANCODE_KP_ENTER, /* 28 0x1c */ + SDL_SCANCODE_RALT, /* 29 0x1d */ + 0, /* 30 0x1e */ + 0, /* 31 0x1f */ + 0, /* 32 0x20 */ + 0, /* 33 0x21 */ + 0, /* 34 0x22 */ + 0, /* 35 0x23 */ + 0, /* 36 0x24 */ + 0, /* 37 0x25 */ + 0, /* 38 0x26 */ + 0, /* 39 0x27 */ + 0, /* 40 0x28 */ + 0, /* 41 0x29 */ + SDL_SCANCODE_LSHIFT, /* 42 0x2a */ + 0, /* 43 0x2b */ + 0, /* 44 0x2c */ + 0, /* 45 0x2d */ + 0, /* 46 0x2e */ + 0, /* 47 0x2f */ + 0, /* 48 0x30 */ + 0, /* 49 0x31 */ + 0, /* 50 0x32 */ + 0, /* 51 0x33 */ + 0, /* 52 0x34 */ + SDL_SCANCODE_KP_DIVIDE, /* 53 0x35 */ + SDL_SCANCODE_RSHIFT, /* 54 0x36 */ + SDL_SCANCODE_PRINTSCREEN, /* 55 0x37 */ + SDL_SCANCODE_RALT, /* 56 0x38 */ + 0, /* 57 0x39 */ + 0, /* 58 0x3a */ + 0, /* 59 0x3b */ + 0, /* 60 0x3c */ + 0, /* 61 0x3d */ + 0, /* 62 0x3e */ + 0, /* 63 0x3f */ + 0, /* 64 0x40 */ + 0, /* 65 0x41 */ + 0, /* 66 0x42 */ + 0, /* 67 0x43 */ + 0, /* 68 0x44 */ + 0, /* 69 0x45 */ + SDL_SCANCODE_PAUSE, /* 70 0x46 */ + SDL_SCANCODE_HOME, /* 71 0x47 */ + SDL_SCANCODE_UP, /* 72 0x48 */ + SDL_SCANCODE_PAGEUP, /* 73 0x49 */ + 0, /* 74 0x4a */ + SDL_SCANCODE_LEFT, /* 75 0x4b */ + 0, /* 76 0x4c */ + SDL_SCANCODE_RIGHT, /* 77 0x4d */ + 0, /* 78 0x4e */ + SDL_SCANCODE_END, /* 79 0x4f */ + SDL_SCANCODE_DOWN, /* 80 0x50 */ + SDL_SCANCODE_PAGEDOWN, /* 81 0x51 */ + SDL_SCANCODE_INSERT, /* 82 0x52 */ + SDL_SCANCODE_DELETE, /* 83 0x53 */ + 0, /* 84 0x54 */ + 0, /* 85 0x55 */ + 0, /* 86 0x56 */ + 0, /* 87 0x57 */ + 0, /* 88 0x58 */ + 0, /* 89 0x59 */ + 0, /* 90 0x5a */ + 0, /* 91 0x5b */ + 0, /* 92 0x5c */ + 0, /* 93 0x5d */ + 0, /* 94 0x5e */ + 0, /* 95 0x5f */ + 0, /* 96 0x60 */ + 0, /* 97 0x61 */ + 0, /* 98 0x62 */ + 0, /* 99 0x63 */ + 0, /* 100 0x64 */ + 0, /* 101 0x65 */ + 0, /* 102 0x66 */ + 0, /* 103 0x67 */ + 0, /* 104 0x68 */ + 0, /* 105 0x69 */ + 0, /* 106 0x6a */ + 0, /* 107 0x6b */ + 0, /* 108 0x6c */ + 0, /* 109 0x6d */ + 0, /* 110 0x6e */ + 0, /* 111 0x6f */ + 0, /* 112 0x70 */ + 0, /* 113 0x71 */ + 0, /* 114 0x72 */ + 0, /* 115 0x73 */ + 0, /* 116 0x74 */ + 0, /* 117 0x75 */ + 0, /* 118 0x76 */ + 0, /* 119 0x77 */ + 0, /* 120 0x78 */ + 0, /* 121 0x79 */ + 0, /* 122 0x7a */ + 0, /* 123 0x7b */ + 0, /* 124 0x7c */ + 0, /* 125 0x7d */ + 0, /* 126 0x7e */ + 0, /* 127 0x7f */ +}; + +static const char shift_digits[16] = { + ')', /* 0 */ + '!', /* 1 */ + '@', /* 2 */ + '#', /* 3 */ + '$', /* 4 */ + '%', /* 5 */ + '^', /* 6 */ + '&', /* 7 */ + '*', /* 8 */ + '(', /* 9 */ +}; + +static volatile Uint8 scancode_buf[100]; +static volatile int scancode_count; + +static void +DOS_KeyboardISR(void) +{ + /* Read scancodes from keyboard into buffer. */ + while (inportb(PS2_STATUS) & 1 && scancode_count < SDL_arraysize(scancode_buf)) { + scancode_buf[scancode_count++] = inportb(PS2_DATA); + } + + /* Acknowledge interrupt. */ + outportb(0x20, 0x20); +} + +static int +DOS_LockKeyboardISR(void) +{ + size_t len = (void *)DOS_LockKeyboardISR - (void *)DOS_KeyboardISR; + + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, "DOS: Keyboard ISR code size is %zd bytes", len); + + /* Lock interrupt service routine. */ + if (_go32_dpmi_lock_code(DOS_KeyboardISR, len)) { + return SDL_SetError("DOS: Failed to lock keyboard ISR code (%zd bytes)", len); + } + + /* Lock scancode buffer. */ + if (_go32_dpmi_lock_data((void *)scancode_buf, sizeof(scancode_buf))) { + return SDL_SetError("DOS: Failed to lock scancode buffer (%zu bytes)", sizeof(scancode_buf)); + } + + /* Lock scancode counter. */ + if (_go32_dpmi_lock_data((void *)&scancode_count, sizeof(scancode_count))) { + return SDL_SetError("DOS: Failed to lock scancode counter (%zu bytes)", sizeof(scancode_count)); + } + + return 0; +} + +static SDL_bool kbd_is_init; +static _go32_dpmi_seginfo kbd_isr, old_kbd_isr; + +static int +DOS_InitKeyboard(void) +{ + if (kbd_is_init) { + return 0; + } + + /* Save the original keyboard interrupt service routine. */ + if (_go32_dpmi_get_protected_mode_interrupt_vector(KEYBOARD_INTERRUPT, &old_kbd_isr)) { + return SDL_SetError("DOS: Failed to get original keyboard ISR"); + } + + /* Lock memory that is touched during an interrupt. */ + if (DOS_LockKeyboardISR()) { + return -1; + } + + /* Setup struct for input parameters. */ + kbd_isr.pm_offset = (unsigned long)DOS_KeyboardISR; + + /* Wrap the keyboard ISR so it can be used. */ + if (_go32_dpmi_allocate_iret_wrapper(&kbd_isr)) { + return SDL_SetError("DOS: Failed to wrap keyboard ISR"); + } + + /* Use the new keyboard ISR. */ + if (_go32_dpmi_set_protected_mode_interrupt_vector(KEYBOARD_INTERRUPT, &kbd_isr)) { + _go32_dpmi_free_iret_wrapper(&kbd_isr); + return SDL_SetError("DOS: Failed to set new keyboard ISR"); + } + + kbd_is_init = SDL_TRUE; + + return 0; +} + +static void +DOS_ProcessScancode(Uint8 raw) +{ + static SDL_bool extended_key = SDL_FALSE; + Uint8 state = raw & 0x80 ? SDL_RELEASED : SDL_PRESSED; + SDL_Scancode scancode; + + /* Check if the code is an extended key prefix. */ + if (raw == 0xE0) { + extended_key = SDL_TRUE; + return; + } + + /* Mask off state bit. */ + raw &= 0x7F; + + /* Convert to SDL scancode. */ + if (extended_key) { + scancode = extended_key_to_sdl_scancode[raw]; + } else { + scancode = bios_to_sdl_scancode[raw]; + } + + /* Reset extended key flag. */ + extended_key = SDL_FALSE; + + /* Send a key event. Return if it wasn't posted. */ + if (SDL_SendKeyboardKey(state, scancode) == 0) return; + + /* If text input events are enabled, send one with basic US layout conversion. */ + if (state == SDL_PRESSED && SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) { + const SDL_Keymod modstate = SDL_GetModState(); + const SDL_Keycode keycode = SDL_GetKeyFromScancode(scancode); + if (((modstate & (KMOD_CTRL | KMOD_ALT)) == 0) && + keycode >= SDLK_SPACE && keycode <= SDLK_z) { + char buf[2]; + if ((modstate & KMOD_SHIFT)) { + if (keycode >= SDLK_0 && keycode <= SDLK_9) { + buf[0] = shift_digits[keycode - '0']; + } else if (keycode >= SDLK_a && keycode <= SDLK_z) { + buf[0] = keycode - ('a' - 'A'); + } + } else { + buf[0] = (char)keycode; + } + buf[1] = '\0'; + SDL_SendKeyboardText(buf); + } + } +} + +static void +DOS_PollKeyboard(void) +{ + int i; + + /* Convert buffered scancodes to SDL key events. */ + for (i = 0; i < scancode_count; i++) { + DOS_ProcessScancode(scancode_buf[i]); + } + + /* Reset scancode buffer count. */ + /* TODO: Do not write to scancode buffer while it's being drained here. */ + scancode_count = 0; + + /* Read any remaining scancodes from keyboard and convert to SDL key events. */ + for (i = 0; inportb(PS2_STATUS) & 1; i++) { + DOS_ProcessScancode(inportb(PS2_DATA)); + } + + /* Warn if scancode buffer reached maximum capacity. */ + if (i) { + SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "DOS: %d keyboard scancode(s) not buffered", i); + } +} + +static void +DOS_QuitKeyboard(void) +{ + if (kbd_is_init) { + return; + } + + /* Restore original keyboard interrupt service routine. */ + _go32_dpmi_set_protected_mode_interrupt_vector(KEYBOARD_INTERRUPT, &old_kbd_isr); + + /* Cleanup keyboard ISR wrapper. */ + _go32_dpmi_free_iret_wrapper(&kbd_isr); + + kbd_is_init = SDL_FALSE; +} + +int +SDL_DOS_Init(void) +{ + return DOS_InitKeyboard(); +} + +void +SDL_DOS_PumpEvents(void) +{ + DOS_PollKeyboard(); +} + +void +SDL_DOS_Quit(void) +{ + DOS_QuitKeyboard(); +} + +#endif /* __MSDOS__ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/core/dos/SDL_dos.h b/src/core/dos/SDL_dos.h new file mode 100644 index 0000000000000..e069815319b35 --- /dev/null +++ b/src/core/dos/SDL_dos.h @@ -0,0 +1,32 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + Copyright (C) 2020 Jay Petacat + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_dos_h_ +#define SDL_dos_h_ + +extern int SDL_DOS_Init(void); +extern void SDL_DOS_PumpEvents(void); +extern void SDL_DOS_Quit(void); + +#endif /* SDL_dos_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/timer/dos/SDL_systimer.c b/src/timer/dos/SDL_systimer.c new file mode 100644 index 0000000000000..fd13687d6ae3d --- /dev/null +++ b/src/timer/dos/SDL_systimer.c @@ -0,0 +1,87 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#if defined(SDL_TIMER_DOS) + +#include +#include + +#include "SDL_timer.h" + +static clock_t start; +static SDL_bool ticks_started = SDL_FALSE; + +void +SDL_TicksInit(void) +{ + if (ticks_started) { + return; + } + start = clock(); + ticks_started = SDL_TRUE; +} + +void +SDL_TicksQuit(void) +{ + ticks_started = SDL_FALSE; +} + +Uint64 +SDL_GetTicks64(void) +{ + if (!ticks_started) { + SDL_TicksInit(); + } + + return (Uint64)((clock() - start) * 1000 / CLOCKS_PER_SEC); +} + +Uint64 +SDL_GetPerformanceCounter(void) +{ +#ifdef HAVE_UCLOCK + return uclock(); +#else + return SDL_GetTicks(); +#endif +} + +Uint64 +SDL_GetPerformanceFrequency(void) +{ +#ifdef HAVE_UCLOCK + return UCLOCKS_PER_SEC; +#else + return 1000; +#endif +} + +void +SDL_Delay(Uint32 ms) +{ + delay(ms); +} + +#endif /* SDL_TIMER_DOS */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 1018fd78c12cb..014a5b7031545 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -481,6 +481,7 @@ extern VideoBootStrap NACL_bootstrap; extern VideoBootStrap VIVANTE_bootstrap; extern VideoBootStrap Emscripten_bootstrap; extern VideoBootStrap QNX_bootstrap; +extern VideoBootStrap SVGA_bootstrap; extern VideoBootStrap OFFSCREEN_bootstrap; extern VideoBootStrap NGAGE_bootstrap; extern VideoBootStrap OS2DIVE_bootstrap; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 4e22f28c580e7..445c721d61c34 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -143,6 +143,9 @@ static VideoBootStrap *bootstrap[] = { &OS2DIVE_bootstrap, &OS2VMAN_bootstrap, #endif +#ifdef SDL_VIDEO_DRIVER_SVGA + &SVGA_bootstrap, +#endif #ifdef SDL_VIDEO_DRIVER_NGAGE &NGAGE_bootstrap, #endif @@ -2702,7 +2705,7 @@ static SDL_bool ShouldAttemptTextureFramebuffer(void) attempt_texture_framebuffer = SDL_FALSE; } #endif -#if defined(__EMSCRIPTEN__) +#if defined(__EMSCRIPTEN__) || defined(__MSDOS__) attempt_texture_framebuffer = SDL_FALSE; #endif } diff --git a/src/video/svga/SDL_svga_events.c b/src/video/svga/SDL_svga_events.c new file mode 100644 index 0000000000000..7e4484286a767 --- /dev/null +++ b/src/video/svga/SDL_svga_events.c @@ -0,0 +1,40 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + Copyright (C) 2020 Jay Petacat + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#ifdef SDL_VIDEO_DRIVER_SVGA + +#include "../../core/dos/SDL_dos.h" + +#include "SDL_svga_events.h" +#include "SDL_svga_mouse.h" + +void +SVGA_PumpEvents(_THIS) +{ + SDL_DOS_PumpEvents(); + DOS_PollMouse(); +} + +#endif /* SDL_VIDEO_DRIVER_SVGA */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/svga/SDL_svga_events.h b/src/video/svga/SDL_svga_events.h new file mode 100644 index 0000000000000..c79258ed3920e --- /dev/null +++ b/src/video/svga/SDL_svga_events.h @@ -0,0 +1,33 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_svga_events_h_ +#define SDL_svga_events_h_ + +#include "../../SDL_internal.h" + +#include "SDL_svga_video.h" + +extern void SVGA_PumpEvents(_THIS); + +#endif /* SDL_svga_events_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/svga/SDL_svga_framebuffer.c b/src/video/svga/SDL_svga_framebuffer.c new file mode 100644 index 0000000000000..62d2c84c33c32 --- /dev/null +++ b/src/video/svga/SDL_svga_framebuffer.c @@ -0,0 +1,212 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#ifdef SDL_VIDEO_DRIVER_SVGA + +#include +#include +#include + +#include "SDL_events.h" +#include "SDL_mouse.h" +#include "SDL_svga_video.h" +#include "SDL_svga_framebuffer.h" + +int +SDL_SVGA_CreateFramebuffer(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch) +{ + SDL_DeviceData *devdata = _this->driverdata; + SDL_DisplayMode mode; + SDL_DisplayModeData *modedata; + SDL_Surface *surface; + SDL_WindowData *windata = window->driverdata; + __dpmi_meminfo meminfo; + int w, h; + + /* Free the old framebuffer surface. */ + SDL_SVGA_DestroyFramebuffer(_this, window); + + /* Get data for current mode. */ + if (SDL_GetWindowDisplayMode(window, &mode)) { + return -1; + } + modedata = mode.driverdata; + + /* Map framebuffer's physical address to linear address. */ + meminfo.address = modedata->framebuffer_phys_addr.segment << 16; + meminfo.address += modedata->framebuffer_phys_addr.offset; + meminfo.size = devdata->vbe_info.total_memory << 16; + if (__dpmi_physical_address_mapping(&meminfo)) { + SDL_SVGA_DestroyFramebuffer(_this, window); + return -1; + } + windata->framebuffer_linear_addr = meminfo.address; + + /* Allocate local descriptor to access memory-mapped framebuffer. */ + windata->framebuffer_selector = __dpmi_allocate_ldt_descriptors(1); + if (windata->framebuffer_selector == -1) { + SDL_SVGA_DestroyFramebuffer(_this, window); + return -1; + } + + /* Setup framebuffer descriptor. */ + if (__dpmi_set_segment_base_address(windata->framebuffer_selector, meminfo.address) || + __dpmi_set_segment_limit(windata->framebuffer_selector, meminfo.size - 1)) { + SDL_SVGA_DestroyFramebuffer(_this, window); + return -1; + } + + /* Create a new surface. */ + SDL_GetWindowSize(window, &w, &h); + surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, mode.format); + if (!surface) { + SDL_SVGA_DestroyFramebuffer(_this, window); + return -1; + } + + /* Populate color palette for indexed pixel formats. */ + if (surface->format->palette) { + SDL_Palette *palette = surface->format->palette; + if (SVGA_SetDACPaletteFormat(8)) { + /* Failed to set to 8-bit, assume 6-bit channel */ + windata->palette_dac_bits = 6; + } else { + windata->palette_dac_bits = 8; + } + if (SVGA_GetPaletteData(palette->colors, palette->ncolors, windata->palette_dac_bits)) { + SDL_SVGA_DestroyFramebuffer(_this, window); + return -1; + } + windata->last_palette = palette; + windata->last_palette_version = palette->version; + } + + /* Save data and set output parameters. */ + window->surface = surface; + *format = mode.format; + *pixels = surface->pixels; + *pitch = surface->pitch; + + return 0; +} + +/* TODO: Draw a real pointer. */ +static void +CopyCursorPixels(SDL_Window * window) +{ + SDL_Surface *surface = window->surface; + SDL_WindowData *windata = window->driverdata; + size_t surface_size = surface->pitch * surface->h; + size_t framebuffer_offset = windata->framebuffer_page ? surface_size : 0; + Uint32 color = SDL_MapRGB(surface->format, 0xFF, 0, 0); + int i, k, x, y; + + SDL_GetMouseState(&x, &y); + x = SDL_max(x, 0); + y = SDL_max(y, 0); + x = SDL_min(x, surface->w - 4); + y = SDL_min(y, surface->h - 4); + + for (i = 0; i < 4; i++) { + for (k = 0; k < 4; k++) { + movedata(_my_ds(), (uintptr_t)&color, windata->framebuffer_selector, + framebuffer_offset + surface->pitch * (y + i) + (x + k) * surface->format->BytesPerPixel, + surface->format->BytesPerPixel); + } + } +} + +int +SDL_SVGA_UpdateFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects) +{ + SDL_WindowData *windata = window->driverdata; + SDL_Surface *surface = window->surface; + size_t framebuffer_offset, surface_size; + + if (!surface) { + return SDL_SetError("Missing SVGA surface"); + } + + surface_size = surface->pitch * surface->h; + + /* Flip the active page flag. */ + windata->framebuffer_page = !windata->framebuffer_page; + framebuffer_offset = windata->framebuffer_page ? surface_size : 0; + + if (surface->format->BitsPerPixel == 8 && + (surface->format->palette != windata->last_palette || + surface->format->palette->version != windata->last_palette_version)) { + /* Update the palette */ + SVGA_SetPaletteData(surface->format->palette->colors, surface->format->palette->ncolors, windata->palette_dac_bits); + windata->last_palette = surface->format->palette; + windata->last_palette_version = surface->format->palette->version; + } + + /* Copy surface pixels to hidden framebuffer. */ + movedata(_my_ds(), (uintptr_t)surface->pixels, windata->framebuffer_selector, + framebuffer_offset, surface_size); + + /* Copy cursor pixels to hidden framebuffer. */ + if (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE) { + CopyCursorPixels(window); + } + + /* Display fresh page to screen. */ + SVGA_SetDisplayStart( + /*x=*/0, /*y=*/windata->framebuffer_page ? surface->h : 0, + /*bytes_per_pixel=*/surface->format->BytesPerPixel, + /*bytes_per_line=*/surface->pitch * surface->format->BytesPerPixel); + + return 0; +} + +void +SDL_SVGA_DestroyFramebuffer(_THIS, SDL_Window * window) +{ + SDL_WindowData *windata = window->driverdata; + + /* Destroy surface. */ + SDL_FreeSurface(window->surface); + window->surface = NULL; + window->surface_valid = SDL_FALSE; + + /* Deallocate local descriptor for framebuffer. */ + if (windata->framebuffer_selector != -1) { + __dpmi_free_ldt_descriptor(windata->framebuffer_selector); + windata->framebuffer_selector = -1; + } + + /* Unmap framebuffer physical address. */ + if (windata->framebuffer_linear_addr) { + __dpmi_meminfo meminfo; + + meminfo.address = windata->framebuffer_linear_addr; + __dpmi_free_physical_address_mapping(&meminfo); + windata->framebuffer_linear_addr = 0; + } + + windata->last_palette = NULL; +} + +#endif /* SDL_VIDEO_DRIVER_SVGA */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/svga/SDL_svga_framebuffer.h b/src/video/svga/SDL_svga_framebuffer.h new file mode 100644 index 0000000000000..3932d20cc5d89 --- /dev/null +++ b/src/video/svga/SDL_svga_framebuffer.h @@ -0,0 +1,33 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_svga_framebuffer_h_ +#define SDL_svga_framebuffer_h_ + +#include "../../SDL_internal.h" + +extern int SDL_SVGA_CreateFramebuffer(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch); +extern int SDL_SVGA_UpdateFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects); +extern void SDL_SVGA_DestroyFramebuffer(_THIS, SDL_Window * window); + +#endif /* SDL_svga_framebuffer_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/svga/SDL_svga_mouse.c b/src/video/svga/SDL_svga_mouse.c new file mode 100644 index 0000000000000..f84372205eb5d --- /dev/null +++ b/src/video/svga/SDL_svga_mouse.c @@ -0,0 +1,151 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + Copyright (C) 2020 Jay Petacat + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "../../SDL_internal.h" + +#ifdef SDL_VIDEO_DRIVER_SVGA + +#include "SDL_svga_mouse.h" + +#include + +#include "../../events/SDL_events_c.h" +#include "../../events/SDL_mouse_c.h" + +#define MOUSE_INTERRUPT 0x33 + +static Uint8 DOS_MouseButtons[] = { + SDL_BUTTON_LEFT, + SDL_BUTTON_RIGHT, + SDL_BUTTON_MIDDLE, +}; + +static SDL_Cursor * +DOS_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y) +{ + SDL_Cursor *cursor = SDL_calloc(1, sizeof(*cursor)); + + return cursor; +} + +static SDL_Cursor * +DOS_CreateSystemCursor(SDL_SystemCursor id) +{ + SDL_Cursor *cursor = SDL_calloc(1, sizeof(*cursor)); + + return cursor; +} + +static void +DOS_FreeCursor(SDL_Cursor * cursor) +{ + SDL_free(cursor); +} + +static int +DOS_ShowCursor(SDL_Cursor * cursor) +{ + __dpmi_regs r; + + r.x.ax = cursor ? 1 : 2; + + return __dpmi_int(MOUSE_INTERRUPT, &r); +} + +static void +DOS_WarpMouse(SDL_Window * window, int x, int y) +{ +} + +void +DOS_InitMouse(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + __dpmi_regs r; + + r.x.ax = 0; + + if (__dpmi_int(MOUSE_INTERRUPT, &r) || r.x.ax != 0xFFFF) { + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "DOS: No mouse installed"); + return; + } + + mouse->CreateCursor = DOS_CreateCursor; + mouse->CreateSystemCursor = DOS_CreateSystemCursor; + mouse->ShowCursor = DOS_ShowCursor; + mouse->FreeCursor = DOS_FreeCursor; + mouse->WarpMouse = DOS_WarpMouse; + + // SDL_SetDefaultCursor(DEFAULT_CURSOR); +} + +void +DOS_QuitMouse(void) +{ +} + +void DOS_PollMouse(void) +{ + static int last_button_status; + int button_status, i; + __dpmi_regs r; + + /* TODO: Determine if movement happened using interrupt callback. */ + + r.x.ax = 0xB; + + if (__dpmi_int(MOUSE_INTERRUPT, &r)) { + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DOS: Failed to query mouse position"); + DOS_QuitMouse(); + return; + } + + if (r.x.cx || r.x.dx) { + SDL_SendMouseMotion(NULL, 0, SDL_TRUE, (Sint16)r.x.cx, (Sint16)r.x.dx); + } + + r.x.ax = 3; + + if (__dpmi_int(MOUSE_INTERRUPT, &r)) { + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "DOS: Failed to query mouse state"); + DOS_QuitMouse(); + return; + } + + button_status = r.x.bx; + + for (i = 0; i < SDL_arraysize(DOS_MouseButtons); i++) { + int mask = 1 << i; + int diff = button_status ^ last_button_status; + + if (diff & mask) { + Uint8 state = button_status & mask ? SDL_PRESSED : SDL_RELEASED; + SDL_SendMouseButton(NULL, 0, state, DOS_MouseButtons[i]); + } + } + + last_button_status = button_status; +} + +#endif /* SDL_VIDEO_DRIVER_SVGA */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/svga/SDL_svga_mouse.h b/src/video/svga/SDL_svga_mouse.h new file mode 100644 index 0000000000000..344496aa74bb2 --- /dev/null +++ b/src/video/svga/SDL_svga_mouse.h @@ -0,0 +1,33 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + Copyright (C) 2020 Jay Petacat + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#ifndef SDL_svga_mouse_h_ +#define SDL_svga_mouse_h_ + +extern void DOS_InitMouse(void); +extern void DOS_PollMouse(void); +extern void DOS_QuitMouse(void); + +#endif /* SDL_svga_mouse_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/svga/SDL_svga_vbe.c b/src/video/svga/SDL_svga_vbe.c new file mode 100644 index 0000000000000..b57e07c13968c --- /dev/null +++ b/src/video/svga/SDL_svga_vbe.c @@ -0,0 +1,426 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* + Some of the asm routines here are based on Allegro 4.2. + Huge thanks to Allegro 4 authors for publishing their code under + a permissive license! +*/ + +#include "../../SDL_internal.h" + +#ifdef SDL_VIDEO_DRIVER_SVGA + +#include "SDL_svga_vbe.h" + +#include +#include +#include +#include + +/* Check the DPMI registers for an error after a VBE function call. */ +/* Returns -128 if the function is not supported or the negated VBE error code. */ +/* TODO: Create named macro definitions for possible error values. */ +#define RETURN_IF_VBE_CALL_FAILED(regs) \ + if ((regs).h.al != 0x4F) return SDL_MIN_SINT8; \ + if ((regs).h.ah != 0) return -(regs).h.ah; + +typedef struct VbeProtectedModeInterface +{ + unsigned short setWindow __attribute__((packed)); + unsigned short setDisplayStart __attribute__((packed)); + unsigned short setPalette __attribute__((packed)); + unsigned short IOPrivInfo __attribute__((packed)); +} VbeProtectedModeInterface; +VbeProtectedModeInterface *PM_Interface; + +/* Protected mode interface functions: */ +void *PM_SetWindow_Ptr; +void *PM_SetDisplayStart_Ptr; +void *PM_SetPalette_Ptr; + +int SVGA_InitProtectedModeInterface() +{ + __dpmi_regs r; + + if (PM_Interface != NULL) { + return 0; + } + + /* call the VESA function */ + r.x.ax = 0x4F0A; + r.x.bx = 0; + __dpmi_int(0x10, &r); + if (r.h.ah) + return -1; + + PM_Interface = SDL_malloc(r.x.cx); + dosmemget(r.x.es * 16 + r.x.di, r.x.cx, PM_Interface); + PM_SetWindow_Ptr = (void *)((char *)PM_Interface + PM_Interface->setWindow); + PM_SetDisplayStart_Ptr = (void *)((char *)PM_Interface + PM_Interface->setDisplayStart); + PM_SetPalette_Ptr = (void *)((char *)PM_Interface + PM_Interface->setPalette); + return 0; +} + +/* Returns a copy of the current %ds selector. */ +static int default_ds(void) +{ + short result; + + __asm__( + " movw %%ds, %0 " + + : "=r"(result)); + + return result; +} + +int +SVGA_GetVBEInfo(VBEInfo * info) +{ + __dpmi_regs r; + + dosmemput("VBE2", 4, __tb); + + r.x.ax = 0x4F00; + r.x.es = __tb_segment; + r.x.di = __tb_offset; + + __dpmi_int(0x10, &r); + + RETURN_IF_VBE_CALL_FAILED(r); + + dosmemget(__tb, sizeof(*info), info); + + /* Unexpected signature */ + if (strncmp(info->vbe_signature, "VESA", 4) != 0) { + return -1; + } + + return 0; +} + +VBEMode +SVGA_GetVBEModeAtIndex(const VBEInfo * info, int index) +{ + VBEMode mode; + + dosmemget(VBE_FLAT_PTR(info->video_mode_ptr) + index * sizeof(mode), sizeof(mode), &mode); + + return mode; +} + +int +SVGA_GetVBEModeInfo(VBEMode mode, VBEModeInfo * info) +{ + __dpmi_regs r; + + r.x.ax = 0x4F01; + r.x.cx = mode; + r.x.es = __tb_segment; + r.x.di = __tb_offset; + + __dpmi_int(0x10, &r); + + RETURN_IF_VBE_CALL_FAILED(r); + + dosmemget(__tb, sizeof(*info), info); + + return 0; +} + +int +SVGA_GetCurrentVBEMode(VBEMode * mode, VBEModeInfo * info) +{ + __dpmi_regs r; + + r.x.ax = 0x4F03; + + __dpmi_int(0x10, &r); + + RETURN_IF_VBE_CALL_FAILED(r); + + *mode = r.x.bx & 0x3FFF; /* High bits are status flags. */ + + if (!info) { + return 0; + } + + return SVGA_GetVBEModeInfo(*mode, info); +} + +int +SVGA_SetVBEMode(VBEMode mode) +{ + __dpmi_regs r; + + mode &= 0x01FF; /* Mode number bit mask. */ + mode |= 0x4000; /* Linear frame buffer flag. */ + + r.x.ax = 0x4F02; + r.x.bx = mode; + r.x.es = 0; + r.x.di = 0; + + __dpmi_int(0x10, &r); + + RETURN_IF_VBE_CALL_FAILED(r); + + return 0; +} + +int +SVGA_GetState(void **state) +{ + size_t state_size; + __dpmi_regs r; + + r.x.ax = 0x4F04; + r.h.dl = 0; /* Get state buffer size. */ + r.x.cx = 0xF; /* All states. */ + + __dpmi_int(0x10, &r); + + RETURN_IF_VBE_CALL_FAILED(r); + + /* Calculate state buffer size. */ + state_size = r.x.bx * 64; + + /* Check that transfer buffer is big enough. */ + if (state_size > __tb_size) { + return SDL_OutOfMemory(); + } + + r.h.dl = 1; /* Save state. */ + r.x.es = __tb_segment; + r.x.bx = __tb_offset; + + __dpmi_int(0x10, &r); + + RETURN_IF_VBE_CALL_FAILED(r); + + /* Allocate state buffer. */ + *state = SDL_calloc(1, state_size); + if (!*state) { + return SDL_OutOfMemory(); + } + + /* Copy state data from DOS transfer buffer. */ + dosmemget(__tb, state_size, *state); + + return state_size; +} + +int +SVGA_SetState(const void *state, size_t size) +{ + __dpmi_regs r; + + /* Check that transfer buffer is big enough. */ + if (size > __tb_size) { + return SDL_OutOfMemory(); + } + + /* Copy state data into DOS transfer buffer. */ + dosmemput(state, size, __tb); + + r.x.ax = 0x4F04; + r.h.dl = 2; /* Restore state. */ + r.x.cx = 0xF; /* All states. */ + r.x.es = __tb_segment; + r.x.bx = __tb_offset; + + __dpmi_int(0x10, &r); + + RETURN_IF_VBE_CALL_FAILED(r); + + return 0; +} + +int SVGA_SetDisplayStart(int x, int y, int bytes_per_pixel, int bytes_per_line) +{ + int seg; + long a; + seg = default_ds(); + + a = ((x * bytes_per_pixel) + (y * bytes_per_line)) / 4; + + asm( + " pushl %%ebp ; " + " pushw %%es ; " + " movw %w1, %%es ; " /* set the IO segment */ + " call *%0 ; " /* call the VESA function */ + " popw %%es ; " + " popl %%ebp ; " + + : /* no outputs */ + + : "S"(PM_SetDisplayStart_Ptr), /* function pointer in esi */ + "a"(seg), /* IO segment in eax */ + "b"(0x80), /* mode in ebx (0x80 = wait for vertical retrace) */ + "c"(a & 0xFFFF), /* low word of address in ecx */ + "d"(a >> 16) /* high word of address in edx */ + + : "memory", "%edi", "%cc" /* clobbers edi and flags */ + ); + + return 0; +} + +int +SVGA_SetDACPaletteFormat(int bits) +{ + __dpmi_regs r; + + r.x.ax = 0x4F08; + r.h.bl = 0; /* Flag to set format */ + r.h.bh = bits; + + __dpmi_int(0x10, &r); + + if (r.h.al != 0x4F) { + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "VBE: Failed to set DAC palette format to %d bits, got al=%02x ah=%02x bh=%d; will assume 6-bit color channels", + (int)bits, (int)r.h.al, (int)r.h.ah, (int)r.h.bh); + } + + RETURN_IF_VBE_CALL_FAILED(r); + + return r.h.bh; +} + +int +SVGA_GetPaletteData(SDL_Color * colors, int num_colors, Uint8 palette_dac_bits) +{ + int i; + __dpmi_regs r; + + r.x.ax = 0x4F09; + r.h.bl = 1; /* Flag to get colors */ + r.x.cx = num_colors; + r.x.dx = 0; /* First color */ + r.x.es = __tb_segment; + r.x.di = __tb_offset; + + __dpmi_int(0x10, &r); + + RETURN_IF_VBE_CALL_FAILED(r); + + dosmemget(__tb, num_colors * sizeof(*colors), colors); + + /* + Palette color components are stored in BGRA order, where + A is the alignment byte. + */ + for (i = 0; i < num_colors; i++) { + Uint8 temp = colors[i].r; + colors[i].r = colors[i].b; + colors[i].b = temp; + colors[i].a = SDL_ALPHA_OPAQUE; + if (palette_dac_bits == 6) { + colors[i].r <<= 2; + colors[i].g <<= 2; + colors[i].b <<= 2; + } + } + + return 0; +} + +int SVGA_SetPaletteData(SDL_Color *colors, int num_colors, Uint8 palette_dac_bits) +{ + /* + Flag to set colors. + + Set to 0x80 to wait for vblank before setting palette (e.g. for vsync). + */ + int mode = 0x80; + int seg; + int i; + Uint8 bgr_colors[256 * 4]; + + if (num_colors > 256) { + SDL_SetError("Too many palette colors"); + return -1; + } + + if (palette_dac_bits == 8) { + for (i = 0; i < num_colors; i++) { + bgr_colors[i * 4] = colors[i].b; + bgr_colors[i * 4 + 1] = colors[i].g; + bgr_colors[i * 4 + 2] = colors[i].r; + bgr_colors[i * 4 + 3] = 0; + } + } else { + for (i = 0; i < num_colors; i++) { + bgr_colors[i * 4] = colors[i].b >> 2; + bgr_colors[i * 4 + 1] = colors[i].g >> 2; + bgr_colors[i * 4 + 2] = colors[i].r >> 2; + bgr_colors[i * 4 + 3] = 0; + } + } + + seg = default_ds(); + asm( + " pushl %%ebp ; " + " pushw %%ds ; " + " movw %w1, %%ds ; " /* set the IO segment */ + " call *%0 ; " /* call the VESA function */ + " popw %%ds ; " + " popl %%ebp ; " + + : /* no outputs */ + + : "S"(PM_SetPalette_Ptr), /* function pointer in esi */ + "a"(seg), /* IO segment in eax */ + "b"(mode), /* mode in ebx */ + "c"(num_colors), /* how many colors in ecx */ + "d"(0), /* first color in edx */ + "D"(bgr_colors) /* palette data pointer in edi */ + + : "memory", "%cc" /* clobbers flags */ + ); + + return 0; +} + +SDL_PixelFormatEnum +SVGA_GetPixelFormat(const VBEModeInfo * info) +{ + if (info->memory_model == VBE_MEM_MODEL_PACKED) { + switch (info->bits_per_pixel) { + /* FIXME: Is it MSB or LSB? */ + case 1: return SDL_PIXELFORMAT_INDEX1MSB; + case 4: return SDL_PIXELFORMAT_INDEX4MSB; + case 8: return SDL_PIXELFORMAT_INDEX8; + } + } + if (info->memory_model == VBE_MEM_MODEL_DIRECT) { + Uint32 r = ~(~(Uint32)0 << info->red_mask_size) << info->red_field_position; + Uint32 g = ~(~(Uint32)0 << info->green_mask_size) << info->green_field_position; + Uint32 b = ~(~(Uint32)0 << info->blue_mask_size) << info->blue_field_position; + return SDL_MasksToPixelFormatEnum(info->bits_per_pixel, r, g, b, 0); + } + return SDL_PIXELFORMAT_UNKNOWN; +} + +#endif /* SDL_VIDEO_DRIVER_SVGA */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/svga/SDL_svga_vbe.h b/src/video/svga/SDL_svga_vbe.h new file mode 100644 index 0000000000000..c5daef29d059d --- /dev/null +++ b/src/video/svga/SDL_svga_vbe.h @@ -0,0 +1,170 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#ifndef SDL_svga_vbe_h_ +#define SDL_svga_vbe_h_ + +#include "../SDL_sysvideo.h" + +typedef Uint16 VBEMode; + +#define VBE_MODE_LIST_END 0xFFFF + +typedef struct VBEFarPtr { + Uint16 offset; + Uint16 segment; +} __attribute__ ((packed)) VBEFarPtr; + +SDL_COMPILE_TIME_ASSERT(VBEFarPtr, sizeof(VBEFarPtr) == 4); + +/* Convert a VBE far pointer to a flat pointer. */ +#define VBE_FLAT_PTR(far) ((far).segment * 16 + (far).offset) + +typedef struct VBEVersion { + Uint8 minor; + Uint8 major; +} __attribute__ ((packed)) VBEVersion; + +SDL_COMPILE_TIME_ASSERT(VBEVersion, sizeof(VBEVersion) == 2); + +typedef struct VBEInfo +{ + char vbe_signature[4]; /* "VESA" 4 byte signature */ + VBEVersion vbe_version; /* VBE version number */ + VBEFarPtr oem_string_ptr; /* Pointer to OEM string */ + Uint32 capabilities; /* Capabilities of video card */ + VBEFarPtr video_mode_ptr; /* Pointer to supported modes */ + Uint16 total_memory; /* Number of 64kb memory blocks */ + + /* VBE 2.0 and above: */ + Uint16 oem_software_rev; /* OEM Software revision number */ + VBEFarPtr oem_vendor_name_ptr; /* Pointer to vendor name string */ + VBEFarPtr oem_product_name_ptr; /* Pointer to product name string */ + VBEFarPtr oem_product_rev_ptr; /* Pointer to product revision string */ + Uint8 reserved[222]; /* VBE implementation scratch data */ + char oem_data[256]; /* Data for OEM strings */ +} __attribute__ ((packed)) VBEInfo; + +SDL_COMPILE_TIME_ASSERT(VBEInfo, sizeof(VBEInfo) == 512); + +#define VBE_CAP_DAC_WIDTH_SWITCH 0x01 +#define VBE_CAP_NO_VGA_COMPAT 0x02 +#define VBE_CAP_RAMDAC_BLANK_BIT 0x04 +#define VBE_CAP_HW_STEREO_SIGNAL 0x08 +#define VBE_CAP_STEREO_VIA_EVC 0x10 + +typedef struct VBEModeInfo +{ + Uint16 mode_attributes; /* Mode attributes */ + Uint8 win_a_attributes; /* Window A attributes */ + Uint8 win_b_attributes; /* Window B attributes */ + Uint16 win_granularity; /* Window granularity */ + Uint16 win_size; /* Window size */ + Uint16 win_a_segment; /* Window A start segment */ + Uint16 win_b_segment; /* Window B start segment */ + VBEFarPtr win_func_ptr; /* Pointer to window function */ + Uint16 bytes_per_scan_line; /* Bytes per scan line */ + + /* VBE 1.2 and above: */ + Uint16 x_resolution; /* Horizontal resolution in pixels or chars */ + Uint16 y_resolution; /* Vertical resolution in pixels or chars */ + Uint8 x_char_size; /* Character cell width in pixels */ + Uint8 y_char_size; /* Character cell height in pixels */ + Uint8 number_of_planes; /* Number of memory planes */ + Uint8 bits_per_pixel; /* Bits per pixel */ + Uint8 number_of_banks; /* Number of banks */ + Uint8 memory_model; /* Memory model type */ + Uint8 bank_size; /* Bank size in KiB */ + Uint8 number_of_image_pages; /* Number of images */ + Uint8 reserved; /* Reserved for page function */ + + /* Direct color fields (required for direct/6 and YUV/7 memory models) */ + Uint8 red_mask_size; /* Size of direct color red mask in bits */ + Uint8 red_field_position; /* Bit position of lsb of red mask */ + Uint8 green_mask_size; /* Size of direct color green mask in bits */ + Uint8 green_field_position; /* Bit position of lsb of green mask */ + Uint8 blue_mask_size; /* Size of direct color blue mask in bits */ + Uint8 blue_field_position; /* Bit position of lsb of blue mask */ + Uint8 rsvd_mask_size; /* Size of direct color reserved mask in bits */ + Uint8 rsvd_field_position; /* Bit position of lsb of reserved mask */ + Uint8 direct_color_mode_info; /* Direct color mode attributes */ + + /* VBE 2.0 and above: */ + VBEFarPtr phys_base_ptr; /* Physical address for flat frame buffer */ + Uint32 off_screen_mem_offset; /* Offset to start of off screen memory */ + Uint16 off_screen_mem_size; /* Amount of off screen memory in KiB */ + + /* VBE 3.0 and above: */ + Uint16 lin_bytes_per_scan_line; /* Bytes per scan line for linear modes */ + Uint8 bnk_number_of_image_pages; /* Number of images for banked modes */ + Uint8 lin_number_of_image_pages; /* Number of images for linear modes */ + Uint8 lin_red_mask_size; /* Size of direct color red mask (linear modes) */ + Uint8 lin_red_field_position; /* Bit position of lsb of red mask (linear modes) */ + Uint8 lin_green_mask_size; /* Size of direct color green mask (linear modes) */ + Uint8 lin_green_field_position; /* Bit position of lsb of green mask (linear modes) */ + Uint8 lin_blue_mask_size; /* Size of direct color blue mask (linear modes) */ + Uint8 lin_blue_field_position; /* Bit position of lsb of blue mask (linear modes) */ + Uint8 lin_rsvd_mask_size; /* Size of direct color reserved mask (linear modes) */ + Uint8 lin_rsvd_field_position; /* Bit position of lsb of reserved mask (linear modes) */ + Uint32 max_pixel_clock; /* Maximum pixel clock (in Hz) for graphics mode */ + + Uint8 reserved_end[190]; +} __attribute__ ((packed)) VBEModeInfo; + +SDL_COMPILE_TIME_ASSERT(VBEModeInfo, sizeof(VBEModeInfo) == 256); + +/* Mode attribute bit flags */ +#define VBE_MODE_ATTR_HARDWARE_SUPPORT 0x0001 +#define VBE_MODE_ATTR_TTY_BIOS_SUPPORT 0x0004 +#define VBE_MODE_ATTR_COLOR_MODE 0x0008 +#define VBE_MODE_ATTR_GRAPHICS_MODE 0x0010 +#define VBE_MODE_ATTR_NO_VGA_COMPAT 0x0020 +#define VBE_MODE_ATTR_NO_WINDOWED_MEM 0x0040 +#define VBE_MODE_ATTR_LINEAR_MEM_AVAIL 0x0080 + +/* Memory model values */ +#define VBE_MEM_MODEL_TEXT 0 +#define VBE_MEM_MODEL_CGA 1 +#define VBE_MEM_MODEL_HERCULES 2 +#define VBE_MEM_MODEL_PLANAR 3 +#define VBE_MEM_MODEL_PACKED 4 +#define VBE_MEM_MODEL_UNCHAINED 5 +#define VBE_MEM_MODEL_DIRECT 6 +#define VBE_MEM_MODEL_YUV 7 + +extern int SVGA_InitProtectedModeInterface(); +extern int SVGA_GetVBEInfo(VBEInfo * info); +extern VBEMode SVGA_GetVBEModeAtIndex(const VBEInfo * info, int index); +extern int SVGA_GetVBEModeInfo(VBEMode mode, VBEModeInfo * info); +extern int SVGA_GetCurrentVBEMode(VBEMode * mode, VBEModeInfo * info); +extern int SVGA_SetVBEMode(VBEMode mode); +extern int SVGA_GetState(void **state); +extern int SVGA_SetState(const void *state, size_t size); +extern int SVGA_SetDisplayStart(int x, int y, int bytes_per_pixel, int bytes_per_line); +extern int SVGA_SetDACPaletteFormat(int bits); +extern int SVGA_GetPaletteData(SDL_Color * colors, int num_colors, Uint8 palette_dac_bits); +extern int SVGA_SetPaletteData(SDL_Color *colors, int num_colors, Uint8 palette_dac_bits); +extern SDL_PixelFormatEnum SVGA_GetPixelFormat(const VBEModeInfo * info); + +#endif /* SDL_svga_vbe_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/svga/SDL_svga_video.c b/src/video/svga/SDL_svga_video.c new file mode 100644 index 0000000000000..1c64b0d1fa34e --- /dev/null +++ b/src/video/svga/SDL_svga_video.c @@ -0,0 +1,285 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + Copyright (C) 2020 Jay Petacat + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#ifdef SDL_VIDEO_DRIVER_SVGA + +#include "SDL_svga_video.h" + +#include "../../core/dos/SDL_dos.h" + +#include "SDL_svga_events.h" +#include "SDL_svga_framebuffer.h" +#include "SDL_svga_mouse.h" + +#define SVGAVID_DRIVER_NAME "svga" + +/* Mandatory mode attributes */ +#define VBE_MODE_ATTRS (VBE_MODE_ATTR_GRAPHICS_MODE | VBE_MODE_ATTR_LINEAR_MEM_AVAIL) + +/* Initialization/Query functions */ +static int SVGA_VideoInit(_THIS); +static void SVGA_GetDisplayModes(_THIS, SDL_VideoDisplay * display); +static int SVGA_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode); +static void SVGA_VideoQuit(_THIS); +static int SVGA_CreateWindow(_THIS, SDL_Window * window); +static void SVGA_DestroyWindow(_THIS, SDL_Window * window); + +/* SVGA driver bootstrap functions */ + +static void +SVGA_DeleteDevice(SDL_VideoDevice * device) +{ + SDL_free(device); +} + +static SDL_VideoDevice * +SVGA_CreateDevice(void) +{ + SDL_VideoDevice *device; + SDL_DeviceData *devdata; + + if (SVGA_InitProtectedModeInterface()) { + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "SVGA: Failed to get protected mode interface"); + return NULL; + } + + devdata = (SDL_DeviceData *) SDL_calloc(1, sizeof(*devdata)); + if (!devdata) { + SDL_OutOfMemory(); + return NULL; + } + + if (SVGA_GetVBEInfo(&devdata->vbe_info) || devdata->vbe_info.vbe_version.major < 2) { + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "SVGA: VESA BIOS Extensions v2.0 or greater is required"); + SDL_Unsupported(); + SDL_free(devdata); + return NULL; + } + + /* Initialize all variables that we clean on shutdown */ + device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(*device)); + if (!device) { + SDL_free(devdata); + SDL_OutOfMemory(); + return NULL; + } + + device->driverdata = devdata; + device->quirk_flags = VIDEO_DEVICE_QUIRK_FULLSCREEN_ONLY; + + /* Set the function pointers */ + device->VideoInit = SVGA_VideoInit; + device->VideoQuit = SVGA_VideoQuit; + device->GetDisplayModes = SVGA_GetDisplayModes; + device->SetDisplayMode = SVGA_SetDisplayMode; + device->PumpEvents = SVGA_PumpEvents; + device->CreateSDLWindow = SVGA_CreateWindow; + device->DestroyWindow = SVGA_DestroyWindow; + device->CreateWindowFramebuffer = SDL_SVGA_CreateFramebuffer; + device->UpdateWindowFramebuffer = SDL_SVGA_UpdateFramebuffer; + device->DestroyWindowFramebuffer = SDL_SVGA_DestroyFramebuffer; + + device->free = SVGA_DeleteDevice; + + return device; +} + +VideoBootStrap SVGA_bootstrap = { + SVGAVID_DRIVER_NAME, "SDL SVGA video driver", + SVGA_CreateDevice, + NULL /* no ShowMessageBox implementation */ +}; + +static int +SVGA_VideoInit(_THIS) +{ + SDL_DeviceData *devdata = _this->driverdata; + + /* Save original video mode. */ + if (SVGA_GetCurrentVBEMode(&devdata->original_mode, NULL)) { + return SDL_SetError("Couldn't query current video mode"); + } + + /* TODO: Use mode info if it exists. */ + + if (SDL_AddBasicVideoDisplay(NULL) < 0) { + return -1; + } + + /* Save original video state. */ + devdata->state_size = SVGA_GetState(&devdata->original_state); + if (devdata->state_size < 0) { + return -1; + } + + /* Initialize keyboard. */ + /* TODO: Just move keyboard stuff under this module and rename to DOS! */ + if (SDL_DOS_Init()) { + return -1; + } + + DOS_InitMouse(); + + return 0; +} + +static void +SVGA_GetDisplayModes(_THIS, SDL_VideoDisplay * display) +{ + SDL_DeviceData *devdata = _this->driverdata; + SDL_DisplayMode mode; + VBEMode vbe_mode; + int index = 0; + + SDL_zero(mode); + + for ( + vbe_mode = SVGA_GetVBEModeAtIndex(&devdata->vbe_info, index++); + vbe_mode != VBE_MODE_LIST_END; + vbe_mode = SVGA_GetVBEModeAtIndex(&devdata->vbe_info, index++) + ) { + SDL_DisplayModeData *modedata; + VBEModeInfo info; + int status = SVGA_GetVBEModeInfo(vbe_mode, &info); + + if (status) { + SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "SVGA_GetVBEModeInfo failed: %d", status); + continue; + } + + /* Mode must support graphics with a linear framebuffer. */ + if ((info.mode_attributes & VBE_MODE_ATTRS) != VBE_MODE_ATTRS) { + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SVGA: Ignoring mode 0x%X: Bad attributes", vbe_mode); + continue; + } + + /* Mode must be a known pixel format. */ + mode.format = SVGA_GetPixelFormat(&info); + if (mode.format == SDL_PIXELFORMAT_UNKNOWN) { + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SVGA: Ignoring mode 0x%X: Bad pixel format", vbe_mode); + continue; + } + + /* Mode must be capable of double buffering. */ + if (!info.number_of_image_pages) { + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SVGA: Ignoring mode 0x%X: No double-buffering", vbe_mode); + continue; + } + + /* Scan lines must be 4-byte aligned to match SDL surface pitch. */ + if (info.bytes_per_scan_line % 4 != 0) { + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SVGA: Ignoring mode 0x%X: Bad pitch", vbe_mode); + continue; + } + + /* Allocate display mode internal data. */ + modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(*modedata)); + if (!modedata) { + return; + } + + mode.w = info.x_resolution; + mode.h = info.y_resolution; + mode.driverdata = modedata; + modedata->vbe_mode = vbe_mode; + modedata->framebuffer_phys_addr = info.phys_base_ptr; + + if (!SDL_AddDisplayMode(display, &mode)) { + SDL_free(modedata); + } + } + + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "SVGA: VBE lists %d modes", index - 1); +} + +static int +SVGA_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode) +{ + SDL_DisplayModeData *modedata = mode->driverdata; + + if (!modedata) { + return SDL_SetError("Missing display mode data"); + } + + if (SVGA_SetVBEMode(modedata->vbe_mode)) { + /* TODO: Include VBE error message. */ + return SDL_SetError("Couldn't set VBE display mode"); + } + + /* TODO: Switch to 8 bit palette format, if possible and relevant. */ + + DOS_InitMouse(); /* TODO: Is this necessary when video mode changes? */ + + return 0; +} + +static void +SVGA_VideoQuit(_THIS) +{ + SDL_DeviceData *devdata = _this->driverdata; + + /* Restore original video state. */ + if (devdata->original_state) { + SVGA_SetState(devdata->original_state, devdata->state_size); + SDL_free(devdata->original_state); + } + + /* Restore original video mode. */ + if (devdata->original_mode) { + SVGA_SetVBEMode(devdata->original_mode); + } + + SDL_DOS_Quit(); + DOS_QuitMouse(); +} + +static int +SVGA_CreateWindow(_THIS, SDL_Window * window) +{ + SDL_WindowData *windata; + + /* TODO: Allow only one window. */ + + /* Allocate window internal data. */ + windata = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData)); + if (!windata) { + return SDL_OutOfMemory(); + } + window->driverdata = windata; + + /* Set framebuffer selector to sentinel value. */ + windata->framebuffer_selector = -1; + + return 0; +} + +static void +SVGA_DestroyWindow(_THIS, SDL_Window * window) +{ + SDL_free(window->driverdata); + window->driverdata = NULL; +} + +#endif /* SDL_VIDEO_DRIVER_SVGA */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/svga/SDL_svga_video.h b/src/video/svga/SDL_svga_video.h new file mode 100644 index 0000000000000..f326027e3f2ba --- /dev/null +++ b/src/video/svga/SDL_svga_video.h @@ -0,0 +1,56 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" + +#ifndef SDL_svga_video_h_ +#define SDL_svga_video_h_ + +#include "../SDL_sysvideo.h" + +#include "SDL_svga_vbe.h" + +typedef struct +{ + VBEInfo vbe_info; + VBEMode original_mode; + void *original_state; + size_t state_size; +} SDL_DeviceData; + +typedef struct +{ + VBEMode vbe_mode; + VBEFarPtr framebuffer_phys_addr; +} SDL_DisplayModeData; + +typedef struct +{ + SDL_Palette *last_palette; + Uint32 last_palette_version; + Uint32 framebuffer_linear_addr; + int framebuffer_selector; + SDL_bool framebuffer_page; + Uint8 palette_dac_bits; +} SDL_WindowData; + +#endif /* SDL_svga_video_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/test/configure b/test/configure index 8ea80bc27ea2d..6f12d61bf3b1f 100755 --- a/test/configure +++ b/test/configure @@ -3664,6 +3664,11 @@ fi MATHLIB="" SYS_GL_LIBS="" ;; + *-*-msdosdjgpp*) + EXE=".exe" + MATHLIB="-lm" + SYS_GL_LIBS="" + ;; *) ISUNIX="true" EXE="" diff --git a/test/configure.ac b/test/configure.ac index e9890163e6999..ef72653434010 100644 --- a/test/configure.ac +++ b/test/configure.ac @@ -82,6 +82,11 @@ case "$host" in MATHLIB="" SYS_GL_LIBS="" ;; + *-*-msdosdjgpp*) + EXE=".exe" + MATHLIB="-lm" + SYS_GL_LIBS="" + ;; *) dnl Oh well, call it Unix... ISUNIX="true" diff --git a/test/testfile.c b/test/testfile.c index 67ef4ae3b4942..f4e89f1c29bb6 100644 --- a/test/testfile.c +++ b/test/testfile.c @@ -152,7 +152,11 @@ int main(int argc, char *argv[]) RWOP_ERR_QUIT(rwops); } if (0 != rwops->read(rwops, test_buf, 1, 1)) { + #ifdef __DJGPP__ + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "DJGPP allowed read on write only file\n"); + #else RWOP_ERR_QUIT(rwops); /* we are in write only mode */ + #endif } rwops->close(rwops);