Preliminary Mac native OSD. Not working yet. [R. Belmont]

This will compile, link, and run a driver all the way to the first info screen, provided you use -video bgfx.

However, although there's a valid NSWindow created, it never actually appears on screen for unknown (but likely silly) reasons.

Inputs are not implemented and fullscreen exists but is untried.
This commit is contained in:
arbee 2019-09-15 20:00:59 -04:00
parent fd505eb0d6
commit 2292cf332c
22 changed files with 2433 additions and 4 deletions

View File

@ -165,6 +165,8 @@ elif outfmt == 'plist':
fp.write('\t<string>%s</string>\n' % product_name)
fp.write('\t<key>CFBundleShortVersionString</key>\n')
fp.write('\t<string>%s.%s.%s</string>\n' % (version_major, version_minor, version_build))
fp.write('\t<key>NSPrincipalClass</key>\n')
fp.write('\t<string>NSApplication</string>\n')
fp.write('</dict>\n')
fp.write('</plist>\n')
fp.flush()

175
scripts/src/osd/mac.lua Normal file
View File

@ -0,0 +1,175 @@
-- license:BSD-3-Clause
-- copyright-holders:MAMEdev Team
---------------------------------------------------------------------------
--
-- mac.lua
--
-- Rules for the building with SDL
--
---------------------------------------------------------------------------
dofile("modules.lua")
function maintargetosdoptions(_target,_subtarget)
osdmodulestargetconf()
configuration { }
end
BASE_TARGETOS = "unix"
local os_version = str_to_version(backtick("sw_vers -productVersion"))
links {
"Cocoa.framework",
}
linkoptions {
"-framework QuartzCore",
"-framework OpenGL",
}
if os_version>=101100 then
linkoptions {
"-weak_framework Metal",
}
end
project ("qtdbg_" .. _OPTIONS["osd"])
uuid (os.uuid("qtdbg_" .. _OPTIONS["osd"]))
kind (LIBTYPE)
dofile("mac_cfg.lua")
includedirs {
MAME_DIR .. "src/emu",
MAME_DIR .. "src/devices", -- accessing imagedev from debugger
MAME_DIR .. "src/osd",
MAME_DIR .. "src/lib",
MAME_DIR .. "src/lib/util",
MAME_DIR .. "src/osd/modules/render",
MAME_DIR .. "3rdparty",
}
configuration { "linux-* or freebsd" }
buildoptions {
"-fPIC",
}
configuration { }
qtdebuggerbuild()
project ("osd_" .. _OPTIONS["osd"])
targetsubdir(_OPTIONS["target"] .."_" .._OPTIONS["subtarget"])
uuid (os.uuid("osd_" .. _OPTIONS["osd"]))
kind (LIBTYPE)
dofile("mac_cfg.lua")
osdmodulesbuild()
includedirs {
MAME_DIR .. "src/emu",
MAME_DIR .. "src/devices", -- accessing imagedev from debugger
MAME_DIR .. "src/osd",
MAME_DIR .. "src/lib",
MAME_DIR .. "src/lib/util",
MAME_DIR .. "src/osd/modules/file",
MAME_DIR .. "src/osd/modules/render",
MAME_DIR .. "3rdparty",
MAME_DIR .. "src/osd/mac",
}
files {
MAME_DIR .. "src/osd/modules/debugger/debugosx.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/breakpointsview.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/breakpointsview.h",
MAME_DIR .. "src/osd/modules/debugger/osx/consoleview.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/consoleview.h",
MAME_DIR .. "src/osd/modules/debugger/osx/debugcommandhistory.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/debugcommandhistory.h",
MAME_DIR .. "src/osd/modules/debugger/osx/debugconsole.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/debugconsole.h",
MAME_DIR .. "src/osd/modules/debugger/osx/debugview.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/debugview.h",
MAME_DIR .. "src/osd/modules/debugger/osx/debugwindowhandler.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/debugwindowhandler.h",
MAME_DIR .. "src/osd/modules/debugger/osx/deviceinfoviewer.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/deviceinfoviewer.h",
MAME_DIR .. "src/osd/modules/debugger/osx/devicesviewer.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/devicesviewer.h",
MAME_DIR .. "src/osd/modules/debugger/osx/disassemblyview.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/disassemblyviewer.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/disassemblyviewer.h",
MAME_DIR .. "src/osd/modules/debugger/osx/errorlogview.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/errorlogview.h",
MAME_DIR .. "src/osd/modules/debugger/osx/disassemblyview.h",
MAME_DIR .. "src/osd/modules/debugger/osx/errorlogviewer.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/errorlogviewer.h",
MAME_DIR .. "src/osd/modules/debugger/osx/memoryview.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/memoryview.h",
MAME_DIR .. "src/osd/modules/debugger/osx/memoryviewer.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/memoryviewer.h",
MAME_DIR .. "src/osd/modules/debugger/osx/pointsviewer.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/pointsviewer.h",
MAME_DIR .. "src/osd/modules/debugger/osx/registersview.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/registersview.h",
MAME_DIR .. "src/osd/modules/debugger/osx/watchpointsview.mm",
MAME_DIR .. "src/osd/modules/debugger/osx/watchpointsview.h",
MAME_DIR .. "src/osd/modules/debugger/osx/debugosx.h",
}
files {
MAME_DIR .. "src/osd/mac/main.mm",
MAME_DIR .. "src/osd/mac/macmain.cpp",
MAME_DIR .. "src/osd/mac/appdelegate.mm",
MAME_DIR .. "src/osd/mac/appdelegate.h",
MAME_DIR .. "src/osd/mac/video.cpp",
MAME_DIR .. "src/osd/mac/window.cpp",
MAME_DIR .. "src/osd/mac/window.h",
MAME_DIR .. "src/osd/mac/windowcontroller.mm",
MAME_DIR .. "src/osd/mac/windowcontroller.h",
MAME_DIR .. "src/osd/mac/mamefswindow.mm",
MAME_DIR .. "src/osd/mac/mamefswindow.h",
MAME_DIR .. "src/osd/mac/oglview.mm",
MAME_DIR .. "src/osd/mac/oglview.h",
MAME_DIR .. "src/osd/modules/osdwindow.cpp",
MAME_DIR .. "src/osd/modules/osdwindow.h",
}
project ("ocore_" .. _OPTIONS["osd"])
targetsubdir(_OPTIONS["target"] .."_" .. _OPTIONS["subtarget"])
uuid (os.uuid("ocore_" .. _OPTIONS["osd"]))
kind (LIBTYPE)
removeflags {
"SingleOutputDir",
}
dofile("mac_cfg.lua")
includedirs {
MAME_DIR .. "src/emu",
MAME_DIR .. "src/osd",
MAME_DIR .. "src/lib",
MAME_DIR .. "src/lib/util",
MAME_DIR .. "src/osd/mac",
}
files {
MAME_DIR .. "src/osd/osdcore.cpp",
MAME_DIR .. "src/osd/osdcore.h",
MAME_DIR .. "src/osd/strconv.cpp",
MAME_DIR .. "src/osd/strconv.h",
MAME_DIR .. "src/osd/osdsync.cpp",
MAME_DIR .. "src/osd/osdsync.h",
MAME_DIR .. "src/osd/modules/osdmodule.cpp",
MAME_DIR .. "src/osd/modules/osdmodule.h",
MAME_DIR .. "src/osd/modules/lib/osdlib_macosx.cpp",
MAME_DIR .. "src/osd/modules/lib/osdlib.h",
MAME_DIR .. "src/osd/modules/file/posixdir.cpp",
MAME_DIR .. "src/osd/modules/file/posixdomain.cpp",
MAME_DIR .. "src/osd/modules/file/posixfile.cpp",
MAME_DIR .. "src/osd/modules/file/posixfile.h",
MAME_DIR .. "src/osd/modules/file/posixptty.cpp",
MAME_DIR .. "src/osd/modules/file/posixsocket.cpp",
}

View File

@ -0,0 +1,31 @@
-- license:BSD-3-Clause
-- copyright-holders:MAMEdev Team
dofile('modules.lua')
forcedincludes {
-- MAME_DIR .. "src/osd/sdl/sdlprefix.h"
}
if not _OPTIONS["DONT_USE_NETWORK"] then
defines {
"USE_NETWORK",
"OSD_NET_USE_PCAP",
}
end
defines {
"OSD_MAC",
"SDLMAME_UNIX",
"SDLMAME_MACOSX",
"SDLMAME_DARWIN"
}
configuration { "osx*" }
includedirs {
MAME_DIR .. "3rdparty/bx/include/compat/osx",
}
configuration { }

View File

@ -104,6 +104,7 @@ function osdmodulesbuild()
MAME_DIR .. "src/osd/modules/input/input_xinput.h",
MAME_DIR .. "src/osd/modules/input/input_winhybrid.cpp",
MAME_DIR .. "src/osd/modules/input/input_uwp.cpp",
MAME_DIR .. "src/osd/modules/input/input_mac.cpp",
MAME_DIR .. "src/osd/modules/output/output_module.h",
MAME_DIR .. "src/osd/modules/output/none.cpp",
MAME_DIR .. "src/osd/modules/output/console.cpp",
@ -115,6 +116,7 @@ function osdmodulesbuild()
MAME_DIR .. "src/osd/modules/monitor/monitor_win32.cpp",
MAME_DIR .. "src/osd/modules/monitor/monitor_dxgi.cpp",
MAME_DIR .. "src/osd/modules/monitor/monitor_sdl.cpp",
MAME_DIR .. "src/osd/modules/monitor/monitor_mac.cpp",
}
includedirs {
ext_includedir("asio"),

15
src/osd/mac/appdelegate.h Normal file
View File

@ -0,0 +1,15 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
//============================================================
//
// appdelegate.h - Cocoa app delegate
//
// Mac OSD by R. Belmont
//
//============================================================
#import <Cocoa/Cocoa.h>
@interface MAMEAppDelegate : NSObject <NSApplicationDelegate>
@end

View File

@ -0,0 +1,54 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
//============================================================
//
// appdelegate.mm - Cocoa app delegate
//
// Mac OSD by R. Belmont
//
//============================================================
#import "appdelegate.h"
extern int mac_run_emulator();
@interface MAMEThread : NSThread
@end
@implementation MAMEThread
- (void)main
{
mac_run_emulator();
}
@end
@interface MAMEAppDelegate ()
@end
@implementation MAMEAppDelegate
MAMEThread *appThread;
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
// run MAME on a thread so event dispatching happens normally
appThread = [[MAMEThread alloc] init];
[appThread start];
}
- (void)applicationWillTerminate:(NSNotification *)notification
{
}
- (void)applicationDidBecomeActive:(NSNotification *)notification
{
}
- (void)applicationDidResignActive:(NSNotification *)notification
{
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSNotification *)notification
{
return NSTerminateNow;
}
@end

271
src/osd/mac/macmain.cpp Normal file
View File

@ -0,0 +1,271 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
//============================================================
//
// macmain.cpp - C++ side main file for MAME on the Mac
//
// Mac OSD by R. Belmont
//
//============================================================
// oslog callback
#include <functional>
#define __ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES 0
#include <Carbon/Carbon.h>
#include <crt_externs.h>
#include <unistd.h>
// MAME headers
#include "osdepend.h"
#include "emu.h"
#include "emuopts.h"
#include "strconv.h"
// OSD headers
#include "video.h"
#include "osdmac.h"
#include "modules/lib/osdlib.h"
#include "modules/diagnostics/diagnostics_module.h"
//============================================================
// OPTIONS
//============================================================
#ifndef INI_PATH
#define INI_PATH "$HOME/Library/Application Support/APP_NAME;$HOME/.APP_NAME;.;ini"
#endif // INI_PATH
//============================================================
// Local variables
//============================================================
const options_entry mac_options::s_option_entries[] =
{
{ MACOPTION_INIPATH, INI_PATH, OPTION_STRING, "path to ini files" },
// End of list
{ nullptr }
};
//============================================================
// mac_options
//============================================================
mac_options::mac_options()
: osd_options()
{
std::string ini_path(INI_PATH);
add_entries(mac_options::s_option_entries);
strreplace(ini_path,"APP_NAME", emulator_info::get_appname_lower());
set_default_value(MACOPTION_INIPATH, ini_path.c_str());
}
//============================================================
// main
//============================================================
// we do some special sauce on Win32...
int mac_run_emulator()
{
int argc = *_NSGetArgc();
char **argv = *_NSGetArgv();
std::vector<std::string> args = osd_get_command_line(argc, argv);
int res = 0;
// disable I/O buffering
setvbuf(stdout, (char *) nullptr, _IONBF, 0);
setvbuf(stderr, (char *) nullptr, _IONBF, 0);
// Initialize crash diagnostics
diagnostics_module::get_instance()->init_crash_diagnostics();
{
mac_options options;
mac_osd_interface osd(options);
osd.register_options();
res = emulator_info::start_frontend(options, osd, args);
}
exit(res);
}
//============================================================
// constructor
//============================================================
mac_osd_interface::mac_osd_interface(mac_options &options)
: osd_common_t(options), m_options(options)
{
}
//============================================================
// destructor
//============================================================
mac_osd_interface::~mac_osd_interface()
{
}
//============================================================
// osd_exit
//============================================================
void mac_osd_interface::osd_exit()
{
osd_common_t::osd_exit();
}
//============================================================
// defines_verbose
//============================================================
#define MAC_EXPAND_STR(_m) #_m
#define MACRO_VERBOSE(_mac) \
do { \
if (strcmp(MAC_EXPAND_STR(_mac), #_mac) != 0) \
osd_printf_verbose("%s=%s ", #_mac, MAC_EXPAND_STR(_mac)); \
} while (0)
#define _mac_VER #mac_MAJOR_VERSION "." #mac_MINOR_VERSION "." #mac_PATCHLEVEL
static void defines_verbose(void)
{
osd_printf_verbose("Build version: %s\n", emulator_info::get_build_version());
osd_printf_verbose("Build architecure: ");
MACRO_VERBOSE(SDLMAME_ARCH);
osd_printf_verbose("\n");
osd_printf_verbose("Build defines 1: ");
MACRO_VERBOSE(SDLMAME_UNIX);
MACRO_VERBOSE(SDLMAME_X11);
MACRO_VERBOSE(SDLMAME_WIN32);
MACRO_VERBOSE(SDLMAME_MACOSX);
MACRO_VERBOSE(SDLMAME_DARWIN);
MACRO_VERBOSE(SDLMAME_LINUX);
MACRO_VERBOSE(SDLMAME_SOLARIS);
MACRO_VERBOSE(SDLMAME_IRIX);
MACRO_VERBOSE(SDLMAME_BSD);
osd_printf_verbose("\n");
osd_printf_verbose("Build defines 1: ");
MACRO_VERBOSE(LSB_FIRST);
MACRO_VERBOSE(PTR64);
MACRO_VERBOSE(MAME_NOASM);
MACRO_VERBOSE(MAME_DEBUG);
MACRO_VERBOSE(BIGENDIAN);
MACRO_VERBOSE(CPP_COMPILE);
MACRO_VERBOSE(SYNC_IMPLEMENTATION);
osd_printf_verbose("\n");
osd_printf_verbose("OpenGL defines: ");
MACRO_VERBOSE(USE_OPENGL);
MACRO_VERBOSE(USE_DISPATCH_GL);
osd_printf_verbose("\n");
osd_printf_verbose("Compiler defines A: ");
MACRO_VERBOSE(__GNUC__);
MACRO_VERBOSE(__GNUC_MINOR__);
MACRO_VERBOSE(__GNUC_PATCHLEVEL__);
MACRO_VERBOSE(__VERSION__);
osd_printf_verbose("\n");
osd_printf_verbose("Compiler defines B: ");
MACRO_VERBOSE(__amd64__);
MACRO_VERBOSE(__x86_64__);
MACRO_VERBOSE(__unix__);
MACRO_VERBOSE(__i386__);
MACRO_VERBOSE(__ppc__);
MACRO_VERBOSE(__ppc64__);
osd_printf_verbose("\n");
osd_printf_verbose("Compiler defines C: ");
MACRO_VERBOSE(_FORTIFY_SOURCE);
MACRO_VERBOSE(__USE_FORTIFY_LEVEL);
osd_printf_verbose("\n");
}
//============================================================
// osd_mac_info
//============================================================
static void osd_mac_info(void)
{
}
//============================================================
// video_register
//============================================================
void mac_osd_interface::video_register()
{
video_options_add("opengl", nullptr);
video_options_add("bgfx", nullptr);
}
//============================================================
// output_oslog
//============================================================
void mac_osd_interface::output_oslog(const char *buffer)
{
fputs(buffer, stderr);
}
//============================================================
// osd_setup_osd_specific_emu_options
//============================================================
void osd_setup_osd_specific_emu_options(emu_options &opts)
{
opts.add_entries(osd_options::s_option_entries);
}
//============================================================
// init
//============================================================
void mac_osd_interface::init(running_machine &machine)
{
// call our parent
osd_common_t::init(machine);
const char *stemp;
// determine if we are benchmarking, and adjust options appropriately
int bench = options().bench();
if (bench > 0)
{
options().set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM);
options().set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM);
options().set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM);
options().set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM);
}
/* get number of processors */
stemp = options().numprocessors();
osd_num_processors = 0;
if (strcmp(stemp, "auto") != 0)
{
osd_num_processors = atoi(stemp);
if (osd_num_processors < 1)
{
osd_printf_warning("numprocessors < 1 doesn't make much sense. Assuming auto ...\n");
osd_num_processors = 0;
}
}
osd_mac_info();
defines_verbose();
osd_common_t::init_subsystems();
if (options().oslog())
{
using namespace std::placeholders;
machine.add_logerror_callback(std::bind(&mac_osd_interface::output_oslog, this, _1));
}
}

19
src/osd/mac/main.mm Normal file
View File

@ -0,0 +1,19 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
//============================================================
//
// main.mm - main file for MAME on Mac
//
// Mac OSD by R. Belmont
//
//============================================================
#import "appdelegate.h"
int main(int argc, char * argv[])
{
[NSApplication sharedApplication];
[NSApp setDelegate: [MAMEAppDelegate new]];
return NSApplicationMain(argc, (const char**)argv);
}

View File

@ -0,0 +1,15 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
//============================================================
//
// mamefswindow.h - our fullscreen window, subclassed from NSWindow
//
// Mac OSD by R. Belmont
//
//============================================================
#import <Cocoa/Cocoa.h>
@interface MAMEFSWindow : NSWindow
@end

View File

@ -0,0 +1,41 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
//============================================================
//
// mamewfsindow.mm - our fullscreen window, subclassed from NSWindow
//
// Mac OSD by R. Belmont
//
//============================================================
#import "mamefswindow.h"
@implementation MAMEFSWindow
-(instancetype)init
{
NSRect screenRect = [[NSScreen mainScreen] frame];
self = [super initWithContentRect:screenRect
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:YES];
// Set the window level to be above the menu bar
[self setLevel:NSMainMenuWindowLevel+1];
[self setOpaque:YES];
[self setHidesOnDeactivate:YES];
return self;
}
-(BOOL)canBecomeKeyWindow
{
return YES;
}
- (void)keyDown:(NSEvent *)event
{
[[self windowController] keyDown:event];
}
@end

19
src/osd/mac/oglview.h Normal file
View File

@ -0,0 +1,19 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
//============================================================
//
// oglview.h - our OpenGL view
//
// Mac OSD by R. Belmont
//
//============================================================
#define GL_SILENCE_DEPRECATION (1)
#import <Cocoa/Cocoa.h>
@interface MAMEGLView : NSOpenGLView
{
}
@end

106
src/osd/mac/oglview.mm Normal file
View File

@ -0,0 +1,106 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
//============================================================
//
// oglview.mm - our OpenGL view
//
// Mac OSD by R. Belmont
//
//============================================================
#import "oglview.h"
#define SUPPORT_RETINA_RESOLUTION 1
@interface MAMEGLView ()
{
}
@end
@implementation MAMEGLView
- (void) awakeFromNib
{
NSOpenGLPixelFormatAttribute attrs[] =
{
NSOpenGLPFADoubleBuffer,
NSOpenGLPFADepthSize, 24,
0
};
NSOpenGLPixelFormat *pf = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:nil];
[self setPixelFormat:pf];
[self setOpenGLContext:context];
#if SUPPORT_RETINA_RESOLUTION
// Opt-In to Retina resolution
[self setWantsBestResolutionOpenGLSurface:YES];
#endif // SUPPORT_RETINA_RESOLUTION
}
- (void) prepareOpenGL
{
[super prepareOpenGL];
[self initGL];
}
- (void) windowWillClose:(NSNotification*)notification
{
}
- (void) initGL
{
[[self openGLContext] makeCurrentContext];
GLint swapInt = 1;
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
}
- (void)reshape
{
[super reshape];
CGLLockContext([[self openGLContext] CGLContextObj]);
// NSRect viewRectPoints = [self bounds];
//#if SUPPORT_RETINA_RESOLUTION
// NSRect viewRectPixels = [self convertRectToBacking:viewRectPoints];
//#else
// NSRect viewRectPixels = viewRectPoints;
//#endif
CGLUnlockContext([[self openGLContext] CGLContextObj]);
}
- (void)renewGState
{
[[self window] disableScreenUpdatesUntilFlush];
[super renewGState];
}
- (void) drawRect: (NSRect) theRect
{
}
- (void) startDrawView
{
[[self openGLContext] makeCurrentContext];
CGLLockContext([[self openGLContext] CGLContextObj]);
}
- (void) completeDrawView
{
CGLFlushDrawable([[self openGLContext] CGLContextObj]);
CGLUnlockContext([[self openGLContext] CGLContextObj]);
}
- (void) dealloc
{
[super dealloc];
}
@end

86
src/osd/mac/osdmac.h Normal file
View File

@ -0,0 +1,86 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
#ifndef _osdmac_h_
#define _osdmac_h_
#include "modules/lib/osdobj_common.h"
#include "modules/osdmodule.h"
#include "modules/font/font_module.h"
//============================================================
// Defines
//============================================================
#define MACOPTION_INIPATH "inipath"
#define MACOPTVAL_OPENGL "opengl"
#define MACOPTVAL_BGFX "bgfx"
#define MACOPTVAL_METAL "metal"
#define MACOPTVAL_GLLIB "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
//============================================================
// TYPE DEFINITIONS
//============================================================
class mac_options : public osd_options
{
public:
// construction/destruction
mac_options();
private:
static const options_entry s_option_entries[];
};
class mac_osd_interface : public osd_common_t
{
public:
// construction/destruction
mac_osd_interface(mac_options &options);
virtual ~mac_osd_interface();
// general overridables
virtual void init(running_machine &machine) override;
virtual void update(bool skip_redraw) override;
// input overridables
virtual void customize_input_type_list(simple_list<input_type_entry> &typelist) override;
virtual void video_register() override;
virtual bool video_init() override;
virtual bool window_init() override;
virtual void video_exit() override;
virtual void window_exit() override;
// sdl specific
void poll_inputs(running_machine &machine);
void release_keys();
bool should_hide_mouse();
void process_events_buf();
virtual mac_options &options() override { return m_options; }
protected:
virtual void build_slider_list() override;
virtual void update_slider_list() override;
private:
virtual void osd_exit() override;
void extract_video_config();
void output_oslog(const char *buffer);
mac_options &m_options;
};
//============================================================
// macwork.cpp
//============================================================
extern int osd_num_processors;
#endif

316
src/osd/mac/video.cpp Normal file
View File

@ -0,0 +1,316 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont
//============================================================
//
// video.cpp - Mac video handling
//
// Mac OSD by R. Belmont
//
//============================================================
// MAME headers
#include "emu.h"
#include "rendutil.h"
#include "ui/uimain.h"
#include "emuopts.h"
#include "uiinput.h"
// MAMEOS headers
#include "video.h"
#include "window.h"
#include "osdmac.h"
#include "modules/lib/osdlib.h"
//============================================================
// CONSTANTS
//============================================================
//============================================================
// GLOBAL VARIABLES
//============================================================
osd_video_config video_config;
//============================================================
// LOCAL VARIABLES
//============================================================
//============================================================
// PROTOTYPES
//============================================================
static void check_osd_inputs(running_machine &machine);
static void get_resolution(const char *defdata, const char *data, osd_window_config *config, int report_error);
//============================================================
// video_init
//============================================================
bool mac_osd_interface::video_init()
{
int index;
// extract data from the options
extract_video_config();
// we need the beam width in a float, contrary to what the core does.
video_config.beamwidth = options().beam_width_min();
// initialize the window system so we can make windows
if (!window_init())
return false;
// create the windows
for (index = 0; index < video_config.numscreens; index++)
{
osd_window_config conf;
memset(&conf, 0, sizeof(conf));
get_resolution(options().resolution(), options().resolution(index), &conf, true);
// create window ...
std::shared_ptr<mac_window_info> win = std::make_shared<mac_window_info>(machine(), index, m_monitor_module->pick_monitor(reinterpret_cast<osd_options &>(options()), index), &conf);
if (win->window_init())
return false;
}
return true;
}
//============================================================
// video_exit
//============================================================
void mac_osd_interface::video_exit()
{
window_exit();
}
//============================================================
// update
//============================================================
void mac_osd_interface::update(bool skip_redraw)
{
osd_common_t::update(skip_redraw);
// if we're not skipping this redraw, update all windows
if (!skip_redraw)
{
// profiler_mark(PROFILER_BLIT);
for (auto window : osd_common_t::s_window_list)
window->update();
// profiler_mark(PROFILER_END);
}
// poll the joystick values here
downcast<mac_osd_interface&>(machine().osd()).poll_inputs(machine());
check_osd_inputs(machine());
// if we're running, disable some parts of the debugger
if ((machine().debug_flags & DEBUG_FLAG_OSD_ENABLED) != 0)
debugger_update();
}
//============================================================
// check_osd_inputs
//============================================================
static void check_osd_inputs(running_machine &machine)
{
// check for toggling fullscreen mode
if (machine.ui_input().pressed(IPT_OSD_1))
{
for (auto curwin : osd_common_t::s_window_list)
std::static_pointer_cast<mac_window_info>(curwin)->toggle_full_screen();
}
auto window = osd_common_t::s_window_list.front();
if (machine.ui_input().pressed(IPT_OSD_2))
{
//FIXME: on a per window basis
video_config.fullstretch = !video_config.fullstretch;
window->target()->set_scale_mode(video_config.fullstretch? SCALE_FRACTIONAL : SCALE_INTEGER);
machine.ui().popup_time(1, "Uneven stretch %s", video_config.fullstretch? "enabled":"disabled");
}
if (machine.ui_input().pressed(IPT_OSD_4))
{
//FIXME: on a per window basis
video_config.keepaspect = !video_config.keepaspect;
window->target()->set_keepaspect(video_config.keepaspect);
machine.ui().popup_time(1, "Keepaspect %s", video_config.keepaspect? "enabled":"disabled");
}
//FIXME: on a per window basis
if (machine.ui_input().pressed(IPT_OSD_5))
{
video_config.filter = !video_config.filter;
machine.ui().popup_time(1, "Filter %s", video_config.filter? "enabled":"disabled");
}
if (machine.ui_input().pressed(IPT_OSD_6))
std::static_pointer_cast<mac_window_info>(window)->modify_prescale(-1);
if (machine.ui_input().pressed(IPT_OSD_7))
std::static_pointer_cast<mac_window_info>(window)->modify_prescale(1);
if (machine.ui_input().pressed(IPT_OSD_8))
window->renderer().record();
}
//============================================================
// extract_video_config
//============================================================
void mac_osd_interface::extract_video_config()
{
const char *stemp;
// global options: extract the data
video_config.windowed = options().window();
video_config.prescale = options().prescale();
video_config.filter = options().filter();
video_config.keepaspect = options().keep_aspect();
video_config.numscreens = options().numscreens();
video_config.fullstretch = options().uneven_stretch();
// if we are in debug mode, never go full screen
if (machine().debug_flags & DEBUG_FLAG_OSD_ENABLED)
video_config.windowed = true;
// default to working video please
video_config.novideo = 0;
// d3d options: extract the data
stemp = options().video();
if (strcmp(stemp, "auto") == 0)
{
stemp = "opengl";
}
if (strcmp(stemp, OSDOPTVAL_NONE) == 0)
{
video_config.mode = VIDEO_MODE_SOFT;
video_config.novideo = 1;
if (!emulator_info::standalone() && options().seconds_to_run() == 0)
osd_printf_warning("Warning: -video none doesn't make much sense without -seconds_to_run\n");
}
else if (strcmp(stemp, MACOPTVAL_OPENGL) == 0)
video_config.mode = VIDEO_MODE_OPENGL;
else if (strcmp(stemp, MACOPTVAL_BGFX) == 0)
{
video_config.mode = VIDEO_MODE_BGFX;
}
else
{
osd_printf_warning("Invalid video value %s; reverting to OpenGL\n", stemp);
video_config.mode = VIDEO_MODE_OPENGL;
}
video_config.switchres = options().switch_res();
video_config.waitvsync = options().wait_vsync();
video_config.syncrefresh = options().sync_refresh();
if (!video_config.waitvsync && video_config.syncrefresh)
{
osd_printf_warning("-syncrefresh specified without -waitvsync. Reverting to -nosyncrefresh\n");
video_config.syncrefresh = 0;
}
if (video_config.prescale < 1 || video_config.prescale > 3)
{
osd_printf_warning("Invalid prescale option, reverting to '1'\n");
video_config.prescale = 1;
}
// default to working video please
video_config.forcepow2texture = options().gl_force_pow2_texture();
video_config.allowtexturerect = !(options().gl_no_texture_rect());
video_config.vbo = options().gl_vbo();
video_config.pbo = options().gl_pbo();
video_config.glsl = options().gl_glsl();
if ( video_config.glsl )
{
int i;
video_config.glsl_filter = options().glsl_filter();
video_config.glsl_shader_mamebm_num=0;
for(i=0; i<GLSL_SHADER_MAX; i++)
{
stemp = options().shader_mame(i);
if (stemp && strcmp(stemp, OSDOPTVAL_NONE) != 0 && strlen(stemp)>0)
{
video_config.glsl_shader_mamebm[i] = (char *) malloc(strlen(stemp)+1);
strcpy(video_config.glsl_shader_mamebm[i], stemp);
video_config.glsl_shader_mamebm_num++;
} else {
video_config.glsl_shader_mamebm[i] = nullptr;
}
}
video_config.glsl_shader_scrn_num=0;
for(i=0; i<GLSL_SHADER_MAX; i++)
{
stemp = options().shader_screen(i);
if (stemp && strcmp(stemp, OSDOPTVAL_NONE) != 0 && strlen(stemp)>0)
{
video_config.glsl_shader_scrn[i] = (char *) malloc(strlen(stemp)+1);
strcpy(video_config.glsl_shader_scrn[i], stemp);
video_config.glsl_shader_scrn_num++;
} else {
video_config.glsl_shader_scrn[i] = nullptr;
}
}
} else {
int i;
video_config.glsl_filter = 0;
video_config.glsl_shader_mamebm_num=0;
for(i=0; i<GLSL_SHADER_MAX; i++)
{
video_config.glsl_shader_mamebm[i] = nullptr;
}
video_config.glsl_shader_scrn_num=0;
for(i=0; i<GLSL_SHADER_MAX; i++)
{
video_config.glsl_shader_scrn[i] = nullptr;
}
}
// misc options: sanity check values
// global options: sanity check values
if (video_config.numscreens < 1 || video_config.numscreens > MAX_VIDEO_WINDOWS)
{
osd_printf_warning("Invalid numscreens value %d; reverting to 1\n", video_config.numscreens);
video_config.numscreens = 1;
}
}
//============================================================
// get_resolution
//============================================================
static void get_resolution(const char *defdata, const char *data, osd_window_config *config, int report_error)
{
config->width = config->height = config->depth = config->refresh = 0;
if (strcmp(data, OSDOPTVAL_AUTO) == 0)
{
if (strcmp(defdata, OSDOPTVAL_AUTO) == 0)
return;
data = defdata;
}
if (sscanf(data, "%dx%dx%d", &config->width, &config->height, &config->depth) < 2 && report_error)
osd_printf_error("Illegal resolution value = %s\n", data);
const char * at_pos = strchr(data, '@');
if (at_pos)
if (sscanf(at_pos + 1, "%d", &config->refresh) < 1 && report_error)
osd_printf_error("Illegal refresh rate in resolution value = %s\n", data);
}

970
src/osd/mac/window.cpp Normal file
View File

@ -0,0 +1,970 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont
//============================================================
//
// window.cpp - Mac window handling
//
// Mac OSD by R. Belmont
//
//============================================================
// standard C headers
#include <math.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <list>
#include <memory>
// MAME headers
#include "emu.h"
#include "emuopts.h"
#include "render.h"
#include "ui/uimain.h"
// OSD headers
#include "window.h"
#include "osdmac.h"
#include "modules/render/drawbgfx.h"
#include "modules/render/drawogl.h"
#include "modules/monitor/monitor_common.h"
//============================================================
// PARAMETERS
//============================================================
// these are arbitrary values since AFAIK there's no way to make X/SDL tell you
#define WINDOW_DECORATION_WIDTH (8) // should be more than plenty
#define WINDOW_DECORATION_HEIGHT (48) // title bar + bottom drag region
// minimum window dimension
#define MIN_WINDOW_DIM 200
#define WMSZ_TOP (0)
#define WMSZ_BOTTOM (1)
#define WMSZ_BOTTOMLEFT (2)
#define WMSZ_BOTTOMRIGHT (3)
#define WMSZ_LEFT (4)
#define WMSZ_TOPLEFT (5)
#define WMSZ_TOPRIGHT (6)
#define WMSZ_RIGHT (7)
// debugger
//static int in_background;
//============================================================
// PROTOTYPES
//============================================================
//============================================================
// window_init
// (main thread)
//============================================================
bool mac_osd_interface::window_init()
{
osd_printf_verbose("Enter macwindow_init\n");
// initialize the drawers
switch (video_config.mode)
{
case VIDEO_MODE_BGFX:
renderer_bgfx::init(machine());
break;
case VIDEO_MODE_OPENGL:
renderer_ogl::init(machine());
break;
}
// set up the window list
osd_printf_verbose("Leave macwindow_init\n");
return true;
}
void mac_osd_interface::update_slider_list()
{
for (auto window : osd_common_t::s_window_list)
{
// check if any window has dirty sliders
if (window->renderer().sliders_dirty())
{
build_slider_list();
return;
}
}
}
void mac_osd_interface::build_slider_list()
{
m_sliders.clear();
for (auto window : osd_common_t::s_window_list)
{
std::vector<ui::menu_item> window_sliders = window->renderer().get_slider_list();
m_sliders.insert(m_sliders.end(), window_sliders.begin(), window_sliders.end());
}
}
//============================================================
// macwindow_exit
// (main thread)
//============================================================
void mac_osd_interface::window_exit()
{
osd_printf_verbose("Enter macwindow_exit\n");
// free all the windows
while (!osd_common_t::s_window_list.empty())
{
auto window = osd_common_t::s_window_list.front();
// Part of destroy removes the window from the list
window->destroy();
}
switch(video_config.mode)
{
case VIDEO_MODE_BGFX:
renderer_bgfx::exit();
break;
case VIDEO_MODE_OPENGL:
renderer_ogl::exit();
break;
default:
break;
}
osd_printf_verbose("Leave macwindow_exit\n");
}
void mac_window_info::capture_pointer()
{
if (!m_mouse_captured)
{
m_mouse_captured = true;
}
}
void mac_window_info::release_pointer()
{
if (m_mouse_captured)
{
m_mouse_captured = false;
}
}
void mac_window_info::hide_pointer()
{
if (!m_mouse_hidden)
{
m_mouse_hidden = true;
}
}
void mac_window_info::show_pointer()
{
if (m_mouse_hidden)
{
m_mouse_hidden = false;
}
}
//============================================================
// macwindow_resize
//============================================================
void mac_window_info::resize(int32_t width, int32_t height)
{
osd_dim cd = get_size();
if (width != cd.width() || height != cd.height())
{
// TODO: change window size here
renderer().notify_changed();
}
}
//============================================================
// notify_changed
//============================================================
void mac_window_info::notify_changed()
{
renderer().notify_changed();
}
//============================================================
// toggle_full_screen
//============================================================
void mac_window_info::toggle_full_screen()
{
// if we are in debug mode, never go full screen
if (machine().debug_flags & DEBUG_FLAG_OSD_ENABLED)
return;
// If we are going fullscreen (leaving windowed) remember our windowed size
if (!fullscreen())
{
m_windowed_dim = get_size();
}
// reset UI to main menu
machine().ui().menu_reset();
// kill off the drawers
renderer_reset();
if (fullscreen() && video_config.switchres)
{
}
//SDL_DestroyWindow(platform_window());
//set_platform_window(nullptr);
downcast<mac_osd_interface &>(machine().osd()).release_keys();
set_renderer(osd_renderer::make_for_type(video_config.mode, shared_from_this()));
// toggle the window mode
set_fullscreen(!fullscreen());
complete_create();
}
void mac_window_info::modify_prescale(int dir)
{
int new_prescale = prescale();
if (dir > 0 && prescale() < 3)
new_prescale = prescale() + 1;
if (dir < 0 && prescale() > 1)
new_prescale = prescale() - 1;
if (new_prescale != prescale())
{
if (m_fullscreen && video_config.switchres)
{
complete_destroy();
m_prescale = new_prescale;
complete_create();
}
else
{
notify_changed();
m_prescale = new_prescale;
}
machine().ui().popup_time(1, "Prescale %d", prescale());
}
}
//============================================================
// update_cursor_state
// (main or window thread)
//============================================================
void mac_window_info::update_cursor_state()
{
// do not do mouse capture if the debugger's enabled to avoid
// the possibility of losing control
if (!(machine().debug_flags & DEBUG_FLAG_OSD_ENABLED))
{
bool should_hide_mouse = downcast<mac_osd_interface&>(machine().osd()).should_hide_mouse();
if (!fullscreen() && !should_hide_mouse)
{
show_pointer();
release_pointer();
}
else
{
hide_pointer();
capture_pointer();
}
}
}
int mac_window_info::xy_to_render_target(int x, int y, int *xt, int *yt)
{
return renderer().xy_to_render_target(x, y, xt, yt);
}
//============================================================
// mac_window_info::window_init
// (main thread)
//============================================================
int mac_window_info::window_init()
{
int result;
// set the initial maximized state
// FIXME: Does not belong here
mac_options &options = downcast<mac_options &>(m_machine.options());
m_startmaximized = options.maximize();
// add us to the list
osd_common_t::s_window_list.push_back(std::static_pointer_cast<mac_window_info>(shared_from_this()));
set_renderer(osd_renderer::make_for_type(video_config.mode, static_cast<osd_window*>(this)->shared_from_this()));
// load the layout
m_target = m_machine.render().target_alloc();
// set the specific view
set_starting_view(m_index, options.view(), options.view(m_index));
// make the window title
if (video_config.numscreens == 1)
sprintf(m_title, "%s: %s [%s]", emulator_info::get_appname(), m_machine.system().type.fullname(), m_machine.system().name);
else
sprintf(m_title, "%s: %s [%s] - Screen %d", emulator_info::get_appname(), m_machine.system().type.fullname(), m_machine.system().name, m_index);
result = complete_create();
// handle error conditions
if (result == 1)
goto error;
return 0;
error:
destroy();
return 1;
}
//============================================================
// mac_window_info::complete_destroy
//============================================================
void mac_window_info::complete_destroy()
{
// Release pointer grab and hide if needed
show_pointer();
release_pointer();
if (fullscreen() && video_config.switchres)
{
}
//SDL_DestroyWindow(platform_window());
// release all keys ...
downcast<mac_osd_interface &>(machine().osd()).release_keys();
}
void mac_window_info::destroy()
{
// remove us from the list
osd_common_t::s_window_list.remove(std::static_pointer_cast<mac_window_info>(shared_from_this()));
// free the textures etc
complete_destroy();
// free the render target, after the textures!
machine().render().target_free(m_target);
}
//============================================================
// pick_best_mode
//============================================================
osd_dim mac_window_info::pick_best_mode()
{
// int minimum_width, minimum_height, target_width, target_height;
// int i;
// int num;
// float size_score, best_score = 0.0f;
osd_dim ret(0,0);
#if 0
// determine the minimum width/height for the selected target
m_target->compute_minimum_size(minimum_width, minimum_height);
// use those as the target for now
target_width = minimum_width * std::max(1, prescale());
target_height = minimum_height * std::max(1, prescale());
// if we're not stretching, allow some slop on the minimum since we can handle it
{
minimum_width -= 4;
minimum_height -= 4;
}
// FIXME: this should be provided by monitor !
num = SDL_GetNumDisplayModes(m_monitor->oshandle());
if (num == 0)
{
osd_printf_error("SDL: No modes available?!\n");
exit(-1);
}
else
{
for (i = 0; i < num; ++i)
{
SDL_DisplayMode mode;
SDL_GetDisplayMode(m_monitor->oshandle(), i, &mode);
// compute initial score based on difference between target and current
size_score = 1.0f / (1.0f + abs((int32_t)mode.w - target_width) + abs((int32_t)mode.h - target_height));
// if the mode is too small, give a big penalty
if (mode.w < minimum_width || mode.h < minimum_height)
size_score *= 0.01f;
// if mode is smaller than we'd like, it only scores up to 0.1
if (mode.w < target_width || mode.h < target_height)
size_score *= 0.1f;
// if we're looking for a particular mode, that's a winner
if (mode.w == m_win_config.width && mode.h == m_win_config.height)
size_score = 2.0f;
// refresh adds some points
if (m_win_config.refresh)
size_score *= 1.0f / (1.0f + abs(m_win_config.refresh - mode.refresh_rate) / 10.0f);
osd_printf_verbose("%4dx%4d@%2d -> %f\n", (int)mode.w, (int)mode.h, (int) mode.refresh_rate, (double) size_score);
// best so far?
if (size_score > best_score)
{
best_score = size_score;
ret = osd_dim(mode.w, mode.h);
}
}
}
#endif
return ret;
}
//============================================================
// sdlwindow_video_window_update
// (main thread)
//============================================================
void mac_window_info::update()
{
osd_ticks_t event_wait_ticks;
// adjust the cursor state
//sdlwindow_update_cursor_state(machine, window);
update_cursor_state();
// if we're visible and running and not in the middle of a resize, draw
if (m_target != nullptr)
{
int tempwidth, tempheight;
// see if the games video mode has changed
m_target->compute_minimum_size(tempwidth, tempheight);
if (osd_dim(tempwidth, tempheight) != m_minimum_dim)
{
m_minimum_dim = osd_dim(tempwidth, tempheight);
if (!this->m_fullscreen)
{
//Don't resize window without user interaction;
//window_resize(blitwidth, blitheight);
}
else if (video_config.switchres)
{
osd_dim tmp = this->pick_best_mode();
resize(tmp.width(), tmp.height());
}
}
if (video_config.waitvsync && video_config.syncrefresh)
event_wait_ticks = osd_ticks_per_second(); // block at most a second
else
event_wait_ticks = 0;
if (m_rendered_event.wait(event_wait_ticks))
{
const int update = 1;
// ensure the target bounds are up-to-date, and then get the primitives
render_primitive_list &primlist = *renderer().get_primitives();
// and redraw now
// Some configurations require events to be polled in the worker thread
downcast< mac_osd_interface& >(machine().osd()).process_events_buf();
// Check whether window has vector screens
{
const screen_device *screen = screen_device_iterator(machine().root_device()).byindex(m_index);
if ((screen != nullptr) && (screen->screen_type() == SCREEN_TYPE_VECTOR))
renderer().set_flags(osd_renderer::FLAG_HAS_VECTOR_SCREEN);
else
renderer().clear_flags(osd_renderer::FLAG_HAS_VECTOR_SCREEN);
}
m_primlist = &primlist;
// if no bitmap, just fill
if (m_primlist == nullptr)
{
}
// otherwise, render with our drawing system
else
{
if( video_config.perftest )
measure_fps(update);
else
renderer().draw(update);
}
/* all done, ready for next */
m_rendered_event.set();
}
}
}
//============================================================
// set_starting_view
// (main thread)
//============================================================
void mac_window_info::set_starting_view(int index, const char *defview, const char *view)
{
int viewindex;
// choose non-auto over auto
if (strcmp(view, "auto") == 0 && strcmp(defview, "auto") != 0)
view = defview;
// query the video system to help us pick a view
viewindex = target()->configured_view(view, index, video_config.numscreens);
// set the view
target()->set_view(viewindex);
}
//============================================================
// complete_create
//============================================================
extern void *CreateMAMEWindow(char *title, int x, int y, int w, int h, bool isFullscreen);
extern void *GetOSWindow(void *wincontroller);
int mac_window_info::complete_create()
{
osd_dim temp(0,0);
// clear out original mode. Needed on OSX
if (fullscreen())
{
// default to the current mode exactly
temp = monitor()->position_size().dim();
// if we're allowed to switch resolutions, override with something better
if (video_config.switchres)
temp = pick_best_mode();
}
else if (m_windowed_dim.width() > 0)
{
// if we have a remembered size force the new window size to it
temp = m_windowed_dim;
}
else if (m_startmaximized)
temp = get_max_bounds(video_config.keepaspect );
else
temp = get_min_bounds(video_config.keepaspect );
// create the window .....
osd_printf_verbose("Enter mac_window_info::complete_create\n");
// get monitor work area for centering
osd_rect work = monitor()->usuable_position_size();
auto window = CreateMAMEWindow(m_title,
work.left() + (work.width() - temp.width()) / 2,
work.top() + (work.height() - temp.height()) / 2,
temp.width(), temp.height(), fullscreen());
if (window == nullptr)
{
osd_printf_error("Window creation failed!\n");
return 1;
}
set_platform_window(window);
// set main window
if (m_index > 0)
{
for (auto w : osd_common_t::s_window_list)
{
if (w->m_index == 0)
{
set_main_window(std::dynamic_pointer_cast<osd_window>(w));
break;
}
}
}
else
{
// We must be the main window
set_main_window(shared_from_this());
}
// update monitor resolution after mode change to ensure proper pixel aspect
monitor()->refresh();
if (fullscreen() && video_config.switchres)
monitor()->update_resolution(temp.width(), temp.height());
// initialize the drawing backend
if (renderer().create())
{
osd_printf_verbose("Exiting mac_window_info::complete_create\n");
return 1;
}
return 0;
}
//============================================================
// draw_video_contents
// (window thread)
//============================================================
void mac_window_info::measure_fps(int update)
{
const unsigned long frames_skip4fps = 100;
static int64_t lastTime=0, sumdt=0, startTime=0;
static unsigned long frames = 0;
int64_t currentTime, t0;
double dt;
double tps;
osd_ticks_t tps_t;
tps_t = osd_ticks_per_second();
tps = (double) tps_t;
t0 = osd_ticks();
renderer().draw(update);
frames++;
currentTime = osd_ticks();
if(startTime==0||frames==frames_skip4fps)
startTime=currentTime;
if( frames>=frames_skip4fps )
sumdt+=currentTime-t0;
if( (currentTime-lastTime)>1L*osd_ticks_per_second() && frames>frames_skip4fps )
{
dt = (double) (currentTime-startTime) / tps; // in decimale sec.
osd_printf_info("%6.2lfs, %4lu F, "
"avrg game: %5.2lf FPS %.2lf ms/f, "
"avrg video: %5.2lf FPS %.2lf ms/f, "
"last video: %5.2lf FPS %.2lf ms/f\n",
dt, frames-frames_skip4fps,
(double)(frames-frames_skip4fps)/dt, // avrg game fps
( (currentTime-startTime) / ((frames-frames_skip4fps)) ) * 1000.0 / osd_ticks_per_second(),
(double)(frames-frames_skip4fps)/((double)(sumdt) / tps), // avrg vid fps
( sumdt / ((frames-frames_skip4fps)) ) * 1000.0 / tps,
1.0/((currentTime-t0) / osd_ticks_per_second()), // this vid fps
(currentTime-t0) * 1000.0 / tps
);
lastTime = currentTime;
}
}
int mac_window_info::wnd_extra_width()
{
return m_fullscreen ? 0 : WINDOW_DECORATION_WIDTH;
}
int mac_window_info::wnd_extra_height()
{
return m_fullscreen ? 0 : WINDOW_DECORATION_HEIGHT;
}
//============================================================
// constrain_to_aspect_ratio
// (window thread)
//============================================================
osd_rect mac_window_info::constrain_to_aspect_ratio(const osd_rect &rect, int adjustment)
{
int32_t extrawidth = wnd_extra_width();
int32_t extraheight = wnd_extra_height();
int32_t propwidth, propheight;
int32_t minwidth, minheight;
int32_t maxwidth, maxheight;
int32_t viswidth, visheight;
int32_t adjwidth, adjheight;
float pixel_aspect;
std::shared_ptr<osd_monitor_info> monitor = m_monitor;
// do not constrain aspect ratio for integer scaled views
if (m_target->scale_mode() != SCALE_FRACTIONAL)
return rect;
// get the pixel aspect ratio for the target monitor
pixel_aspect = monitor->pixel_aspect();
// determine the proposed width/height
propwidth = rect.width() - extrawidth;
propheight = rect.height() - extraheight;
// based on which edge we are adjusting, take either the width, height, or both as gospel
// and scale to fit using that as our parameter
switch (adjustment)
{
case WMSZ_BOTTOM:
case WMSZ_TOP:
m_target->compute_visible_area(10000, propheight, pixel_aspect, m_target->orientation(), propwidth, propheight);
break;
case WMSZ_LEFT:
case WMSZ_RIGHT:
m_target->compute_visible_area(propwidth, 10000, pixel_aspect, m_target->orientation(), propwidth, propheight);
break;
default:
m_target->compute_visible_area(propwidth, propheight, pixel_aspect, m_target->orientation(), propwidth, propheight);
break;
}
// get the minimum width/height for the current layout
m_target->compute_minimum_size(minwidth, minheight);
// clamp against the absolute minimum
propwidth = std::max(propwidth, MIN_WINDOW_DIM);
propheight = std::max(propheight, MIN_WINDOW_DIM);
// clamp against the minimum width and height
propwidth = std::max(propwidth, minwidth);
propheight = std::max(propheight, minheight);
// clamp against the maximum (fit on one screen for full screen mode)
if (m_fullscreen)
{
maxwidth = monitor->position_size().width() - extrawidth;
maxheight = monitor->position_size().height() - extraheight;
}
else
{
maxwidth = monitor->usuable_position_size().width() - extrawidth;
maxheight = monitor->usuable_position_size().height() - extraheight;
// further clamp to the maximum width/height in the window
if (m_win_config.width != 0)
maxwidth = std::min(maxwidth, m_win_config.width + extrawidth);
if (m_win_config.height != 0)
maxheight = std::min(maxheight, m_win_config.height + extraheight);
}
// clamp to the maximum
propwidth = std::min(propwidth, maxwidth);
propheight = std::min(propheight, maxheight);
// compute the visible area based on the proposed rectangle
m_target->compute_visible_area(propwidth, propheight, pixel_aspect, m_target->orientation(), viswidth, visheight);
// compute the adjustments we need to make
adjwidth = (viswidth + extrawidth) - rect.width();
adjheight = (visheight + extraheight) - rect.height();
// based on which corner we're adjusting, constrain in different ways
osd_rect ret(rect);
switch (adjustment)
{
case WMSZ_BOTTOM:
case WMSZ_BOTTOMRIGHT:
case WMSZ_RIGHT:
ret = rect.resize(rect.width() + adjwidth, rect.height() + adjheight);
break;
case WMSZ_BOTTOMLEFT:
ret = rect.move_by(-adjwidth, 0).resize(rect.width() + adjwidth, rect.height() + adjheight);
break;
case WMSZ_LEFT:
case WMSZ_TOPLEFT:
case WMSZ_TOP:
ret = rect.move_by(-adjwidth, -adjheight).resize(rect.width() + adjwidth, rect.height() + adjheight);
break;
case WMSZ_TOPRIGHT:
ret = rect.move_by(0, -adjheight).resize(rect.width() + adjwidth, rect.height() + adjheight);
break;
}
return ret;
}
//============================================================
// get_min_bounds
// (window thread)
//============================================================
osd_dim mac_window_info::get_min_bounds(int constrain)
{
int32_t minwidth, minheight;
//assert(GetCurrentThreadId() == window_threadid);
// get the minimum target size
m_target->compute_minimum_size(minwidth, minheight);
// expand to our minimum dimensions
if (minwidth < MIN_WINDOW_DIM)
minwidth = MIN_WINDOW_DIM;
if (minheight < MIN_WINDOW_DIM)
minheight = MIN_WINDOW_DIM;
// account for extra window stuff
minwidth += wnd_extra_width();
minheight += wnd_extra_height();
// if we want it constrained, figure out which one is larger
if (constrain && m_target->scale_mode() == SCALE_FRACTIONAL)
{
// first constrain with no height limit
osd_rect test1(0,0,minwidth,10000);
test1 = constrain_to_aspect_ratio(test1, WMSZ_BOTTOMRIGHT);
// then constrain with no width limit
osd_rect test2(0,0,10000,minheight);
test2 = constrain_to_aspect_ratio(test2, WMSZ_BOTTOMRIGHT);
// pick the larger
if (test1.width() > test2.width())
{
minwidth = test1.width();
minheight = test1.height();
}
else
{
minwidth = test2.width();
minheight = test2.height();
}
}
// remove extra window stuff
minwidth -= wnd_extra_width();
minheight -= wnd_extra_height();
return osd_dim(minwidth, minheight);
}
//============================================================
// get_size
//============================================================
osd_dim mac_window_info::get_size()
{
int w=0; int h=0;
// TODO: get window size from ObjC
// SDL_GetWindowSize(platform_window(), &w, &h);
return osd_dim(w,h);
}
//============================================================
// get_max_bounds
// (window thread)
//============================================================
osd_dim mac_window_info::get_max_bounds(int constrain)
{
//assert(GetCurrentThreadId() == window_threadid);
// compute the maximum client area
// m_monitor->refresh();
osd_rect maximum = m_monitor->usuable_position_size();
// clamp to the window's max
int tempw = maximum.width();
int temph = maximum.height();
if (m_win_config.width != 0)
{
int temp = m_win_config.width + wnd_extra_width();
if (temp < maximum.width())
tempw = temp;
}
if (m_win_config.height != 0)
{
int temp = m_win_config.height + wnd_extra_height();
if (temp < maximum.height())
temph = temp;
}
maximum = maximum.resize(tempw, temph);
// constrain to fit
if (constrain && m_target->scale_mode() == SCALE_FRACTIONAL)
maximum = constrain_to_aspect_ratio(maximum, WMSZ_BOTTOMRIGHT);
// remove extra window stuff
maximum = maximum.resize(maximum.width() - wnd_extra_width(), maximum.height() - wnd_extra_height());
return maximum.dim();
}
//============================================================
// construction and destruction
//============================================================
mac_window_info::mac_window_info(
running_machine &a_machine,
int index,
std::shared_ptr<osd_monitor_info> a_monitor,
const osd_window_config *config)
: osd_window_t(*config)
, m_next(nullptr)
, m_startmaximized(0)
// Following three are used by input code to defer resizes
, m_minimum_dim(0, 0)
, m_windowed_dim(0, 0)
, m_rendered_event(0, 1)
, m_target(nullptr)
, m_machine(a_machine)
, m_monitor(a_monitor)
, m_fullscreen(0)
, m_mouse_captured(false)
, m_mouse_hidden(false)
{
m_index = index;
//FIXME: these should be per_window in config-> or even better a bit set
m_fullscreen = !video_config.windowed;
m_prescale = video_config.prescale;
m_windowed_dim = osd_dim(config->width, config->height);
}
mac_window_info::~mac_window_info()
{
}
//============================================================
// osd_set_aggressive_input_focus
//============================================================
void osd_set_aggressive_input_focus(bool aggressive_focus)
{
// dummy implementation for now
}

134
src/osd/mac/window.h Normal file
View File

@ -0,0 +1,134 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont
//============================================================
//
// window.h - SDL window handling
//
// Mac OSD by R. Belmont
//
//============================================================
#ifndef __MACWINDOW__
#define __MACWINDOW__
#include "osdmac.h"
#include "video.h"
#include "modules/osdwindow.h"
#include <cstdint>
#include <memory>
#include <list>
//============================================================
// TYPE DEFINITIONS
//============================================================
class render_target;
typedef uintptr_t HashT;
#define OSDWORK_CALLBACK(name) void *name(void *param, ATTR_UNUSED int threadid)
class mac_window_info : public osd_window_t<void *>
{
public:
mac_window_info(running_machine &a_machine, int index, std::shared_ptr<osd_monitor_info> a_monitor,
const osd_window_config *config);
~mac_window_info();
int window_init();
void update() override;
void toggle_full_screen();
void modify_prescale(int dir);
void resize(int32_t width, int32_t height);
void destroy() override;
void capture_pointer() override;
void release_pointer() override;
void show_pointer() override;
void hide_pointer() override;
void notify_changed();
osd_dim get_size() override;
int xy_to_render_target(int x, int y, int *xt, int *yt);
running_machine &machine() const override { return m_machine; }
osd_monitor_info *monitor() const override { return m_monitor.get(); }
int fullscreen() const override { return m_fullscreen; }
render_target *target() override { return m_target; }
int prescale() const { return m_prescale; }
// Pointer to next window
mac_window_info * m_next;
private:
// window handle and info
char m_title[256];
int m_startmaximized;
// dimensions
osd_dim m_minimum_dim;
osd_dim m_windowed_dim;
// rendering info
osd_event m_rendered_event;
render_target * m_target;
//int m_extra_flags;
// returns 0 on success, else 1
int complete_create();
void complete_destroy();
private:
int wnd_extra_width();
int wnd_extra_height();
void set_starting_view(int index, const char *defview, const char *view);
osd_rect constrain_to_aspect_ratio(const osd_rect &rect, int adjustment);
osd_dim get_min_bounds(int constrain);
osd_dim get_max_bounds(int constrain);
void update_cursor_state();
osd_dim pick_best_mode();
void set_fullscreen(int afullscreen) { m_fullscreen = afullscreen; }
// Pointer to machine
running_machine & m_machine;
// monitor info
std::shared_ptr<osd_monitor_info> m_monitor;
int m_fullscreen;
bool m_mouse_captured;
bool m_mouse_hidden;
void measure_fps(int update);
};
struct osd_draw_callbacks
{
osd_renderer *(*create)(osd_window *window);
};
//============================================================
// PROTOTYPES
//============================================================
//============================================================
// PROTOTYPES - drawogl.c
//============================================================
int drawogl_init(running_machine &machine, osd_draw_callbacks *callbacks);
//============================================================
// PROTOTYPES - drawbgfx.c
//============================================================
int drawbgfx_init(running_machine &machine, osd_draw_callbacks *callbacks);
#endif /* __MACWINDOW__ */

View File

@ -0,0 +1,16 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
//============================================================
//
// windowcontroller.mm - our window/fullscreen manager
//
// Mac OSD by R. Belmont
//
//============================================================
#import <Cocoa/Cocoa.h>
#import "oglview.h"
@interface MAMEWindowController : NSWindowController
@end

View File

@ -0,0 +1,121 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
//============================================================
//
// windowcontroller.mm - our window/fullscreen manager
//
// Mac OSD by R. Belmont
//
//============================================================
#import "windowcontroller.h"
#import "mamefswindow.h"
@interface MAMEWindowController ()
{
MAMEFSWindow *_fullscreenWindow;
NSWindow* _standardWindow;
}
@end
@implementation MAMEWindowController
- (instancetype)initWithWindow:(NSWindow *)window
{
self = [super initWithWindow:window];
if (self)
{
_fullscreenWindow = nil;
_standardWindow = window;
}
return self;
}
- (void) goFullscreen
{
if(_fullscreenWindow)
{
return;
}
_fullscreenWindow = [[MAMEFSWindow alloc] init];
NSRect viewRect = [_fullscreenWindow frame];
[self.window.contentView setFrameSize: viewRect.size];
[_fullscreenWindow setContentView:self.window.contentView];
_standardWindow = [self window];
[_standardWindow orderOut:self];
[self setWindow:_fullscreenWindow];
[_fullscreenWindow makeKeyAndOrderFront:self];
}
- (void) goWindow
{
if(_fullscreenWindow == nil)
{
return;
}
NSRect viewRect = [_standardWindow frame];
[self.window.contentView setFrame:viewRect];
[self setWindow:_standardWindow];
[[self window] setContentView:_fullscreenWindow.contentView];
[[self window] makeKeyAndOrderFront:self];
_fullscreenWindow = nil;
}
- (void) keyDown:(NSEvent *)event
{
// unichar c = [[event charactersIgnoringModifiers] characterAtIndex:0];
[super keyDown:event];
}
- (NSWindow *) getWindow
{
if(_fullscreenWindow == nil)
{
return _standardWindow;
}
return _fullscreenWindow;
}
@end
void *GetOSWindow(void *wincontroller)
{
MAMEWindowController *wc = (MAMEWindowController *)wincontroller;
return [wc getWindow];
}
void *CreateMAMEWindow(char *title, int x, int y, int w, int h, bool isFullscreen)
{
NSRect bounds = NSMakeRect(x, y, w, h);
NSUInteger style = NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask;
NSWindow *window = [NSWindow alloc];
MAMEWindowController *controller = [MAMEWindowController alloc];
dispatch_sync(dispatch_get_main_queue(), ^{
[window initWithContentRect:bounds
styleMask:style
backing:NSBackingStoreBuffered
defer:NO];
[controller initWithWindow:window];
});
if (isFullscreen)
{
[controller goFullscreen];
}
[window makeKeyAndOrderFront:nil];
return (void *)controller;
}

View File

@ -32,6 +32,9 @@
#include "GL/wglext.h"
#endif
#endif
#elif defined(OSD_MAC)
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#else
#include <SDL2/SDL_version.h>

View File

@ -15,8 +15,12 @@
#include <SDL2/SDL_syswm.h>
#endif
#else
#if defined(OSD_MAC)
extern void *GetOSWindow(void *wincontroller);
#else
#include <SDL2/SDL_syswm.h>
#endif
#endif
// MAMEOS headers
#include "emu.h"
@ -143,6 +147,17 @@ inline void winSetHwnd(::HWND _window)
pd.backBufferDS = NULL;
bgfx::setPlatformData(pd);
}
#elif defined(OSD_MAC)
inline void macSetWindow(void *_window)
{
bgfx::PlatformData pd;
pd.ndt = NULL;
pd.nwh = GetOSWindow(_window);
pd.context = NULL;
pd.backBuffer = NULL;
pd.backBufferDS = NULL;
bgfx::setPlatformData(pd);
}
#elif defined(OSD_SDL)
static void* sdlNativeWindowHandle(SDL_Window* _window)
{
@ -240,6 +255,8 @@ int renderer_bgfx::create()
#elif defined(OSD_UWP)
winrtSetWindow(AsInspectable(std::static_pointer_cast<uwp_window_info>(win)->platform_window()));
#elif defined(OSD_MAC)
macSetWindow(std::static_pointer_cast<mac_window_info>(win)->platform_window());
#else
sdlSetWindow(std::dynamic_pointer_cast<sdl_window_info>(win)->platform_window());
#endif
@ -296,6 +313,8 @@ int renderer_bgfx::create()
m_framebuffer = m_targets->create_backbuffer(std::static_pointer_cast<win_window_info>(win)->platform_window(), m_width[win->m_index], m_height[win->m_index]);
#elif defined(OSD_UWP)
m_framebuffer = m_targets->create_backbuffer(AsInspectable(std::static_pointer_cast<uwp_window_info>(win)->platform_window()), m_width[win->m_index], m_height[win->m_index]);
#elif defined(OSD_MAC)
m_framebuffer = m_targets->create_backbuffer(GetOSWindow(std::static_pointer_cast<mac_window_info>(win)->platform_window()), m_width[win->m_index], m_height[win->m_index]);
#else
m_framebuffer = m_targets->create_backbuffer(sdlNativeWindowHandle(std::dynamic_pointer_cast<sdl_window_info>(win)->platform_window()), m_width[win->m_index], m_height[win->m_index]);
#endif
@ -949,6 +968,8 @@ bool renderer_bgfx::update_dimensions()
m_framebuffer = m_targets->create_backbuffer(std::static_pointer_cast<win_window_info>(win)->platform_window(), width, height);
#elif defined(OSD_UWP)
m_framebuffer = m_targets->create_backbuffer(AsInspectable(std::static_pointer_cast<uwp_window_info>(win)->platform_window()), width, height);
#elif defined(OSD_MAC)
m_framebuffer = m_targets->create_backbuffer(GetOSWindow(std::static_pointer_cast<mac_window_info>(win)->platform_window()), width, height);
#else
m_framebuffer = m_targets->create_backbuffer(sdlNativeWindowHandle(std::dynamic_pointer_cast<sdl_window_info>(win)->platform_window()), width, height);
#endif

View File

@ -21,7 +21,11 @@
#include "emu.h"
#include "emuopts.h"
#ifndef OSD_WINDOWS
#ifdef OSD_MAC
#define GL_SILENCE_DEPRECATION (1)
#endif
#if !defined(OSD_WINDOWS) && !defined(OSD_MAC)
// standard SDL headers
#define TOBEMIGRATED 1
#include <SDL2/SDL.h>
@ -36,7 +40,7 @@
#include "modules/opengl/gl_shader_tool.h"
#include "modules/opengl/gl_shader_mgr.h"
#if defined(SDLMAME_MACOSX)
#if defined(SDLMAME_MACOSX) || defined(OSD_MAC)
#ifndef APIENTRY
#define APIENTRY
#endif
@ -237,7 +241,7 @@ void renderer_ogl::set_blendmode(int blendmode)
//============================================================
// OGL 1.3
#ifdef GL_ARB_multitexture
#if defined(GL_ARB_multitexture) && !defined(OSD_MAC)
static PFNGLACTIVETEXTUREARBPROC pfn_glActiveTexture = nullptr;
#else
static PFNGLACTIVETEXTUREPROC pfn_glActiveTexture = nullptr;
@ -558,6 +562,9 @@ int renderer_ogl::create()
// create renderer
#if defined(OSD_WINDOWS)
m_gl_context = global_alloc(win_gl_context(std::static_pointer_cast<win_window_info>(win)->platform_window()));
#elif defined(OSD_MAC)
// TODO
// m_gl_context = global_alloc(mac_gl_context(std::static_pointer_cast<mac_window_info>(win)->platform_window()));
#else
m_gl_context = global_alloc(sdl_gl_context(std::static_pointer_cast<sdl_window_info>(win)->platform_window()));
#endif
@ -886,7 +893,7 @@ void renderer_ogl::loadGLExtensions()
if ( m_useglsl )
{
#ifdef GL_ARB_multitexture
#if defined(GL_ARB_multitexture) && !defined(OSD_MAC)
pfn_glActiveTexture = (PFNGLACTIVETEXTUREARBPROC) m_gl_context->getProcAddress("glActiveTextureARB");
#else
pfn_glActiveTexture = (PFNGLACTIVETEXTUREPROC) m_gl_context->getProcAddress("glActiveTexture");

View File

@ -15,7 +15,11 @@
// OSD headers
#ifndef OSD_WINDOWS
#ifdef OSD_MAC
#include "osdmac.h"
#else
#include "osdsdl.h"
#endif
#include "window.h"
#else
#include "../windows/window.h"
@ -24,6 +28,7 @@ typedef uint64_t HashT;
#if defined(OSD_WINDOWS)
#include "winglcontext.h"
#elif defined (OSD_MAC)
#else
#include "sdlglcontext.h"
#endif