diff options
Diffstat (limited to 'src/osd/modules/lib')
-rw-r--r-- | src/osd/modules/lib/osdlib.h | 136 | ||||
-rw-r--r-- | src/osd/modules/lib/osdlib_macosx.cpp | 228 | ||||
-rw-r--r-- | src/osd/modules/lib/osdlib_unix.cpp | 261 | ||||
-rw-r--r-- | src/osd/modules/lib/osdlib_uwp.cpp | 190 | ||||
-rw-r--r-- | src/osd/modules/lib/osdlib_win32.cpp | 239 | ||||
-rw-r--r-- | src/osd/modules/lib/osdobj_common.cpp | 686 | ||||
-rw-r--r-- | src/osd/modules/lib/osdobj_common.h | 149 |
7 files changed, 1115 insertions, 774 deletions
diff --git a/src/osd/modules/lib/osdlib.h b/src/osd/modules/lib/osdlib.h index 0095244d6fe..967cb0d61ae 100644 --- a/src/osd/modules/lib/osdlib.h +++ b/src/osd/modules/lib/osdlib.h @@ -12,15 +12,21 @@ // - osd_ticks // - osd_sleep //============================================================ +#ifndef MAME_OSD_LIB_OSDLIB_H +#define MAME_OSD_LIB_OSDLIB_H -#ifndef __OSDLIB__ -#define __OSDLIB__ +#pragma once +#include <cstdint> +#include <initializer_list> #include <string> +#include <string_view> +#include <system_error> #include <type_traits> #include <vector> #include <memory> + /*----------------------------------------------------------------------------- osd_process_kill: kill the current process @@ -33,7 +39,7 @@ None. -----------------------------------------------------------------------------*/ -void osd_process_kill(void); +void osd_process_kill(); /*----------------------------------------------------------------------------- @@ -53,10 +59,108 @@ void osd_process_kill(void); int osd_setenv(const char *name, const char *value, int overwrite); -/*----------------------------------------------------------------------------- - osd_get_clipboard_text: retrieves text from the clipboard ------------------------------------------------------------------------------*/ -std::string osd_get_clipboard_text(void); +/// \brief Get clipboard text +/// +/// Gets current clipboard content as UTF-8 text. Returns an empty +/// string if the clipboard contents cannot be converted to plain text. +/// \return Clipboard contents or an empty string. +std::string osd_get_clipboard_text() noexcept; + + +/// \brief Set clipboard text +/// +/// Sets the desktop environment's clipboard contents to the supplied +/// UTF-8 text. The contents of the clipboard may be changed on error. +/// \param [in] text The text to copy to the clipboard. +/// \return An error condition if the operation failed or is +/// unsupported. +std::error_condition osd_set_clipboard_text(std::string_view text) noexcept; + + +namespace osd { + +bool invalidate_instruction_cache(void const *start, std::size_t size) noexcept; + + +class virtual_memory_allocation +{ +public: + enum : unsigned + { + NONE = 0x00, + READ = 0x01, + WRITE = 0x02, + EXECUTE = 0x04, + READ_WRITE = READ | WRITE, + READ_EXECUTE = READ | EXECUTE, + READ_WRITE_EXECUTE = READ | WRITE | EXECUTE + }; + + virtual_memory_allocation(virtual_memory_allocation const &) = delete; + virtual_memory_allocation &operator=(virtual_memory_allocation const &) = delete; + + virtual_memory_allocation() noexcept { } + virtual_memory_allocation(std::initializer_list<std::size_t> blocks, unsigned intent) noexcept + { + m_memory = do_alloc(blocks, intent, m_size, m_page_size); + } + virtual_memory_allocation(virtual_memory_allocation &&that) noexcept : m_memory(that.m_memory), m_size(that.m_size), m_page_size(that.m_page_size) + { + that.m_memory = nullptr; + that.m_size = that.m_page_size = 0U; + } + ~virtual_memory_allocation() + { + if (m_memory) + do_free(m_memory, m_size); + } + + explicit operator bool() const noexcept { return bool(m_memory); } + void *get() noexcept { return m_memory; } + std::size_t size() const noexcept { return m_size; } + std::size_t page_size() const noexcept { return m_page_size; } + + bool set_access(std::size_t start, std::size_t size, unsigned access) noexcept + { + if ((start % m_page_size) || (size % m_page_size) || (start > m_size) || ((m_size - start) < size)) + return false; + else + return do_set_access(reinterpret_cast<std::uint8_t *>(m_memory) + start, size, access); + } + + virtual_memory_allocation &operator=(std::nullptr_t) noexcept + { + if (m_memory) + do_free(m_memory, m_size); + m_memory = nullptr; + m_size = m_page_size = 0U; + return *this; + } + + virtual_memory_allocation &operator=(virtual_memory_allocation &&that) noexcept + { + if (&that != this) + { + if (m_memory) + do_free(m_memory, m_size); + m_memory = that.m_memory; + m_size = that.m_size; + m_page_size = that.m_page_size; + that.m_memory = nullptr; + that.m_size = that.m_page_size = 0U; + } + return *this; + } + +private: + static void *do_alloc(std::initializer_list<std::size_t> blocks, unsigned intent, std::size_t &size, std::size_t &page_size) noexcept; + static void do_free(void *start, std::size_t size) noexcept; + static bool do_set_access(void *start, std::size_t size, unsigned access) noexcept; + + void *m_memory = nullptr; + std::size_t m_size = 0U, m_page_size = 0U; +}; + /*----------------------------------------------------------------------------- dynamic_module: load functions from optional shared libraries @@ -69,7 +173,6 @@ std::string osd_get_clipboard_text(void); revisions of a same library) -----------------------------------------------------------------------------*/ -namespace osd { class dynamic_module { public: @@ -77,10 +180,10 @@ public: static ptr open(std::vector<std::string> &&libraries); - virtual ~dynamic_module() { }; + virtual ~dynamic_module() { } template <typename T> - typename std::enable_if<std::is_pointer<T>::value, T>::type bind(char const *symbol) + typename std::enable_if_t<std::is_pointer_v<T>, T> bind(char const *symbol) { return reinterpret_cast<T>(get_symbol_address(symbol)); } @@ -102,20 +205,9 @@ protected: // Calling then looks like: DYNAMIC_CALL(CreateDXGIFactory1, p1, p2, etc) //========================================================================================================= -#if !defined(OSD_UWP) - #define OSD_DYNAMIC_API(apiname, ...) osd::dynamic_module::ptr m_##apiname##module = osd::dynamic_module::open( { __VA_ARGS__ } ) #define OSD_DYNAMIC_API_FN(apiname, ret, conv, fname, ...) ret(conv *m_##fname##_pfn)( __VA_ARGS__ ) = m_##apiname##module->bind<ret(conv *)( __VA_ARGS__ )>(#fname) #define OSD_DYNAMIC_CALL(fname, ...) (*m_##fname##_pfn) ( __VA_ARGS__ ) #define OSD_DYNAMIC_API_TEST(fname) (m_##fname##_pfn != nullptr) -#else - -#define OSD_DYNAMIC_API(apiname, ...) -#define OSD_DYNAMIC_API_FN(apiname, ret, conv, fname, ...) -#define OSD_DYNAMIC_CALL(fname, ...) fname( __VA_ARGS__ ) -#define OSD_DYNAMIC_API_TEST(fname) (true) - -#endif - -#endif /* __OSDLIB__ */ +#endif // MAME_OSD_LIB_OSDLIB_H diff --git a/src/osd/modules/lib/osdlib_macosx.cpp b/src/osd/modules/lib/osdlib_macosx.cpp index 372293ec1a3..54836f9ec69 100644 --- a/src/osd/modules/lib/osdlib_macosx.cpp +++ b/src/osd/modules/lib/osdlib_macosx.cpp @@ -8,26 +8,26 @@ // //============================================================ -#include <stdlib.h> -#include <unistd.h> -#include <sys/mman.h> -#include <sys/sysctl.h> -#include <sys/types.h> -#include <signal.h> -#include <dlfcn.h> +// MAME headers +#include "osdcore.h" +#include "osdlib.h" +#include <csignal> #include <cstdio> +#include <cstdlib> #include <iomanip> #include <memory> +#include <dlfcn.h> +#include <sys/mman.h> +#include <sys/sysctl.h> +#include <sys/types.h> +#include <unistd.h> #include <mach/mach.h> #include <mach/mach_time.h> #include <Carbon/Carbon.h> -// MAME headers -#include "osdcore.h" -#include "osdlib.h" //============================================================ // osd_getenv @@ -56,36 +56,6 @@ void osd_process_kill() kill(getpid(), SIGKILL); } -//============================================================ -// osd_alloc_executable -// -// allocates "size" bytes of executable memory. this must take -// things like NX support into account. -//============================================================ - -void *osd_alloc_executable(size_t size) -{ -#if defined(SDLMAME_BSD) || defined(SDLMAME_MACOSX) - return (void *)mmap(0, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0); -#elif defined(SDLMAME_UNIX) - return (void *)mmap(0, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, 0, 0); -#endif -} - -//============================================================ -// osd_free_executable -// -// frees memory allocated with osd_alloc_executable -//============================================================ - -void osd_free_executable(void *ptr, size_t size) -{ -#ifdef SDLMAME_SOLARIS - munmap((char *)ptr, size); -#else - munmap(ptr, size); -#endif -} //============================================================ // osd_break_into_debugger @@ -98,7 +68,7 @@ void osd_break_into_debugger(const char *message) struct kinfo_proc info; info.kp_proc.p_flag = 0; std::size_t infosz = sizeof(info); - sysctl(mib, ARRAY_LENGTH(mib), &info, &infosz, nullptr, 0); + sysctl(mib, std::size(mib), &info, &infosz, nullptr, 0); if (info.kp_proc.p_flag & P_TRACED) { printf("MAME exception: %s\n", message); @@ -113,10 +83,26 @@ void osd_break_into_debugger(const char *message) //============================================================ +// osd_get_cache_line_size +//============================================================ + +std::pair<std::error_condition, unsigned> osd_get_cache_line_size() noexcept +{ + size_t result = 0; + size_t resultsize = sizeof(result); + int const err = sysctlbyname("hw.cachelinesize", &result, &resultsize, 0, 0); + if (!err) + return std::make_pair(std::error_condition(), unsigned(result)); + else + return std::make_pair(std::error_condition(err, std::generic_category()), 0U); +} + + +//============================================================ // osd_get_clipboard_text //============================================================ -std::string osd_get_clipboard_text(void) +std::string osd_get_clipboard_text() noexcept { std::string result; bool has_result = false; @@ -152,31 +138,48 @@ std::string osd_get_clipboard_text(void) CFStringEncoding encoding; if (UTTypeConformsTo(flavor_type, kUTTypeUTF16PlainText)) encoding = kCFStringEncodingUTF16; - else if (UTTypeConformsTo (flavor_type, kUTTypeUTF8PlainText)) + else if (UTTypeConformsTo(flavor_type, kUTTypeUTF8PlainText)) encoding = kCFStringEncodingUTF8; - else if (UTTypeConformsTo (flavor_type, kUTTypePlainText)) + else if (UTTypeConformsTo(flavor_type, kUTTypePlainText)) encoding = kCFStringEncodingMacRoman; else continue; CFDataRef flavor_data; err = PasteboardCopyItemFlavorData(pasteboard_ref, item_id, flavor_type, &flavor_data); + if (err) + continue; - if (!err) + CFDataRef utf8_data; + if (kCFStringEncodingUTF8 == encoding) + { + utf8_data = flavor_data; + } + else { CFStringRef string_ref = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, flavor_data, encoding); - CFDataRef data_ref = CFStringCreateExternalRepresentation (kCFAllocatorDefault, string_ref, kCFStringEncodingUTF8, '?'); - CFRelease(string_ref); CFRelease(flavor_data); + if (!string_ref) + continue; - CFIndex const length = CFDataGetLength(data_ref); - CFRange const range = CFRangeMake(0, length); - - result.resize(length); - CFDataGetBytes(data_ref, range, reinterpret_cast<unsigned char *>(&result[0])); - has_result = true; + utf8_data = CFStringCreateExternalRepresentation(kCFAllocatorDefault, string_ref, kCFStringEncodingUTF8, '?'); + CFRelease(string_ref); + } - CFRelease(data_ref); + if (utf8_data) + { + CFIndex const length = CFDataGetLength(utf8_data); + CFRange const range = CFRangeMake(0, length); + try + { + result.resize(length); + CFDataGetBytes(utf8_data, range, reinterpret_cast<UInt8 *>(result.data())); + has_result = true; + } + catch (std::bad_alloc const &) + { + } + CFRelease(utf8_data); } } @@ -188,34 +191,72 @@ std::string osd_get_clipboard_text(void) return result; } + //============================================================ -// osd_getpid +// osd_set_clipboard_text //============================================================ -int osd_getpid(void) +std::error_condition osd_set_clipboard_text(std::string_view text) noexcept { - return getpid(); + // FIXME: better conversion of OSStatus to std::error_condition + OSStatus err; + + CFDataRef const data = CFDataCreate(kCFAllocatorDefault, reinterpret_cast<UInt8 const *>(text.data()), text.length()); + if (!data) + return std::errc::not_enough_memory; + + PasteboardRef pasteboard_ref; + err = PasteboardCreate(kPasteboardClipboard, &pasteboard_ref); + if (err) + { + CFRelease(data); + return std::errc::io_error; + } + + err = PasteboardClear(pasteboard_ref); + if (err) + { + CFRelease(data); + CFRelease(pasteboard_ref); + return std::errc::io_error; + } + + err = PasteboardPutItemFlavor(pasteboard_ref, PasteboardItemID(1), kUTTypeUTF8PlainText, data, kPasteboardFlavorNoFlags); + CFRelease(data); + CFRelease(pasteboard_ref); + if (err) + return std::errc::io_error; + + return std::error_condition(); } + //============================================================ -// dynamic_module_posix_impl +// osd_getpid //============================================================ +int osd_getpid() noexcept +{ + return getpid(); +} + + namespace osd { + +namespace { + class dynamic_module_posix_impl : public dynamic_module { public: - dynamic_module_posix_impl(std::vector<std::string> &libraries) - : m_module(nullptr) + dynamic_module_posix_impl(std::vector<std::string> &&libraries) : m_libraries(std::move(libraries)) { - m_libraries = libraries; } virtual ~dynamic_module_posix_impl() override { - if (m_module != nullptr) + if (m_module) dlclose(m_module); - }; + } protected: virtual generic_fptr_t get_symbol_address(char const *symbol) override @@ -225,19 +266,17 @@ protected: * one of them, all additional symbols will be loaded from the same library */ if (m_module) - { return reinterpret_cast<generic_fptr_t>(dlsym(m_module, symbol)); - } for (auto const &library : m_libraries) { - void *module = dlopen(library.c_str(), RTLD_LAZY); + void *const module = dlopen(library.c_str(), RTLD_LAZY); if (module != nullptr) { - generic_fptr_t function = reinterpret_cast<generic_fptr_t>(dlsym(module, symbol)); + generic_fptr_t const function = reinterpret_cast<generic_fptr_t>(dlsym(module, symbol)); - if (function != nullptr) + if (function) { m_module = module; return function; @@ -254,12 +293,61 @@ protected: private: std::vector<std::string> m_libraries; - void * m_module; + void * m_module = nullptr; }; +} // anonymous namespace + + +bool invalidate_instruction_cache(void const *start, std::size_t size) noexcept +{ + char const *const begin(reinterpret_cast<char const *>(start)); + char const *const end(begin + size); + __builtin___clear_cache(const_cast<char *>(begin), const_cast<char *>(end)); + return true; +} + + +void *virtual_memory_allocation::do_alloc(std::initializer_list<std::size_t> blocks, unsigned intent, std::size_t &size, std::size_t &page_size) noexcept +{ + long const p(sysconf(_SC_PAGE_SIZE)); + if (0 >= p) + return nullptr; + std::size_t s(0); + for (std::size_t b : blocks) + s += (b + p - 1) / p; + s *= p; + if (!s) + return nullptr; + void *const result(mmap(nullptr, s, PROT_NONE, MAP_ANON | MAP_SHARED, -1, 0)); + if (result == (void *)-1) + return nullptr; + size = s; + page_size = p; + return result; +} + +void virtual_memory_allocation::do_free(void *start, std::size_t size) noexcept +{ + munmap(start, size); +} + +bool virtual_memory_allocation::do_set_access(void *start, std::size_t size, unsigned access) noexcept +{ + int prot((NONE == access) ? PROT_NONE : 0); + if (access & READ) + prot |= PROT_READ; + if (access & WRITE) + prot |= PROT_WRITE; + if (access & EXECUTE) + prot |= PROT_EXEC; + return mprotect(start, size, prot) == 0; +} + + dynamic_module::ptr dynamic_module::open(std::vector<std::string> &&names) { - return std::make_unique<dynamic_module_posix_impl>(names); + return std::make_unique<dynamic_module_posix_impl>(std::move(names)); } } // namespace osd diff --git a/src/osd/modules/lib/osdlib_unix.cpp b/src/osd/modules/lib/osdlib_unix.cpp index 178fb4594cb..1cfa9b1f183 100644 --- a/src/osd/modules/lib/osdlib_unix.cpp +++ b/src/osd/modules/lib/osdlib_unix.cpp @@ -8,23 +8,25 @@ // //============================================================ -#include <stdlib.h> -#include <unistd.h> -#include <sys/mman.h> -#include <sys/types.h> -#include <signal.h> -#include <dlfcn.h> +// MAME headers +#include "osdcore.h" +#include "osdlib.h" +#include <SDL2/SDL.h> + +#include <csignal> #include <cstdio> +#include <cstdlib> +#include <cstring> #include <iomanip> #include <memory> +#include <string_view> +#include <dlfcn.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <unistd.h> -// MAME headers -#include "osdcore.h" -#include "osdlib.h" - -#include <SDL2/SDL.h> //============================================================ // osd_getenv @@ -53,105 +55,175 @@ void osd_process_kill() kill(getpid(), SIGKILL); } + //============================================================ -// osd_alloc_executable -// -// allocates "size" bytes of executable memory. this must take -// things like NX support into account. +// osd_break_into_debugger //============================================================ -void *osd_alloc_executable(size_t size) +void osd_break_into_debugger(const char *message) { -#if defined(SDLMAME_BSD) || defined(SDLMAME_MACOSX) || defined(SDLMAME_EMSCRIPTEN) - return (void *)mmap(0, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0); +#if defined(__linux__) + bool do_break = false; + FILE *const f = std::fopen("/proc/self/status", "r"); + if (f) + { + using namespace std::literals; + + std::string_view const tag = "TracerPid:\t"sv; + char buf[128]; + bool ignore = false; + while (std::fgets(buf, std::size(buf), f)) + { + // ignore excessively long lines + auto const len = strnlen(buf, std::size(buf)); + bool const noeol = !len || ('\n' != buf[len - 1]); + if (ignore || noeol) + { + ignore = noeol; + continue; + } + + if (!std::strncmp(buf, tag.data(), tag.length())) + { + long tpid; + if ((std::sscanf(buf + tag.length(), "%ld", &tpid) == 1) && (0 != tpid)) + do_break = true; + break; + } + } + std::fclose(f); + } +#elif defined(MAME_DEBUG) + bool const do_break = true; #else - return (void *)mmap(0, size, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, 0, 0); + bool const do_break = false; #endif + if (do_break) + { + printf("MAME exception: %s\n", message); + printf("Attempting to fall into debugger\n"); + kill(getpid(), SIGTRAP); + } + else + { + printf("Ignoring MAME exception: %s\n", message); + } } + //============================================================ -// osd_free_executable -// -// frees memory allocated with osd_alloc_executable +// osd_get_cache_line_size //============================================================ -void osd_free_executable(void *ptr, size_t size) +std::pair<std::error_condition, unsigned> osd_get_cache_line_size() noexcept { -#ifdef SDLMAME_SOLARIS - munmap((char *)ptr, size); -#else - munmap(ptr, size); +#if defined(__linux__) + FILE *const f = std::fopen("/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size", "r"); + if (!f) + return std::make_pair(std::error_condition(errno, std::generic_category()), 0U); + + unsigned result = 0; + auto const cnt = std::fscanf(f, "%u", &result); + std::fclose(f); + if (1 == cnt) + return std::make_pair(std::error_condition(), result); + else + return std::make_pair(std::errc::io_error, 0U); +#else // defined(__linux__) + return std::make_pair(std::errc::not_supported, 0U); #endif } -//============================================================ -// osd_break_into_debugger -//============================================================ -void osd_break_into_debugger(const char *message) +#ifdef SDLMAME_ANDROID +std::string osd_get_clipboard_text() noexcept { - #ifdef MAME_DEBUG - printf("MAME exception: %s\n", message); - printf("Attempting to fall into debugger\n"); - kill(getpid(), SIGTRAP); - #else - printf("Ignoring MAME exception: %s\n", message); - #endif + return std::string(); } -#ifdef SDLMAME_ANDROID -std::string osd_get_clipboard_text(void) +std::error_condition osd_set_clipboard_text(std::string_view text) noexcept { - return std::string(); + return std::errc::io_error; // TODO: better error code? } #else //============================================================ // osd_get_clipboard_text //============================================================ -std::string osd_get_clipboard_text(void) +std::string osd_get_clipboard_text() noexcept { + // TODO: better error handling std::string result; if (SDL_HasClipboardText()) { - char *temp = SDL_GetClipboardText(); - result.assign(temp); - SDL_free(temp); + char *const temp = SDL_GetClipboardText(); + if (temp) + { + try + { + result.assign(temp); + } + catch (std::bad_alloc const &) + { + } + SDL_free(temp); + } } return result; } + +//============================================================ +// osd_set_clipboard_text +//============================================================ + +std::error_condition osd_set_clipboard_text(std::string_view text) noexcept +{ + try + { + std::string const clip(text); // need to do this to ensure there's a terminating NUL for SDL + if (0 > SDL_SetClipboardText(clip.c_str())) + { + // SDL_GetError returns a message, can't really convert it to an error condition + return std::errc::io_error; // TODO: better error code? + } + + return std::error_condition(); + } + catch (std::bad_alloc const &) + { + return std::errc::not_enough_memory; + } +} #endif //============================================================ // osd_getpid //============================================================ -int osd_getpid(void) +int osd_getpid() noexcept { return getpid(); } -//============================================================ -// dynamic_module_posix_impl -//============================================================ namespace osd { + +namespace { + class dynamic_module_posix_impl : public dynamic_module { public: - dynamic_module_posix_impl(std::vector<std::string> &libraries) - : m_module(nullptr) + dynamic_module_posix_impl(std::vector<std::string> &&libraries) : m_libraries(std::move(libraries)) { - m_libraries = libraries; } virtual ~dynamic_module_posix_impl() override { - if (m_module != nullptr) + if (m_module) dlclose(m_module); - }; + } protected: virtual generic_fptr_t get_symbol_address(char const *symbol) override @@ -161,19 +233,17 @@ protected: * one of them, all additional symbols will be loaded from the same library */ if (m_module) - { return reinterpret_cast<generic_fptr_t>(dlsym(m_module, symbol)); - } for (auto const &library : m_libraries) { - void *module = dlopen(library.c_str(), RTLD_LAZY); + void *const module = dlopen(library.c_str(), RTLD_LAZY); if (module != nullptr) { - generic_fptr_t function = reinterpret_cast<generic_fptr_t>(dlsym(module, symbol)); + generic_fptr_t const function = reinterpret_cast<generic_fptr_t>(dlsym(module, symbol)); - if (function != nullptr) + if (function) { m_module = module; return function; @@ -190,12 +260,81 @@ protected: private: std::vector<std::string> m_libraries; - void * m_module; + void * m_module = nullptr; }; +} // anonymous namespace + + +bool invalidate_instruction_cache(void const *start, std::size_t size) noexcept +{ +#if !defined(SDLMAME_EMSCRIPTEN) + char const *const begin(reinterpret_cast<char const *>(start)); + char const *const end(begin + size); + __builtin___clear_cache(const_cast<char *>(begin), const_cast<char *>(end)); +#endif + return true; +} + + +void *virtual_memory_allocation::do_alloc(std::initializer_list<std::size_t> blocks, unsigned intent, std::size_t &size, std::size_t &page_size) noexcept +{ + long const p(sysconf(_SC_PAGE_SIZE)); + if (0 >= p) + return nullptr; + std::size_t s(0); + for (std::size_t b : blocks) + s += (b + p - 1) / p; + s *= p; + if (!s) + return nullptr; +#if defined __NetBSD__ + int req((NONE == intent) ? PROT_NONE : 0); + if (intent & READ) + req |= PROT_READ; + if (intent & WRITE) + req |= PROT_WRITE; + if (intent & EXECUTE) + req |= PROT_EXEC; + int const prot(PROT_MPROTECT(req)); +#else + int const prot(PROT_NONE); +#endif +#if defined(SDLMAME_BSD) || defined(SDLMAME_MACOSX) || defined(SDLMAME_EMSCRIPTEN) + int const fd(-1); +#else + // TODO: portable applications are supposed to use -1 for anonymous mappings - detect whatever requires 0 specifically + int const fd(0); +#endif + void *const result(mmap(nullptr, s, prot, MAP_ANON | MAP_SHARED, fd, 0)); + if (result == (void *)-1) + return nullptr; + size = s; + page_size = p; + return result; +} + +void virtual_memory_allocation::do_free(void *start, std::size_t size) noexcept +{ + munmap(reinterpret_cast<char *>(start), size); +} + +bool virtual_memory_allocation::do_set_access(void *start, std::size_t size, unsigned access) noexcept +{ + int prot((NONE == access) ? PROT_NONE : 0); + if (access & READ) + prot |= PROT_READ; + if (access & WRITE) + prot |= PROT_WRITE; + if (access & EXECUTE) + prot |= PROT_EXEC; + return mprotect(reinterpret_cast<char *>(start), size, prot) == 0; +} + + dynamic_module::ptr dynamic_module::open(std::vector<std::string> &&names) { - return std::make_unique<dynamic_module_posix_impl>(names); + return std::make_unique<dynamic_module_posix_impl>(std::move(names)); } } // namespace osd diff --git a/src/osd/modules/lib/osdlib_uwp.cpp b/src/osd/modules/lib/osdlib_uwp.cpp deleted file mode 100644 index 8d20c552cab..00000000000 --- a/src/osd/modules/lib/osdlib_uwp.cpp +++ /dev/null @@ -1,190 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes -//============================================================ -// -// sdlos_*.c - OS specific low level code -// -// SDLMAME by Olivier Galibert and R. Belmont -// -//============================================================ - -#include <windows.h> -#include <mmsystem.h> - -#include <stdlib.h> - -#include <cstdio> -#include <memory> - -// MAME headers -#include "osdlib.h" -#include "osdcomm.h" -#include "osdcore.h" -#include "strconv.h" - -#include <windows.h> -#include <wrl\client.h> - -#include "strconv.h" - -using namespace Platform; -using namespace Windows::ApplicationModel::DataTransfer; -using namespace Windows::Foundation; - -#include <map> - -//============================================================ -// GLOBAL VARIABLES -//============================================================ - -std::map<const char *, std::unique_ptr<char>> g_runtime_environment; - -//============================================================ -// osd_getenv -//============================================================ - -const char *osd_getenv(const char *name) -{ - for (auto iter = g_runtime_environment.begin(); iter != g_runtime_environment.end(); iter++) - { - if (stricmp(iter->first, name) == 0) - { - osd_printf_debug("ENVIRONMENT: Get %s = value: '%s'", name, iter->second.get()); - return iter->second.get(); - } - } - - return nullptr; -} - - -//============================================================ -// osd_setenv -//============================================================ - -int osd_setenv(const char *name, const char *value, int overwrite) -{ - if (!overwrite) - { - if (osd_getenv(name) != nullptr) - return 0; - } - - auto buf = std::make_unique<char>(strlen(name) + strlen(value) + 2); - sprintf(buf.get(), "%s=%s", name, value); - - g_runtime_environment[name] = std::move(buf); - osd_printf_debug("ENVIRONMENT: Set %s to value: '%s'", name, buf.get()); - - return 0; -} - -//============================================================ -// osd_process_kill -//============================================================ - -void osd_process_kill() -{ - TerminateProcess(GetCurrentProcess(), -1); -} - -//============================================================ -// osd_alloc_executable -// -// allocates "size" bytes of executable memory. this must take -// things like NX support into account. -//============================================================ - -void *osd_alloc_executable(size_t size) -{ - return nullptr; -} - - -//============================================================ -// osd_free_executable -// -// frees memory allocated with osd_alloc_executable -//============================================================ - -void osd_free_executable(void *ptr, size_t size) -{ -} - - -//============================================================ -// osd_break_into_debugger -//============================================================ - -void osd_break_into_debugger(const char *message) -{ - if (IsDebuggerPresent()) - { - OutputDebugStringA(message); - __debugbreak(); - } -} - -//============================================================ -// get_clipboard_text_by_format -//============================================================ - -static bool get_clipboard_text_by_format(std::string &result_text, UINT format, std::string (*convert)(LPCVOID data)) -{ - DataPackageView^ dataPackageView; - IAsyncOperation<String^>^ getTextOp; - String^ clipboardText; - - dataPackageView = Clipboard::GetContent(); - getTextOp = dataPackageView->GetTextAsync(); - clipboardText = getTextOp->GetResults(); - - result_text = convert(clipboardText->Data()); - return !result_text.empty(); -} - -//============================================================ -// convert_wide -//============================================================ - -static std::string convert_wide(LPCVOID data) -{ - return osd::text::from_wstring((LPCWSTR) data); -} - -//============================================================ -// convert_ansi -//============================================================ - -static std::string convert_ansi(LPCVOID data) -{ - return osd::text::from_astring((LPCSTR) data); -} - -//============================================================ -// osd_get_clipboard_text -//============================================================ - -std::string osd_get_clipboard_text(void) -{ - std::string result; - - // try to access unicode text - if (!get_clipboard_text_by_format(result, CF_UNICODETEXT, convert_wide)) - { - // try to access ANSI text - get_clipboard_text_by_format(result, CF_TEXT, convert_ansi); - } - - return result; -} - -//============================================================ -// osd_getpid -//============================================================ - -int osd_getpid(void) -{ - return GetCurrentProcessId(); -} - diff --git a/src/osd/modules/lib/osdlib_win32.cpp b/src/osd/modules/lib/osdlib_win32.cpp index 911f95c3bfe..cf3fd7c9320 100644 --- a/src/osd/modules/lib/osdlib_win32.cpp +++ b/src/osd/modules/lib/osdlib_win32.cpp @@ -8,27 +8,27 @@ // //============================================================ -#include <windows.h> -#include <mmsystem.h> - -#include <stdlib.h> -#ifndef _MSC_VER -#include <unistd.h> -#endif - -#include <cstdio> -#include <memory> - // MAME headers #include "osdlib.h" #include "osdcomm.h" #include "osdcore.h" #include "strconv.h" -#ifdef OSD_WINDOWS #include "winutf8.h" +#include "winutil.h" + +#include <algorithm> +#include <cstdio> +#include <cstdlib> + +#include <windows.h> +#include <memoryapi.h> + +#ifndef _MSC_VER +#include <unistd.h> #endif + //============================================================ // GLOBAL VARIABLES //============================================================ @@ -82,30 +82,6 @@ void osd_process_kill() TerminateProcess(GetCurrentProcess(), -1); } -//============================================================ -// osd_alloc_executable -// -// allocates "size" bytes of executable memory. this must take -// things like NX support into account. -//============================================================ - -void *osd_alloc_executable(size_t size) -{ - return VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); -} - - -//============================================================ -// osd_free_executable -// -// frees memory allocated with osd_alloc_executable -//============================================================ - -void osd_free_executable(void *ptr, size_t size) -{ - VirtualFree(ptr, 0, MEM_RELEASE); -} - //============================================================ // osd_break_into_debugger @@ -130,6 +106,42 @@ void osd_break_into_debugger(const char *message) #endif } + +//============================================================ +// osd_get_cache_line_size +//============================================================ + +std::pair<std::error_condition, unsigned> osd_get_cache_line_size() noexcept +{ + DWORD resultsize = 0; + if (GetLogicalProcessorInformation(nullptr, &resultsize) || (ERROR_INSUFFICIENT_BUFFER != GetLastError()) || !resultsize) + return std::make_pair(std::errc::operation_not_permitted, 0U); + + auto const result = reinterpret_cast<SYSTEM_LOGICAL_PROCESSOR_INFORMATION *>(std::malloc(resultsize)); + if (!result) + return std::make_pair(std::errc::not_enough_memory, 0U); + + if (!GetLogicalProcessorInformation(result, &resultsize)) + { + std::free(result); + return std::make_pair(std::errc::operation_not_permitted, 0U); + } + + for (unsigned i = 0; i < (resultsize / sizeof(result[0])); ++i) + { + if ((RelationCache == result[i].Relationship) && (1 == result[i].Cache.Level)) + { + unsigned const linesize = result[i].Cache.LineSize; + std::free(result); + return std::make_pair(std::error_condition(), linesize); + } + } + + std::free(result); + return std::make_pair(std::errc::operation_not_permitted, 0U); +} + + //============================================================ // get_clipboard_text_by_format //============================================================ @@ -192,25 +204,92 @@ static std::string convert_ansi(LPCVOID data) // osd_get_clipboard_text //============================================================ -std::string osd_get_clipboard_text(void) +std::string osd_get_clipboard_text() noexcept { std::string result; - // try to access unicode text - if (!get_clipboard_text_by_format(result, CF_UNICODETEXT, convert_wide)) + // TODO: better error handling + try + { + // try to access unicode text + if (!get_clipboard_text_by_format(result, CF_UNICODETEXT, convert_wide)) + { + // try to access ANSI text + get_clipboard_text_by_format(result, CF_TEXT, convert_ansi); + } + } + catch (...) { - // try to access ANSI text - get_clipboard_text_by_format(result, CF_TEXT, convert_ansi); } return result; } //============================================================ +// osd_set_clipboard_text +//============================================================ + +std::error_condition osd_set_clipboard_text(std::string_view text) noexcept +{ + try + { + // convert the text to a wide char string and create a moveable global block + std::wstring const wtext = osd::text::to_wstring(text); + HGLOBAL const clip = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(wchar_t)); + if (!clip) + return win_error_to_error_condition(GetLastError()); + LPWSTR const lock = reinterpret_cast<LPWSTR>(GlobalLock(clip)); + if (!lock) + { + DWORD const err(GetLastError()); + GlobalFree(clip); + return win_error_to_error_condition(err); + } + + // clear current clipboard contents + if (!OpenClipboard(nullptr)) + { + DWORD const err(GetLastError()); + GlobalUnlock(clip); + GlobalFree(clip); + return win_error_to_error_condition(err); + } + if (!EmptyClipboard()) + { + DWORD const err(GetLastError()); + CloseClipboard(); + GlobalUnlock(clip); + GlobalFree(clip); + return win_error_to_error_condition(err); + } + + // copy the text (plus NUL terminator) to the moveable block and put it on the clipboard + std::copy_n(wtext.c_str(), wtext.length() + 1, lock); + GlobalUnlock(clip); + if (!SetClipboardData(CF_UNICODETEXT, clip)) + { + DWORD const err(GetLastError()); + CloseClipboard(); + GlobalFree(clip); + return win_error_to_error_condition(err); + } + + // clean up + if (!CloseClipboard()) + return win_error_to_error_condition(GetLastError()); + return std::error_condition(); + } + catch (std::bad_alloc const &) + { + return std::errc::not_enough_memory; + } +} + +//============================================================ // osd_getpid //============================================================ -int osd_getpid(void) +int osd_getpid() noexcept { return GetCurrentProcessId(); } @@ -219,29 +298,25 @@ int osd_getpid(void) // osd_dynamic_bind //============================================================ -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) // for classic desktop applications #define load_library(filename) LoadLibrary(filename) -#else -// for Windows Store universal applications -#define load_library(filename) LoadPackagedLibrary(filename, 0) -#endif namespace osd { + +namespace { + class dynamic_module_win32_impl : public dynamic_module { public: - dynamic_module_win32_impl(std::vector<std::string> &libraries) - : m_module(nullptr) + dynamic_module_win32_impl(std::vector<std::string> &&libraries) : m_libraries(std::move(libraries)) { - m_libraries = libraries; } virtual ~dynamic_module_win32_impl() override { - if (m_module != nullptr) + if (m_module) FreeLibrary(m_module); - }; + } protected: virtual generic_fptr_t get_symbol_address(char const *symbol) override @@ -251,20 +326,18 @@ protected: * one of them, all additional symbols will be loaded from the same library */ if (m_module) - { return reinterpret_cast<generic_fptr_t>(GetProcAddress(m_module, symbol)); - } for (auto const &library : m_libraries) { - osd::text::tstring tempstr = osd::text::to_tstring(library); - HMODULE module = load_library(tempstr.c_str()); + osd::text::tstring const tempstr = osd::text::to_tstring(library); + HMODULE const module = load_library(tempstr.c_str()); - if (module != nullptr) + if (module) { - generic_fptr_t function = reinterpret_cast<generic_fptr_t>(GetProcAddress(module, symbol)); + auto const function = reinterpret_cast<generic_fptr_t>(GetProcAddress(module, symbol)); - if (function != nullptr) + if (function) { m_module = module; return function; @@ -281,12 +354,56 @@ protected: private: std::vector<std::string> m_libraries; - HMODULE m_module; + HMODULE m_module = nullptr; }; +} // anonymous namespace + + +bool invalidate_instruction_cache(void const *start, std::size_t size) noexcept +{ + return FlushInstructionCache(GetCurrentProcess(), start, size) != 0; +} + + +void *virtual_memory_allocation::do_alloc(std::initializer_list<std::size_t> blocks, unsigned intent, std::size_t &size, std::size_t &page_size) noexcept +{ + SYSTEM_INFO info; + GetSystemInfo(&info); + SIZE_T s(0); + for (std::size_t b : blocks) + s += (b + info.dwPageSize - 1) / info.dwPageSize; + s *= info.dwPageSize; + if (!s) + return nullptr; + LPVOID const result(VirtualAlloc(nullptr, s, MEM_COMMIT, PAGE_NOACCESS)); + if (result) + { + size = s; + page_size = info.dwPageSize; + } + return result; +} + +void virtual_memory_allocation::do_free(void *start, std::size_t size) noexcept +{ + VirtualFree(start, 0, MEM_RELEASE); +} + +bool virtual_memory_allocation::do_set_access(void *start, std::size_t size, unsigned access) noexcept +{ + DWORD p; + if (access & EXECUTE) + p = (access & WRITE) ? PAGE_EXECUTE_READWRITE : (access & READ) ? PAGE_EXECUTE_READ : PAGE_EXECUTE; + else + p = (access & WRITE) ? PAGE_READWRITE : (access & READ) ? PAGE_READONLY : PAGE_NOACCESS; + return VirtualAlloc(start, size, MEM_COMMIT, p) != nullptr; +} + + dynamic_module::ptr dynamic_module::open(std::vector<std::string> &&names) { - return std::make_unique<dynamic_module_win32_impl>(names); + return std::make_unique<dynamic_module_win32_impl>(std::move(names)); } } // namespace osd diff --git a/src/osd/modules/lib/osdobj_common.cpp b/src/osd/modules/lib/osdobj_common.cpp index 51474b810b0..24148889570 100644 --- a/src/osd/modules/lib/osdobj_common.cpp +++ b/src/osd/modules/lib/osdobj_common.cpp @@ -2,164 +2,188 @@ // copyright-holders:Aaron Giles /*************************************************************************** - osdepend.c + osdobj_common.h OS-dependent code interface. ***************************************************************************/ +#include "osdobj_common.h" + +#include "modules/osdwindow.h" +#include "modules/debugger/debug_module.h" +#include "modules/font/font_module.h" +#include "modules/input/input_module.h" +#include "modules/midi/midi_module.h" +#include "modules/netdev/netdev_module.h" +#include "modules/monitor/monitor_module.h" +#include "modules/netdev/netdev_module.h" +#include "modules/render/render_module.h" +#include "modules/sound/sound_module.h" + +#include "watchdog.h" #include "emu.h" -#include "osdepend.h" -#include "modules/lib/osdobj_common.h" +#include "../frontend/mame/ui/menuitem.h" + +#include <iostream> + const options_entry osd_options::s_option_entries[] = { - { nullptr, nullptr, OPTION_HEADER, "OSD KEYBOARD MAPPING OPTIONS" }, + { nullptr, nullptr, core_options::option_type::HEADER, "OSD INPUT MAPPING OPTIONS" }, #if defined(SDLMAME_MACOSX) || defined(OSD_MAC) - { OSDOPTION_UIMODEKEY, "DEL", OPTION_STRING, "key to enable/disable MAME controls when emulated system has keyboard inputs" }, + { OSDOPTION_UIMODEKEY, "DEL", core_options::option_type::STRING, "key to enable/disable MAME controls when emulated system has keyboard inputs" }, #else - { OSDOPTION_UIMODEKEY, "SCRLOCK", OPTION_STRING, "key to enable/disable MAME controls when emulated system has keyboard inputs" }, + { OSDOPTION_UIMODEKEY, "auto", core_options::option_type::STRING, "key to enable/disable MAME controls when emulated system has keyboard inputs" }, #endif // SDLMAME_MACOSX - - { nullptr, nullptr, OPTION_HEADER, "OSD FONT OPTIONS" }, - { OSD_FONT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for UI font: " }, - - { nullptr, nullptr, OPTION_HEADER, "OSD OUTPUT OPTIONS" }, - { OSD_OUTPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for output notifications: " }, - - { nullptr, nullptr, OPTION_HEADER, "OSD INPUT OPTIONS" }, - { OSD_KEYBOARDINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for keyboard input: " }, - { OSD_MOUSEINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for mouse input: " }, - { OSD_LIGHTGUNINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for lightgun input: " }, - { OSD_JOYSTICKINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for joystick input: " }, - - { nullptr, nullptr, OPTION_HEADER, "OSD CLI OPTIONS" }, - { OSDCOMMAND_LIST_MIDI_DEVICES ";mlist", "0", OPTION_COMMAND, "list available MIDI I/O devices" }, - { OSDCOMMAND_LIST_NETWORK_ADAPTERS ";nlist", "0", OPTION_COMMAND, "list available network adapters" }, - - { nullptr, nullptr, OPTION_HEADER, "OSD DEBUGGING OPTIONS" }, - { OSDOPTION_DEBUGGER, OSDOPTVAL_AUTO, OPTION_STRING, "debugger used: " }, - { OSDOPTION_DEBUGGER_PORT, "23946", OPTION_INTEGER, "port to use for gdbstub debugger" }, - { OSDOPTION_DEBUGGER_FONT ";dfont", OSDOPTVAL_AUTO, OPTION_STRING, "font to use for debugger views" }, - { OSDOPTION_DEBUGGER_FONT_SIZE ";dfontsize", "0", OPTION_FLOAT, "font size to use for debugger views" }, - { OSDOPTION_WATCHDOG ";wdog", "0", OPTION_INTEGER, "force the program to terminate if no updates within specified number of seconds" }, - - { nullptr, nullptr, OPTION_HEADER, "OSD PERFORMANCE OPTIONS" }, - { OSDOPTION_NUMPROCESSORS ";np", OSDOPTVAL_AUTO, OPTION_STRING, "number of processors; this overrides the number the system reports" }, - { OSDOPTION_BENCH, "0", OPTION_INTEGER, "benchmark for the given number of emulated seconds; implies -video none -sound none -nothrottle" }, - - { nullptr, nullptr, OPTION_HEADER, "OSD VIDEO OPTIONS" }, -// OS X can be trusted to have working hardware OpenGL, so default to it on for the best user experience - { OSDOPTION_VIDEO, OSDOPTVAL_AUTO, OPTION_STRING, "video output method: " }, - { OSDOPTION_NUMSCREENS "(1-4)", "1", OPTION_INTEGER, "number of output screens/windows to create; usually, you want just one" }, - { OSDOPTION_WINDOW ";w", "0", OPTION_BOOLEAN, "enable window mode; otherwise, full screen mode is assumed" }, - { OSDOPTION_MAXIMIZE ";max", "1", OPTION_BOOLEAN, "default to maximized windows" }, - { OSDOPTION_WAITVSYNC ";vs", "0", OPTION_BOOLEAN, "enable waiting for the start of VBLANK before flipping screens (reduces tearing effects)" }, - { OSDOPTION_SYNCREFRESH ";srf", "0", OPTION_BOOLEAN, "enable using the start of VBLANK for throttling instead of the game time" }, - { OSD_MONITOR_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "monitor discovery method: " }, + { OSDOPTION_CONTROLLER_MAP_FILE ";ctrlmap", OSDOPTVAL_NONE, core_options::option_type::PATH, "game controller mapping file" }, + { OSDOPTION_BACKGROUND_INPUT, "0", core_options::option_type::BOOLEAN, "don't ignore input when losing UI focus" }, + + { nullptr, nullptr, core_options::option_type::HEADER, "OSD FONT OPTIONS" }, + { OSD_FONT_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "provider for UI font: " }, + + { nullptr, nullptr, core_options::option_type::HEADER, "OSD OUTPUT OPTIONS" }, + { OSD_OUTPUT_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "provider for output notifications: " }, + + { nullptr, nullptr, core_options::option_type::HEADER, "OSD INPUT OPTIONS" }, + { OSD_KEYBOARDINPUT_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "provider for keyboard input: " }, + { OSD_MOUSEINPUT_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "provider for mouse input: " }, + { OSD_LIGHTGUNINPUT_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "provider for lightgun input: " }, + { OSD_JOYSTICKINPUT_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "provider for joystick input: " }, + + { nullptr, nullptr, core_options::option_type::HEADER, "OSD CLI OPTIONS" }, + { OSDCOMMAND_LIST_MIDI_DEVICES ";mlist", "0", core_options::option_type::COMMAND, "list available MIDI I/O devices" }, + { OSDCOMMAND_LIST_NETWORK_ADAPTERS ";nlist", "0", core_options::option_type::COMMAND, "list available network adapters" }, + + { nullptr, nullptr, core_options::option_type::HEADER, "OSD DEBUGGING OPTIONS" }, + { OSDOPTION_DEBUGGER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "debugger used: " }, + { OSDOPTION_DEBUGGER_HOST, "localhost", core_options::option_type::STRING, "address to bind to for gdbstub debugger" }, + { OSDOPTION_DEBUGGER_PORT, "23946", core_options::option_type::INTEGER, "port to use for gdbstub debugger" }, + { OSDOPTION_DEBUGGER_FONT ";dfont", OSDOPTVAL_AUTO, core_options::option_type::STRING, "font to use for debugger views" }, + { OSDOPTION_DEBUGGER_FONT_SIZE ";dfontsize", "0", core_options::option_type::FLOAT, "font size to use for debugger views" }, + { OSDOPTION_WATCHDOG ";wdog", "0", core_options::option_type::INTEGER, "force the program to terminate if no updates within specified number of seconds" }, + + { nullptr, nullptr, core_options::option_type::HEADER, "OSD PERFORMANCE OPTIONS" }, + { OSDOPTION_NUMPROCESSORS ";np", OSDOPTVAL_AUTO, core_options::option_type::STRING, "number of processors; this overrides the number the system reports" }, + { OSDOPTION_BENCH, "0", core_options::option_type::INTEGER, "benchmark for the given number of emulated seconds; implies -video none -sound none -nothrottle" }, + + { nullptr, nullptr, core_options::option_type::HEADER, "OSD VIDEO OPTIONS" }, + { OSDOPTION_VIDEO, OSDOPTVAL_AUTO, core_options::option_type::STRING, "video output method: " }, + { OSDOPTION_NUMSCREENS "(1-4)", "1", core_options::option_type::INTEGER, "number of output screens/windows to create; usually, you want just one" }, + { OSDOPTION_WINDOW ";w", "0", core_options::option_type::BOOLEAN, "enable window mode; otherwise, full screen mode is assumed" }, + { OSDOPTION_MAXIMIZE ";max", "1", core_options::option_type::BOOLEAN, "default to maximized windows" }, + { OSDOPTION_WAITVSYNC ";vs", "0", core_options::option_type::BOOLEAN, "enable waiting for the start of VBLANK before flipping screens (reduces tearing effects)" }, + { OSDOPTION_SYNCREFRESH ";srf", "0", core_options::option_type::BOOLEAN, "enable using the start of VBLANK for throttling instead of the game time" }, + { OSD_MONITOR_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "monitor discovery method: " }, // per-window options - { nullptr, nullptr, OPTION_HEADER, "OSD PER-WINDOW VIDEO OPTIONS" }, - { OSDOPTION_SCREEN, OSDOPTVAL_AUTO, OPTION_STRING, "explicit name of the first screen; 'auto' here will try to make a best guess" }, - { OSDOPTION_ASPECT ";screen_aspect", OSDOPTVAL_AUTO, OPTION_STRING, "aspect ratio for all screens; 'auto' here will try to make a best guess" }, - { OSDOPTION_RESOLUTION ";r", OSDOPTVAL_AUTO, OPTION_STRING, "preferred resolution for all screens; format is <width>x<height>[@<refreshrate>] or 'auto'" }, - { OSDOPTION_VIEW, OSDOPTVAL_AUTO, OPTION_STRING, "preferred view for all screens" }, - - { OSDOPTION_SCREEN "0", OSDOPTVAL_AUTO, OPTION_STRING, "explicit name of the first screen; 'auto' here will try to make a best guess" }, - { OSDOPTION_ASPECT "0", OSDOPTVAL_AUTO, OPTION_STRING, "aspect ratio of the first screen; 'auto' here will try to make a best guess" }, - { OSDOPTION_RESOLUTION "0;r0", OSDOPTVAL_AUTO, OPTION_STRING, "preferred resolution of the first screen; format is <width>x<height>[@<refreshrate>] or 'auto'" }, - { OSDOPTION_VIEW "0", OSDOPTVAL_AUTO, OPTION_STRING, "preferred view for the first screen" }, - - { OSDOPTION_SCREEN "1", OSDOPTVAL_AUTO, OPTION_STRING, "explicit name of the second screen; 'auto' here will try to make a best guess" }, - { OSDOPTION_ASPECT "1", OSDOPTVAL_AUTO, OPTION_STRING, "aspect ratio of the second screen; 'auto' here will try to make a best guess" }, - { OSDOPTION_RESOLUTION "1;r1", OSDOPTVAL_AUTO, OPTION_STRING, "preferred resolution of the second screen; format is <width>x<height>[@<refreshrate>] or 'auto'" }, - { OSDOPTION_VIEW "1", OSDOPTVAL_AUTO, OPTION_STRING, "preferred view for the second screen" }, - - { OSDOPTION_SCREEN "2", OSDOPTVAL_AUTO, OPTION_STRING, "explicit name of the third screen; 'auto' here will try to make a best guess" }, - { OSDOPTION_ASPECT "2", OSDOPTVAL_AUTO, OPTION_STRING, "aspect ratio of the third screen; 'auto' here will try to make a best guess" }, - { OSDOPTION_RESOLUTION "2;r2", OSDOPTVAL_AUTO, OPTION_STRING, "preferred resolution of the third screen; format is <width>x<height>[@<refreshrate>] or 'auto'" }, - { OSDOPTION_VIEW "2", OSDOPTVAL_AUTO, OPTION_STRING, "preferred view for the third screen" }, - - { OSDOPTION_SCREEN "3", OSDOPTVAL_AUTO, OPTION_STRING, "explicit name of the fourth screen; 'auto' here will try to make a best guess" }, - { OSDOPTION_ASPECT "3", OSDOPTVAL_AUTO, OPTION_STRING, "aspect ratio of the fourth screen; 'auto' here will try to make a best guess" }, - { OSDOPTION_RESOLUTION "3;r3", OSDOPTVAL_AUTO, OPTION_STRING, "preferred resolution of the fourth screen; format is <width>x<height>[@<refreshrate>] or 'auto'" }, - { OSDOPTION_VIEW "3", OSDOPTVAL_AUTO, OPTION_STRING, "preferred view for the fourth screen" }, + { nullptr, nullptr, core_options::option_type::HEADER, "OSD PER-WINDOW VIDEO OPTIONS" }, + { OSDOPTION_SCREEN, OSDOPTVAL_AUTO, core_options::option_type::STRING, "explicit name of the first screen; 'auto' here will try to make a best guess" }, + { OSDOPTION_ASPECT ";screen_aspect", OSDOPTVAL_AUTO, core_options::option_type::STRING, "aspect ratio for all screens; 'auto' here will try to make a best guess" }, + { OSDOPTION_RESOLUTION ";r", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred resolution for all screens; format is <width>x<height>[@<refreshrate>] or 'auto'" }, + { OSDOPTION_VIEW, OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred view for all screens" }, + + { OSDOPTION_SCREEN "0", OSDOPTVAL_AUTO, core_options::option_type::STRING, "explicit name of the first screen; 'auto' here will try to make a best guess" }, + { OSDOPTION_ASPECT "0", OSDOPTVAL_AUTO, core_options::option_type::STRING, "aspect ratio of the first screen; 'auto' here will try to make a best guess" }, + { OSDOPTION_RESOLUTION "0;r0", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred resolution of the first screen; format is <width>x<height>[@<refreshrate>] or 'auto'" }, + { OSDOPTION_VIEW "0", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred view for the first screen" }, + + { OSDOPTION_SCREEN "1", OSDOPTVAL_AUTO, core_options::option_type::STRING, "explicit name of the second screen; 'auto' here will try to make a best guess" }, + { OSDOPTION_ASPECT "1", OSDOPTVAL_AUTO, core_options::option_type::STRING, "aspect ratio of the second screen; 'auto' here will try to make a best guess" }, + { OSDOPTION_RESOLUTION "1;r1", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred resolution of the second screen; format is <width>x<height>[@<refreshrate>] or 'auto'" }, + { OSDOPTION_VIEW "1", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred view for the second screen" }, + + { OSDOPTION_SCREEN "2", OSDOPTVAL_AUTO, core_options::option_type::STRING, "explicit name of the third screen; 'auto' here will try to make a best guess" }, + { OSDOPTION_ASPECT "2", OSDOPTVAL_AUTO, core_options::option_type::STRING, "aspect ratio of the third screen; 'auto' here will try to make a best guess" }, + { OSDOPTION_RESOLUTION "2;r2", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred resolution of the third screen; format is <width>x<height>[@<refreshrate>] or 'auto'" }, + { OSDOPTION_VIEW "2", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred view for the third screen" }, + + { OSDOPTION_SCREEN "3", OSDOPTVAL_AUTO, core_options::option_type::STRING, "explicit name of the fourth screen; 'auto' here will try to make a best guess" }, + { OSDOPTION_ASPECT "3", OSDOPTVAL_AUTO, core_options::option_type::STRING, "aspect ratio of the fourth screen; 'auto' here will try to make a best guess" }, + { OSDOPTION_RESOLUTION "3;r3", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred resolution of the fourth screen; format is <width>x<height>[@<refreshrate>] or 'auto'" }, + { OSDOPTION_VIEW "3", OSDOPTVAL_AUTO, core_options::option_type::STRING, "preferred view for the fourth screen" }, // full screen options - { nullptr, nullptr, OPTION_HEADER, "OSD FULL SCREEN OPTIONS" }, - { OSDOPTION_SWITCHRES, "0", OPTION_BOOLEAN, "enable resolution switching" }, + { nullptr, nullptr, core_options::option_type::HEADER, "OSD FULL SCREEN OPTIONS" }, + { OSDOPTION_SWITCHRES, "0", core_options::option_type::BOOLEAN, "enable resolution switching" }, - { nullptr, nullptr, OPTION_HEADER, "OSD ACCELERATED VIDEO OPTIONS" }, - { OSDOPTION_FILTER ";glfilter;flt", "1", OPTION_BOOLEAN, "use bilinear filtering when scaling emulated video" }, - { OSDOPTION_PRESCALE "(1-3)", "1", OPTION_INTEGER, "scale emulated video by this factor before applying filters/shaders" }, + { nullptr, nullptr, core_options::option_type::HEADER, "OSD ACCELERATED VIDEO OPTIONS" }, + { OSDOPTION_FILTER ";glfilter;flt", "1", core_options::option_type::BOOLEAN, "use bilinear filtering when scaling emulated video" }, + { OSDOPTION_PRESCALE "(1-20)", "1", core_options::option_type::INTEGER, "scale emulated video by this factor before applying filters/shaders" }, #if USE_OPENGL - { nullptr, nullptr, OPTION_HEADER, "OpenGL-SPECIFIC OPTIONS" }, - { OSDOPTION_GL_FORCEPOW2TEXTURE, "0", OPTION_BOOLEAN, "force power-of-two texture sizes (default no)" }, - { OSDOPTION_GL_NOTEXTURERECT, "0", OPTION_BOOLEAN, "don't use OpenGL GL_ARB_texture_rectangle (default on)" }, - { OSDOPTION_GL_VBO, "1", OPTION_BOOLEAN, "enable OpenGL VBO if available (default on)" }, - { OSDOPTION_GL_PBO, "1", OPTION_BOOLEAN, "enable OpenGL PBO if available (default on)" }, - { OSDOPTION_GL_GLSL, "0", OPTION_BOOLEAN, "enable OpenGL GLSL if available (default off)" }, - { OSDOPTION_GLSL_FILTER, "1", OPTION_STRING, "enable OpenGL GLSL filtering instead of FF filtering 0-plain, 1-bilinear (default), 2-bicubic" }, - { OSDOPTION_SHADER_MAME "0", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 0" }, - { OSDOPTION_SHADER_MAME "1", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 1" }, - { OSDOPTION_SHADER_MAME "2", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 2" }, - { OSDOPTION_SHADER_MAME "3", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 3" }, - { OSDOPTION_SHADER_MAME "4", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 4" }, - { OSDOPTION_SHADER_MAME "5", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 5" }, - { OSDOPTION_SHADER_MAME "6", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 6" }, - { OSDOPTION_SHADER_MAME "7", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 7" }, - { OSDOPTION_SHADER_MAME "8", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 8" }, - { OSDOPTION_SHADER_MAME "9", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader set mame bitmap 9" }, - { OSDOPTION_SHADER_SCREEN "0", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 0" }, - { OSDOPTION_SHADER_SCREEN "1", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 1" }, - { OSDOPTION_SHADER_SCREEN "2", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 2" }, - { OSDOPTION_SHADER_SCREEN "3", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 3" }, - { OSDOPTION_SHADER_SCREEN "4", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 4" }, - { OSDOPTION_SHADER_SCREEN "5", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 5" }, - { OSDOPTION_SHADER_SCREEN "6", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 6" }, - { OSDOPTION_SHADER_SCREEN "7", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 7" }, - { OSDOPTION_SHADER_SCREEN "8", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 8" }, - { OSDOPTION_SHADER_SCREEN "9", OSDOPTVAL_NONE, OPTION_STRING, "custom OpenGL GLSL shader screen bitmap 9" }, + { nullptr, nullptr, core_options::option_type::HEADER, "OpenGL-SPECIFIC OPTIONS" }, + { OSDOPTION_GL_FORCEPOW2TEXTURE, "0", core_options::option_type::BOOLEAN, "force power-of-two texture sizes (default no)" }, + { OSDOPTION_GL_NOTEXTURERECT, "0", core_options::option_type::BOOLEAN, "don't use OpenGL GL_ARB_texture_rectangle (default on)" }, + { OSDOPTION_GL_VBO, "1", core_options::option_type::BOOLEAN, "enable OpenGL VBO if available (default on)" }, + { OSDOPTION_GL_PBO, "1", core_options::option_type::BOOLEAN, "enable OpenGL PBO if available (default on)" }, + { OSDOPTION_GL_GLSL, "0", core_options::option_type::BOOLEAN, "enable OpenGL GLSL if available (default off)" }, + { OSDOPTION_GLSL_FILTER, "1", core_options::option_type::STRING, "enable OpenGL GLSL filtering instead of FF filtering 0-plain, 1-bilinear (default), 2-bicubic" }, + { OSDOPTION_SHADER_MAME "0", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 0" }, + { OSDOPTION_SHADER_MAME "1", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 1" }, + { OSDOPTION_SHADER_MAME "2", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 2" }, + { OSDOPTION_SHADER_MAME "3", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 3" }, + { OSDOPTION_SHADER_MAME "4", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 4" }, + { OSDOPTION_SHADER_MAME "5", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 5" }, + { OSDOPTION_SHADER_MAME "6", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 6" }, + { OSDOPTION_SHADER_MAME "7", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 7" }, + { OSDOPTION_SHADER_MAME "8", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 8" }, + { OSDOPTION_SHADER_MAME "9", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader set mame bitmap 9" }, + { OSDOPTION_SHADER_SCREEN "0", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 0" }, + { OSDOPTION_SHADER_SCREEN "1", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 1" }, + { OSDOPTION_SHADER_SCREEN "2", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 2" }, + { OSDOPTION_SHADER_SCREEN "3", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 3" }, + { OSDOPTION_SHADER_SCREEN "4", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 4" }, + { OSDOPTION_SHADER_SCREEN "5", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 5" }, + { OSDOPTION_SHADER_SCREEN "6", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 6" }, + { OSDOPTION_SHADER_SCREEN "7", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 7" }, + { OSDOPTION_SHADER_SCREEN "8", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 8" }, + { OSDOPTION_SHADER_SCREEN "9", OSDOPTVAL_NONE, core_options::option_type::STRING, "custom OpenGL GLSL shader screen bitmap 9" }, #endif - { nullptr, nullptr, OPTION_HEADER, "OSD SOUND OPTIONS" }, - { OSDOPTION_SOUND, OSDOPTVAL_AUTO, OPTION_STRING, "sound output method: " }, - { OSDOPTION_AUDIO_LATENCY "(1-5)", "2", OPTION_INTEGER, "set audio latency (increase to reduce glitches, decrease for responsiveness)" }, + { nullptr, nullptr, core_options::option_type::HEADER, "OSD SOUND OPTIONS" }, + { OSDOPTION_SOUND, OSDOPTVAL_AUTO, core_options::option_type::STRING, "sound output method: " }, + { OSDOPTION_AUDIO_LATENCY "(0-5)", "2", core_options::option_type::INTEGER, "set audio latency (increase to reduce glitches, decrease for responsiveness)" }, #ifndef NO_USE_PORTAUDIO - { nullptr, nullptr, OPTION_HEADER, "PORTAUDIO OPTIONS" }, - { OSDOPTION_PA_API, OSDOPTVAL_NONE, OPTION_STRING, "PortAudio API" }, - { OSDOPTION_PA_DEVICE, OSDOPTVAL_NONE, OPTION_STRING, "PortAudio device" }, - { OSDOPTION_PA_LATENCY "(0-0.25)", "0", OPTION_FLOAT, "suggested latency in seconds, 0 for default" }, + { nullptr, nullptr, core_options::option_type::HEADER, "PORTAUDIO OPTIONS" }, + { OSDOPTION_PA_API, OSDOPTVAL_NONE, core_options::option_type::STRING, "PortAudio API" }, + { OSDOPTION_PA_DEVICE, OSDOPTVAL_NONE, core_options::option_type::STRING, "PortAudio device" }, + { OSDOPTION_PA_LATENCY "(0-0.25)", "0", core_options::option_type::FLOAT, "suggested latency in seconds, 0 for default" }, #endif #ifdef SDLMAME_MACOSX - { nullptr, nullptr, OPTION_HEADER, "CoreAudio-SPECIFIC OPTIONS" }, - { OSDOPTION_AUDIO_OUTPUT, OSDOPTVAL_AUTO, OPTION_STRING, "audio output device" }, - { OSDOPTION_AUDIO_EFFECT "0", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 0" }, - { OSDOPTION_AUDIO_EFFECT "1", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 1" }, - { OSDOPTION_AUDIO_EFFECT "2", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 2" }, - { OSDOPTION_AUDIO_EFFECT "3", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 3" }, - { OSDOPTION_AUDIO_EFFECT "4", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 4" }, - { OSDOPTION_AUDIO_EFFECT "5", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 5" }, - { OSDOPTION_AUDIO_EFFECT "6", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 6" }, - { OSDOPTION_AUDIO_EFFECT "7", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 7" }, - { OSDOPTION_AUDIO_EFFECT "8", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 8" }, - { OSDOPTION_AUDIO_EFFECT "9", OSDOPTVAL_NONE, OPTION_STRING, "AudioUnit effect 9" }, + { nullptr, nullptr, core_options::option_type::HEADER, "CoreAudio-SPECIFIC OPTIONS" }, + { OSDOPTION_AUDIO_OUTPUT, OSDOPTVAL_AUTO, core_options::option_type::STRING, "audio output device" }, + { OSDOPTION_AUDIO_EFFECT "0", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 0" }, + { OSDOPTION_AUDIO_EFFECT "1", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 1" }, + { OSDOPTION_AUDIO_EFFECT "2", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 2" }, + { OSDOPTION_AUDIO_EFFECT "3", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 3" }, + { OSDOPTION_AUDIO_EFFECT "4", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 4" }, + { OSDOPTION_AUDIO_EFFECT "5", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 5" }, + { OSDOPTION_AUDIO_EFFECT "6", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 6" }, + { OSDOPTION_AUDIO_EFFECT "7", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 7" }, + { OSDOPTION_AUDIO_EFFECT "8", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 8" }, + { OSDOPTION_AUDIO_EFFECT "9", OSDOPTVAL_NONE, core_options::option_type::STRING, "AudioUnit effect 9" }, #endif - { nullptr, nullptr, OPTION_HEADER, "BGFX POST-PROCESSING OPTIONS" }, - { OSDOPTION_BGFX_PATH, "bgfx", OPTION_STRING, "path to BGFX-related files" }, - { OSDOPTION_BGFX_BACKEND, "auto", OPTION_STRING, "BGFX backend to use (d3d9, d3d11, metal, opengl, gles)" }, - { OSDOPTION_BGFX_DEBUG, "0", OPTION_BOOLEAN, "enable BGFX debugging statistics" }, - { OSDOPTION_BGFX_SCREEN_CHAINS, "default", OPTION_STRING, "comma-delimited list of screen chain JSON names, colon-delimited per-window" }, - { OSDOPTION_BGFX_SHADOW_MASK, "slot-mask.png", OPTION_STRING, "shadow mask texture name" }, - { OSDOPTION_BGFX_LUT, "", OPTION_STRING, "LUT texture name" }, - { OSDOPTION_BGFX_AVI_NAME, OSDOPTVAL_AUTO, OPTION_STRING, "filename for BGFX output logging" }, + { nullptr, nullptr, core_options::option_type::HEADER, "OSD MIDI OPTIONS" }, + { OSDOPTION_MIDI_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "MIDI I/O method: " }, + + { nullptr, nullptr, core_options::option_type::HEADER, "OSD EMULATED NETWORKING OPTIONS" }, + { OSDOPTION_NETWORK_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "Emulated networking provider: " }, + + { nullptr, nullptr, core_options::option_type::HEADER, "BGFX POST-PROCESSING OPTIONS" }, + { OSDOPTION_BGFX_PATH, "bgfx", core_options::option_type::PATH, "path to BGFX-related files" }, + { OSDOPTION_BGFX_BACKEND, "auto", core_options::option_type::STRING, "BGFX backend to use (d3d9, d3d11, d3d12, metal, opengl, gles, vulkan)" }, + { OSDOPTION_BGFX_DEBUG, "0", core_options::option_type::BOOLEAN, "enable BGFX debugging statistics" }, + { OSDOPTION_BGFX_SCREEN_CHAINS, "", core_options::option_type::STRING, "comma-delimited list of screen chain JSON names, colon-delimited per-window" }, + { OSDOPTION_BGFX_SHADOW_MASK, "slot-mask.png", core_options::option_type::STRING, "shadow mask texture name" }, + { OSDOPTION_BGFX_LUT, "lut-default.png", core_options::option_type::STRING, "LUT texture name" }, + { OSDOPTION_BGFX_AVI_NAME, OSDOPTVAL_AUTO, core_options::option_type::PATH, "filename for BGFX output logging" }, - // End of list + // End of list { nullptr } }; @@ -170,7 +194,7 @@ osd_options::osd_options() } // Window list -std::list<std::shared_ptr<osd_window>> osd_common_t::s_window_list; +std::list<std::unique_ptr<osd_window> > osd_common_t::s_window_list; //------------------------------------------------- // osd_interface - constructor @@ -184,6 +208,7 @@ osd_common_t::osd_common_t(osd_options &options) , m_sound(nullptr) , m_debugger(nullptr) , m_midi(nullptr) + , m_network(nullptr) , m_keyboard_input(nullptr) , m_mouse_input(nullptr) , m_lightgun_input(nullptr) @@ -205,7 +230,7 @@ osd_common_t::~osd_common_t() osd_output::pop(this); } -#define REGISTER_MODULE(_O, _X ) { extern const module_type _X; _O . register_module( _X ); } +#define REGISTER_MODULE(O, X) { extern const module_type X; O.register_module(X); } void osd_common_t::register_options() { @@ -215,6 +240,26 @@ void osd_common_t::register_options() REGISTER_MODULE(m_mod_man, FONT_SDL); REGISTER_MODULE(m_mod_man, FONT_NONE); +#if defined(SDLMAME_EMSCRIPTEN) + REGISTER_MODULE(m_mod_man, RENDERER_SDL1); // don't bother trying to use video acceleration in browsers +#endif +#if defined(OSD_WINDOWS) + REGISTER_MODULE(m_mod_man, RENDERER_D3D); // this is only built for OSD=windows, there's no dummy stub +#endif +#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32) + REGISTER_MODULE(m_mod_man, RENDERER_BGFX); // try BGFX before GDI on windows to get DirectX 10/11 acceleration +#endif + REGISTER_MODULE(m_mod_man, RENDERER_GDI); // GDI ahead of OpenGL as there's a chance Windows has no OpenGL + REGISTER_MODULE(m_mod_man, RENDERER_OPENGL); +#if !defined(OSD_WINDOWS) && !defined(SDLMAME_WIN32) + REGISTER_MODULE(m_mod_man, RENDERER_BGFX); // try BGFX after OpenGL on other operating systems for now +#endif + REGISTER_MODULE(m_mod_man, RENDERER_SDL2); +#if !defined(SDLMAME_EMSCRIPTEN) + REGISTER_MODULE(m_mod_man, RENDERER_SDL1); +#endif + REGISTER_MODULE(m_mod_man, RENDERER_NONE); + REGISTER_MODULE(m_mod_man, SOUND_DSOUND); REGISTER_MODULE(m_mod_man, SOUND_XAUDIO2); REGISTER_MODULE(m_mod_man, SOUND_COREAUDIO); @@ -223,6 +268,12 @@ void osd_common_t::register_options() #ifndef NO_USE_PORTAUDIO REGISTER_MODULE(m_mod_man, SOUND_PORTAUDIO); #endif +#ifndef NO_USE_PULSEAUDIO + REGISTER_MODULE(m_mod_man, SOUND_PULSEAUDIO); +#endif +#ifndef NO_USE_PIPEWIRE + REGISTER_MODULE(m_mod_man, SOUND_PIPEWIRE); +#endif REGISTER_MODULE(m_mod_man, SOUND_NONE); REGISTER_MODULE(m_mod_man, MONITOR_SDL); @@ -254,7 +305,6 @@ void osd_common_t::register_options() REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_RAWINPUT); REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_DINPUT); REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_WIN32); - REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_UWP); REGISTER_MODULE(m_mod_man, KEYBOARD_NONE); REGISTER_MODULE(m_mod_man, MOUSEINPUT_SDL); @@ -263,16 +313,17 @@ void osd_common_t::register_options() REGISTER_MODULE(m_mod_man, MOUSEINPUT_WIN32); REGISTER_MODULE(m_mod_man, MOUSE_NONE); + REGISTER_MODULE(m_mod_man, LIGHTGUNINPUT_SDL); REGISTER_MODULE(m_mod_man, LIGHTGUN_X11); REGISTER_MODULE(m_mod_man, LIGHTGUNINPUT_RAWINPUT); REGISTER_MODULE(m_mod_man, LIGHTGUNINPUT_WIN32); REGISTER_MODULE(m_mod_man, LIGHTGUN_NONE); - REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_SDL); + REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_SDLGAME); + REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_SDLJOY); REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_WINHYBRID); REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_DINPUT); REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_XINPUT); - REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_UWP); REGISTER_MODULE(m_mod_man, JOYSTICK_NONE); REGISTER_MODULE(m_mod_man, OUTPUT_NONE); @@ -282,95 +333,34 @@ void osd_common_t::register_options() // after initialization we know which modules are supported - - const char *names[20]; - int num; - std::vector<const char *> dnames; - - m_mod_man.get_module_names(OSD_MONITOR_PROVIDER, 20, &num, names); - for (int i = 0; i < num; i++) - dnames.push_back(names[i]); - update_option(OSD_MONITOR_PROVIDER, dnames); - - m_mod_man.get_module_names(OSD_FONT_PROVIDER, 20, &num, names); - dnames.clear(); - for (int i = 0; i < num; i++) - dnames.push_back(names[i]); - update_option(OSD_FONT_PROVIDER, dnames); - - m_mod_man.get_module_names(OSD_KEYBOARDINPUT_PROVIDER, 20, &num, names); - dnames.clear(); - for (int i = 0; i < num; i++) - dnames.push_back(names[i]); - update_option(OSD_KEYBOARDINPUT_PROVIDER, dnames); - - m_mod_man.get_module_names(OSD_MOUSEINPUT_PROVIDER, 20, &num, names); - dnames.clear(); - for (int i = 0; i < num; i++) - dnames.push_back(names[i]); - update_option(OSD_MOUSEINPUT_PROVIDER, dnames); - - m_mod_man.get_module_names(OSD_LIGHTGUNINPUT_PROVIDER, 20, &num, names); - dnames.clear(); - for (int i = 0; i < num; i++) - dnames.push_back(names[i]); - update_option(OSD_LIGHTGUNINPUT_PROVIDER, dnames); - - m_mod_man.get_module_names(OSD_JOYSTICKINPUT_PROVIDER, 20, &num, names); - dnames.clear(); - for (int i = 0; i < num; i++) - dnames.push_back(names[i]); - update_option(OSD_JOYSTICKINPUT_PROVIDER, dnames); - - m_mod_man.get_module_names(OSD_SOUND_PROVIDER, 20, &num, names); - dnames.clear(); - for (int i = 0; i < num; i++) - dnames.push_back(names[i]); - update_option(OSD_SOUND_PROVIDER, dnames); - -#if 0 - // Register midi options and update options - m_mod_man.get_module_names(OSD_MIDI_PROVIDER, 20, &num, names); - dnames.clear(); - for (int i = 0; i < num; i++) - dnames.push_back(names[i]); - update_option(OSD_MIDI_PROVIDER, dnames); -#endif - - // Register debugger options and update options - m_mod_man.get_module_names(OSD_DEBUG_PROVIDER, 20, &num, names); - dnames.clear(); - for (int i = 0; i < num; i++) - dnames.push_back(names[i]); - update_option(OSD_DEBUG_PROVIDER, dnames); - - m_mod_man.get_module_names(OSD_OUTPUT_PROVIDER, 20, &num, names); - dnames.clear(); - for (int i = 0; i < num; i++) - dnames.push_back(names[i]); - update_option(OSD_OUTPUT_PROVIDER, dnames); - - // Register video options and update options - video_options_add("none", nullptr); - video_register(); - update_option(OSDOPTION_VIDEO, m_video_names); + update_option(OSD_FONT_PROVIDER, m_mod_man.get_module_names(OSD_FONT_PROVIDER)); + update_option(OSD_RENDERER_PROVIDER, m_mod_man.get_module_names(OSD_RENDERER_PROVIDER)); + update_option(OSD_SOUND_PROVIDER, m_mod_man.get_module_names(OSD_SOUND_PROVIDER)); + update_option(OSD_MONITOR_PROVIDER, m_mod_man.get_module_names(OSD_MONITOR_PROVIDER)); + update_option(OSD_KEYBOARDINPUT_PROVIDER, m_mod_man.get_module_names(OSD_KEYBOARDINPUT_PROVIDER)); + update_option(OSD_MOUSEINPUT_PROVIDER, m_mod_man.get_module_names(OSD_MOUSEINPUT_PROVIDER)); + update_option(OSD_LIGHTGUNINPUT_PROVIDER, m_mod_man.get_module_names(OSD_LIGHTGUNINPUT_PROVIDER)); + update_option(OSD_JOYSTICKINPUT_PROVIDER, m_mod_man.get_module_names(OSD_JOYSTICKINPUT_PROVIDER)); + update_option(OSD_MIDI_PROVIDER, m_mod_man.get_module_names(OSD_MIDI_PROVIDER)); + update_option(OSD_NETDEV_PROVIDER, m_mod_man.get_module_names(OSD_NETDEV_PROVIDER)); + update_option(OSD_DEBUG_PROVIDER, m_mod_man.get_module_names(OSD_DEBUG_PROVIDER)); + update_option(OSD_OUTPUT_PROVIDER, m_mod_man.get_module_names(OSD_OUTPUT_PROVIDER)); } -void osd_common_t::update_option(const std::string &key, std::vector<const char *> &values) +void osd_common_t::update_option(const std::string &key, std::vector<std::string_view> const &values) { std::string current_value(m_options.description(key.c_str())); std::string new_option_value(""); for (unsigned int index = 0; index < values.size(); index++) { - std::string t(values[index]); if (new_option_value.length() > 0) { - if( index != (values.size()-1)) + if (index != (values.size() - 1)) new_option_value.append(", "); else new_option_value.append(" or "); } - new_option_value.append(t); + new_option_value.append(values[index]); } m_option_descs[key] = current_value + new_option_value; @@ -381,28 +371,28 @@ void osd_common_t::update_option(const std::string &key, std::vector<const char //------------------------------------------------- // output_callback - callback for osd_printf_... //------------------------------------------------- -void osd_common_t::output_callback(osd_output_channel channel, const char *msg, va_list args) +void osd_common_t::output_callback(osd_output_channel channel, const util::format_argument_pack<char> &args) { switch (channel) { - case OSD_OUTPUT_CHANNEL_ERROR: - case OSD_OUTPUT_CHANNEL_WARNING: - vfprintf(stderr, msg, args); - break; - case OSD_OUTPUT_CHANNEL_INFO: - case OSD_OUTPUT_CHANNEL_LOG: - vfprintf(stdout, msg, args); - break; - case OSD_OUTPUT_CHANNEL_VERBOSE: - if (verbose()) vfprintf(stdout, msg, args); - break; - case OSD_OUTPUT_CHANNEL_DEBUG: + case OSD_OUTPUT_CHANNEL_ERROR: + case OSD_OUTPUT_CHANNEL_WARNING: + util::stream_format(std::cerr, args); + break; + case OSD_OUTPUT_CHANNEL_INFO: + case OSD_OUTPUT_CHANNEL_LOG: + util::stream_format(std::cout, args); + break; + case OSD_OUTPUT_CHANNEL_VERBOSE: + if (verbose()) util::stream_format(std::cout, args); + break; + case OSD_OUTPUT_CHANNEL_DEBUG: #ifdef MAME_DEBUG - vfprintf(stdout, msg, args); + util::stream_format(std::cout, args); #endif - break; - default: - break; + break; + default: + break; } } @@ -442,7 +432,7 @@ void osd_common_t::init(running_machine &machine) m_machine = &machine; - osd_options &options = downcast<osd_options &>(machine.options()); + auto &options = downcast<osd_options &>(machine.options()); // extract the verbose printing option if (options.verbose()) set_verbose(true); @@ -478,9 +468,6 @@ void osd_common_t::update(bool skip_redraw) // if (m_watchdog != nullptr) m_watchdog->reset(); - - update_slider_list(); - } @@ -522,46 +509,65 @@ void osd_common_t::debugger_update() } -//------------------------------------------------- -// update_audio_stream - update the stereo audio -// stream -//------------------------------------------------- +bool osd_common_t::sound_external_per_channel_volume() +{ + return m_sound->external_per_channel_volume(); +} -void osd_common_t::update_audio_stream(const int16_t *buffer, int samples_this_frame) +bool osd_common_t::sound_split_streams_per_source() { - // - // This method is called whenever the system has new audio data to stream. - // It provides an array of stereo samples in L-R order which should be - // output at the configured sample_rate. - // - m_sound->update_audio_stream(m_machine->video().throttled(), buffer,samples_this_frame); + return m_sound->split_streams_per_source(); } +uint32_t osd_common_t::sound_get_generation() +{ + return m_sound->get_generation(); +} -//------------------------------------------------- -// set_mastervolume - set the system volume -//------------------------------------------------- +osd::audio_info osd_common_t::sound_get_information() +{ + return m_sound->get_information(); +} -void osd_common_t::set_mastervolume(int attenuation) +uint32_t osd_common_t::sound_stream_sink_open(uint32_t node, std::string name, uint32_t rate) { - // - // Attenuation is the attenuation in dB (a negative number). - // To convert from dB to a linear volume scale do the following: - // volume = MAX_VOLUME; - // while (attenuation++ < 0) - // volume /= 1.122018454; // = (10 ^ (1/20)) = 1dB - // - if (m_sound != nullptr) - m_sound->set_mastervolume(attenuation); + return m_sound->stream_sink_open(node, name, rate); } +uint32_t osd_common_t::sound_stream_source_open(uint32_t node, std::string name, uint32_t rate) +{ + return m_sound->stream_source_open(node, name, rate); +} + +void osd_common_t::sound_stream_set_volumes(uint32_t id, const std::vector<float> &db) +{ + m_sound->stream_set_volumes(id, db); +} + +void osd_common_t::sound_stream_close(uint32_t id) +{ + m_sound->stream_close(id); +} + +void osd_common_t::sound_stream_sink_update(uint32_t id, const int16_t *buffer, int samples_this_frame) +{ + m_sound->stream_sink_update(id, buffer, samples_this_frame); +} + +void osd_common_t::sound_stream_source_update(uint32_t id, int16_t *buffer, int samples_this_frame) +{ + m_sound->stream_source_update(id, buffer, samples_this_frame); +} + + + //------------------------------------------------- // customize_input_type_list - provide OSD // additions/modifications to the input list //------------------------------------------------- -void osd_common_t::customize_input_type_list(simple_list<input_type_entry> &typelist) +void osd_common_t::customize_input_type_list(std::vector<input_type_entry> &typelist) { // // inptport.c defines some general purpose defaults for key and joystick bindings. @@ -583,6 +589,31 @@ void osd_common_t::customize_input_type_list(simple_list<input_type_entry> &type std::vector<ui::menu_item> osd_common_t::get_slider_list() { + // check if any window has dirty sliders + bool dirty = false; + for (const auto &window : window_list()) + { + if (window->has_renderer() && window->renderer().sliders_dirty()) + { + dirty = true; + break; + } + } + + if (dirty) + { + m_sliders.clear(); + + for (const auto &window : osd_common_t::window_list()) + { + if (window->has_renderer()) + { + std::vector<ui::menu_item> window_sliders = window->renderer().get_slider_list(); + m_sliders.insert(m_sliders.end(), window_sliders.begin(), window_sliders.end()); + } + } + } + return m_sliders; } @@ -607,28 +638,50 @@ bool osd_common_t::execute_command(const char *command) { if (strcmp(command, OSDCOMMAND_LIST_NETWORK_ADAPTERS) == 0) { - osd_module *om = select_module_options(options(), OSD_NETDEV_PROVIDER); - - if (om->probe()) + auto &om = select_module_options<netdev_module>(OSD_NETDEV_PROVIDER); + auto const interfaces = om.list_devices(); + if (interfaces.empty()) { - om->init(options()); - osd_list_network_adapters(); - om->exit(); + printf("No supported network interfaces were found\n"); } + else + { + printf("Available network interfaces:\n"); + for (auto &entry : interfaces) + { + printf(" %.*s\n", int(entry.description.length()), entry.description.data()); + } + } + dynamic_cast<osd_module &>(om).exit(); return true; } else if (strcmp(command, OSDCOMMAND_LIST_MIDI_DEVICES) == 0) { - osd_module *om = select_module_options(options(), OSD_MIDI_PROVIDER); - midi_module *pm = select_module_options<midi_module *>(options(), OSD_MIDI_PROVIDER); - - if (om->probe()) + auto &om = select_module_options<midi_module>(OSD_MIDI_PROVIDER); + auto const ports = om.list_midi_ports(); + if (ports.empty()) + { + printf("No MIDI ports were found\n"); + } + else { - om->init(options()); - pm->list_midi_devices(); - om->exit(); + printf("MIDI input ports:\n"); + for (auto const &port : ports) + { + if (port.input) + printf(port.default_input ? "%s (default)\n" : "%s\n", port.name.c_str()); + } + + printf("\nMIDI output ports:\n"); + for (auto const &port : ports) + { + if (port.output) + printf(port.default_output ? "%s (default)\n" : "%s\n", port.name.c_str()); + } } + dynamic_cast<osd_module &>(om).exit(); + return true; } @@ -644,10 +697,10 @@ static void output_notifier_callback(const char *outname, int32_t value, void *p void osd_common_t::init_subsystems() { // monitors have to be initialized before video init - m_monitor_module = select_module_options<monitor_module *>(options(), OSD_MONITOR_PROVIDER); - assert(m_monitor_module != nullptr); - m_monitor_module->init(options()); + m_monitor_module = &select_module_options<monitor_module>(OSD_MONITOR_PROVIDER); + // various modules depend on having a window handle + m_render = &select_module_options<render_module>(OSD_RENDERER_PROVIDER); if (!video_init()) { video_exit(); @@ -657,32 +710,24 @@ void osd_common_t::init_subsystems() exit(-1); } - m_keyboard_input = select_module_options<input_module *>(options(), OSD_KEYBOARDINPUT_PROVIDER); - m_mouse_input = select_module_options<input_module *>(options(), OSD_MOUSEINPUT_PROVIDER); - m_lightgun_input = select_module_options<input_module *>(options(), OSD_LIGHTGUNINPUT_PROVIDER); - m_joystick_input = select_module_options<input_module *>(options(), OSD_JOYSTICKINPUT_PROVIDER); - - m_font_module = select_module_options<font_module *>(options(), OSD_FONT_PROVIDER); - m_sound = select_module_options<sound_module *>(options(), OSD_SOUND_PROVIDER); - m_sound->m_sample_rate = options().sample_rate(); - m_sound->m_audio_latency = options().audio_latency(); + m_keyboard_input = &select_module_options<input_module>(OSD_KEYBOARDINPUT_PROVIDER); + m_mouse_input = &select_module_options<input_module>(OSD_MOUSEINPUT_PROVIDER); + m_lightgun_input = &select_module_options<input_module>(OSD_LIGHTGUNINPUT_PROVIDER); + m_joystick_input = &select_module_options<input_module>(OSD_JOYSTICKINPUT_PROVIDER); - m_debugger = select_module_options<debug_module *>(options(), OSD_DEBUG_PROVIDER); + m_font_module = &select_module_options<font_module>(OSD_FONT_PROVIDER); + m_sound = &select_module_options<sound_module>(OSD_SOUND_PROVIDER); - select_module_options<netdev_module *>(options(), OSD_NETDEV_PROVIDER); + m_debugger = &select_module_options<debug_module>(OSD_DEBUG_PROVIDER); - m_midi = select_module_options<midi_module *>(options(), OSD_MIDI_PROVIDER); + m_midi = &select_module_options<midi_module>(OSD_MIDI_PROVIDER); - m_output = select_module_options<output_module *>(options(), OSD_OUTPUT_PROVIDER); - m_output->set_machine(&machine()); - machine().output().set_notifier(nullptr, output_notifier_callback, this); + m_network = &select_module_options<netdev_module>(OSD_NETDEV_PROVIDER); - m_mod_man.init(options()); + m_output = &select_module_options<output_module>(OSD_OUTPUT_PROVIDER); + machine().output().set_global_notifier(output_notifier_callback, this); input_init(); - // we need pause callbacks - machine().add_notifier(MACHINE_NOTIFY_PAUSE, machine_notify_delegate(&osd_common_t::input_pause, this)); - machine().add_notifier(MACHINE_NOTIFY_RESUME, machine_notify_delegate(&osd_common_t::input_resume, this)); } bool osd_common_t::video_init() @@ -700,10 +745,6 @@ bool osd_common_t::no_sound() return (strcmp(options().sound(),"none")==0) ? true : false; } -void osd_common_t::video_register() -{ -} - bool osd_common_t::input_init() { m_keyboard_input->input_init(machine()); @@ -713,20 +754,12 @@ bool osd_common_t::input_init() return true; } -void osd_common_t::input_pause() +void osd_common_t::poll_input_modules(bool relative_reset) { - m_keyboard_input->pause(); - m_mouse_input->pause(); - m_lightgun_input->pause(); - m_joystick_input->pause(); -} - -void osd_common_t::input_resume() -{ - m_keyboard_input->resume(); - m_mouse_input->resume(); - m_lightgun_input->resume(); - m_joystick_input->resume(); + m_keyboard_input->poll_if_necessary(relative_reset); + m_mouse_input->poll_if_necessary(relative_reset); + m_lightgun_input->poll_if_necessary(relative_reset); + m_joystick_input->poll_if_necessary(relative_reset); } void osd_common_t::exit_subsystems() @@ -744,13 +777,46 @@ void osd_common_t::window_exit() void osd_common_t::osd_exit() { + // destroy the renderers before shutting down their parent module + for (auto it = window_list().rbegin(); window_list().rend() != it; ++it) + (*it)->renderer_reset(); + m_mod_man.exit(); exit_subsystems(); } -void osd_common_t::video_options_add(const char *name, void *type) +osd_font::ptr osd_common_t::font_alloc() +{ + return m_font_module->font_alloc(); +} + +bool osd_common_t::get_font_families(std::string const &font_path, std::vector<std::pair<std::string, std::string> > &result) +{ + return m_font_module->get_font_families(font_path, result); +} + +std::unique_ptr<osd::midi_input_port> osd_common_t::create_midi_input(std::string_view name) +{ + return m_midi->create_input(name); +} + +std::unique_ptr<osd::midi_output_port> osd_common_t::create_midi_output(std::string_view name) +{ + return m_midi->create_output(name); +} + +std::vector<osd::midi_port_info> osd_common_t::list_midi_ports() +{ + return m_midi->list_midi_ports(); +} + +std::unique_ptr<osd::network_device> osd_common_t::open_network_device(int id, osd::network_handler &handler) +{ + return m_network->open_device(id, handler); +} + +std::vector<osd::network_device_info> osd_common_t::list_network_devices() { - //m_video_options.add(name, type, false); - m_video_names.push_back(name); + return m_network->list_devices(); } diff --git a/src/osd/modules/lib/osdobj_common.h b/src/osd/modules/lib/osdobj_common.h index 37e043f53ad..ff0d0b9a6dd 100644 --- a/src/osd/modules/lib/osdobj_common.h +++ b/src/osd/modules/lib/osdobj_common.h @@ -2,41 +2,48 @@ // copyright-holders:Aaron Giles /*************************************************************************** - osdepend.h + osdobj_common.h OS-dependent code interface. *******************************************************************c********/ - -#pragma once - #ifndef MAME_OSD_LIB_OSDOBJ_COMMON_H #define MAME_OSD_LIB_OSDOBJ_COMMON_H +#pragma once + +#include "osdcore.h" #include "osdepend.h" -#include "watchdog.h" + #include "modules/osdmodule.h" -#include "modules/font/font_module.h" -#include "modules/input/input_module.h" -#include "modules/sound/sound_module.h" -#include "modules/debugger/debug_module.h" -#include "modules/netdev/netdev_module.h" -#include "modules/midi/midi_module.h" #include "modules/output/output_module.h" -#include "modules/monitor/monitor_module.h" + #include "emuopts.h" -#include "../frontend/mame/ui/menuitem.h" + +#include "strformat.h" + +#include <iosfwd> +#include <list> +#include <memory> +#include <string> +#include <string_view> +#include <unordered_map> +#include <vector> + //============================================================ // Defines //============================================================ #define OSDOPTION_UIMODEKEY "uimodekey" +#define OSDOPTION_CONTROLLER_MAP_FILE "controller_map" +#define OSDOPTION_BACKGROUND_INPUT "background_input" #define OSDCOMMAND_LIST_MIDI_DEVICES "listmidi" #define OSDCOMMAND_LIST_NETWORK_ADAPTERS "listnetwork" #define OSDOPTION_DEBUGGER "debugger" +#define OSDOPTION_DEBUGGER_HOST "debugger_host" #define OSDOPTION_DEBUGGER_PORT "debugger_port" #define OSDOPTION_DEBUGGER_FONT "debugger_font" #define OSDOPTION_DEBUGGER_FONT_SIZE "debugger_font_size" @@ -81,8 +88,9 @@ #define OSDOPTION_AUDIO_OUTPUT "audio_output" #define OSDOPTION_AUDIO_EFFECT "audio_effect" -#define OSDOPTVAL_AUTO "auto" -#define OSDOPTVAL_NONE "none" +#define OSDOPTION_MIDI_PROVIDER "midiprovider" + +#define OSDOPTION_NETWORK_PROVIDER "networkprovider" #define OSDOPTION_BGFX_PATH "bgfx_path" #define OSDOPTION_BGFX_BACKEND "bgfx_backend" @@ -92,6 +100,9 @@ #define OSDOPTION_BGFX_LUT "bgfx_lut" #define OSDOPTION_BGFX_AVI_NAME "bgfx_avi_name" +#define OSDOPTVAL_AUTO "auto" +#define OSDOPTVAL_NONE "none" + //============================================================ // TYPE DEFINITIONS //============================================================ @@ -104,9 +115,12 @@ public: // keyboard mapping const char *ui_mode_key() const { return value(OSDOPTION_UIMODEKEY); } + const char *controller_mapping_file() const { return value(OSDOPTION_CONTROLLER_MAP_FILE); } + bool background_input() const { return bool_value(OSDOPTION_BACKGROUND_INPUT); } // debugging options const char *debugger() const { return value(OSDOPTION_DEBUGGER); } + const char *debugger_host() const { return value(OSDOPTION_DEBUGGER_HOST); } int debugger_port() const { return int_value(OSDOPTION_DEBUGGER_PORT); } const char *debugger_font() const { return value(OSDOPTION_DEBUGGER_FONT); } float debugger_font_size() const { return float_value(OSDOPTION_DEBUGGER_FONT_SIZE); } @@ -129,10 +143,10 @@ public: const char *aspect() const { return value(OSDOPTION_ASPECT); } const char *resolution() const { return value(OSDOPTION_RESOLUTION); } const char *view() const { return value(OSDOPTION_VIEW); } - const char *screen(int index) const { return value(string_format("%s%d", OSDOPTION_SCREEN, index).c_str()); } - const char *aspect(int index) const { return value(string_format("%s%d", OSDOPTION_ASPECT, index).c_str()); } - const char *resolution(int index) const { return value(string_format("%s%d", OSDOPTION_RESOLUTION, index).c_str()); } - const char *view(int index) const { return value(string_format("%s%d", OSDOPTION_VIEW, index).c_str()); } + const char *screen(int index) const { return value(util::string_format("%s%d", OSDOPTION_SCREEN, index)); } + const char *aspect(int index) const { return value(util::string_format("%s%d", OSDOPTION_ASPECT, index)); } + const char *resolution(int index) const { return value(util::string_format("%s%d", OSDOPTION_RESOLUTION, index)); } + const char *view(int index) const { return value(util::string_format("%s%d", OSDOPTION_VIEW, index)); } // full screen options bool switch_res() const { return bool_value(OSDOPTION_SWITCHRES); } @@ -148,8 +162,8 @@ public: bool gl_pbo() const { return bool_value(OSDOPTION_GL_PBO); } bool gl_glsl() const { return bool_value(OSDOPTION_GL_GLSL); } int glsl_filter() const { return int_value(OSDOPTION_GLSL_FILTER); } - const char *shader_mame(int index) const { return value(string_format("%s%d", OSDOPTION_SHADER_MAME, index).c_str()); } - const char *shader_screen(int index) const { return value(string_format("%s%d", OSDOPTION_SHADER_SCREEN, index).c_str()); } + const char *shader_mame(int index) const { return value(util::string_format("%s%d", OSDOPTION_SHADER_MAME, index)); } + const char *shader_screen(int index) const { return value(util::string_format("%s%d", OSDOPTION_SHADER_SCREEN, index)); } // sound options const char *sound() const { return value(OSDOPTION_SOUND); } @@ -157,7 +171,7 @@ public: // CoreAudio specific options const char *audio_output() const { return value(OSDOPTION_AUDIO_OUTPUT); } - const char *audio_effect(int index) const { return value(string_format("%s%d", OSDOPTION_AUDIO_EFFECT, index).c_str()); } + const char *audio_effect(int index) const { return value(util::string_format("%s%d", OSDOPTION_AUDIO_EFFECT, index)); } // BGFX specific options const char *bgfx_path() const { return value(OSDOPTION_BGFX_PATH); } @@ -171,13 +185,24 @@ public: // PortAudio options const char *pa_api() const { return value(OSDOPTION_PA_API); } const char *pa_device() const { return value(OSDOPTION_PA_DEVICE); } - const float pa_latency() const { return float_value(OSDOPTION_PA_LATENCY); } + float pa_latency() const { return float_value(OSDOPTION_PA_LATENCY); } static const options_entry s_option_entries[]; }; // ======================> osd_interface + +class debug_module; +class font_module; +class input_module; +class midi_module; +class monitor_module; +class netdev_module; +class osd_watchdog; class osd_window; +class output_module; +class render_module; +class sound_module; // description of the currently-running machine class osd_common_t : public osd_interface, osd_output @@ -199,24 +224,40 @@ public: virtual void wait_for_debugger(device_t &device, bool firststop) override; // audio overridables - virtual void update_audio_stream(const int16_t *buffer, int samples_this_frame) override; - virtual void set_mastervolume(int attenuation) override; virtual bool no_sound() override; + virtual bool sound_external_per_channel_volume() override; + virtual bool sound_split_streams_per_source() override; + virtual uint32_t sound_get_generation() override; + virtual osd::audio_info sound_get_information() override; + virtual uint32_t sound_stream_sink_open(uint32_t node, std::string name, uint32_t rate) override; + virtual uint32_t sound_stream_source_open(uint32_t node, std::string name, uint32_t rate) override; + virtual void sound_stream_set_volumes(uint32_t id, const std::vector<float> &db) override; + virtual void sound_stream_close(uint32_t id) override; + virtual void sound_stream_sink_update(uint32_t id, const int16_t *buffer, int samples_this_frame) override; + virtual void sound_stream_source_update(uint32_t id, int16_t *buffer, int samples_this_frame) override; // input overridables - virtual void customize_input_type_list(simple_list<input_type_entry> &typelist) override; + virtual void customize_input_type_list(std::vector<input_type_entry> &typelist) override; // video overridables virtual void add_audio_to_recording(const int16_t *buffer, int samples_this_frame) override; virtual std::vector<ui::menu_item> get_slider_list() override; + // font interface + virtual osd_font::ptr font_alloc() override; + virtual bool get_font_families(std::string const &font_path, std::vector<std::pair<std::string, std::string> > &result) override; + // command option overrides virtual bool execute_command(const char *command) override; - virtual osd_font::ptr font_alloc() override { return m_font_module->font_alloc(); } - virtual bool get_font_families(std::string const &font_path, std::vector<std::pair<std::string, std::string> > &result) override { return m_font_module->get_font_families(font_path, result); } + // MIDI interface + virtual std::unique_ptr<osd::midi_input_port> create_midi_input(std::string_view name) override; + virtual std::unique_ptr<osd::midi_output_port> create_midi_output(std::string_view name) override; + virtual std::vector<osd::midi_port_info> list_midi_ports() override; - virtual osd_midi_device *create_midi_device() override { return m_midi->create_midi_device(); } + // network interface + virtual std::unique_ptr<osd::network_device> open_network_device(int id, osd::network_handler &handler) override; + virtual std::vector<osd::network_device_info> list_network_devices() override; // FIXME: everything below seems to be osd specific and not part of // this INTERFACE but part of the osd IMPLEMENTATION @@ -229,36 +270,34 @@ public: virtual void init_subsystems(); virtual bool video_init(); - virtual void video_register(); virtual bool window_init(); - virtual void input_resume(); - virtual void exit_subsystems(); virtual void video_exit(); virtual void window_exit(); virtual void osd_exit(); - virtual void video_options_add(const char *name, void *type); - virtual osd_options &options() { return m_options; } // osd_output interface ... - virtual void output_callback(osd_output_channel channel, const char *msg, va_list args) override; + virtual void output_callback(osd_output_channel channel, const util::format_argument_pack<char> &args) override; bool verbose() const { return m_print_verbose; } virtual void set_verbose(bool print_verbose) override { m_print_verbose = print_verbose; } void notify(const char *outname, int32_t value) const { m_output->notify(outname, value); } - static std::list<std::shared_ptr<osd_window>> s_window_list; + virtual void process_events() = 0; + virtual bool has_focus() const = 0; + + static const std::list<std::unique_ptr<osd_window> > &window_list() { return s_window_list; } protected: virtual bool input_init(); - virtual void input_pause(); - virtual void build_slider_list() { } - virtual void update_slider_list() { } + void poll_input_modules(bool relative_reset); + + static std::list<std::unique_ptr<osd_window> > s_window_list; private: // internal state @@ -270,31 +309,30 @@ private: osd_module_manager m_mod_man; font_module *m_font_module; - void update_option(const std::string &key, std::vector<const char *> &values); + void update_option(const std::string &key, std::vector<std::string_view> const &values); // FIXME: should be elsewhere - osd_module *select_module_options(const core_options &opts, const std::string &opt_name) + template<class C> + C &select_module_options(const std::string &opt_name) { - std::string opt_val = opts.exists(opt_name) ? opts.value(opt_name.c_str()) : ""; - if (opt_val.compare("auto")==0) + std::string opt_val = options().exists(opt_name) ? options().value(opt_name) : ""; + if (opt_val == "auto") + { opt_val = ""; + } else if (!m_mod_man.type_has_name(opt_name.c_str(), opt_val.c_str())) { - osd_printf_warning("Value %s not supported for option %s - falling back to auto\n", opt_val.c_str(), opt_name.c_str()); + osd_printf_warning("Value %s not supported for option %s - falling back to auto\n", opt_val, opt_name); opt_val = ""; } - return m_mod_man.select_module(opt_name.c_str(), opt_val.c_str()); - } - - template<class C> - C select_module_options(const core_options &opts, const std::string &opt_name) - { - return dynamic_cast<C>(select_module_options(opts, opt_name)); + return m_mod_man.select_module<C>(*this, options(), opt_name.c_str(), opt_val.c_str()); } protected: + render_module* m_render; sound_module* m_sound; debug_module* m_debugger; midi_module* m_midi; + netdev_module* m_network; input_module* m_keyboard_input; input_module* m_mouse_input; input_module* m_lightgun_input; @@ -305,16 +343,7 @@ protected: std::vector<ui::menu_item> m_sliders; private: - std::vector<const char *> m_video_names; std::unordered_map<std::string, std::string> m_option_descs; }; - -// this template function creates a stub which constructs a debugger -template<class _DeviceClass> -debug_module *osd_debugger_creator() -{ - return global_alloc(_DeviceClass()); -} - #endif // MAME_OSD_LIB_OSDOBJ_COMMON_H |