diff --git a/build.sh b/build.sh index be3f2c60fe..4fcdddd3ff 100755 --- a/build.sh +++ b/build.sh @@ -26,6 +26,21 @@ CoverityBuild=0 cppcheck=0 clangTidy=0 +if [[ $(uname -s) == 'Darwin' ]]; then + ncpu=$(sysctl -n hw.ncpu) + release=$(uname -r) + if [[ ${release:0:2} -lt 13 ]]; then + echo "This old OSX version is not supported! Build will fail." + toolfile=cmake/darwin-compiler-i386-clang.cmake + else + echo "Using Mavericks build with C++11 support." + toolfile=cmake/darwin13-compiler-i386-clang.cmake + fi +else + ncpu=$(grep -w -c processor /proc/cpuinfo) + toolfile=cmake/linux-compiler-i386-multilib.cmake +fi + for ARG in "$@"; do case "$ARG" in --clean ) cleanBuild=1 ;; @@ -44,7 +59,7 @@ for ARG in "$@"; do --wx28 ) flags+=(-DWX28_API=TRUE) ;; --gtk3 ) flags+=(-DGTK3_API=TRUE) ;; --no-simd ) flags+=(-DDISABLE_ADVANCE_SIMD=TRUE) ;; - --cross-multilib ) flags+=(-DCMAKE_TOOLCHAIN_FILE=cmake/linux-compiler-i386-multilib.cmake); useCross=1; ;; + --cross-multilib ) flags+=(-DCMAKE_TOOLCHAIN_FILE=$toolfile); useCross=1; ;; --no-cross-multilib ) useCross=0; ;; --coverity ) CoverityBuild=1; cleanBuild=1; ;; -D* ) flags+=($ARG) ;; @@ -98,7 +113,7 @@ fi if [[ "$useCross" -eq 2 ]] && [[ "$(getconf LONG_BIT 2> /dev/null)" != 32 ]]; then echo "Forcing cross compilation." - flags+=(-DCMAKE_TOOLCHAIN_FILE=cmake/linux-compiler-i386-multilib.cmake) + flags+=(-DCMAKE_TOOLCHAIN_FILE=$toolfile) elif [[ "$useCross" -ne 1 ]]; then useCross=0 fi @@ -125,11 +140,7 @@ else cmake "${flags[@]}" $root 2>&1 | tee -a $log fi -if [[ $(uname -s) == 'Darwin' ]]; then - ncpu=$(sysctl -n hw.ncpu) -else - ncpu=$(grep -w -c processor /proc/cpuinfo) -fi + ############################################################ # CPP check build @@ -151,7 +162,7 @@ if [[ "$cppcheck" -eq 1 ]] && [[ -x `which cppcheck` ]]; then log=cpp_check__${flat_d}.log rm -f $log - cppcheck $check -j $ncpu --platform=unix32 $define $root/$d |& tee $log + cppcheck $check -j $ncpu --platform=unix32 $define $root/$d 2>&1 | tee $log # Create a small summary (warning it might miss some issues) fgrep -e "(warning)" -e "(error)" -e "(style)" -e "(performance)" -e "(portability)" $log >> $summary done diff --git a/cmake/BuildParameters.cmake b/cmake/BuildParameters.cmake index 889c0ba062..88f702911e 100644 --- a/cmake/BuildParameters.cmake +++ b/cmake/BuildParameters.cmake @@ -250,7 +250,9 @@ set(AGGRESSIVE_WARNING "-Wstrict-aliasing -Wstrict-overflow=2 ") if (USE_CLANG) # -Wno-deprecated-register: glib issue... set(DEFAULT_WARNINGS "${DEFAULT_WARNINGS} -Wno-deprecated-register") - set(COMMON_FLAG "${COMMON_FLAG} -no-integrated-as") + if (NOT APPLE) + set(COMMON_FLAG "${COMMON_FLAG} -no-integrated-as") + endif() set(DBG "-g") else() set(DBG "-ggdb") diff --git a/cmake/FindLibc.cmake b/cmake/FindLibc.cmake index 848528bea1..1456ae974a 100644 --- a/cmake/FindLibc.cmake +++ b/cmake/FindLibc.cmake @@ -7,10 +7,16 @@ if(LIBC_LIBRARIES) set(LIBC_FIND_QUIETLY TRUE) endif(LIBC_LIBRARIES) -find_library(librt NAMES rt) find_library(libdl NAMES dl) find_library(libm NAMES m) -set(LIBC_LIBRARIES ${librt} ${libdl} ${libm}) + +# OSX doesn't have rt. On Linux timer and aio dependency. +if(APPLE) + set(LIBC_LIBRARIES ${librt} ${libdl} ${libm}) +else() + find_library(librt NAMES rt) + set(LIBC_LIBRARIES ${librt} ${libdl} ${libm}) +endif() # handle the QUIETLY and REQUIRED arguments and set LIBC_FOUND to TRUE if # all listed variables are TRUE diff --git a/cmake/SearchForStuff.cmake b/cmake/SearchForStuff.cmake index 62d41b01a7..04c56018ce 100644 --- a/cmake/SearchForStuff.cmake +++ b/cmake/SearchForStuff.cmake @@ -31,9 +31,9 @@ else() list(APPEND wxWidgets_CONFIG_OPTIONS --version=3.0) endif() -if(GTK3_API) +if(GTK3_API AND NOT APPLE) list(APPEND wxWidgets_CONFIG_OPTIONS --toolkit=gtk3) -else() +elseif(NOT APPLE) list(APPEND wxWidgets_CONFIG_OPTIONS --toolkit=gtk2) endif() diff --git a/cmake/SelectPcsx2Plugins.cmake b/cmake/SelectPcsx2Plugins.cmake index baa464a037..a0cd3c5ccb 100644 --- a/cmake/SelectPcsx2Plugins.cmake +++ b/cmake/SelectPcsx2Plugins.cmake @@ -31,6 +31,8 @@ endmacro(print_dep) #------------------------------------------------------------------------------- if (GTK2_FOUND OR GTK3_FOUND) set(GTKn_FOUND TRUE) +elseif(APPLE) # Not we have but that we don't change all if(gtkn) entries + set(GTKn_FOUND TRUE) else() set(GTKn_FOUND FALSE) endif() @@ -71,8 +73,8 @@ else() set(pcsx2_core FALSE) print_dep("Skip build of pcsx2 core: miss some dependencies" "${msg_dep_pcsx2}") endif() -# Linux need also gtk2 -if(UNIX AND pcsx2_core AND NOT GTKn_FOUND) +# Linux, BSD, use gtk2, but not OSX +if(UNIX AND pcsx2_core AND NOT GTKn_FOUND AND NOT APPLE) set(pcsx2_core FALSE) print_dep("Skip build of pcsx2 core: miss some dependencies" "${msg_dep_pcsx2}") endif() @@ -253,7 +255,8 @@ endif() # -SDL # -common_libs #--------------------------------------- -if(ALSA_FOUND AND PORTAUDIO_FOUND AND SOUNDTOUCH_FOUND AND SDLn_FOUND AND common_libs) +if((APPLE AND PORTAUDIO_FOUND AND SOUNDTOUCH_FOUND AND SDLn_FOUND AND common_libs) + OR (LINUX AND ALSA_FOUND AND PORTAUDIO_FOUND AND SOUNDTOUCH_FOUND AND SDLn_FOUND AND common_libs)) set(spu2-x TRUE) elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/plugins/spu2-x") set(spu2-x FALSE) diff --git a/cmake/darwin13-compiler-i386-clang.cmake b/cmake/darwin13-compiler-i386-clang.cmake new file mode 100644 index 0000000000..40785dbd7f --- /dev/null +++ b/cmake/darwin13-compiler-i386-clang.cmake @@ -0,0 +1,20 @@ +# Tell cmake we are cross compiling and targeting darwin +#set(CMAKE_SYSTEM_NAME Darwin) +#set(CMAKE_SYSTEM_PROCESSOR i686) + +# Use clang and target i686-apple-darwin13.0.0 (Mavericks) +set(CMAKE_C_COMPILER clang -m32) +#set(CMAKE_C_COMPILER_TARGET i686-apple-darwin13.0.0) +set(CMAKE_CXX_COMPILER clang++ -m32) +#set(CMAKE_CXX_COMPILER_TARGET i686-apple-darwin13.0.0) + +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpmath=sse -msse2") +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse -msse2") + +# If given a CMAKE_FIND_ROOT_PATH then +# FIND_PROGRAM ignores CMAKE_FIND_ROOT_PATH (probably can't run) +# FIND_{LIBRARY,INCLUDE,PACKAGE} only uses the files in CMAKE_FIND_ROOT_PATH. +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) diff --git a/common/include/PS2Eext.h b/common/include/PS2Eext.h index 1ffb27dfc7..b6aaaf1d57 100644 --- a/common/include/PS2Eext.h +++ b/common/include/PS2Eext.h @@ -20,17 +20,24 @@ #include #include -#ifdef _MSC_VER +#if defined(_MSC_VER) #include #include #include #define EXPORT_C_(type) extern "C" type CALLBACK -#else + +#elif defined(GTK_MAJOR_VERSION) + #include #include #define EXPORT_C_(type) extern "C" __attribute__((stdcall,externally_visible,visibility("default"))) type + +#else + +#define EXPORT_C_(type) extern "C" __attribute__((stdcall,externally_visible,visibility("default"))) type + #endif //#include "PS2Edefs.h" @@ -183,7 +190,7 @@ struct PluginConf } }; -#ifdef __linux__ +#if defined(GTK_MAJOR_VERSION) static void SysMessage(const char *fmt, ...) { @@ -243,6 +250,48 @@ static void __forceinline PluginNullAbout(const char *aboutText) #define ENTRY_POINT /* We don't need no stinkin' entry point! */ + +#elif defined(__WXMAC__) || defined(__APPLE__) + +static void SysMessage(const char *fmt, ...) +{ + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + if (msg[strlen(msg)-1] == '\n') msg[strlen(msg)-1] = 0; + + // TODO OSX can we use WX MessageBox here or should Cocoa MessageBox used? +} + +static void SysMessage(const wchar_t *fmt, ...) +{ + va_list list; + wchar_t msg[512]; + + va_start(list, fmt); + //vsprintf(msg, fmt, list); + va_end(list); + + // TODO OSX can we use WX MessageBox here or should Cocoa MessageBox used? +} + +static void __forceinline PluginNullConfigure(std::string desc, int &log) +{ + SysMessage("This space intentionally left blank."); +} + +static void __forceinline PluginNullAbout(const char *aboutText) +{ + SysMessage(aboutText); +} + +#define ENTRY_POINT /* We don't need no stinkin' entry point! */ // TODO OSX WTF is this anyway? + + #else #define usleep(x) Sleep(x / 1000) diff --git a/common/include/Pcsx2Defs.h b/common/include/Pcsx2Defs.h index 528521b6e0..0aaf732026 100644 --- a/common/include/Pcsx2Defs.h +++ b/common/include/Pcsx2Defs.h @@ -23,6 +23,14 @@ #define __linux__ #endif +// make sure __POSIX__ is defined for all systems where we assume POSIX +// compliance +#if defined(__linux__) || defined(__APPLE__) || defined(__unix__) || defined(__CYGWIN__) || defined(__LINUX__) +# if !defined(__POSIX__) +# define __POSIX__ 1 +# endif +#endif + #include "Pcsx2Types.h" #ifdef _MSC_VER diff --git a/common/include/Utilities/MemcpyFast.h b/common/include/Utilities/MemcpyFast.h index 4200e22ba6..3efa3bbf2d 100644 --- a/common/include/Utilities/MemcpyFast.h +++ b/common/include/Utilities/MemcpyFast.h @@ -15,7 +15,7 @@ #pragma once -#ifdef __linux__ +#if defined(__POSIX__) # include "lnx_memzero.h" #else # include "win_memzero.h" diff --git a/common/include/Utilities/PageFaultSource.h b/common/include/Utilities/PageFaultSource.h index a22b32b66e..8868c8f3df 100644 --- a/common/include/Utilities/PageFaultSource.h +++ b/common/include/Utilities/PageFaultSource.h @@ -271,7 +271,7 @@ protected: virtual void CommitBlocks( uptr page, uint blocks ); }; -#ifdef __linux__ +#ifdef __POSIX__ # define PCSX2_PAGEFAULT_PROTECT # define PCSX2_PAGEFAULT_EXCEPT diff --git a/common/include/Utilities/Threading.h b/common/include/Utilities/Threading.h index 7751204dbd..e21522ae2e 100644 --- a/common/include/Utilities/Threading.h +++ b/common/include/Utilities/Threading.h @@ -19,6 +19,10 @@ #include // EBUSY #include +#ifdef __APPLE__ +#include +#endif + #include "Pcsx2Defs.h" #include "ScopedPtr.h" #include "TraceLog.h" @@ -66,11 +70,7 @@ extern ConsoleLogSource_Threading pxConLog_Thread; //#define PCSX2_THREAD_LOCAL 0 // uncomment this line to force-disable native TLS (useful for testing TlsVariable on windows/linux) #ifndef PCSX2_THREAD_LOCAL -# ifdef __WXMAC__ -# define PCSX2_THREAD_LOCAL 0 -# else -# define PCSX2_THREAD_LOCAL 1 -# endif +# define PCSX2_THREAD_LOCAL 1 #endif class wxTimeSpan; @@ -252,7 +252,12 @@ namespace Threading class Semaphore { protected: +#ifdef __APPLE__ + semaphore_t m_sema; + int m_counter; +#else sem_t m_sema; +#endif public: Semaphore(); diff --git a/common/src/Utilities/CMakeLists.txt b/common/src/Utilities/CMakeLists.txt index c58a4f4d22..dea7c7dcc8 100644 --- a/common/src/Utilities/CMakeLists.txt +++ b/common/src/Utilities/CMakeLists.txt @@ -44,6 +44,7 @@ endif(CMAKE_BUILD_TYPE STREQUAL Release) # variable with all sources of this library set(UtilitiesSources + VirtualMemory.cpp AlignedMalloc.cpp ../../include/Utilities/FixedPointTypes.inl ../../include/Utilities/EventSource.inl @@ -57,8 +58,6 @@ set(UtilitiesSources HashTools.cpp IniInterface.cpp Linux/LnxHostSys.cpp - Linux/LnxMisc.cpp - Linux/LnxThreads.cpp Mutex.cpp PathUtils.cpp PrecompiledHeader.cpp @@ -68,12 +67,10 @@ set(UtilitiesSources pxStreams.cpp pxTranslate.cpp pxWindowTextWriter.cpp - Semaphore.cpp StringHelpers.cpp ThreadingDialogs.cpp ThreadTools.cpp vssprintf.cpp - VirtualMemory.cpp wxAppWithHelpers.cpp wxGuiTools.cpp wxHelpers.cpp @@ -112,7 +109,22 @@ set(UtilitiesHeaders ../../include/Utilities/wxAppWithHelpers.h ../../include/Utilities/wxBaseTools.h ../../include/Utilities/wxGuiTools.h - PrecompiledHeader.h) + PrecompiledHeader.h +) + +if(APPLE) + LIST(APPEND UtilitiesSources + Darwin/DarwinThreads.cpp + Darwin/DarwinMisc.cpp + Darwin/DarwinSemaphore.cpp + ) +else() + LIST(APPEND UtilitiesSources + Linux/LnxThreads.cpp + Linux/LnxMisc.cpp + Semaphore.cpp + ) +endif() set(UtilitiesFinalSources ${UtilitiesSources} diff --git a/common/src/Utilities/Console.cpp b/common/src/Utilities/Console.cpp index 97f1623469..9761b43b7e 100644 --- a/common/src/Utilities/Console.cpp +++ b/common/src/Utilities/Console.cpp @@ -32,7 +32,7 @@ static DeclareTls(ConsoleColors) conlog_Color( DefaultConsoleColor ); static wxString m_buffer; // used by ConsoleBuffer static Mutex m_bufferlock; // used by ConsoleBuffer -#ifdef __linux__ +#ifdef __POSIX__ static FILE *stdout_fp = stdout; void Console_SetStdout(FILE *fp) diff --git a/common/src/Utilities/Darwin/DarwinMisc.cpp b/common/src/Utilities/Darwin/DarwinMisc.cpp new file mode 100644 index 0000000000..a8624ece0e --- /dev/null +++ b/common/src/Utilities/Darwin/DarwinMisc.cpp @@ -0,0 +1,150 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2014 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "../PrecompiledHeader.h" + +#include +#include + +#include +#include + +#include + +#define NELEM(x) \ + ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) + +// Darwin (OSX) is a bit different from Linux when requesting properties of +// the OS because of its BSD/Mach heritage. Helpfully, most of this code +// should translate pretty well to other *BSD systems. (e.g.: the sysctl(3) +// interface). +// +// For an overview of all of Darwin's sysctls, check: +// https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/sysctl.3.html + +// Return the total physical memory on the machine, in bytes. Returns 0 on +// failure (not supported by the operating system). +u64 GetPhysicalMemory() +{ + static u64 mem = 0; + + // fetch the total memory only once, as its an expensive system call and + // doesn't change during the course of the program. Thread-safety is + // ensured by atomic operations with full-barriers (usually compiled + // down to XCHG on x86). + if (__atomic_load_n(&mem, __ATOMIC_SEQ_CST) == 0) { + u64 getmem = 0; + size_t len = sizeof(getmem); + int mib[] = { CTL_HW, HW_MEMSIZE }; + if (sysctl(mib, NELEM(mib), &getmem, &len, NULL, 0) < 0) { + perror("sysctl:"); + } + __atomic_store_n(&mem, getmem, __ATOMIC_SEQ_CST); + } + + return mem; +} + +void InitCPUTicks() +{ +} + +// returns the performance-counter frequency: ticks per second (Hz) +// +// usage: +// u64 seconds_passed = GetCPUTicks() / GetTickFrequency(); +// u64 millis_passed = (GetCPUTicks() * 1000) / GetTickFrequency(); +// +// NOTE: multiply, subtract, ... your ticks before dividing by +// GetTickFrequency() to maintain good precision. +u64 GetTickFrequency() +{ + static u64 freq = 0; + + // by the time denom is not 0, the structure will have been fully + // updated and no more atomic accesses are necessary. + if (__atomic_load_n(&freq, __ATOMIC_SEQ_CST) == 0) { + mach_timebase_info_data_t info; + + // mach_timebase_info() is a syscall, very slow, that's why we take + // pains to only do it once. On x86(-64), the result is guaranteed + // to be info.denom == info.numer == 1 (i.e.: the frequency is 1e9, + // which means GetCPUTicks is just nanoseconds). + if (mach_timebase_info(&info) != KERN_SUCCESS) { + abort(); + } + + // store the calculated value atomically + __atomic_store_n(&freq, (u64) 1e9 * (u64) info.denom / (u64) info.numer, __ATOMIC_SEQ_CST); + } + + return freq; +} + +// return the number of "ticks" since some arbitrary, fixed time in the +// past. On OSX x86(-64), this is actually the number of nanoseconds passed, +// because mach_timebase_info.numer == denom == 1. So "ticks" == +// nanoseconds. +u64 GetCPUTicks() +{ + return mach_absolute_time(); +} + +wxString GetOSVersionString() +{ + wxString version; + static int initialized = 0; + + // fetch the OS description only once (thread-safely) + if (__atomic_load_n(&initialized, __ATOMIC_SEQ_CST) == 0) { + char type[32] = {0}; + char release[32] = {0}; + char arch[32] = {0}; + +#define SYSCTL_GET(var, base, name) \ + do { \ + int mib[] = { base, name }; \ + size_t len = sizeof(var); \ + sysctl(mib, NELEM(mib), NULL, &len, NULL, 0); \ + sysctl(mib, NELEM(mib), var, &len, NULL, 0); \ + } while (0) + + SYSCTL_GET(release, CTL_KERN, KERN_OSRELEASE); + SYSCTL_GET(type, CTL_KERN, KERN_OSTYPE); + SYSCTL_GET(arch, CTL_HW, HW_MACHINE); + +#undef SYSCTL_KERN + + // I know strcat is not good, but stpcpy is not universally + // available yet. + char buf[128] = {0}; + strcat(buf, type); + strcat(buf, " "); + strcat(buf, release); + strcat(buf, " "); + strcat(buf, arch); + + version = buf; + + __atomic_store_n(&initialized, 1, __ATOMIC_SEQ_CST); + } + + return version; +} + +void ScreensaverAllow(bool allow) +{ + // no-op +} diff --git a/common/src/Utilities/Darwin/DarwinSemaphore.cpp b/common/src/Utilities/Darwin/DarwinSemaphore.cpp new file mode 100644 index 0000000000..8171a54d5c --- /dev/null +++ b/common/src/Utilities/Darwin/DarwinSemaphore.cpp @@ -0,0 +1,243 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2014 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include +#include // assert + +#include // pthread_setcancelstate() + +#include // gettimeofday() + +#include +#include // semaphore_create() and semaphore_destroy() +#include // semaphore_*() +#include // mach_error_string() +#include // mach_absolute_time() + +#include "PrecompiledHeader.h" + +#include "Threading.h" +#include "ThreadingInternal.h" + +#include "wxBaseTools.h" +#include "wxGuiTools.h" + +// -------------------------------------------------------------------------------------- +// Semaphore Implementation for Darwin/OSX +// +// Sadly, Darwin/OSX needs its own implementation of Semaphores instead of +// relying on phtreads, because OSX unnamed semaphore (the best kind) +// support is very poor. +// +// This implementation makes use of Mach primitives instead. These are also +// what Grand Central Dispatch (GCD) is based on, as far as I understand: +// http://newosxbook.com/articles/GCD.html. +// +// -------------------------------------------------------------------------------------- + +#define MACH_CHECK(mach_retval) \ + do { \ + kern_return_t _kr = (mach_retval); \ + if (_kr != KERN_SUCCESS) { \ + fprintf(stderr, "mach error: %s", mach_error_string(_kr)); \ + assert(_kr == KERN_SUCCESS); \ + } \ + } while (0) + +Threading::Semaphore::Semaphore() +{ + // other platforms explicitly make a thread-private (unshared) semaphore + // here. But it seems Mach doesn't support that. + MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t *)&m_sema, SYNC_POLICY_FIFO, 0)); + __atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST); +} + +Threading::Semaphore::~Semaphore() throw() +{ + MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t) m_sema)); + __atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST); +} + +void Threading::Semaphore::Reset() +{ + MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t) m_sema)); + MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t *) &m_sema, SYNC_POLICY_FIFO, 0)); + __atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST); +} + +void Threading::Semaphore::Post() +{ + MACH_CHECK(semaphore_signal(m_sema)); + __atomic_add_fetch(&m_counter, 1, __ATOMIC_SEQ_CST); +} + +void Threading::Semaphore::Post(int multiple) +{ + for (int i = 0; i < multiple; ++i) { + MACH_CHECK(semaphore_signal(m_sema)); + } + __atomic_add_fetch(&m_counter, multiple, __ATOMIC_SEQ_CST); +} + +void Threading::Semaphore::WaitWithoutYield() +{ + pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead."); + MACH_CHECK(semaphore_wait(m_sema)); + __atomic_sub_fetch(&m_counter, 1, __ATOMIC_SEQ_CST); +} + +bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan& timeout) +{ + // This method is the reason why there has to be a special Darwin + // implementation of Semaphore. Note that semaphore_timedwait() is prone + // to returning with KERN_ABORTED, which basically signifies that some + // signal has worken it up. The best official "documentation" for + // semaphore_timedwait() is the way it's used in Grand Central Dispatch, + // which is open-source. + + // on x86 platforms, mach_absolute_time() returns nanoseconds + // TODO(aktau): on iOS a scale value from mach_timebase_info will be necessary + u64 const kOneThousand = 1000; + u64 const kOneBillion = kOneThousand * kOneThousand * kOneThousand; + u64 const delta = timeout.GetMilliseconds().GetValue() * (kOneThousand * kOneThousand); + mach_timespec_t ts; + kern_return_t kr = KERN_ABORTED; + for (u64 now = mach_absolute_time(), deadline = now + delta; + kr == KERN_ABORTED; now = mach_absolute_time()) { + if (now > deadline) { + // timed out by definition + return false; + } + + u64 timeleft = deadline - now; + ts.tv_sec = timeleft / kOneBillion; + ts.tv_nsec = timeleft % kOneBillion; + + // possible return values of semaphore_timedwait() (from XNU sources): + // internal kernel val -> return value + // THREAD_INTERRUPTED -> KERN_ABORTED + // THREAD_TIMED_OUT -> KERN_OPERATION_TIMED_OUT + // THREAD_AWAKENED -> KERN_SUCCESS + // THREAD_RESTART -> KERN_TERMINATED + // default -> KERN_FAILURE + kr = semaphore_timedwait(m_sema, ts); + } + + if (kr == KERN_OPERATION_TIMED_OUT) { + return false; + } + + // while it's entirely possible to have KERN_FAILURE here, we should + // probably assert so we can study and correct the actual error here + // (the thread dying while someone is wainting for it). + MACH_CHECK(kr); + + __atomic_sub_fetch(&m_counter, 1, __ATOMIC_SEQ_CST); + return true; +} + +// This is a wxApp-safe implementation of Wait, which makes sure and executes the App's +// pending messages *if* the Wait is performed on the Main/GUI thread. This ensures that +// user input continues to be handled and that windows continue to repaint. If the Wait is +// called from another thread, no message pumping is performed. +void Threading::Semaphore::Wait() +{ +#if wxUSE_GUI + if(!wxThread::IsMain() || (wxTheApp == NULL)) { + WaitWithoutYield(); + } + else if(_WaitGui_RecursionGuard( L"Semaphore::Wait" )) { + ScopedBusyCursor hourglass( Cursor_ReallyBusy ); + WaitWithoutYield(); + } + else { + while (!WaitWithoutYield(def_yieldgui_interval)) { + YieldToMain(); + } + } +#else + WaitWithoutYield(); +#endif +} + +// This is a wxApp-safe implementation of WaitWithoutYield, which makes sure and executes the App's +// pending messages *if* the Wait is performed on the Main/GUI thread. This ensures that +// user input continues to be handled and that windows continue to repaint. If the Wait is +// called from another thread, no message pumping is performed. +// +// Returns: +// false if the wait timed out before the semaphore was signaled, or true if the signal was +// reached prior to timeout. +// +bool Threading::Semaphore::Wait(const wxTimeSpan& timeout) +{ +#if wxUSE_GUI + if(!wxThread::IsMain() || (wxTheApp == NULL)) { + return WaitWithoutYield(timeout); + } + else if (_WaitGui_RecursionGuard( L"Semaphore::TimedWait")) { + ScopedBusyCursor hourglass(Cursor_ReallyBusy); + return WaitWithoutYield(timeout); + } + else { + //ScopedBusyCursor hourglass( Cursor_KindaBusy ); + wxTimeSpan countdown((timeout)); + + do { + if (WaitWithoutYield(def_yieldgui_interval)) break; + YieldToMain(); + countdown -= def_yieldgui_interval; + } while (countdown.GetMilliseconds() > 0); + + return countdown.GetMilliseconds() > 0; + } +#else + return WaitWithoutYield(timeout); +#endif +} + +// Performs an uncancellable wait on a semaphore; restoring the thread's previous cancel state +// after the wait has completed. Useful for situations where the semaphore itself is stored on +// the stack and passed to another thread via GUI message or such, avoiding complications where +// the thread might be canceled and the stack value becomes invalid. +// +// Performance note: this function has quite a bit more overhead compared to Semaphore::WaitWithoutYield(), so +// consider manually specifying the thread as uncancellable and using WaitWithoutYield() instead if you need +// to do a lot of no-cancel waits in a tight loop worker thread, for example. +// +// I'm unsure how to do this with pure Mach primitives, the docs in +// osfmk/man seem a bit out of date so perhaps there's a possibility, but +// since as far as I know Mach threads are 1-to-1 on BSD uthreads (and thus +// POSIX threads), this should work. -- aktau +void Threading::Semaphore::WaitNoCancel() +{ + int oldstate; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); + Wait(); + pthread_setcancelstate(oldstate, NULL); +} + +void Threading::Semaphore::WaitNoCancel(const wxTimeSpan& timeout) +{ + int oldstate; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); + Wait(timeout); + pthread_setcancelstate(oldstate, NULL); +} + +int Threading::Semaphore::Count() +{ + return __atomic_load_n(&m_counter, __ATOMIC_SEQ_CST); +} diff --git a/common/src/Utilities/Darwin/DarwinThreads.cpp b/common/src/Utilities/Darwin/DarwinThreads.cpp new file mode 100644 index 0000000000..6fb6520a43 --- /dev/null +++ b/common/src/Utilities/Darwin/DarwinThreads.cpp @@ -0,0 +1,133 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2014 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "../PrecompiledHeader.h" +#include "PersistentThread.h" + +#include + +#if !defined(__APPLE__) +# error "DarwinThreads.cpp should only be compiled by projects or makefiles targeted at OSX." +#else + +#include +#include +#include + +// Note: assuming multicore is safer because it forces the interlocked routines to use +// the LOCK prefix. The prefix works on single core CPUs fine (but is slow), but not +// having the LOCK prefix is very bad indeed. + +__forceinline void Threading::Sleep( int ms ) +{ + usleep(1000 * ms); +} + +// For use in spin/wait loops, acts as a hint to Intel CPUs and should, in theory +// improve performance and reduce cpu power consumption. +__forceinline void Threading::SpinWait() +{ + // If this doesn't compile you can just comment it out (it only serves as a + // performance hint and isn't required). + __asm__ ( "pause" ); +} + +__forceinline void Threading::EnableHiresScheduler() +{ + // Darwin has customizable schedulers, see xnu/osfmk/man. Not + // implemented yet though (and not sure if useful for pcsx2). +} + +__forceinline void Threading::DisableHiresScheduler() +{ + // see EnableHiresScheduler() +} + +// Just like on Windows, this is not really the number of ticks per second, +// but just a factor by which one has to divide GetThreadCpuTime() or +// pxThread::GetCpuTime() if one wants to receive a value in seconds. NOTE: +// doing this will of course yield precision loss. +u64 Threading::GetThreadTicksPerSecond() +{ + return 1000000; // the *CpuTime() functions return values in microseconds +} + +// gets the CPU time used by the current thread (both system and user), in +// microseconds, returns 0 on failure +static u64 getthreadtime(thread_port_t thread) { + mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; + thread_basic_info_data_t info; + + kern_return_t kr = thread_info(thread, THREAD_BASIC_INFO, + (thread_info_t) &info, &count); + if (kr != KERN_SUCCESS) { + return 0; + } + + // add system and user time + return (u64) info.user_time.seconds * (u64) 1e6 + + (u64) info.user_time.microseconds + + (u64) info.system_time.seconds * (u64) 1e6 + + (u64) info.system_time.microseconds; +} + +// Returns the current timestamp (not relative to a real world clock) in +// units of 100 nanoseconds. The weird units are to mirror the Windows +// counterpart in WinThreads.cpp, which uses the GetThreadTimes() API. On +// OSX/Darwin, this is only accurate up until 1ms (and possibly less), so +// not very good. +u64 Threading::GetThreadCpuTime() +{ + // we could also use mach_thread_self() and mach_port_deallocate(), but + // that calls upon mach traps (kinda like system calls). Unless I missed + // something in the COMMPAGE (like Linux vDSO) which makes overrides it + // to be user-space instead. In contract, + // pthread_mach_thread_np(pthread_self()) is entirely in user-space. + u64 us = getthreadtime(pthread_mach_thread_np(pthread_self())); + return us * 10ULL; +} + +u64 Threading::pxThread::GetCpuTime() const +{ + // Get the cpu time for the thread belonging to this object. Use m_native_id and/or + // m_native_handle to implement it. Return value should be a measure of total time the + // thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(), + // which typically would be an OS-provided scalar or some sort). + if (!m_native_id) { + return 0; + } + + return getthreadtime((thread_port_t) m_native_id) * 10ULL; +} + +void Threading::pxThread::_platform_specific_OnStartInThread() +{ + m_native_id = (uptr) mach_thread_self(); +} + +void Threading::pxThread::_platform_specific_OnCleanupInThread() +{ + // cleanup of handles that were upened in + // _platform_specific_OnStartInThread + mach_port_deallocate(mach_task_self(), (thread_port_t) m_native_id); +} + +// name can be up to 16 bytes +void Threading::pxThread::_DoSetThreadName(const char *name) +{ + pthread_setname_np(name); +} + +#endif diff --git a/common/src/Utilities/Linux/LnxHostSys.cpp b/common/src/Utilities/Linux/LnxHostSys.cpp index 2213b23139..d400411e0e 100644 --- a/common/src/Utilities/Linux/LnxHostSys.cpp +++ b/common/src/Utilities/Linux/LnxHostSys.cpp @@ -24,6 +24,12 @@ #include #include +// Apple uses the MAP_ANON define instead of MAP_ANONYMOUS, but they mean +// the same thing. +#if defined(__APPLE__) && !defined(MAP_ANONYMOUS) +# define MAP_ANONYMOUS MAP_ANON +#endif + extern void SignalExit(int sig); static const uptr m_pagemask = getpagesize()-1; diff --git a/common/src/Utilities/Mutex.cpp b/common/src/Utilities/Mutex.cpp index fdcd5b7f19..19d0735c16 100644 --- a/common/src/Utilities/Mutex.cpp +++ b/common/src/Utilities/Mutex.cpp @@ -31,6 +31,57 @@ namespace Threading // Mutex Implementations // -------------------------------------------------------------------------------------- +#if defined(_WIN32) || (defined(_POSIX_TIMEOUTS) && _POSIX_TIMEOUTS >= 200112L) +// good, we have pthread_mutex_timedlock +#define xpthread_mutex_timedlock pthread_mutex_timedlock +#else +// We have to emulate pthread_mutex_timedlock(). This could be a serious +// performance drain if its used a lot. + +#include // gettimeofday() + +// sleep for 10ms at a time +#define TIMEDLOCK_EMU_SLEEP_NS 10000000ULL + +// Original POSIX docs: +// +// The pthread_mutex_timedlock() function shall lock the mutex object +// referenced by mutex. If the mutex is already locked, the calling thread +// shall block until the mutex becomes available as in the +// pthread_mutex_lock() function. If the mutex cannot be locked without +// waiting for another thread to unlock the mutex, this wait shall be +// terminated when the specified timeout expires. +// +// This is an implementation that emulates pthread_mutex_timedlock() via +// pthread_mutex_trylock(). +static int xpthread_mutex_timedlock( + pthread_mutex_t *mutex, + const struct timespec *abs_timeout) +{ + int err = 0; + + while ((err = pthread_mutex_trylock(mutex)) == EBUSY) { + // acquiring lock failed, sleep some + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = TIMEDLOCK_EMU_SLEEP_NS; + int status; + while ((status = nanosleep(&ts, &ts)) == -1); + + // check if the timeout has expired, gettimeofday() is implemented + // efficiently (in userspace) on OSX + struct timeval now; + int res = gettimeofday(&now, NULL); + if (abs_timeout->tv_sec == 0 || now.tv_sec > abs_timeout->tv_sec || + (u64) now.tv_usec * 1000ULL > (u64) abs_timeout->tv_nsec) { + return ETIMEDOUT; + } + } + + return err; +} +#endif + Threading::Mutex::Mutex() { pthread_mutex_init( &m_mutex, NULL ); @@ -125,7 +176,7 @@ bool Threading::Mutex::AcquireWithoutYield( const wxTimeSpan& timeout ) { wxDateTime megafail( wxDateTime::UNow() + timeout ); const timespec fail = { megafail.GetTicks(), megafail.GetMillisecond() * 1000000 }; - return pthread_mutex_timedlock( &m_mutex, &fail ) == 0; + return xpthread_mutex_timedlock( &m_mutex, &fail ) == 0; } void Threading::Mutex::Release() diff --git a/pcsx2/AsyncFileReader.h b/pcsx2/AsyncFileReader.h index 4eca98e9a5..ef691b009d 100644 --- a/pcsx2/AsyncFileReader.h +++ b/pcsx2/AsyncFileReader.h @@ -18,8 +18,10 @@ #ifdef WIN32 # include # undef Yield -#else +#elif defined(__linux__) # include +#elif defined(__APPLE__) +# include #endif class AsyncFileReader @@ -70,9 +72,12 @@ class FlatFileReader : public AsyncFileReader HANDLE hEvent; bool asyncInProgress; -#else +#elif defined(__linux__) int m_fd; // FIXME don't know if overlap as an equivalent on linux io_context_t m_aio_context; +#elif defined(__POSIX__) + int m_fd; // TODO OSX don't know if overlap as an equivalent on OSX + struct aiocb m_aio_context; #endif bool shareWrite; diff --git a/pcsx2/CDVD/CsoFileReader.cpp b/pcsx2/CDVD/CsoFileReader.cpp index 9105e34bc3..bf200e00e9 100644 --- a/pcsx2/CDVD/CsoFileReader.cpp +++ b/pcsx2/CDVD/CsoFileReader.cpp @@ -18,7 +18,7 @@ #include "CompressedFileReaderUtils.h" #include "CsoFileReader.h" #include "Pcsx2Types.h" -#ifdef __linux__ +#ifdef __POSIX__ #include #else #include diff --git a/pcsx2/CDVD/zlib_indexed.h b/pcsx2/CDVD/zlib_indexed.h index 4fc9496b15..f9c8efae84 100644 --- a/pcsx2/CDVD/zlib_indexed.h +++ b/pcsx2/CDVD/zlib_indexed.h @@ -101,7 +101,7 @@ Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 #include #include #include -#ifdef __linux__ +#ifdef __POSIX__ #include #else #include diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index b33c43d7d8..60e92a500f 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -63,7 +63,7 @@ set(pcsx2Sources FiFo.cpp FPU.cpp Gif.cpp - Gif_Logger.cpp + Gif_Logger.cpp Gif_Unit.cpp GS.cpp GSState.cpp @@ -82,9 +82,9 @@ set(pcsx2Sources Memory.cpp MMI.cpp MTGS.cpp - MTVU.cpp - MultipartFileReader.cpp - OutputIsoFile.cpp + MTVU.cpp + MultipartFileReader.cpp + OutputIsoFile.cpp Patch.cpp Patch_Memory.cpp Pcsx2Config.cpp @@ -149,7 +149,7 @@ set(pcsx2Headers IopMem.h IopSio2.h # Mdec.h - MTVU.h + MTVU.h Memory.h MemoryTypes.h NakedAsm.h @@ -402,6 +402,12 @@ set(pcsx2LinuxSources Linux/LnxFlatFileReader.cpp ) +set(pcsx2OSXSources +# Linux/LnxConsolePipe.cpp +# Linux/LnxKeyCodes.cpp + Darwin/DarwinFlatFileReader.cpp + ) + # Linux headers set(pcsx2LinuxHeaders ) @@ -588,7 +594,7 @@ set(Common ${pcsx2CDVDHeaders} ${pcsx2DebugToolsSources} ${pcsx2GuiSources} - ${pcsx2GuiResources} + ${pcsx2GuiResources} ${pcsx2GuiHeaders} ${pcsx2IPUSources} ${pcsx2IPUHeaders} @@ -620,9 +626,10 @@ if(Windows) endif() # MacOSX -if(MacOSX) +if(APPLE) set(Platform - ) + ${pcsx2OSXSources} + ${pcsx2LinuxHeaders}) endif() set(pcsx2FinalSources diff --git a/pcsx2/Darwin/DarwinFlatFileReader.cpp b/pcsx2/Darwin/DarwinFlatFileReader.cpp new file mode 100644 index 0000000000..6e2efb8936 --- /dev/null +++ b/pcsx2/Darwin/DarwinFlatFileReader.cpp @@ -0,0 +1,112 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2014 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#include "PrecompiledHeader.h" +#include "AsyncFileReader.h" + +#warning This reader is not yet implemented. Crash boom bang if used + +//FlatFileReader::FlatFileReader(void) +FlatFileReader::FlatFileReader(bool shareWrite) : shareWrite(shareWrite) +{ + printf("FLATC\n"); + m_blocksize = 2048; + m_fd = 0; + //m_aio_context = 0; +} + +FlatFileReader::~FlatFileReader(void) +{ + Close(); +} + +bool FlatFileReader::Open(const wxString& fileName) +{ + printf("OB\n"); + m_filename = fileName; + + int err = 0; //io_setup(64, &m_aio_context); + if (err) return false; + + m_fd = wxOpen(fileName, O_RDONLY, 0); + + return (m_fd != 0); +} + +int FlatFileReader::ReadSync(void* pBuffer, uint sector, uint count) +{ + printf("RAD\n"); + BeginRead(pBuffer, sector, count); + return FinishRead(); +} + +void FlatFileReader::BeginRead(void* pBuffer, uint sector, uint count) +{ + printf("RWEADB\n"); + u64 offset; + offset = sector * (u64)m_blocksize + m_dataoffset; + + u32 bytesToRead = count * m_blocksize; + + struct aiocb iocb; + struct aiocb* iocbs = &iocb; + + //io_prep_pread(&iocb, m_fd, pBuffer, bytesToRead, offset); + //io_submit(m_aio_context, 1, &iocbs); +} + +int FlatFileReader::FinishRead(void) +{ + printf("FINISH\n"); + u32 bytes; + + int min_nr = 1; + int max_nr = 1; + /* struct io_event* events = new io_event[max_nr]; + + int event = io_getevents(m_aio_context, min_nr, max_nr, events, NULL); + if (event < 1) { + return -1; + }*/ + + return 1; +} + +void FlatFileReader::CancelRead(void) +{ + printf("CANCEL\n"); + // Will be done when m_aio_context context is destroyed + // Note: io_cancel exists but need the iocb structure as parameter + // int io_cancel(aio_context_t ctx_id, struct iocb *iocb, + // struct io_event *result); +} + +void FlatFileReader::Close(void) +{ + printf("CLOSE\n"); + if (m_fd) close(m_fd); + + //io_destroy(m_aio_context); + aio_cancel(m_fd, &m_aio_context); + + m_fd = 0; + //m_aio_context = 0; +} + +uint FlatFileReader::GetBlockCount(void) const +{ + printf("BLOCKS\n"); + return (int)(Path::GetFileSize(m_filename) / m_blocksize); +} diff --git a/pcsx2/DebugTools/Debug.h b/pcsx2/DebugTools/Debug.h index a55c0080ac..f6f6149aa6 100644 --- a/pcsx2/DebugTools/Debug.h +++ b/pcsx2/DebugTools/Debug.h @@ -335,6 +335,14 @@ extern void __Log( const char* fmt, ... ); # define SysTraceActive(trace) (false) #endif +#ifdef __WXMAC__ + // Not available on OSX, apparently always double buffered window. +# define SetDoubleBuffered(x) + + // TODO OSX OsxKeyCodes.cpp pending +# define NewPipeRedir(x) NULL +#endif + #define macTrace(trace) SysTraceActive(trace) && SysTrace.trace.Write #define SIF_LOG macTrace(SIF) diff --git a/pcsx2/IPU/yuv2rgb.cpp b/pcsx2/IPU/yuv2rgb.cpp index 065cb35a20..5fae01f7b6 100644 --- a/pcsx2/IPU/yuv2rgb.cpp +++ b/pcsx2/IPU/yuv2rgb.cpp @@ -58,7 +58,13 @@ void yuv2rgb_reference(void) } } -#ifdef _M_X86_32 +// TODO OSX optimize me +#ifdef __APPLE__ +void yuv2rgb_sse2() { + yuv2rgb_reference(); +} + +#elif defined(_M_X86_32) // Everything below is bit accurate to the IPU specification (except maybe rounding). // Know the specification before you touch it. #define SSE_BYTES(x) {x, x, x, x, x, x, x, x, x, x, x, x, x, x, x, x} diff --git a/pcsx2/NakedAsm.h b/pcsx2/NakedAsm.h index 4589bccc02..b8cd585c40 100644 --- a/pcsx2/NakedAsm.h +++ b/pcsx2/NakedAsm.h @@ -17,7 +17,7 @@ #ifndef NAKED_ASM_H #define NAKED_ASM_H -#ifdef __linux__ +#ifdef __POSIX__ extern "C" { diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp index 3f4ecd5a5d..854566e7b8 100644 --- a/pcsx2/gui/AppMain.cpp +++ b/pcsx2/gui/AppMain.cpp @@ -50,6 +50,19 @@ #include #endif +// Safe to remove these lines when this is handled properly. +#ifdef __WXMAC__ +// Great joy.... +#undef EBP +#undef ESP +#undef EDI +#undef ESI +#undef EDX +#undef EAX +#undef EBX +#undef ECX +#include // needed to implement the app! +#endif IMPLEMENT_APP(Pcsx2App) @@ -277,6 +290,8 @@ void Pcsx2App::PadKeyDispatch( const keyEvent& ev ) //returns 0 for normal keys and a WXK_* value for special keys #ifdef __WXMSW__ const int vkey = TranslateVKToWXK(ev.key); +#elif defined( __WXMAC__ ) + const int vkey = wxCharCodeWXToOSX( (wxKeyCode) ev.key ); #elif defined( __WXGTK__ ) const int vkey = TranslateGDKtoWXK( ev.key ); #else @@ -415,7 +430,7 @@ public: return Path::Combine( GetDataDir(), L"Langs" ); } -#ifdef __linux__ +#ifdef __POSIX__ wxString GetUserLocalDataDir() const { // I got memory corruption inside wxGetEnv when I heavily toggle the GS renderer (F9). It seems wxGetEnv diff --git a/pcsx2/gui/CpuUsageProvider.cpp b/pcsx2/gui/CpuUsageProvider.cpp index 4ee87d0a89..1e13623912 100644 --- a/pcsx2/gui/CpuUsageProvider.cpp +++ b/pcsx2/gui/CpuUsageProvider.cpp @@ -18,7 +18,7 @@ #include "CpuUsageProvider.h" #include "System.h" -#ifndef __linux__ +#ifndef __POSIX__ #include "SysThreads.h" #endif diff --git a/pcsx2/x86/aVUzerorec.S b/pcsx2/x86/aVUzerorec.S index 472eeacb3b..37cd85b658 100644 --- a/pcsx2/x86/aVUzerorec.S +++ b/pcsx2/x86/aVUzerorec.S @@ -1,7 +1,34 @@ // iVUzerorec.cpp assembly routines // zerofrog(@gmail.com) -.intel_syntax noprefix + +#ifdef __APPLE__ + #define svudispfntemp _svudispfntemp + #define s_TotalVUCycles _s_TotalVUCycles + #define s_callstack _s_callstack + #define s_vu1ebp _s_vu1ebp + #define s_vu1esp _s_vu1esp + #define s_vu1esi _s_vu1esi + #define s_vuedi _s_vuedi + #define s_vuebx _s_vuebx + #define s_saveebx _s_saveebx + #define s_saveecx _s_saveecx + #define s_saveedx _s_saveedx + #define s_saveesi _s_saveesi + #define s_saveedi _s_saveedi + #define s_saveebp _s_saveebp + #define s_writeQ _s_writeQ + #define s_writeP _s_writeP + #define g_curdebugvu _g_curdebugvu + #define SuperVUGetProgram _SuperVUGetProgram + #define SuperVUCleanupProgram _SuperVUCleanupProgram + #define SuperVUExecuteProgram _SuperVUExecuteProgram + #define SuperVUEndProgram _SuperVUEndProgram + #define g_sseVUMXCSR _g_sseVUMXCSR + #define g_sseMXCSR _g_sseMXCSR +#endif + +.intel_syntax noprefix .extern s_TotalVUCycles .extern s_callstack .extern s_vu1esp @@ -26,7 +53,7 @@ SuperVUExecuteProgram: mov s_vuebx, ebx mov s_vu1esp, esp - and esp, -16 // align stack for GCC compilance + and esp, -16 // align stack for GCC compilance ldmxcsr g_sseVUMXCSR mov dword ptr s_writeQ, 0xffffffff @@ -35,17 +62,17 @@ SuperVUExecuteProgram: .globl SuperVUEndProgram SuperVUEndProgram: - // restore cpu state - ldmxcsr g_sseMXCSR - mov esi, s_vu1esi - mov edi, s_vuedi - mov ebx, s_vuebx - + // restore cpu state + ldmxcsr g_sseMXCSR + mov esi, s_vu1esi + mov edi, s_vuedi + mov ebx, s_vuebx + mov esp, s_vu1esp - call SuperVUCleanupProgram - jmp [s_callstack] // so returns correctly + call SuperVUCleanupProgram + jmp [s_callstack] // so returns correctly -#if defined(__linux__) && defined(__ELF__) +#if defined(__POSIX__) && defined(__ELF__) .section .note.GNU-stack,"",%progbits #endif diff --git a/pcsx2/x86/sVU_zerorec.h b/pcsx2/x86/sVU_zerorec.h index 07f5a9913f..15a64a8daa 100644 --- a/pcsx2/x86/sVU_zerorec.h +++ b/pcsx2/x86/sVU_zerorec.h @@ -20,13 +20,13 @@ #include "sVU_Micro.h" //Using assembly code from an external file. -#ifdef __linux__ +#ifdef __POSIX__ extern "C" { #endif extern void SuperVUExecuteProgram(u32 startpc, int vuindex); extern void SuperVUEndProgram(); extern void svudispfntemp(); -#ifdef __linux__ +#ifdef __POSIX__ } #endif diff --git a/plugins/spu2-x/src/Config.h b/plugins/spu2-x/src/Config.h index 68a8fbe03c..f8ff31fe5f 100644 --- a/plugins/spu2-x/src/Config.h +++ b/plugins/spu2-x/src/Config.h @@ -83,7 +83,7 @@ extern u32 OutputModule; extern int SndOutLatencyMS; extern int SynchMode; -#ifndef __linux__ +#ifndef __POSIX__ extern wchar_t dspPlugin[]; extern int dspPluginModule; diff --git a/plugins/spu2-x/src/Global.h b/plugins/spu2-x/src/Global.h index e08f48544c..b8eda4d429 100644 --- a/plugins/spu2-x/src/Global.h +++ b/plugins/spu2-x/src/Global.h @@ -68,7 +68,11 @@ static __forceinline T GetClamped( T src, T min, T max ) return std::min( std::max( src, min ), max ); } +#ifdef __WXMAC__ +#include "PS2Eext.h" +#else extern void SysMessage(const char *fmt, ...); +#endif extern void SysMessage(const wchar_t *fmt, ...); ////////////////////////////////////////////////////////////// diff --git a/plugins/spu2-x/src/Linux/Alsa.cpp b/plugins/spu2-x/src/Linux/Alsa.cpp index 093c95adba..7a67c7501a 100644 --- a/plugins/spu2-x/src/Linux/Alsa.cpp +++ b/plugins/spu2-x/src/Linux/Alsa.cpp @@ -17,6 +17,8 @@ // Adapted from ZeroSPU2 code by Zerofrog. Heavily modified by Arcum42. +#ifdef __linux__ + #include #include "Global.h" @@ -260,3 +262,5 @@ public: } static Alsa; SndOutModule *AlsaOut = &Alsa; + +#endif diff --git a/plugins/spu2-x/src/Linux/Config.cpp b/plugins/spu2-x/src/Linux/Config.cpp index 0dadeebc6f..701d753cc0 100644 --- a/plugins/spu2-x/src/Linux/Config.cpp +++ b/plugins/spu2-x/src/Linux/Config.cpp @@ -141,7 +141,9 @@ void ReadSettings() SynchMode = CfgReadInt( L"OUTPUT", L"Synch_Mode", 0); PortaudioOut->ReadSettings(); +#ifndef __APPLE__ SDLOut->ReadSettings(); +#endif SoundtouchCfg::ReadSettings(); DebugConfig::ReadSettings(); @@ -185,7 +187,9 @@ void WriteSettings() CfgWriteInt(L"DEBUG", L"DelayCycles", delayCycles); PortaudioOut->WriteSettings(); +#ifndef __APPLE__ SDLOut->WriteSettings(); +#endif SoundtouchCfg::WriteSettings(); DebugConfig::WriteSettings(); } @@ -200,6 +204,7 @@ void debug_dialog() DebugConfig::DisplayDialog(); } +#ifdef __linux__ void DisplayDialog() { int return_value; @@ -379,6 +384,12 @@ void DisplayDialog() gtk_widget_destroy (dialog); } +#else +void DisplayDialog() +{ + +} +#endif void configure() { diff --git a/plugins/spu2-x/src/Linux/Config.h b/plugins/spu2-x/src/Linux/Config.h index d17980dc2b..538f445e83 100644 --- a/plugins/spu2-x/src/Linux/Config.h +++ b/plugins/spu2-x/src/Linux/Config.h @@ -18,7 +18,10 @@ #ifndef CONFIG_H_INCLUDED #define CONFIG_H_INCLUDED +#ifdef __linux__ #include +#endif + #include #include diff --git a/plugins/spu2-x/src/Linux/ConfigDebug.cpp b/plugins/spu2-x/src/Linux/ConfigDebug.cpp index bbeea7c1c1..249985cf8e 100644 --- a/plugins/spu2-x/src/Linux/ConfigDebug.cpp +++ b/plugins/spu2-x/src/Linux/ConfigDebug.cpp @@ -154,6 +154,7 @@ void WriteSettings() } +#ifdef __linux__ void DisplayDialog() { GtkWidget *dialog; @@ -285,5 +286,10 @@ void DisplayDialog() WriteSettings(); } - +#else +void DisplayDialog() +{ + +} +#endif } diff --git a/plugins/spu2-x/src/Linux/ConfigSoundTouch.cpp b/plugins/spu2-x/src/Linux/ConfigSoundTouch.cpp index cfa69a1242..5b06256ea8 100644 --- a/plugins/spu2-x/src/Linux/ConfigSoundTouch.cpp +++ b/plugins/spu2-x/src/Linux/ConfigSoundTouch.cpp @@ -71,9 +71,11 @@ namespace SoundtouchCfg CfgWriteInt( L"SOUNDTOUCH", L"OverlapMS", OverlapMS ); } +#ifdef __linux__ static GtkWidget *seq_label, *seek_label, *over_label; static GtkWidget *seq_slide, *seek_slide, *over_slide; + void restore_defaults() { gtk_range_set_value(GTK_RANGE(seq_slide), 30); @@ -81,6 +83,7 @@ namespace SoundtouchCfg gtk_range_set_value(GTK_RANGE(over_slide), 10); } + void DisplayDialog() { int return_value; @@ -158,4 +161,15 @@ namespace SoundtouchCfg WriteSettings(); } +#else + void DisplayDialog() + { + + } + + void restore_defaults() + { + + } +#endif } diff --git a/plugins/spu2-x/src/Linux/Dialogs.cpp b/plugins/spu2-x/src/Linux/Dialogs.cpp index 9b1ca43cea..522d9ff728 100644 --- a/plugins/spu2-x/src/Linux/Dialogs.cpp +++ b/plugins/spu2-x/src/Linux/Dialogs.cpp @@ -17,10 +17,12 @@ // To be continued... - #include "Dialogs.h" -#include +#include "Dialogs.h" #include +#ifdef __linux__ +#include + void SysMessage(const char *fmt, ...) { va_list list; @@ -59,6 +61,7 @@ void SysMessage(const wchar_t *fmt, ...) gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } +#endif void DspUpdate() { diff --git a/plugins/spu2-x/src/Mixer.cpp b/plugins/spu2-x/src/Mixer.cpp index b7799c6b2c..32f71aac0a 100644 --- a/plugins/spu2-x/src/Mixer.cpp +++ b/plugins/spu2-x/src/Mixer.cpp @@ -270,6 +270,20 @@ static __forceinline void GetNextDataDummy(V_Core& thiscore, uint voiceidx) ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// // // +#if defined(__clang__) +#include +static s32 rotr(u32 x, u32 s) +{ + //return (x >> s) | (x << (32 - s)); + return (x >> s) | (x << (sizeof(x) * CHAR_BIT - s)); +} + +static s32 rotl(u32 x, u32 s) +{ + //return (x << s) | (x >> (32 - s)); + return (x << s) | (x >> (sizeof(x) * CHAR_BIT - s)); +} +#endif static s32 __forceinline GetNoiseValues() { @@ -292,7 +306,7 @@ static s32 __forceinline GetNoiseValues() ROR eax,3 MOV Seed,eax } -#else +#elif !defined(__clang__) // Linux with GCC __asm__ ( ".intel_syntax\n" "MOV %%eax,%1\n" @@ -307,6 +321,14 @@ static s32 __forceinline GetNoiseValues() ".att_syntax\n" : "=r"(Seed) :"r"(Seed) : "%eax", "%esi" ); +#else // Clang and others + s32 s = rotr(Seed,5); + s ^= 0x9a; + s32 k = rotl(s,2); + k+=s; + k^=s; + k = rotr(k,3); + Seed=k; #endif return retval; } @@ -819,7 +841,7 @@ static int p_cachestat_counter=0; // Gcc does not want to inline it when lto is enabled because some functions growth too much. // The function is big enought to see any speed impact. -- Gregory -#ifndef __linux__ +#ifndef __POSIX__ __forceinline #endif void Mix() diff --git a/plugins/spu2-x/src/PS2E-spu2.cpp b/plugins/spu2-x/src/PS2E-spu2.cpp index ee7df1e9c6..2efbd15de3 100644 --- a/plugins/spu2-x/src/PS2E-spu2.cpp +++ b/plugins/spu2-x/src/PS2E-spu2.cpp @@ -20,6 +20,10 @@ #include "Dma.h" #include "Dialogs.h" +#ifdef __POSIX__ +#include "PS2Eext.h" +#endif + #include "svnrev.h" #ifdef _MSC_VER @@ -446,7 +450,7 @@ EXPORT_C_(s32) SPU2open(void *pDsp) { SndBuffer::Init(); -#ifndef __linux__ +#ifndef __POSIX__ DspLoadLibrary(dspPlugin,dspPluginModule); #endif WaveDump::Open(); @@ -467,7 +471,7 @@ EXPORT_C_(void) SPU2close() FileLog("[%10d] SPU2 Close\n",Cycles); -#ifndef __linux__ +#ifndef __POSIX__ DspCloseLibrary(); #endif diff --git a/plugins/spu2-x/src/PS2E-spu2.h b/plugins/spu2-x/src/PS2E-spu2.h index 7c008ab2ee..112947802c 100644 --- a/plugins/spu2-x/src/PS2E-spu2.h +++ b/plugins/spu2-x/src/PS2E-spu2.h @@ -20,7 +20,7 @@ #include "Pcsx2Defs.h" #include "PS2Edefs.h" -#ifdef __linux__ +#ifdef __POSIX__ //Until I get around to putting in Linux svn code, this is an unknown svn version. #define SVN_REV_UNKNOWN #endif @@ -51,7 +51,7 @@ EXPORT_C_(void) SPU2irqCallback(void (*SPU2callback)()); #else // These defines are useless and gcc-4.6 complain about redefinition // so we remove them on linux -#ifndef __linux__ +#ifndef __POSIX__ EXPORT_C_(void) SPU2readDMA4Mem(u16 *pMem, u32 size); EXPORT_C_(void) SPU2writeDMA4Mem(u16 *pMem, u32 size); EXPORT_C_(void) SPU2interruptDMA4(); diff --git a/plugins/spu2-x/src/SndOut.cpp b/plugins/spu2-x/src/SndOut.cpp index d76a2d48d7..34812fc90b 100644 --- a/plugins/spu2-x/src/SndOut.cpp +++ b/plugins/spu2-x/src/SndOut.cpp @@ -92,8 +92,10 @@ SndOutModule* mods[]= WaveOut, #endif PortaudioOut, -#ifdef __linux__ +#if defined(SPU2X_SDL) || defined(SPU2X_SDL2) SDLOut, +#endif +#if defined(__linux__) /* && defined(__ALSA__)*/ AlsaOut, #endif NULL // signals the end of our list @@ -465,7 +467,7 @@ void SndBuffer::Write( const StereoOut32& Sample ) ssFreeze--; memset( sndTempBuffer, 0, sizeof(StereoOut32) * SndOutPacketSize ); // Play silence } -#ifndef __linux__ +#ifndef __POSIX__ if( dspPluginEnabled ) { // Convert in, send to winamp DSP, and convert out. diff --git a/plugins/spu2-x/src/SndOut.h b/plugins/spu2-x/src/SndOut.h index c64062c3a4..520e08572b 100644 --- a/plugins/spu2-x/src/SndOut.h +++ b/plugins/spu2-x/src/SndOut.h @@ -673,8 +673,10 @@ extern SndOutModule* DSoundOut; extern SndOutModule* XAudio2Out; #endif extern SndOutModule* PortaudioOut; -#ifdef __linux__ +#if defined(SPU2X_SDL) || defined(SPU2X_SDL2) extern SndOutModule * const SDLOut; +#endif +#ifdef __linux__ extern SndOutModule* AlsaOut; #endif diff --git a/plugins/spu2-x/src/SndOut_Portaudio.cpp b/plugins/spu2-x/src/SndOut_Portaudio.cpp index e42c77f7db..d0cfeeafda 100644 --- a/plugins/spu2-x/src/SndOut_Portaudio.cpp +++ b/plugins/spu2-x/src/SndOut_Portaudio.cpp @@ -588,6 +588,9 @@ public: #ifdef __linux__ // By default on linux use the ALSA API (+99% users) -- Gregory CfgReadStr( L"PORTAUDIO", L"HostApi", api, L"ALSA" ); +#elif defined(__APPLE__) + // Suppose OSX only has CoreAudio... + CfgReadStr( L"PORTAUDIO", L"HostApi", api, L"CoreAudio" ); #else CfgReadStr( L"PORTAUDIO", L"HostApi", api, L"WASAPI" ); #endif diff --git a/plugins/spu2-x/src/Wavedump_wav.cpp b/plugins/spu2-x/src/Wavedump_wav.cpp index 17e37f9ffd..90f2fc9aad 100644 --- a/plugins/spu2-x/src/Wavedump_wav.cpp +++ b/plugins/spu2-x/src/Wavedump_wav.cpp @@ -16,7 +16,7 @@ */ #include "Global.h" -#ifdef __linux__ +#ifdef __POSIX__ #include "WavFile.h" #else #include "soundtouch/source/SoundStretch/WavFile.h" @@ -53,7 +53,7 @@ namespace WaveDump for( int srcidx=0; srcidx